NadekoBot/src/NadekoBot/Modules/Searches/Services/StreamNotificationService.cs

191 lines
8.6 KiB
C#
Raw Normal View History

2017-05-27 08:19:27 +00:00
using Discord;
using Discord.WebSocket;
using NadekoBot.Extensions;
using NadekoBot.Services;
2017-05-27 08:19:27 +00:00
using NadekoBot.Services.Database.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
2017-07-17 19:42:36 +00:00
using NadekoBot.Modules.Searches.Common;
using NadekoBot.Modules.Searches.Common.Exceptions;
using NadekoBot.Services.Impl;
2017-05-27 08:19:27 +00:00
2017-07-17 19:42:36 +00:00
namespace NadekoBot.Modules.Searches.Services
2017-05-27 08:19:27 +00:00
{
public class StreamNotificationService : INService
2017-05-27 08:19:27 +00:00
{
private readonly Timer _streamCheckTimer;
private bool firstStreamNotifPass { get; set; } = true;
private readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private readonly DbService _db;
private readonly DiscordSocketClient _client;
2017-05-27 08:19:27 +00:00
private readonly NadekoStrings _strings;
public StreamNotificationService(DbService db, DiscordSocketClient client, NadekoStrings strings)
2017-05-27 08:19:27 +00:00
{
_db = db;
_client = client;
_strings = strings;
_streamCheckTimer = new Timer(async (state) =>
{
var oldCachedStatuses = new ConcurrentDictionary<string, StreamStatus>(_cachedStatuses);
_cachedStatuses.Clear();
IEnumerable<FollowedStream> streams;
using (var uow = _db.UnitOfWork)
{
2017-06-20 02:23:11 +00:00
streams = uow.GuildConfigs.GetAllFollowedStreams(client.Guilds.Select(x => (long)x.Id).ToList());
2017-05-27 08:19:27 +00:00
}
await Task.WhenAll(streams.Select(async fs =>
{
try
{
var newStatus = await GetStreamStatus(fs).ConfigureAwait(false);
if (firstStreamNotifPass)
{
return;
}
StreamStatus oldStatus;
if (oldCachedStatuses.TryGetValue(newStatus.ApiLink, out oldStatus) &&
oldStatus.IsLive != newStatus.IsLive)
{
var server = _client.GetGuild(fs.GuildId);
var channel = server?.GetTextChannel(fs.ChannelId);
if (channel == null)
return;
try
{
await channel.EmbedAsync(GetEmbed(fs, newStatus, channel.Guild.Id)).ConfigureAwait(false);
}
catch
{
// ignored
}
}
}
catch
{
// ignored
}
}));
firstStreamNotifPass = false;
}, null, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(60));
2017-05-27 08:19:27 +00:00
}
public async Task<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
{
string response;
StreamStatus result;
switch (stream.Type)
{
2017-08-06 15:34:52 +00:00
case FollowedStream.FollowedStreamType.Smashcast:
2017-05-27 08:19:27 +00:00
var hitboxUrl = $"https://api.hitbox.tv/media/status/{stream.Username.ToLowerInvariant()}";
if (checkCache && _cachedStatuses.TryGetValue(hitboxUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(hitboxUrl).ConfigureAwait(false);
}
var hbData = JsonConvert.DeserializeObject<HitboxResponse>(response);
if (!hbData.Success)
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = hbData.IsLive,
ApiLink = hitboxUrl,
Views = hbData.Views
};
_cachedStatuses.AddOrUpdate(hitboxUrl, result, (key, old) => result);
return result;
case FollowedStream.FollowedStreamType.Twitch:
var twitchUrl = $"https://api.twitch.tv/kraken/streams/{Uri.EscapeUriString(stream.Username.ToLowerInvariant())}?client_id=67w6z9i09xv2uoojdm9l0wsyph4hxo6";
if (checkCache && _cachedStatuses.TryGetValue(twitchUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(twitchUrl).ConfigureAwait(false);
}
var twData = JsonConvert.DeserializeObject<TwitchResponse>(response);
if (twData.Error != null)
{
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
}
result = new StreamStatus()
{
IsLive = twData.IsLive,
ApiLink = twitchUrl,
Views = twData.Stream?.Viewers.ToString() ?? "0"
};
_cachedStatuses.AddOrUpdate(twitchUrl, result, (key, old) => result);
return result;
2017-08-06 14:07:48 +00:00
case FollowedStream.FollowedStreamType.Mixer:
var beamUrl = $"https://mixer.com/api/v1/channels/{stream.Username.ToLowerInvariant()}";
2017-05-27 08:19:27 +00:00
if (checkCache && _cachedStatuses.TryGetValue(beamUrl, out result))
return result;
using (var http = new HttpClient())
{
response = await http.GetStringAsync(beamUrl).ConfigureAwait(false);
}
var bmData = JsonConvert.DeserializeObject<BeamResponse>(response);
if (bmData.Error != null)
throw new StreamNotFoundException($"{stream.Username} [{stream.Type}]");
result = new StreamStatus()
{
IsLive = bmData.IsLive,
ApiLink = beamUrl,
Views = bmData.ViewersCurrent.ToString()
};
_cachedStatuses.AddOrUpdate(beamUrl, result, (key, old) => result);
return result;
default:
break;
}
return null;
}
public EmbedBuilder GetEmbed(FollowedStream fs, StreamStatus status, ulong guildId)
{
var embed = new EmbedBuilder().WithTitle(fs.Username)
.WithUrl(GetLink(fs))
.AddField(efb => efb.WithName(GetText(fs, "status"))
.WithValue(status.IsLive ? "Online" : "Offline")
.WithIsInline(true))
.AddField(efb => efb.WithName(GetText(fs, "viewers"))
.WithValue(status.IsLive ? status.Views : "-")
.WithIsInline(true))
.AddField(efb => efb.WithName(GetText(fs, "platform"))
.WithValue(fs.Type.ToString())
.WithIsInline(true))
.WithColor(status.IsLive ? NadekoBot.OkColor : NadekoBot.ErrorColor);
return embed;
}
public string GetText(FollowedStream fs, string key, params object[] replacements) =>
_strings.GetText(key,
fs.GuildId,
"Searches".ToLowerInvariant(),
replacements);
public string GetLink(FollowedStream fs)
{
2017-08-06 15:34:52 +00:00
if (fs.Type == FollowedStream.FollowedStreamType.Smashcast)
2017-08-06 14:07:48 +00:00
return $"https://www.hitbox.tv/{fs.Username}/";
2017-05-27 08:19:27 +00:00
if (fs.Type == FollowedStream.FollowedStreamType.Twitch)
2017-08-06 14:07:48 +00:00
return $"https://www.twitch.tv/{fs.Username}/";
if (fs.Type == FollowedStream.FollowedStreamType.Mixer)
return $"https://www.mixer.com/{fs.Username}/";
2017-05-27 08:19:27 +00:00
return "??";
}
}
}