//http://rms0.org?a=r1 - Helpful.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.WebSocket;
using Discord.Commands;
using Discord;
using System.IO;
using Newtonsoft.Json;
namespace GoLive
{
public class TwitchNotificationService
{
DiscordSocketClient _client = null;
List<UserShout> shoutEntities = new List<UserShout>();
public bool Initialized = false;
public TwitchNotificationService(DiscordSocketClient client)
{
LogMessage l2 = new LogMessage(LogSeverity.Warning, "GoLive", "TwitchNotificationService constructor called.");
Client_Log(l2);
_client = client;
_client.GuildMemberUpdated += _client_GuildMemberUpdated;
//Read shouts.json, otherwise create it.
using (FileStream fs = File.Open("shouts.json", FileMode.OpenOrCreate))
{
using (StreamReader sr = new StreamReader(fs))
{
string f = sr.ReadToEnd();
if (!string.IsNullOrWhiteSpace(f))
{
JsonSerializerSettings s = new JsonSerializerSettings();
s.Formatting = Formatting.Indented;
s.ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor;
s.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
s.TypeNameHandling = TypeNameHandling.Arrays;
shoutEntities = ((Newtonsoft.Json.Linq.JArray)JsonConvert.DeserializeObject(f,s)).ToObject<List<UserShout>>();
if (shoutEntities == null)
{
shoutEntities = new List<UserShout>();
LogMessage l = new LogMessage(LogSeverity.Warning, "GoLive", "WARNING: Shouts.json is null or invalid.");
Client_Log(l);
}
}
}
}
}
private Task Client_Log(LogMessage arg)
{
Console.WriteLine(arg);
return Task.Delay(0);
}
/// <summary>
/// Service. Add a new shout entity.
/// </summary>
/// <param name="context"></param>
/// <param name="user"></param>
/// <param name="SupressEveryone"></param>
/// <returns></returns>
public async Task AddShoutEntity(ICommandContext context, SocketGuildUser user, bool SupressEveryone)
{
UserShout item = shoutEntities.FirstOrDefault(x => x.userID == user.Id);
if (item != null)
{
//That user is already in the list. Cool! Check the channel and alter nothing else.
if(item.ChannelIDs.Contains(context.Channel.Id))
{
await context.Channel.SendMessageAsync("This channel already has a notification for this user. Please use a different channel.\r\n"+
"**Please note: You cannot add multiple twitch accounts to the same user.**");
return;//Cancel the operation. NO SAVE.
}
else
{
item.AddChannel(context.Channel.Id);//An existing channelID wasn't found. Add it to the list.
await context.Channel.SendMessageAsync($"This channel is now subscribed to going live alerts from (Discord user: {user.Username})");
}
}
else
{
shoutEntities.Add(new UserShout(user.Id, context.Channel.Id, SupressEveryone));
//Add a brand new item to our shout list.
await context.Channel.SendMessageAsync($"This channel is now subscribed to going live alerts from (Discord user: {user.Username})");
}
//Save shouts.json.
using (FileStream fs = File.Create("shouts.json"))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(JsonConvert.SerializeObject(shoutEntities,Formatting.Indented));//Output and save a file.
sw.Flush();
}
}
}
/// <summary>
/// Service. Removes an entire user's stream alerts.
/// </summary>
/// <param name="context"></param>
/// <param name="user"></param>
/// <returns></returns>
public async Task RemoveShoutEntity(ICommandContext context, SocketGuildUser user)
{
UserShout item = shoutEntities.FirstOrDefault(x => x.userID == user.Id);
if (item != null)
{
//That user is already in the list. Cool! Check the channel and alter nothing else.
shoutEntities.Remove(item);
await context.Channel.SendMessageAsync($"Removed {(await context.Guild.GetUserAsync(item.userID)).Username}'s stream alert.");
}
else
{
await context.Channel.SendMessageAsync($"Hey! This user doesn't have any stream alerts. Try that again please.");
return;
}
//Save shouts.json.
using (FileStream fs = File.Create("shouts.json"))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(JsonConvert.SerializeObject(shoutEntities, Formatting.Indented));//Output and save a file.
sw.Flush();
}
}
}
/// <summary>
/// Service. Remove a channel from a user's stream alert. This must be called from the channel where the alert is set.
/// </summary>
/// <param name="context"></param>
/// <param name="user"></param>
/// <returns></returns>
public async Task RemoveEntityChannel(ICommandContext context, SocketGuildUser user)
{
UserShout item = shoutEntities.FirstOrDefault(x => x.userID == user.Id);
SocketTextChannel channel = context.Channel as SocketTextChannel;
if (item != null)
{
//That user is already in the list. Cool! Check the channel and alter nothing else.
ulong chToRem = item.ChannelIDs.FirstOrDefault(x => x == channel.Id);
if(chToRem == 0)
{
await context.Channel.SendMessageAsync($"A notification for {(await context.Guild.GetUserAsync(item.userID)).Username}'s stream alert does not exist for this channel.");
return;
}
item.ChannelIDs.Remove(chToRem);
await context.Channel.SendMessageAsync($"Removed {(await context.Guild.GetUserAsync(item.userID)).Username}'s stream alert. from this channel.");
}
else
{
await context.Channel.SendMessageAsync($"Hey! This user doesn't have any stream alerts. Try that again please.");
return;
}
//Save shouts.json.
using (FileStream fs = File.Create("shouts.json"))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine(JsonConvert.SerializeObject(shoutEntities, Formatting.Indented));//Output and save a file.
sw.Flush();
}
}
}
private async Task _client_GuildMemberUpdated(SocketGuildUser arg1, SocketGuildUser arg2)
{
if (arg1.Game?.StreamType == StreamType.NotStreaming && arg2.Game?.StreamType == StreamType.Twitch)//Event gets fired for every guild??
{
//add role.
await arg2.AddRoleAsync(arg2.Guild.GetRole(arg2.Guild.Roles.FirstOrDefault(x => x.Name == "🔴 Live!").Id));
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " went live! [Guild: "+arg2.Guild.Name+"]"));
UserShout Shout = shoutEntities.FirstOrDefault(x => x.userID == arg2.Id);
if (Shout != null)
{
foreach (var item in Shout.ChannelIDs)
{
SocketTextChannel ch = _client.GetChannel(item) as SocketTextChannel;
string[] array = arg2.Game?.StreamUrl.Split('/');
if (ch.Guild == arg2.Guild)
{
if (Shout.SupressEveryone)
{
await ch.SendMessageAsync(array.Last() + " just went live! " + arg2.Game?.StreamUrl);
}
else
{
await ch.SendMessageAsync("@everyone " + array.Last() + " just went live! " + arg2.Game?.StreamUrl);
}
}
}
}
}
if (arg1.Game?.StreamType == StreamType.Twitch && arg2.Game?.StreamType == StreamType.NotStreaming)
{
//remove the role
await arg2.RemoveRoleAsync(arg2.Guild.GetRole(arg2.Guild.Roles.FirstOrDefault(x => x.Name == "🔴 Live!").Id));
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " Ended stream. [Guild: " + arg2.Guild.Name + "]"));
}
}
public async Task Initialize()
{
Initialized = true;
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", "Called Initialization. Checking all users. (This could take a minute)"));
foreach (SocketGuild guild in _client.Guilds)
{
foreach (SocketGuildUser arg2 in guild.Users)
{
if (arg2.Game?.StreamType == StreamType.Twitch)//Event gets fired twice??
{
await arg2.AddRoleAsync(arg2.Guild.GetRole(arg2.Guild.Roles.FirstOrDefault(x => x.Name == "🔴 Live!").Id));
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " is live!"));
}
if (arg2.Game?.StreamType == StreamType.NotStreaming)
{
await arg2.RemoveRoleAsync(arg2.Guild.GetRole(arg2.Guild.Roles.FirstOrDefault(x => x.Name == "🔴 Live!").Id));
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " is not live"));
}
}
}
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", "Operation complete! Listening for further updates."));
}
public async Task ShoutTest(ICommandContext context)
{
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", "HEY!!! TEST!"));
foreach (SocketGuild guild in _client.Guilds)
{
foreach (SocketGuildUser arg2 in guild.Users)
{
if (arg2.Game?.StreamType == StreamType.Twitch)
{
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", "user streamtype twitch."+ arg2.Username));
await arg2.AddRoleAsync(arg2.Guild.GetRole(arg2.Guild.Roles.FirstOrDefault(x => x.Name == "🔴 Live!").Id));
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " is live!"));
//add role.
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " went live! [Guild: " + arg2.Guild.Name + "]"));
UserShout Shout = shoutEntities.FirstOrDefault(x => x.userID == arg2.Id);
if (Shout != null)
{
foreach (var item in Shout.ChannelIDs)
{
SocketTextChannel ch = _client.GetChannel(item) as SocketTextChannel;
string[] array = arg2.Game?.StreamUrl.Split('/');
if (ch.Guild == arg2.Guild)
{
if (Shout.SupressEveryone)
{
await ch.SendMessageAsync(array.Last() + " just went live! " + arg2.Game?.StreamUrl);
}
else
{
await ch.SendMessageAsync("@everyone " + array.Last() + " just went live! " + arg2.Game?.StreamUrl);
}
}
}
}
}
if (arg2.Game?.StreamType == StreamType.NotStreaming)
{
await arg2.RemoveRoleAsync(arg2.Guild.GetRole(arg2.Guild.Roles.FirstOrDefault(x => x.Name == "🔴 Live!").Id));
await Client_Log(new LogMessage(LogSeverity.Info, "GoLive", arg2.Username + " is not live"));
}
}
}
}
}
public class UserShout
{
#region Properties
public ulong userID { get; set; }
public List<ulong> ChannelIDs { get; set; }
public bool SupressEveryone { get; set; }
#endregion
/// <summary>
/// Create a new UserShout data entry.
/// </summary>
/// <param name="User">the ID of the user</param>
/// <param name="ChannelID">The channel where GoLive shoutouts will be posted</param>
/// <param name="twitchUsername">The user's twitch username</param>
/// <param name="supressEveryone">Prevent @everyone from being added to the shoutout.</param>
public UserShout(ulong User, ulong ChannelID, bool supressEveryone)
{
userID = User;
ChannelIDs = new List<ulong>();
ChannelIDs.Add(ChannelID);
SupressEveryone = supressEveryone;
}
/// <summary>
/// Adds a channel to the list of channels to send the shoutout.
/// </summary>
/// <param name="id"></param>
public void AddChannel(ulong id)
{
ChannelIDs.Add(id);
}
/// <summary>
/// Removes a channel from the list of channels to send the shoutout.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool DeleteChannel(uint id)
{
return ChannelIDs.Remove(id);
}
}
public class GoLiveModule: ModuleBase
{
DiscordSocketClient _client { get; set; }
TwitchNotificationService _service { get; set; }
public GoLiveModule(DiscordSocketClient discord, TwitchNotificationService service)
{
_client = discord;
_service = service;
}
[Command("AddAlert"), RequireUserPermission(GuildPermission.ManageGuild), Remarks("[CMDMgmt]")]
public async Task AddAlert(IGuildUser user, bool SupressEveryone)
{
await _service.AddShoutEntity(Context, user as SocketGuildUser, SupressEveryone);
}
[Command("RemoveAlertChannel"), RequireUserPermission(GuildPermission.ManageGuild), Remarks("[CMDMgmt]")]
public async Task delchalert(IGuildUser user)
{
await _service.RemoveEntityChannel(Context, user as SocketGuildUser);
}
[Command("RemoveAlert"), RequireUserPermission(GuildPermission.ManageGuild), Remarks("[CMDMgmt]")]
public async Task delAlert(IGuildUser user)
{
await _service.RemoveShoutEntity(Context, user as SocketGuildUser);
}
[Command("AboutGoLive")]
public async Task about()
{
EmbedBuilder builder = new EmbedBuilder();
builder.WithAuthor(_client.CurrentUser);
builder.WithTitle($"GoLive v{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}");
builder.Description = "A module for the twitch streamer. Offering visibility for other streamers in your guild. Below are supported commands.";
builder.AddField("AddAlert", $"Users who have permission to manage the guild can add GoingLive alerts to a channel.\r\nUSAGE:`{Context.Message.Content[0].ToString()}AddAlert <discordUser> <TwitchUsername> <SupressEveryone>` where SupressEveryone will turn off @ everyone pings if true.");
builder.AddField("InitGoLive", $"Add this command to the OnStart.bcmd file, to enable the module when the bot starts. Otherwise, live alerts will not work.\r\nOnStart.bcmd entry: `%p_InitGoLive`");
builder.AddField("AboutGoLive", "Show this information again.");
await Context.Channel.SendMessageAsync("",false,builder.Build());
}
[Command("InitGoLive",RunMode = RunMode.Async)]
public async Task Init()
{
if(_service.Initialized)
{
await Context.Channel.SendMessageAsync("The GoLive module has already been started. No further action required.");
return;
}
await _service.Initialize();
}
[Command("testGoLive", RunMode = RunMode.Async), RequireUserPermission(GuildPermission.ManageGuild), Remarks("[CMDMgmt]")]
public async Task TEST_ALL_THINGS()
{
await _service.ShoutTest(Context);
}
}
}
Comments