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
///