From a0c672a1c245eb8e6700defcb9ea62b51e7e8902 Mon Sep 17 00:00:00 2001 From: Linkslumps Date: Sun, 28 Apr 2019 15:07:59 -0300 Subject: [PATCH] Issue #35 Curate the Live Channels Display on Hompage Changes made to show live channels sorted by view count, also displaying time online. Modified the Feeling Lucky button to display a random live channel. --- .../Data/ICrudRepository.cs | 1 + .../Twitch/ChannelLiveState.cs | 7 ++- .../Twitch/TwitchResult.cs | 26 +++++++++ .../DapperCrudRepository.cs | 30 +++++++++++ .../TwitchStreamService.cs | 53 +++++++++++-------- .../Controllers/IsLiveController.cs | 37 +++++++++++-- .../Pages/Index.cshtml | 9 ++-- .../Pages/Index.cshtml.cs | 19 ++++--- 8 files changed, 144 insertions(+), 38 deletions(-) diff --git a/src/DevChatter.DevStreams.Core/Data/ICrudRepository.cs b/src/DevChatter.DevStreams.Core/Data/ICrudRepository.cs index 1b23715..9229368 100644 --- a/src/DevChatter.DevStreams.Core/Data/ICrudRepository.cs +++ b/src/DevChatter.DevStreams.Core/Data/ICrudRepository.cs @@ -11,6 +11,7 @@ public interface ICrudRepository Task> GetAll(); Task> GetAll(string filter, object args); Task> GetAll(string filter, string orderBy, object args); + Task> GetAllChannelInfo(); Task Update(T model) where T : DataEntity; Task Delete(int id) where T : DataEntity; Task Delete(T model) where T : DataEntity; diff --git a/src/DevChatter.DevStreams.Core/Twitch/ChannelLiveState.cs b/src/DevChatter.DevStreams.Core/Twitch/ChannelLiveState.cs index e53d874..b459572 100644 --- a/src/DevChatter.DevStreams.Core/Twitch/ChannelLiveState.cs +++ b/src/DevChatter.DevStreams.Core/Twitch/ChannelLiveState.cs @@ -1,8 +1,13 @@ -namespace DevChatter.DevStreams.Core.Twitch +using System; + +namespace DevChatter.DevStreams.Core.Twitch { public class ChannelLiveState { public string TwitchId { get; set; } public bool IsLive { get; set; } + public DateTime startedAt { get; set; } + public int viewerCount { get; set; } + } } diff --git a/src/DevChatter.DevStreams.Core/Twitch/TwitchResult.cs b/src/DevChatter.DevStreams.Core/Twitch/TwitchResult.cs index c3d13cd..5a042fc 100644 --- a/src/DevChatter.DevStreams.Core/Twitch/TwitchResult.cs +++ b/src/DevChatter.DevStreams.Core/Twitch/TwitchResult.cs @@ -50,4 +50,30 @@ public class StreamResult public List Data { get; set; } public Pagination Pagination { get; set; } } + public class ChannelResultData + { + public int _total { get; set; } + public List follows { get; set; } + } + + public class ChannelResult + { + public DateTime created_at { get; set; } + public bool notifications { get; set; } + public ChannelFollowResult channel { get; set; } + } + + public class ChannelFollowResult + { + public int _id { get; set; } + public DateTime created_at { get; set; } + public string display_name { get; set; } + public int followers { get; set; } + public string game { get; set; } + public string logo { get; set; } + public DateTime updated_at { get; set; } + public string url { get; set; } + public string video_banner { get; set; } + public int views { get; set; } + } } diff --git a/src/DevChatter.DevStreams.Infra.Dapper/DapperCrudRepository.cs b/src/DevChatter.DevStreams.Infra.Dapper/DapperCrudRepository.cs index a310fb2..a4a627c 100644 --- a/src/DevChatter.DevStreams.Infra.Dapper/DapperCrudRepository.cs +++ b/src/DevChatter.DevStreams.Infra.Dapper/DapperCrudRepository.cs @@ -86,6 +86,36 @@ public async Task> GetAll(string filter, string orderBy, object args) } } + /// + /// Returns all the channel data for a channel object. + /// + /// All Channel Info in a List Object + public async Task> GetAllChannelInfo() + { + string sql = "SELECT * FROM Channels;"; + string sql2 = "SELECT * FROM TwitchChannels;"; + + string combinedSQL = sql + sql2; + + using (IDbConnection connection = new SqlConnection(_dbSettings.DefaultConnection)) + { + var dbQuery = await connection.QueryMultipleAsync(combinedSQL); + List channels = dbQuery.Read().ToList(); + var twitchChannels = dbQuery.Read(); + + foreach (var channel in channels) + { + if (twitchChannels.Where(x => x?.ChannelId == channel?.Id).Any()) + { + channel.Twitch = twitchChannels.Where(x => x?.ChannelId == channel?.Id).First(); + } + } + + return channels; + } + + } + public async Task Update(T model) where T : DataEntity { using (IDbConnection connection = new SqlConnection(_dbSettings.DefaultConnection)) diff --git a/src/DevChatter.DevStreams.Infra.Twitch/TwitchStreamService.cs b/src/DevChatter.DevStreams.Infra.Twitch/TwitchStreamService.cs index 0bfec52..78889eb 100644 --- a/src/DevChatter.DevStreams.Infra.Twitch/TwitchStreamService.cs +++ b/src/DevChatter.DevStreams.Infra.Twitch/TwitchStreamService.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Net.Http; using System.Threading.Tasks; +using DevChatter.DevStreams.Core.Model; namespace DevChatter.DevStreams.Infra.Twitch { @@ -19,11 +20,20 @@ public TwitchStreamService(IOptions twitchSettings) _twitchSettings = twitchSettings.Value; } - /// - /// Returns the subset of the channels which are currently live on Twitch. - /// - /// Names of the Channels to check for live status. - /// The names of the subset of channels that are currently live. + + + public async Task IsLive(string twitchId) + { + // TODO: Have this just check cache or do a refresh based on getting *all* data. + + var url = $"{_twitchSettings.BaseApiUrl}/streams?user_id={twitchId}"; + var jsonResult = await Get(url); + + var result = JsonConvert.DeserializeObject(jsonResult); + + return new ChannelLiveState{TwitchId = twitchId, IsLive = result.Data.Any()}; + } + public async Task> GetChannelLiveStates(List twitchIds) { if (!twitchIds.Any()) @@ -37,27 +47,24 @@ public async Task> GetChannelLiveStates(List twit var result = JsonConvert.DeserializeObject(jsonResult); - var liveChannels = result.Data.Where(x => x.Type == "live").ToList(); + var liveChannels = result.Data.ToList(); - return twitchIds - .Select(twitchId => new ChannelLiveState - { - TwitchId = twitchId, - IsLive = liveChannels.Any(x => x.User_id == twitchId) - }) - .ToList(); - } + var returnStat = new List(); - public async Task IsLive(string twitchId) - { - // TODO: Have this just check cache or do a refresh based on getting *all* data. - - var url = $"{_twitchSettings.BaseApiUrl}/streams?user_id={twitchId}"; - var jsonResult = await Get(url); - - var result = JsonConvert.DeserializeObject(jsonResult); + if (twitchIds.Any()) + { + returnStat = twitchIds + .Select(twitchId => new ChannelLiveState + { + TwitchId = twitchId, + IsLive = liveChannels.Any(x => x.User_id == twitchId), + startedAt = result.Data.Where(x => x.User_id == twitchId).Select(x => x.Started_at.ToUniversalTime()).DefaultIfEmpty().First(), + viewerCount = result.Data.Where(x => x.User_id == twitchId).Select(x => x.Viewer_count).DefaultIfEmpty().First() - return new ChannelLiveState{TwitchId = twitchId, IsLive = result.Data.Any()}; + }) + .ToList(); + } + return returnStat; } // TODO: Extract to composed dependency diff --git a/src/DevChatter.DevStreams.Web/Controllers/IsLiveController.cs b/src/DevChatter.DevStreams.Web/Controllers/IsLiveController.cs index 37f47ce..702c57d 100644 --- a/src/DevChatter.DevStreams.Web/Controllers/IsLiveController.cs +++ b/src/DevChatter.DevStreams.Web/Controllers/IsLiveController.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using System; namespace DevChatter.DevStreams.Web.Controllers { @@ -26,20 +27,46 @@ public IsLiveController(ICrudRepository crudRepository, /// - /// Get all live streams. + /// Get all live streams info. /// - /// + /// TwitchName, isLive = True, started_At, View Count [HttpGet] public async Task Get() { List channels = await _crudRepository.GetAll(); List twitchIds = channels.Select(x => x.TwitchId).ToList(); - var liveTwitchIds = (await _twitchService.GetChannelLiveStates(twitchIds)) + var liveTwitchData = (await _twitchService.GetChannelLiveStates(twitchIds)); + + var sortedLiveData = liveTwitchData.OrderByDescending(o => o.viewerCount).ToList(); + + var liveTwitchIds = sortedLiveData .Where(x => x.IsLive) .Select(x => x.TwitchId) .ToList(); - var liveChannelNames = channels.Where(c => liveTwitchIds.Contains(c.TwitchId)).Select(c => c.TwitchName); - return Ok(liveChannelNames); + + var liveChannelSorted = sortedLiveData + .OrderByDescending(x => x.viewerCount) + .Select(x => channels.Where(y => y.TwitchId == x.TwitchId).Where(v => x.IsLive).Select(z => z.TwitchName)) + .Where(x => x.Any()) + .ToList(); + + var timeDifference = sortedLiveData + .Where(x => liveTwitchIds.Contains(x.TwitchId)) + .Select(x => (DateTime.UtcNow - x.startedAt.ToUniversalTime())); + + var viewerCount = sortedLiveData + .Where(x => liveTwitchIds.Contains(x.TwitchId)) + .Select(x => x.viewerCount) + .ToList(); + + var responseObject = new + { + Channel = liveChannelSorted, + viewCount = viewerCount, + timeOnline = timeDifference + }; + + return Ok(responseObject); } [HttpGet, Route("{twitchId}")] diff --git a/src/DevChatter.DevStreams.Web/Pages/Index.cshtml b/src/DevChatter.DevStreams.Web/Pages/Index.cshtml index 2f3c04e..9ef0b5a 100644 --- a/src/DevChatter.DevStreams.Web/Pages/Index.cshtml +++ b/src/DevChatter.DevStreams.Web/Pages/Index.cshtml @@ -8,9 +8,12 @@

Live Now

@*TODO: Show channels that are live right now.*@
    -
  • - {{liveChannel}} -
  • +
  • + {{liveChannel[0]}} + views: {{ liveChannels.viewCount[index] }} + Online: {{ liveChannels.timeOnline[index] }} + +
diff --git a/src/DevChatter.DevStreams.Web/Pages/Index.cshtml.cs b/src/DevChatter.DevStreams.Web/Pages/Index.cshtml.cs index 8c6adc3..45b9f3c 100644 --- a/src/DevChatter.DevStreams.Web/Pages/Index.cshtml.cs +++ b/src/DevChatter.DevStreams.Web/Pages/Index.cshtml.cs @@ -51,19 +51,26 @@ public async Task OnGetAsync() public async Task OnGetLuckyAsync() { - List channels = await _repo.GetAll(); + List channels = await _repo.GetAllChannelInfo(); + List twitchIds = channels.Select(x => x?.Twitch?.TwitchId) .Where(x => !string.IsNullOrWhiteSpace(x)) .ToList(); - var liveChannelIds = (await _twitchService.GetChannelLiveStates(twitchIds)) + + var liveTwitchId = (await _twitchService.GetChannelLiveStates(twitchIds)) .Where(x => x.IsLive) .Select(x => x.TwitchId) - .ToList(); - var result = new Result(); + .ToList().PickOneRandomElement(); + + var liveChannel = channels + .Where(x => x?.Twitch?.TwitchId == liveTwitchId) + .Select(x => x?.Name); + + var result = new Result(); ; - if (liveChannelIds.Any()) + if (liveChannel.Any()) { - result.ChannelName = liveChannelIds.PickOneRandomElement(); + result.ChannelName = liveChannel.First(); } else {