I’ve got a working Discord bot that posts embeds when a Twitch streamer goes live. The issue is I set up a timer to check every 5 minutes if the stream is active, but it keeps spamming the Discord channel with the same embed repeatedly.
What I need is a way to check if I have already sent a “live” notification and only post it once for each stream session. Additionally, I want to handle brief disconnections (like when streamers experience internet issues) without flooding the channel with duplicate alerts.
Here’s the code I’m currently using to monitor streams:
using Microsoft.Extensions.DependencyInjection;
using Discord;
using Discord.WebSocket;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace StreamBot.Handlers
{
public class YouTubeMonitor
{
private readonly IConfiguration _settings;
private readonly DiscordSocketClient _bot;
private readonly IServiceProvider _provider;
private readonly Microsoft.Extensions.Logging.ILogger _log;
public YouTubeMonitor(IServiceProvider provider)
{
System.Timers.Timer checkTimer = new System.Timers.Timer(15000); // 15 seconds
checkTimer.Elapsed += async (sender, e) => CheckStreamStatus();
checkTimer.Start();
_settings = provider.GetRequiredService<IConfiguration>();
_bot = provider.GetRequiredService<DiscordSocketClient>();
_log = provider.GetRequiredService<ILogger<StreamHandler>>();
_provider = provider;
_bot.Ready += CheckStreamStatus;
}
public class StreamData
{
[JsonProperty("stream_id")] public string stream_id { get; set; }
[JsonProperty("channel_id")] public string channel_id { get; set; }
[JsonProperty("streamer_name")] public string streamer_name { get; set; }
[JsonProperty("category_id")] public string category_id { get; set; }
[JsonProperty("category_name")] public string category_name { get; set; }
[JsonProperty("broadcast_type")] public string broadcast_type { get; set; }
[JsonProperty("stream_title")] public string stream_title { get; set; }
[JsonProperty("viewers")] public int viewers { get; set; }
[JsonProperty("preview_url")] public string preview_url { get; set; }
}
public class StreamResponse
{
public List<StreamData> data { get; set; }
}
public class ChannelInfo
{
[JsonProperty("avatar_url")] public string avatar_url { get; set; }
}
public class ChannelResponse
{
public List<ChannelInfo> data { get; set; }
}
public async Task CheckStreamStatus()
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Client-ID", $"{_settings["api_key"]}");
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $"{_settings["access_token"]}");
HttpResponseMessage streamResponse = await httpClient.GetAsync($"https://api.youtube.com/v3/streams?channel={_settings["monitored_channel"]}");
HttpContent streamContent = streamResponse.Content;
string streamJson = await streamResponse.Content.ReadAsStringAsync();
var streamInfo = JsonConvert.DeserializeObject<StreamResponse>(streamJson);
HttpResponseMessage channelResponse = await httpClient.GetAsync($"https://api.youtube.com/v3/channels?name={_settings["monitored_channel"]}");
HttpContent channelContent = channelResponse.Content;
string channelJson = await channelResponse.Content.ReadAsStringAsync();
var channelInfo = JsonConvert.DeserializeObject<ChannelResponse>(channelJson);
if (!(streamInfo == default(StreamResponse) || streamInfo.data.Count == 0))
{
Console.WriteLine($"Status: {streamInfo.data[0].broadcast_type}");
Console.WriteLine($"Creator: {streamInfo.data[0].streamer_name}");
Console.WriteLine($"Title: {streamInfo.data[0].stream_title}");
Console.WriteLine($"Category: {streamInfo.data[0].category_name}");
Console.WriteLine($"Thumbnail: {streamInfo.data[0].preview_url.Replace("{w}x{h}", "1280x720")}");
Console.WriteLine($"Watchers: {streamInfo.data[0].viewers}");
var notification = new EmbedBuilder{};
notification.WithFooter(footer => footer.Text = "StreamBot")
.WithTitle($"{streamInfo.data[0].stream_title}")
.WithAuthor($"{streamInfo.data[0].streamer_name} started streaming!", $"{channelInfo.data[0].avatar_url}")
.WithImageUrl($"{streamInfo.data[0].preview_url.Replace("{w}x{h}", "1280x720")}")
.WithDescription($"Now playing {streamInfo.data[0].category_name} with {streamInfo.data[0].viewers} watchers \n [Join Stream](https://youtube.com/{streamInfo.data[0].streamer_name})")
.WithColor(Color.Red)
.WithUrl($"https://youtube.com/{streamInfo.data[0].streamer_name}")
.WithCurrentTimestamp();
ulong targetChannel = Convert.ToUInt64(_settings["notification_channel"]);
var messageChannel = _bot.GetChannel(targetChannel) as IMessageChannel;
var notification_msg = await messageChannel.SendMessageAsync(embed: notification.Build());
}
else
{
Console.WriteLine("Stream Offline");
}
_log.LogInformation("YouTube Monitor executed");
}
}
}
What changes can I make to avoid spam while keeping checks for stream status frequent?