diff --git a/TwitchLib.PubSub/Enums/HypeTrainEventType.cs b/TwitchLib.PubSub/Enums/HypeTrainEventType.cs new file mode 100644 index 0000000..e96971d --- /dev/null +++ b/TwitchLib.PubSub/Enums/HypeTrainEventType.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TwitchLib.PubSub.Enums +{ + public enum HypeTrainEventType + { + Progression, + LevelUp + } +} diff --git a/TwitchLib.PubSub/Events/OnHypeTrainLevelUp.cs b/TwitchLib.PubSub/Events/OnHypeTrainLevelUp.cs new file mode 100644 index 0000000..e7185d3 --- /dev/null +++ b/TwitchLib.PubSub/Events/OnHypeTrainLevelUp.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using TwitchLib.PubSub.Models.Responses.Messages.HypeTrain; + +namespace TwitchLib.PubSub.Events +{ + public class OnHypeTrainLevelUp + { + /// + /// Details about the hype train level up event. + /// + public HypeTrainLevelUp LevelUp; + /// + /// The ID of the channel that this event fired from. + /// + public string ChannelId; + } +} diff --git a/TwitchLib.PubSub/Events/OnHypeTrainProgressionArgs.cs b/TwitchLib.PubSub/Events/OnHypeTrainProgressionArgs.cs new file mode 100644 index 0000000..f3b9f9c --- /dev/null +++ b/TwitchLib.PubSub/Events/OnHypeTrainProgressionArgs.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using TwitchLib.PubSub.Models.Responses.Messages.HypeTrain; + +namespace TwitchLib.PubSub.Events +{ + public class OnHypeTrainProgressionArgs + { + /// + /// Details about the hype train. + /// + public HypeTrainProgression Progression; + /// + /// The ID of the channel that this event fired from. + /// + public string ChannelId; + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Message.cs b/TwitchLib.PubSub/Models/Responses/Message.cs index 3dcbf40..5bf96f0 100644 --- a/TwitchLib.PubSub/Models/Responses/Message.cs +++ b/TwitchLib.PubSub/Models/Responses/Message.cs @@ -1,6 +1,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using TwitchLib.PubSub.Models.Responses.Messages; +using TwitchLib.PubSub.Models.Responses.Messages.HypeTrain; using TwitchLib.PubSub.Models.Responses.Messages.UserModerationNotifications; namespace TwitchLib.PubSub.Models.Responses @@ -83,6 +84,9 @@ public Message(string jsonStr) case "low-trust-users": MessageData = new LowTrustUsers(encodedJsonMessage); break; + case "hype-train-events-v1": + MessageData = new HypeTrainEvent(encodedJsonMessage); + break; } } } diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainEvent.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainEvent.cs new file mode 100644 index 0000000..1d349d7 --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainEvent.cs @@ -0,0 +1,32 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Text; +using TwitchLib.PubSub.Enums; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public class HypeTrainEvent : MessageData + { + public HypeTrainEventType Type { get; protected set; } + public HypeTrainEventData Data { get; protected set; } + + + public HypeTrainEvent(string jsonStr) + { + JToken json = JObject.Parse(jsonStr); + switch (json.SelectToken("type").ToString()) + { + case "hype-train-progression": + Type = HypeTrainEventType.Progression; + Data = json["data"].ToObject(); + break; + case "hype-train-level-up": + Type = HypeTrainEventType.LevelUp; + Data = json["data"].ToObject(); + break; + } + } + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainEventData.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainEventData.cs new file mode 100644 index 0000000..2a2bb46 --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainEventData.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public abstract class HypeTrainEventData + { + // Leave empty for now + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainLevelUp.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainLevelUp.cs new file mode 100644 index 0000000..0f4117f --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainLevelUp.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public class HypeTrainLevelUp : HypeTrainEventData + { + [JsonProperty(PropertyName = "time_to_expire")] + public long TimeToExpire { get; protected set; } + [JsonProperty(PropertyName = "progress")] + public Progress Progress { get; protected set; } + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainProgression.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainProgression.cs new file mode 100644 index 0000000..2464426 --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/HypeTrainProgression.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public class HypeTrainProgression : HypeTrainEventData + { + [JsonProperty(PropertyName = "user_id")] + public string UserId { get; protected set; } + [JsonProperty(PropertyName = "sequence_id")] + public int SequenceId { get; protected set; } + [JsonProperty(PropertyName = "action")] + public string Action { get; protected set; } + [JsonProperty(PropertyName = "source")] + public string Source { get; protected set; } + [JsonProperty(PropertyName = "quantity")] + public int Quantity { get; protected set; } + [JsonProperty(PropertyName = "progress")] + public Progress Progress { get; protected set; } + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Level.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Level.cs new file mode 100644 index 0000000..5c847bf --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Level.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public class Level + { + [JsonProperty(PropertyName = "value")] + public int Value { get; protected set; } + [JsonProperty(PropertyName = "goal")] + public int Goal { get; protected set; } + [JsonProperty(PropertyName = "rewards")] + public Reward[] Rewards { get; protected set; } + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Progress.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Progress.cs new file mode 100644 index 0000000..b311afa --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Progress.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public class Progress + { + [JsonProperty(PropertyName = "level")] + public Level Level { get; protected set; } + [JsonProperty(PropertyName = "value")] + public int Value { get; protected set; } + [JsonProperty(PropertyName = "goal")] + public int Goal { get; protected set; } + [JsonProperty(PropertyName = "total")] + public int Total { get; protected set; } + [JsonProperty(PropertyName = "remaining_seconds")] + public int RemainingSeconds { get; protected set; } + } +} diff --git a/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Reward.cs b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Reward.cs new file mode 100644 index 0000000..2f592bd --- /dev/null +++ b/TwitchLib.PubSub/Models/Responses/Messages/HypeTrain/Reward.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace TwitchLib.PubSub.Models.Responses.Messages.HypeTrain +{ + public class Reward + { + [JsonProperty(PropertyName = "id")] + public string Id { get; protected set; } + [JsonProperty(PropertyName = "type")] + public string Type { get; protected set; } + [JsonProperty(PropertyName = "group_id")] + public string GroupId { get; protected set; } + [JsonProperty(PropertyName = "reward_level")] + public int RewardLevel { get; protected set; } + } +} diff --git a/TwitchLib.PubSub/TwitchPubSub.cs b/TwitchLib.PubSub/TwitchPubSub.cs index 8136f83..0605e6a 100644 --- a/TwitchLib.PubSub/TwitchPubSub.cs +++ b/TwitchLib.PubSub/TwitchPubSub.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -16,6 +17,7 @@ using TwitchLib.PubSub.Models; using TwitchLib.PubSub.Models.Responses.Messages; using TwitchLib.PubSub.Models.Responses.Messages.AutomodCaughtMessage; +using TwitchLib.PubSub.Models.Responses.Messages.HypeTrain; using TwitchLib.PubSub.Models.Responses.Messages.Redemption; using TwitchLib.PubSub.Models.Responses.Messages.UserModerationNotifications; using Timer = System.Timers.Timer; @@ -291,6 +293,16 @@ public class TwitchPubSub : ITwitchPubSub /// Fires when a moderation event hits a user /// public event EventHandler OnAutomodCaughtUserMessage; + /// + /// + /// Fires when hype train event is received + /// + public event EventHandler OnHypeTrainProgression; + /// + /// + /// Fires when an existing hype train levels up + /// + public event EventHandler OnHypeTrainLevelUp; #endregion /// @@ -456,6 +468,20 @@ private async Task ParseMessageAsync(string message) channelId = channelId ?? ""; switch (msg.Topic.Split('.')[0]) { + case "hype-train-events-v1": + var hypeTrainEvent = msg.MessageData as HypeTrainEvent; + switch(hypeTrainEvent.Type) + { + case HypeTrainEventType.Progression: + var progression = hypeTrainEvent.Data as HypeTrainProgression; + OnHypeTrainProgression?.Invoke(this, new OnHypeTrainProgressionArgs { ChannelId = channelId, Progression = progression }); + break; + case HypeTrainEventType.LevelUp: + var levelUp = hypeTrainEvent.Data as HypeTrainLevelUp; + OnHypeTrainLevelUp?.Invoke(this, new OnHypeTrainLevelUp { ChannelId = channelId, LevelUp = levelUp }); + break; + } + return; case "user-moderation-notifications": var userModerationNotifications = msg.MessageData as UserModerationNotifications; switch(userModerationNotifications.Type) @@ -995,6 +1021,17 @@ public void ListenToLowTrustUsers(string channelTwitchId, string suspiciousUser) _topicToChannelId[topic] = channelTwitchId; ListenToTopic(topic); } + + /// + /// A hype train makes progress or levels up. + /// + /// The channel twitch identifier + public void ListenToHypeTrains(string channelTwitchId) + { + var topic = $"hype-train-events-v1.{channelTwitchId}"; + _topicToChannelId[topic] = channelTwitchId; + ListenToTopic(topic); + } #endregion ///