Skip to content

Commit

Permalink
Merge pull request #37 from laurencee/YoutubeChannelSupport
Browse files Browse the repository at this point in the history
Allow adding youtube channels by channelid
  • Loading branch information
laurencee authored Nov 19, 2017
2 parents b391f09 + 2ec03dd commit 9ff7e13
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 29 deletions.
8 changes: 4 additions & 4 deletions ExternalAPIs.Tests/YoutubeClientShould.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,18 @@ public async Task ThrowNotFoudExceptionForInvalidVideoId()
}

[Fact, Trait("Category", "LocalOnly")]
public async Task GetChannelIdFromChannelName()
public async Task GetChannelIdFromUsername()
{
const string channelName = "LoLChampSeries";
var channelId = await sut.GetChannelIdFromChannelName(channelName);
var channelId = await sut.GetChannelIdFromUsername(channelName);

Assert.NotNull(channelId);
}

[Fact, Trait("Category", "LocalOnly")]
public async Task GetLiveVideos()
{
// channelId of the value returned by the test "GetChannelIdFromChannelName"
// channelId of the value returned by the test "GetChannelIdFromUsername"
const string channelId = "UCvqRdlKsE5Q8mf8YXbdIJLw";
var onlineVideos = await sut.GetLivestreamVideos(channelId);

Expand Down
6 changes: 1 addition & 5 deletions ExternalAPIs/Youtube/Dto/QueryRoot/GetChannelIdByNameRoot.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace ExternalAPIs.Youtube.Dto.QueryRoot
Expand Down
7 changes: 3 additions & 4 deletions ExternalAPIs/Youtube/IYoutubeReadonlyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ namespace ExternalAPIs.Youtube
public interface IYoutubeReadonlyClient
{
/// <summary> A channel in youtube can have multiple livestreams running at one time </summary>
/// <param name="channelId">A channel id discovered from querying <see cref="GetChannelIdFromChannelName"/></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<SearchLiveVideosRoot> GetLivestreamVideos(string channelId, CancellationToken cancellationToken = default(CancellationToken));

Task<string> GetChannelIdFromChannelName(string channelName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary> Discover the channel id given a username </summary>
Task<string> GetChannelIdFromUsername(string userName, CancellationToken cancellationToken = default(CancellationToken));

/// <summary> Get the details for a youtube videoid </summary>
Task<VideoRoot> GetLivestreamDetails(string videoId, CancellationToken cancellationToken = default(CancellationToken));
}
}
2 changes: 1 addition & 1 deletion ExternalAPIs/Youtube/RequestConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public static class RequestConstants
public const string VideoLivestreamDetails = GoogleApiRoot + @"videos?part=LiveStreamingDetails&key=" + API_KEY;
public const string VideoSnippet = GoogleApiRoot + @"videos?part=Snippet&key=" + API_KEY;
public const string SearchChannelLiveVideos = GoogleApiRoot + @"search?type=video&eventType=live&part=snippet,id&channelId={0}&key=" + API_KEY;
public const string GetChannelIdByName = GoogleApiRoot + @"channels?forUsername={0}&part=id&key=" + API_KEY;
public const string GetChannelIdByUsername = GoogleApiRoot + @"channels?forUsername={0}&part=id&key=" + API_KEY;
}
}
10 changes: 5 additions & 5 deletions ExternalAPIs/Youtube/YoutubeReadonlyClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ public class YoutubeReadonlyClient : IYoutubeReadonlyClient
return searchChannelLiveVideos;
}

public async Task<string> GetChannelIdFromChannelName(string channelName, CancellationToken cancellationToken = default(CancellationToken))
public async Task<string> GetChannelIdFromUsername(string userName, CancellationToken cancellationToken = default(CancellationToken))
{
if (IsNullOrWhiteSpace(channelName))
throw new ArgumentException("Argument is null or whitespace", nameof(channelName));
if (IsNullOrWhiteSpace(userName))
throw new ArgumentException("Argument is null or whitespace", nameof(userName));

var request = RequestConstants.GetChannelIdByName.Replace("{0}", channelName);
var request = RequestConstants.GetChannelIdByUsername.Replace("{0}", userName);
var channelDetails = await HttpClientExtensions.ExecuteRequest<GetChannelIdByNameRoot>(request, cancellationToken);
if (channelDetails.Items == null || channelDetails.Items.Count == 0)
throw new HttpRequestWithStatusException(HttpStatusCode.BadRequest, "Channel name not found " + channelName);
throw new HttpRequestWithStatusException(HttpStatusCode.BadRequest, "No channel found for username" + userName);

return channelDetails.Items?.FirstOrDefault()?.Id;
}
Expand Down
4 changes: 2 additions & 2 deletions GlobalAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]

[assembly: AssemblyVersion("2.11.0.0")]
[assembly: AssemblyFileVersion("2.11.0.0")]
[assembly: AssemblyVersion("2.11.1.0")]
[assembly: AssemblyFileVersion("2.11.1.0")]
5 changes: 5 additions & 0 deletions Livestream.Monitor/Model/ApiClients/LivestreamQueryResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@ public LivestreamQueryResult(ChannelIdentifier channelIdentifier)
public bool IsSuccess => FailedQueryException == null;

public FailedQueryException FailedQueryException { get; set; }

public override string ToString()
{
return $"{ChannelIdentifier} - IsSuccess: {IsSuccess}";
}
}
}
21 changes: 13 additions & 8 deletions Livestream.Monitor/Model/ApiClients/YoutubeApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ public Task<List<LivestreamQueryResult>> GetUserFollows(string userName)
throw new NotImplementedException();
}

private async Task<string> GetChannelIdByChannelName(string channelName, CancellationToken cancellationToken)
private async Task<string> GetChannelIdByUsername(string userName, CancellationToken cancellationToken)
{
string channelId = (string)cache.Get(channelName);
string channelId = (string)cache.Get(userName);
if (channelId != null)
return channelId;

channelId = await youtubeClient.GetChannelIdFromChannelName(channelName, cancellationToken);
channelId = await youtubeClient.GetChannelIdFromUsername(userName, cancellationToken);
// the id will never change so cache it forever once it's found
cache.Add(channelName, channelId, DateTimeOffset.MaxValue);
cache.Add(userName, channelId, DateTimeOffset.MaxValue);
return channelId;
}

Expand All @@ -135,7 +135,12 @@ private async Task<List<LivestreamQueryResult>> QueryChannels(

try
{
var channelId = await GetChannelIdByChannelName(channelIdentifier.ChannelId, cancellationToken);
string channelId;
if (channelIdentifier.ChannelId.StartsWith("UC") || channelIdentifier.ChannelId.StartsWith("HC"))
channelId = channelIdentifier.ChannelId;
else
channelId = await GetChannelIdByUsername(channelIdentifier.ChannelId, cancellationToken);

var videoIds = await GetVideoIdsByChannelId(channelId, cancellationToken);
var livestreamModels = await GetLivestreamModels(channelIdentifier, videoIds, cancellationToken);
queryResults.AddRange(livestreamModels.Select(x => new LivestreamQueryResult(channelIdentifier)
Expand All @@ -150,7 +155,7 @@ private async Task<List<LivestreamQueryResult>> QueryChannels(
{
queryResults.Add(new LivestreamQueryResult(channelIdentifier)
{
LivestreamModel = new LivestreamModel("offline", channelIdentifier)
LivestreamModel = new LivestreamModel("offline-" + channelIdentifier.ChannelId, channelIdentifier)
{
DisplayName = channelIdentifier.ChannelId,
Description = "[Offline youtube stream]",
Expand Down Expand Up @@ -208,12 +213,12 @@ private async Task<List<LivestreamModel>> GetLivestreamModels(ChannelIdentifier
}
retryCount++;
}

if (livestreamDetails == null) continue;

var snippet = videoRoot.Items?.FirstOrDefault()?.Snippet;
if (snippet == null) continue;

var livestreamModel = new LivestreamModel(videoId, channelIdentifier) { Live = snippet.LiveBroadcastContent != "none" };
if (!livestreamModel.Live) continue;

Expand Down

0 comments on commit 9ff7e13

Please sign in to comment.