diff --git a/colour/colour.go b/colour/colour.go new file mode 100644 index 0000000..dfbe303 --- /dev/null +++ b/colour/colour.go @@ -0,0 +1,11 @@ +package colour + +var Reset = "\033[0m" +var Red = "\033[31m" +var Green = "\033[32m" +var Yellow = "\033[33m" +var Blue = "\033[34m" +var Purple = "\033[35m" +var Cyan = "\033[36m" +var Gray = "\033[37m" +var White = "\033[97m" diff --git a/twitch/api.go b/twitch/api.go index 2346947..8284b16 100644 --- a/twitch/api.go +++ b/twitch/api.go @@ -13,6 +13,7 @@ import ( "path" "strconv" + "codeberg.org/arimelody/ari-stream-tools/colour" "codeberg.org/arimelody/ari-stream-tools/twitch/api" ) @@ -76,14 +77,20 @@ func (srv *Service) handleNotification(payload *api.EventSubPayload) error { switch payload.Subscription.Type { - case "channel.follow": + case api.CHANNEL_FOLLOW: var event api.FollowEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.FollowEvent: %v", err) } - log.Printf("New follow: %s", event.UserName) + log.Printf("%sFollowed: %s%s", colour.Green, event.UserName, colour.Reset) + srv.labels.LatestFollower.Text = event.UserName srv.labels.LatestFollower.C <- event.UserName + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("New Follow: %s", event.UserName), + Type: SYSTEM_CHAT_FOLLOW, + } + if err := os.WriteFile( path.Join(DATA_PATH, "state", LABEL_LATEST_FOLLOWER), []byte(event.UserName), 0640, @@ -91,14 +98,46 @@ func (srv *Service) handleNotification(payload *api.EventSubPayload) error { return fmt.Errorf("Failed to write %s state: %v", LABEL_LATEST_FOLLOWER, err) } - case "channel.subscribe": + case api.CHANNEL_SUBSCRIBE: var event api.SubscribeEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.SubscribeEvent: %v", err) } - log.Printf("New subscription: %s", event.UserName) + log.Printf("%sSubscribed: %s%s", colour.Purple, event.UserName, colour.Reset) + srv.labels.LatestSubscriber.Text = event.UserName srv.labels.LatestSubscriber.C <- event.UserName + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("New Sub: %s", event.UserName), + Type: SYSTEM_CHAT_SUBSCRIBE, + } + + if err := os.WriteFile( + path.Join(DATA_PATH, "state", LABEL_LATEST_SUBSCRIBER), + []byte(event.UserName), 0640, + ); err != nil { + return fmt.Errorf("Failed to write %s state: %v", LABEL_LATEST_SUBSCRIBER, err) + } + case api.CHANNEL_SUBSCRIPTION_MESSAGE: + var event api.SubscribeMessageEvent + err := json.Unmarshal(jsonData, &event) + if err != nil { return fmt.Errorf("Failed to cast to api.SubscribeMessageEvent: %v", err) } + log.Printf("%sResub: %s x%d%s", colour.Purple, event.UserName, event.CumulativeMonths, colour.Reset) + if event.StreakMonths > 1 { + log.Printf("%s is on a %d-month streak!", event.UserName, event.StreakMonths) + } + if len(event.Message.Text) > 0 { + log.Printf("%s: %s", event.UserLogin, event.Message.Text) + } + + srv.labels.LatestSubscriber.Text = event.UserName + srv.labels.LatestSubscriber.C <- event.UserName + + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("Resub: %s x%d", event.UserName, event.CumulativeMonths), + Type: SYSTEM_CHAT_SUBSCRIBE, + } + if err := os.WriteFile( path.Join(DATA_PATH, "state", LABEL_LATEST_SUBSCRIBER), []byte(event.UserName), 0640, @@ -106,14 +145,19 @@ func (srv *Service) handleNotification(payload *api.EventSubPayload) error { return fmt.Errorf("Failed to write %s state: %v", LABEL_LATEST_SUBSCRIBER, err) } - case "channel.cheer": + case api.CHANNEL_CHEER: var event api.CheerEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.CheerEvent: %v", err) } - log.Printf("%s cheered x%d bits: %s", event.UserName, event.Bits, event.Message) + log.Printf("%s%s cheered x%d bits:%s %s", colour.Cyan, event.UserName, event.Bits, colour.Reset, event.Message) srv.labels.LatestCheer.Text = event.UserName srv.labels.LatestCheer.C <- event.UserName + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("Cheer x%d %s: %s", event.Bits, event.UserName, event.Message), + Type: SYSTEM_CHAT_CHEER, + } + if err := os.WriteFile( path.Join(DATA_PATH, "state", LABEL_LATEST_CHEER), []byte(event.UserName), 0640, @@ -121,54 +165,117 @@ func (srv *Service) handleNotification(payload *api.EventSubPayload) error { return fmt.Errorf("Failed to write %s state: %v", LABEL_LATEST_CHEER, err) } - case "channel.raid": + case api.CHANNEL_RAID: var event api.RaidEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.RaidEvent: %v", err) } - log.Printf("%s is now raiding with %d viewers!", event.FromUserName, event.Viewers) + log.Printf("%sRAID: %s with %d viewers!%s", colour.Red, event.FromUserName, event.Viewers, colour.Reset) - case "channel.channel_points_custom_reward_redemption.add": + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("%s raiding with %d viewers!", event.FromUserName, event.Viewers), + Type: SYSTEM_CHAT_RAID, + } + + case api.CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD: var event api.ChannelPointCustomRewardRedeemEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.ChannelPointCustomRewardRedeemEvent: %v", err) } log.Printf( - "%s just redeemed %s for %d channel points.", + "%s redeemed %s for %d channel points.", event.UserName, event.Reward.Title, event.Reward.Cost, ) - case "channel.shoutout.create": + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("%s redeemed %s", event.UserName, event.Reward.Title), + Type: SYSTEM_CHAT_POINT_REDEEM, + } + + case api.SHOUTOUT_CREATE: var event api.ShoutoutCreate err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.ShoutoutCreate: %v", err) } - log.Printf( - "%s gave a shoutout to %s.", - event.FromUserName, - event.ToUserName, - ) + log.Printf("%s%s shouted out %s!%s", colour.Yellow, event.FromUserName, event.ToUserName, colour.Reset) - case "channel.chat.message": + srv.SystemChatC <- &systemChatMessage{ + Text: fmt.Sprintf("Shoutout %s!", event.ToUserName), + Type: SYSTEM_CHAT_SHOUTOUT, + } + + case api.CHANNEL_CHAT_MESSAGE: var event api.ChatEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.ChatEvent: %v", err) } - if event.Cheer != nil { return nil } - log.Printf( - "[%s] %s: %s", - event.MessageID, - event.ChatterLogin, - event.Message.Text, - ) - case "channel.chat.message_delete": + if event.Cheer != nil { return nil } + var modifier ChatMessageModifier = CHAT_MODIFIER_NONE + + if event.MessageType == api.MESSAGE_CHANNEL_POINTS_HIGHLIGHTED { + modifier = CHAT_MODIFIER_HIGHLIGHT + log.Printf("Highlighted from %s: %s", event.ChatterLogin, event.Message.Text) + } else { + log.Printf("%s: %s", event.ChatterLogin, event.Message.Text) + } + + srv.ChatC <- &chatMessage{ + ID: event.MessageID, + Username: event.ChatterLogin, + Colour: event.Color, + Text: event.Message.Text, + Fragments: event.Message.Fragments, + Modifier: modifier, + } + + case api.CHANNEL_CHAT_MESSAGE_DELETE: var event api.ChatDeleteEvent err := json.Unmarshal(jsonData, &event) if err != nil { return fmt.Errorf("Failed to cast to api.ChatDeleteEvent: %v", err) } - log.Printf( - "Message %s by %s deleted.", - event.MessageID, - event.TargetLogin, - ) + log.Printf("Message %s deleted.", event.TargetLogin) + srv.DeleteChatC <- &deleteChatMessage{ + Username: "", + MessageID: event.MessageID, + } + + case api.CHANNEL_CHAT_NOTIFICATION: + var event api.ChatNotificationEvent + err := json.Unmarshal(jsonData, &event) + if err != nil { return fmt.Errorf("Failed to cast to api.ChatNotificationEvent: %v", err) } + switch event.NoticeType { + case api.NOTICE_ANNOUNCEMENT: + log.Printf("%sANNOUNCEMENT from %s:%s %s", colour.Yellow, event.ChatterName, colour.Reset, event.Message.Text) + srv.ChatC <- &chatMessage{ + ID: event.MessageID, + Username: event.ChatterName, + Colour: event.Color, + Text: event.Message.Text, + Fragments: event.Message.Fragments, + + Modifier: CHAT_MODIFIER_ANNOUNCEMENT, + AnnouncementColour: event.Announcement.Color, + } + } + + case api.CHANNEL_CHAT_CLEAR: + log.Printf("Chat cleared.") + srv.DeleteChatC <- &deleteChatMessage{ + Username: "*", + MessageID: "*", + } + case api.CHANNEL_CHAT_CLEAR_USER_MESSAGES: + var event api.ChatClearUserMessagesEvent + err := json.Unmarshal(jsonData, &event) + if err != nil { return fmt.Errorf("Failed to cast to api.ChatClearUserMessagesEvent: %v", err) } + log.Printf("Messages from %s cleared.", event.TargetName) + srv.DeleteChatC <- &deleteChatMessage{ + Username: event.TargetName, + MessageID: "*", + } + + // TODO: polls (creation and results) + + default: + log.Printf("Unhandled message type %s.", payload.Subscription.Type) } @@ -177,7 +284,7 @@ func (srv *Service) handleNotification(payload *api.EventSubPayload) error { func (srv *Service) subscribeToEvent( ctx context.Context, - subscriptionType string, + subscriptionType api.SubscriptionType, version string, condition map[string]string, sessionID string, @@ -189,7 +296,7 @@ func (srv *Service) subscribeToEvent( } Request struct { - Type string `json:"type"` + Type api.SubscriptionType `json:"type"` Version string `json:"version"` Condition map[string]string `json:"condition"` Transport Transport `json:"transport"` @@ -247,90 +354,154 @@ func (srv *Service) subscribeToEvent( return nil } +// Calls subscribeToEvent with helpful logging +func (srv *Service) subscribeToEventHelper( + ctx context.Context, + subscriptionType api.SubscriptionType, + version string, + condition map[string]string, + sessionID string, +) { + if err := srv.subscribeToEvent(ctx, subscriptionType, version, condition, sessionID); err != nil { + log.Printf("Failed to subscribe to %s: %v", subscriptionType, err) + } +} + func (srv *Service) subscribeToDefaultEvents(ctx context.Context) { - // channel.follow - if err := srv.subscribeToEvent( - ctx, "channel.follow", "2", + // Channel Updates + srv.subscribeToEventHelper( + ctx, api.CHANNEL_UPDATE, "2", + map[string]string{ + "broadcaster_user_id": srv.channelID, + }, + srv.eventSubSession.ID, + ) + + // Follows + srv.subscribeToEventHelper( + ctx, api.CHANNEL_FOLLOW, "2", map[string]string{ "broadcaster_user_id": srv.channelID, "moderator_user_id": srv.channelID, }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.follow: %v", err) - } + ) - // channel.subscribe - if err := srv.subscribeToEvent( - ctx, "channel.subscribe", "1", + // Subscriptions + srv.subscribeToEventHelper( + ctx, api.CHANNEL_SUBSCRIBE, "1", map[string]string{ "broadcaster_user_id": srv.channelID }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.subscribe: %v", err) - } + ) - // channel.cheer - if err := srv.subscribeToEvent( - ctx, "channel.cheer", "1", + // Subscription Message + srv.subscribeToEventHelper( + ctx, api.CHANNEL_SUBSCRIPTION_MESSAGE, "1", map[string]string{ "broadcaster_user_id": srv.channelID }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.cheer: %v", err) - } + ) - // channel.raid - if err := srv.subscribeToEvent( - ctx, "channel.raid", "1", + // Gift Subscriptions + srv.subscribeToEventHelper( + ctx, api.CHANNEL_SUBSCRIPTION_GIFT, "1", + map[string]string{ "broadcaster_user_id": srv.channelID }, + srv.eventSubSession.ID, + ) + + // Cheer + srv.subscribeToEventHelper( + ctx, api.CHANNEL_CHEER, "1", + map[string]string{ "broadcaster_user_id": srv.channelID }, + srv.eventSubSession.ID, + ) + + // Raid + srv.subscribeToEventHelper( + ctx, api.CHANNEL_RAID, "1", map[string]string{ "to_broadcaster_user_id": srv.channelID }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.raid: %v", err) - } + ) - // channel.channel_points_custom_reward_redemption.add - if err := srv.subscribeToEvent( - ctx, "channel.channel_points_custom_reward_redemption.add", "1", + // Channel Point Redeems + srv.subscribeToEventHelper( + ctx, api.CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD, "1", map[string]string{ "broadcaster_user_id": srv.channelID }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.channel_points_custom_reward_redemption.add: %v", err) - } + ) - // channel.shoutout.create - if err := srv.subscribeToEvent( - ctx, "channel.shoutout.create", "1", + // Shoutouts + srv.subscribeToEventHelper( + ctx, api.SHOUTOUT_CREATE, "1", map[string]string{ "broadcaster_user_id": srv.channelID, "moderator_user_id": srv.channelID, }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.shoutout.create: %v", err) - } + ) - // channel.chat.message - if err := srv.subscribeToEvent( - ctx, "channel.chat.message", "1", + // Chat Messages + srv.subscribeToEventHelper( + ctx, api.CHANNEL_CHAT_MESSAGE, "1", map[string]string{ "broadcaster_user_id": srv.channelID, "user_id": srv.channelID, }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.chat.message: %v", err) - } + ) - // channel.chat.message_delete - if err := srv.subscribeToEvent( - ctx, "channel.chat.message_delete", "1", + // Chat Message Deletions + srv.subscribeToEventHelper( + ctx, api.CHANNEL_CHAT_MESSAGE_DELETE, "1", map[string]string{ "broadcaster_user_id": srv.channelID, "user_id": srv.channelID, }, srv.eventSubSession.ID, - ); err != nil { - log.Printf("Failed to subscribe to channel.chat.message_delete: %v", err) - } + ) + + // Chat Notifications + srv.subscribeToEventHelper( + ctx, api.CHANNEL_CHAT_NOTIFICATION, "1", + map[string]string{ + "broadcaster_user_id": srv.channelID, + "user_id": srv.channelID, + }, + srv.eventSubSession.ID, + ) + + // Chat Clear + srv.subscribeToEventHelper( + ctx, api.CHANNEL_CHAT_CLEAR, "1", + map[string]string{ + "broadcaster_user_id": srv.channelID, + "user_id": srv.channelID, + }, + srv.eventSubSession.ID, + ) + + // Clear User Messages + srv.subscribeToEventHelper( + ctx, api.CHANNEL_CHAT_CLEAR_USER_MESSAGES, "1", + map[string]string{ + "broadcaster_user_id": srv.channelID, + "user_id": srv.channelID, + }, + srv.eventSubSession.ID, + ) + + // Polls (Starting) + srv.subscribeToEventHelper( + ctx, api.CHANNEL_POLL_BEGIN, "1", + map[string]string{ "broadcaster_user_id": srv.channelID }, + srv.eventSubSession.ID, + ) + + // Polls (Ending) + srv.subscribeToEventHelper( + ctx, api.CHANNEL_POLL_END, "1", + map[string]string{ "broadcaster_user_id": srv.channelID }, + srv.eventSubSession.ID, + ) } type ( @@ -383,6 +554,10 @@ func (srv *Service) getFollowers( return resData, nil } +// Unfortunately, this function is very unreliable for pulling chronological +// subscription records. Twitch API does not currently provide a mechanism for +// fetching the latest subscriber; this will need to be tracked manually. +/* type ( Subscriber struct { BroadcasterID string `json:"broadcaster_id"` @@ -409,10 +584,6 @@ type ( Points int `json:"points"` } ) -// Unfortunately, this function is very unreliable for pulling chronological -// subscription records. Twitch API does not currently provide a mechanism for -// fetching the latest subscriber; this will need to be tracked manually. -/* func (srv *Service) getSubscribers( ctx context.Context, broadcasterID string, diff --git a/twitch/api/api.go b/twitch/api/api.go index 24b4cd1..d02b0a6 100644 --- a/twitch/api/api.go +++ b/twitch/api/api.go @@ -22,7 +22,7 @@ type ( EventSubSubscription struct { ID string `json:"id"` Status string `json:"status"` - Type string `json:"type"` + Type SubscriptionType `json:"type"` Version string `json:"version"` Cost int `json:"cost"` Condition any `json:"condition"` diff --git a/twitch/api/chat-message.go b/twitch/api/chat-message.go new file mode 100644 index 0000000..895ee64 --- /dev/null +++ b/twitch/api/chat-message.go @@ -0,0 +1,10 @@ +package api + +type ChatMessageType string + +const MESSAGE_TEXT ChatMessageType = "text" +const MESSAGE_CHANNEL_POINTS_HIGHLIGHTED ChatMessageType = "channel_points_highlighted" +const MESSAGE_CHANNEL_POINTS_SUB_ONLY ChatMessageType = "channel_points_sub_only" +const MESSAGE_USER_INTRO ChatMessageType = "user_intro" +const MESSAGE_POWER_UPS_MESSAGE_EFFECT ChatMessageType = "power_ups_message_effect" +const MESSAGE_POWER_UPS_GIGANTIFIED_EMOTE ChatMessageType = "power_ups_gigantified_emote" diff --git a/twitch/api/event.go b/twitch/api/event.go index f229f95..72aca02 100644 --- a/twitch/api/event.go +++ b/twitch/api/event.go @@ -22,6 +22,24 @@ type ( IsGift bool `json:"is_gift"` } + SubscribeMessageEmote struct { + Begin int `json:"begin"` + End int `json:"end"` + ID string `json:"id"` + } + SubscribeMessageContent struct { + Text string `json:"text"` + Emotes []SubscribeMessageEmote `json:"emotes"` + } + SubscribeMessageEvent struct { + ChannelEvent + Tier string `json:"tier"` + Message SubscribeMessageContent `json:"message"` + CumulativeMonths int `json:"cumulative_months"` + StreakMonths int `json:"streak_months"` + DurationMonths int `json:"duration_months"` + } + CheerEvent struct { ChannelEvent Message string `json:"message"` @@ -97,11 +115,11 @@ type ( } ChatMessageFragment struct { Type string `json:"type"` - Text string `json:"text"` - Cheermote *ChatMessageCheermote `json:"cheermote"` - Emote *ChatMessageEmote `json:"emote"` - Mention *ChatMessageMention `json:"mention"` - Gif *ChatMessageGif `json:"gif"` + Text string `json:"text,omitempty"` + Cheermote *ChatMessageCheermote `json:"cheermote,omitempty"` + Emote *ChatMessageEmote `json:"emote,omitempty"` + Mention *ChatMessageMention `json:"mention,omitempty"` + Gif *ChatMessageGif `json:"gif,omitempty"` } ChatMessage struct { Text string `json:"text"` @@ -143,7 +161,7 @@ type ( MessageID string `json:"message_id"` Message ChatMessage `json:"message"` - MessageType string `json:"message_type"` + MessageType ChatMessageType `json:"message_type"` Badges []ChatBadge `json:"badges"` Cheer *ChatCheer `json:"cheer"` @@ -163,7 +181,7 @@ type ( IsSourceOnly bool `json:"is_source_only"` } - ChatDeleteEvent struct { + ChatClearUserMessagesEvent struct { BroadcasterID string `json:"broadcaster_user_id"` BroadcasterLogin string `json:"broadcaster_user_login"` BroadcasterName string `json:"broadcaster_user_name"` @@ -171,7 +189,54 @@ type ( TargetID string `json:"target_user_id"` TargetLogin string `json:"target_user_login"` TargetName string `json:"target_user_name"` - + } + ChatDeleteEvent struct { + ChatClearUserMessagesEvent MessageID string `json:"message_id"` } + + ChatAnnouncement struct { + Color string `json:"color"` + } + CharityDonationAmount struct { + Value int `json:"value"` + DecimalPlace int `json:"decimal_place"` + Currency string `json:"currency"` + } + CharityDonation struct { + CharityName string `json:"charity_name"` + Amount CharityDonationAmount `json:"amount"` + } + WatchStreak struct { + StreakCount int `json:"streak_count"` + ChannelPointsAwarded int `json:"channel_points_awarded"` + } + Modiversary struct { + Months int `json:"months"` + } + ChatNotificationEvent struct { + BroadcasterID string `json:"broadcaster_user_id"` + BroadcasterLogin string `json:"broadcaster_user_login"` + BroadcasterName string `json:"broadcaster_user_name"` + + ChatterID string `json:"chatter_user_id"` + ChatterName string `json:"chatter_user_name"` + ChatterIsAnonymous bool `json:"chatter_is_anonymous"` + + Color string `json:"color"` + Badges []ChatBadge `json:"badges"` + + // The message Twitch shows in the chat room for this notice. + SystemMessage string `json:"system_message"` + + MessageID string `json:"message_id"` + Message ChatMessage `json:"message"` + + NoticeType ChatNoticeType `json:"notice_type"` + + Announcement ChatAnnouncement `json:"announcement"` + CharityDonation CharityDonation `json:"charity_donation"` + WatchStreak WatchStreak `json:"watch_streak"` + Modiversary Modiversary `json:"modiversary"` + } ) diff --git a/twitch/api/notice.go b/twitch/api/notice.go new file mode 100644 index 0000000..940a8d9 --- /dev/null +++ b/twitch/api/notice.go @@ -0,0 +1,29 @@ +package api + +type ChatNoticeType string + +const NOTICE_SUB ChatNoticeType = "sub" +const NOTICE_RESUB ChatNoticeType = "resub" +const NOTICE_SUB_GIFT ChatNoticeType = "sub_gift" +const NOTICE_COMMUNITY_SUB_GIFT ChatNoticeType = "community_sub_gift" +const NOTICE_GIFT_PAID_UPGRADE ChatNoticeType = "gift_paid_upgrade" +const NOTICE_PRIME_PAID_UPGRADE ChatNoticeType = "prime_paid_upgrade" +const NOTICE_RAID ChatNoticeType = "raid" +const NOTICE_UNRAID ChatNoticeType = "unraid" +const NOTICE_PAY_IT_FORWARD ChatNoticeType = "pay_it_forward" +const NOTICE_ANNOUNCEMENT ChatNoticeType = "announcement" +const NOTICE_BITS_BADGE_TIER ChatNoticeType = "bits_badge_tier" +const NOTICE_CHARITY_DONATION ChatNoticeType = "charity_donation" +const NOTICE_WATCH_STREAK ChatNoticeType = "watch_streak" +const NOTICE_MODIVERSARY ChatNoticeType = "modiversary" +const NOTICE_SHARED_CHAT_SUB ChatNoticeType = "shared_chat_sub" +const NOTICE_SHARED_CHAT_RESUB ChatNoticeType = "shared_chat_resub" +const NOTICE_SHARED_CHAT_SUB_GIFT ChatNoticeType = "shared_chat_sub_gift" +const NOTICE_SHARED_CHAT_COMMUNITY_SUB_GIFT ChatNoticeType = "shared_chat_community_sub_gift" +const NOTICE_SHARED_CHAT_GIFT_PAID_UPGRADE ChatNoticeType = "shared_chat_gift_paid_upgrade" +const NOTICE_SHARED_CHAT_PRIME_PAID_UPGRADE ChatNoticeType = "shared_chat_prime_paid_upgrade" +const NOTICE_SHARED_CHAT_RAID ChatNoticeType = "shared_chat_raid" +const NOTICE_SHARED_CHAT_PAY_IT_FORWARD ChatNoticeType = "shared_chat_pay_it_forward" +const NOTICE_SHARED_CHAT_ANNOUNCEMENT ChatNoticeType = "shared_chat_announcement" +const NOTICE_SHARED_CHAT_MODIVERSARY ChatNoticeType = "shared_chat_modiversary" +const NOTICE_UNKNOWN ChatNoticeType = "unknown" diff --git a/twitch/api/subscriptions.go b/twitch/api/subscriptions.go new file mode 100644 index 0000000..a53125c --- /dev/null +++ b/twitch/api/subscriptions.go @@ -0,0 +1,206 @@ +package api + +type SubscriptionType string + +// Automod + +// Version 1 - A user is notified if a message is caught by automod for review. +const AUTOMOD_MESSAGE_HOLD SubscriptionType = "automod.message.hold" +// Version 2 - A user is notified if a message is caught by automod for review. Only public blocked terms trigger notifications, not private ones. +const AUTOMOD_MESSAGE_HOLD_V2 SubscriptionType = "automod.message.hold" +// Version 1 - A message in the automod queue had its status changed. +const AUTOMOD_MESSAGE_UPDATE SubscriptionType = "automod.message.update" +// Version 2 - A message in the automod queue had its status changed. Only public blocked terms trigger notifications, not private ones. +const AUTOMOD_MESSAGE_UPDATE_V2 SubscriptionType = "automod.message.update" +// Version 1 - A notification is sent when a broadcaster’s automod settings are updated. +const AUTOMOD_SETTINGS_UPDATE SubscriptionType = "automod.settings.update" +// Version 1 - A notification is sent when a broadcaster’s automod terms are updated. Changes to private terms are not sent. +const AUTOMOD_TERMS_UPDATE SubscriptionType = "automod.terms.update" + +// Channel + +// Version 1 - A notification is sent whenever Bits are used on a channel. +const CHANNEL_BITS_USE SubscriptionType = "channel.bits.use" +// Version 2 - A broadcaster updates their channel properties e.g., category, title, content classification labels, broadcast, or language. +const CHANNEL_UPDATE SubscriptionType = "channel.update" +// Version 2 - A specified channel receives a follow. +const CHANNEL_FOLLOW SubscriptionType = "channel.follow" +// Version 1 - A midroll commercial break has started running. +const CHANNEL_AD_BREAK_BEGIN SubscriptionType = "channel.ad_break.begin" + +// Chat + +// Version 1 - A moderator or bot has cleared all messages from the chat room. +const CHANNEL_CHAT_CLEAR SubscriptionType = "channel.chat.clear" +// Version 1 - A moderator or bot has cleared all messages from a specific user. +const CHANNEL_CHAT_CLEAR_USER_MESSAGES SubscriptionType = "channel.chat.clear_user_messages" +// Version 1 - Any user sends a message to a specific chat room. +const CHANNEL_CHAT_MESSAGE SubscriptionType = "channel.chat.message" +// Version 1 - A moderator has removed a specific message. +const CHANNEL_CHAT_MESSAGE_DELETE SubscriptionType = "channel.chat.message_delete" +// Version 1 - A notification for when an event that appears in chat has occurred. +const CHANNEL_CHAT_NOTIFICATION SubscriptionType = "channel.chat.notification" +// Version 1 - A notification for when a broadcaster’s chat settings are updated. +const CHANNEL_CHAT_SETTINGS_UPDATE SubscriptionType = "channel.chat_settings.update" +// Version 1 - A user is notified if their message is caught by automod. +const CHANNEL_CHAT_USER_MESSAGE_HOLD SubscriptionType = "channel.chat.user_message_hold" +// Version 1 - A user is notified if their message’s automod status is updated. +const CHANNEL_CHAT_USER_MESSAGE_UPDATE SubscriptionType = "channel.chat.user_message_update" + +// Shared Chat + +// Version 1 - A notification when a channel becomes active in an active shared chat session. +const CHANNEL_SHARED_CHAT_SESSION_BEGIN SubscriptionType = "channel.shared_chat.begin" +// Version 1 - A notification when the active shared chat session the channel is in changes. +const CHANNEL_SHARED_CHAT_SESSION_UPDATE SubscriptionType = "channel.shared_chat.update" +// Version 1 - A notification when a channel leaves a shared chat session or the session ends. +const CHANNEL_SHARED_CHAT_SESSION_END SubscriptionType = "channel.shared_chat.end" + +// Subscriptions + +// Version 1 - A notification is sent when a specified channel receives a subscriber. This does not include resubscribes. +const CHANNEL_SUBSCRIBE SubscriptionType = "channel.subscribe" +// Version 1 - A notification when a subscription to the specified channel ends. +const CHANNEL_SUBSCRIPTION_END SubscriptionType = "channel.subscription.end" +// Version 1 - A notification when a viewer gives a gift subscription to one or more users in the specified channel. +const CHANNEL_SUBSCRIPTION_GIFT SubscriptionType = "channel.subscription.gift" +// Version 1 - A notification when a user sends a resubscription chat message in a specific channel. +const CHANNEL_SUBSCRIPTION_MESSAGE SubscriptionType = "channel.subscription.message" + +// Version 1 - A user cheers on the specified channel. +const CHANNEL_CHEER SubscriptionType = "channel.cheer" +// Version 1 - A broadcaster raids another broadcaster’s channel. +const CHANNEL_RAID SubscriptionType = "channel.raid" + +// Version 1 - A viewer is banned from the specified channel. +const CHANNEL_BAN SubscriptionType = "channel.ban" +// Version 1 - A viewer is unbanned from the specified channel. +const CHANNEL_UNBAN SubscriptionType = "channel.unban" +// Version 1 - A user creates an unban request. +const CHANNEL_UNBAN_REQUEST_CREATE SubscriptionType = "channel.unban_request.create" +// Version 1 - An unban request has been resolved. +const CHANNEL_UNBAN_REQUEST_RESOLVE SubscriptionType = "channel.unban_request.resolve" + +// Version 1 - A moderator performs a moderation action in a channel. +const CHANNEL_MODERATE SubscriptionType = "channel.moderate" +// Version 2 - A moderator performs a moderation action in a channel. Includes warnings. +const CHANNEL_MODERATE_V2 SubscriptionType = "channel.moderate" +// Version 1 - Moderator privileges were added to a user on a specified channel. +const CHANNEL_MODERATOR_ADD SubscriptionType = "channel.moderator.add" +// Version 1 - Moderator privileges were removed from a user on a specified channel. +const CHANNEL_MODERATOR_REMOVE SubscriptionType = "channel.moderator.remove" + +// Version beta - The host began a new Guest Star session. +const CHANNEL_GUEST_STAR_SESSION_BEGIN SubscriptionType = "channel.guest_star_session.begin" +// Version beta - A running Guest Star session has ended. +const CHANNEL_GUEST_STAR_SESSION_END SubscriptionType = "channel.guest_star_session.end" +// Version beta - A guest or a slot is updated in an active Guest Star session. +const CHANNEL_GUEST_STAR_GUEST_UPDATE SubscriptionType = "channel.guest_star_guest.update" +// Version beta - The host preferences for Guest Star have been updated. +const CHANNEL_GUEST_STAR_SETTINGS_UPDATE SubscriptionType = "channel.guest_star_settings.update" + +// Version 1 - A viewer has redeemed an automatic channel points reward on the specified channel. +const CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD SubscriptionType = "channel.channel_points_automatic_reward_redemption.add" +// Version 2 - A viewer has redeemed an automatic channel points reward on the specified channel. +const CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD_V2 SubscriptionType = "channel.channel_points_automatic_reward_redemption.add" +// Version 1 - A custom channel points reward has been created for the specified channel. +const CHANNEL_POINTS_CUSTOM_REWARD_ADD SubscriptionType = "channel.channel_points_custom_reward.add" +// Version 1 - A custom channel points reward has been updated for the specified channel. +const CHANNEL_POINTS_CUSTOM_REWARD_UPDATE SubscriptionType = "channel.channel_points_custom_reward.update" +// Version 1 - A custom channel points reward has been removed from the specified channel. +const CHANNEL_POINTS_CUSTOM_REWARD_REMOVE SubscriptionType = "channel.channel_points_custom_reward.remove" +// Version 1 - A viewer has redeemed a custom channel points reward on the specified channel. +const CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD SubscriptionType = "channel.channel_points_custom_reward_redemption.add" +// Version 1 - A redemption of a channel points custom reward has been updated for the specified channel. +const CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE SubscriptionType = "channel.channel_points_custom_reward_redemption.update" +// Version 1 - A viewer has redeemed a custom Power-up on the specified channel. +const CHANNEL_CUSTOM_POWER_UPS_REDEMPTION_ADD SubscriptionType = "channel.custom_power_up_redemption.add" + +// Version 1 - A poll started on a specified channel. +const CHANNEL_POLL_BEGIN SubscriptionType = "channel.poll.begin" +// Version 1 - Users respond to a poll on a specified channel. +const CHANNEL_POLL_PROGRESS SubscriptionType = "channel.poll.progress" +// Version 1 - A poll ended on a specified channel. +const CHANNEL_POLL_END SubscriptionType = "channel.poll.end" + +// Version 1 - A Prediction started on a specified channel. +const CHANNEL_PREDICTION_BEGIN SubscriptionType = "channel.prediction.begin" +// Version 1 - Users participated in a Prediction on a specified channel. +const CHANNEL_PREDICTION_PROGRESS SubscriptionType = "channel.prediction.progress" +// Version 1 - A Prediction was locked on a specified channel. +const CHANNEL_PREDICTION_LOCK SubscriptionType = "channel.prediction.lock" +// Version 1 - A Prediction ended on a specified channel. +const CHANNEL_PREDICTION_END SubscriptionType = "channel.prediction.end" + +// Version 1 - A chat message has been sent by a suspicious user. +const CHANNEL_SUSPICIOUS_USER_MESSAGE SubscriptionType = "channel.suspicious_user.message" +// Version 1 - A suspicious user has been updated. +const CHANNEL_SUSPICIOUS_USER_UPDATE SubscriptionType = "channel.suspicious_user.update" + +// Version 1 - A VIP is added to the channel. +const CHANNEL_VIP_ADD SubscriptionType = "channel.vip.add" +// Version 1 - A VIP is removed from the channel. +const CHANNEL_VIP_REMOVE SubscriptionType = "channel.vip.remove" + +// Version 1 - A user acknowledges a warning. Broadcasters and moderators can see the warning’s details. +const CHANNEL_WARNING_ACKNOWLEDGEMENT SubscriptionType = "channel.warning.acknowledge" +// Version 1 - A user is sent a warning. Broadcasters and moderators can see the warning’s details. +const CHANNEL_WARNING_SEND SubscriptionType = "channel.warning.send" + +// Version 1 - Sends an event notification when a user donates to the broadcaster’s charity campaign. +const CHARITY_DONATION SubscriptionType = "channel.charity_campaign.donate" +// Version 1 - Sends an event notification when the broadcaster starts a charity campaign. +const CHARITY_CAMPAIGN_START SubscriptionType = "channel.charity_campaign.start" +// Version 1 - Sends an event notification when progress is made towards the campaign’s goal or when the broadcaster changes the fundraising goal. +const CHARITY_CAMPAIGN_PROGRESS SubscriptionType = "channel.charity_campaign.progress" +// Version 1 - Sends an event notification when the broadcaster stops a charity campaign. +const CHARITY_CAMPAIGN_STOP SubscriptionType = "channel.charity_campaign.stop" + +// Version 1 - Sends a notification when EventSub disables a shard due to the status of the underlying transport changing. +const CONDUIT_SHARD_DISABLED SubscriptionType = "conduit.shard.disabled" + +// Version 1 - An entitlement for a Drop is granted to a user. +const DROP_ENTITLEMENT_GRANT SubscriptionType = "drop.entitlement.grant" + +// Version 1 - A Bits transaction occurred for a specified Twitch Extension. +const EXTENSION_BITS_TRANSACTION_CREATE SubscriptionType = "extension.bits_transaction.create" + +// Version 1 - Get notified when a broadcaster begins a goal. +const GOAL_BEGIN SubscriptionType = "channel.goal.begin" +// Version 1 - Get notified when progress (either positive or negative) is made towards a broadcaster’s goal. +const GOAL_PROGRESS SubscriptionType = "channel.goal.progress" +// Version 1 - Get notified when a broadcaster ends a goal. +const GOAL_END SubscriptionType = "channel.goal.end" + +// Version 2 - A Hype Train begins on the specified channel. +const HYPE_TRAIN_BEGIN SubscriptionType = "channel.hype_train.begin" +// Version 2 - A Hype Train makes progress on the specified channel. +const HYPE_TRAIN_PROGRESS SubscriptionType = "channel.hype_train.progress" +// Version 2 - A Hype Train ends on the specified channel. +const HYPE_TRAIN_END SubscriptionType = "channel.hype_train.end" + +// Version 1 - Sends a notification when the broadcaster activates Shield Mode. +const SHIELD_MODE_BEGIN SubscriptionType = "channel.shield_mode.begin" +// Version 1 - Sends a notification when the broadcaster deactivates Shield Mode. +const SHIELD_MODE_END SubscriptionType = "channel.shield_mode.end" + +// Version 1 - Sends a notification when the specified broadcaster sends a Shoutout. +const SHOUTOUT_CREATE SubscriptionType = "channel.shoutout.create" +// Version 1 - Sends a notification when the specified broadcaster receives a Shoutout. +const SHOUTOUT_RECEIVED SubscriptionType = "channel.shoutout.receive" + +// Version 1 - The specified broadcaster starts a stream. +const STREAM_ONLINE SubscriptionType = "stream.online" +// Version 1 - The specified broadcaster stops a stream. +const STREAM_OFFLINE SubscriptionType = "stream.offline" + +// Version 1 - A user’s authorization has been granted to your client id. +const USER_AUTHORIZATION_GRANT SubscriptionType = "user.authorization.grant" +// Version 1 - A user’s authorization has been revoked for your client id. +const USER_AUTHORIZATION_REVOKE SubscriptionType = "user.authorization.revoke" + +// Version 1 - A user has updated their account. +const USER_UPDATE SubscriptionType = "user.update" + +// Version 1 - A user receives a whisper. +const WHISPER_RECEIVED SubscriptionType = "user.whisper.message" diff --git a/twitch/pages/chat.html b/twitch/pages/chat.html new file mode 100644 index 0000000..d0e06ab --- /dev/null +++ b/twitch/pages/chat.html @@ -0,0 +1,14 @@ + + +
+ + +