2017-09-01 08:55:02 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Google.Apis.YouTube.v3;
|
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
|
|
2018-02-20 04:57:14 +00:00
|
|
|
|
namespace YTManager.Tasks {
|
|
|
|
|
public class FetchVideos {
|
|
|
|
|
// Get a bunch of videos from youtube that the channel generated.
|
2018-02-28 23:33:40 +00:00
|
|
|
|
public static async Task<List<Models.Video>> Get_YTVideos(string channelID, int max = 50) {
|
2017-09-01 08:55:02 +00:00
|
|
|
|
// YT API access key
|
|
|
|
|
var youtubeService = new YouTubeService(new Google.Apis.Services.BaseClientService.Initializer()
|
|
|
|
|
{
|
|
|
|
|
ApiKey = "AIzaSyCuIYkMc5SktlnXRXNaDf2ObX-fQvtWCnQ",
|
|
|
|
|
ApplicationName = "testingapppp"
|
|
|
|
|
});
|
|
|
|
|
|
2018-02-28 23:33:40 +00:00
|
|
|
|
// Max cannot be larger than 50, so clamp it.
|
|
|
|
|
max = max > 50 ? 50 : max;
|
|
|
|
|
|
2018-02-20 04:57:14 +00:00
|
|
|
|
// Search youtube for all the relevant data of the channel.
|
2018-02-28 23:33:40 +00:00
|
|
|
|
var videos_query = youtubeService.Search.List("snippet");
|
|
|
|
|
videos_query.ChannelId = channelID;
|
|
|
|
|
videos_query.Order = SearchResource.ListRequest.OrderEnum.Date;
|
|
|
|
|
videos_query.MaxResults = max;
|
|
|
|
|
var videos_response = await videos_query.ExecuteAsync();
|
2018-02-20 04:57:14 +00:00
|
|
|
|
|
|
|
|
|
// Convert the response into models.
|
2018-02-28 23:33:40 +00:00
|
|
|
|
var videos = videos_response.Items?
|
2018-02-20 04:57:14 +00:00
|
|
|
|
.Where(i => i.Id.Kind == "youtube#video")
|
|
|
|
|
.Select(newvid => new Models.Video
|
|
|
|
|
{
|
|
|
|
|
Title = newvid.Snippet.Title,
|
|
|
|
|
Description = newvid.Snippet.Description,
|
|
|
|
|
YoutubeID = newvid.Id.VideoId,
|
|
|
|
|
AddedToYT = newvid.Snippet.PublishedAt.GetValueOrDefault(),
|
|
|
|
|
AddedtoDB = DateTime.Now,
|
2018-03-05 06:08:55 +00:00
|
|
|
|
ThumbnailURL = newvid.Snippet.Thumbnails.Medium.Url,
|
|
|
|
|
Tags = new string[] {}
|
2018-02-20 04:57:14 +00:00
|
|
|
|
}).ToList();
|
2018-02-28 23:33:40 +00:00
|
|
|
|
|
|
|
|
|
// Search youtube to get the length and tags for each video.
|
|
|
|
|
var duration_query = youtubeService.Videos.List("contentDetails,snippet");
|
|
|
|
|
duration_query.Id = string.Join(',', videos.Select(v => v.YoutubeID));
|
|
|
|
|
var duration_response = await duration_query.ExecuteAsync();
|
|
|
|
|
|
|
|
|
|
// Pair each video with the result.
|
|
|
|
|
foreach(var contentdetail in duration_response.Items.Where(i => i.Kind == "youtube#video")){
|
|
|
|
|
var vid = videos.Single(v => v.YoutubeID == contentdetail.Id);
|
|
|
|
|
|
|
|
|
|
// Yes, really, ISO8601 time span => c#'s TimeSpan is not in TimeSpan, it's in xmlconvert! Wtf?!
|
|
|
|
|
vid.Duration = System.Xml.XmlConvert.ToTimeSpan(contentdetail.ContentDetails.Duration);
|
|
|
|
|
|
|
|
|
|
// Copy over all the created tags if any tags were provided.
|
2018-03-05 06:08:55 +00:00
|
|
|
|
if (contentdetail.Snippet.Tags != null)
|
|
|
|
|
vid.Tags = contentdetail.Snippet.Tags.Select(t => t.ToLower()).ToArray();
|
2018-02-28 23:33:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send back the parsed vids.
|
|
|
|
|
return videos;
|
2018-02-20 04:57:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-20 05:13:06 +00:00
|
|
|
|
// Gets some info about a youtube channel.
|
2018-02-20 04:57:14 +00:00
|
|
|
|
public static async Task<Models.Channel> Get_YTChannel(string channelID) {
|
|
|
|
|
// YT API access key
|
|
|
|
|
var youtubeService = new YouTubeService(new Google.Apis.Services.BaseClientService.Initializer()
|
|
|
|
|
{
|
|
|
|
|
ApiKey = "AIzaSyCuIYkMc5SktlnXRXNaDf2ObX-fQvtWCnQ",
|
|
|
|
|
ApplicationName = "testingapppp"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Search youtube for all the relevant data of the channel.
|
|
|
|
|
var query = youtubeService.Channels.List("snippet");
|
|
|
|
|
query.Id = channelID;
|
|
|
|
|
query.MaxResults = 1;
|
|
|
|
|
var response = await query.ExecuteAsync();
|
|
|
|
|
|
|
|
|
|
// Parse the response into a channel.
|
|
|
|
|
return new Models.Channel {
|
|
|
|
|
Description = response.Items.First().Snippet.Description,
|
|
|
|
|
Title = response.Items.First().Snippet.Title,
|
|
|
|
|
ThumbnailURL = response.Items.First().Snippet.Thumbnails.Medium.Url,
|
|
|
|
|
YoutubeID = channelID,
|
2018-02-20 06:16:30 +00:00
|
|
|
|
AddedtoDB = DateTime.Now,
|
2018-02-24 06:10:12 +00:00
|
|
|
|
Refreshed = DateTime.MinValue,
|
2018-03-05 06:08:55 +00:00
|
|
|
|
UserTags = new string[]{},
|
|
|
|
|
Videos = { }
|
2018-02-20 04:57:14 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update videos for all our channels.
|
|
|
|
|
public static async Task MassUpdate(string dbstr) {
|
2018-02-18 19:06:16 +00:00
|
|
|
|
// Get the interface to the database.
|
2017-09-01 08:55:02 +00:00
|
|
|
|
var ops = new DbContextOptionsBuilder<MediaDB>();
|
2018-02-20 04:57:14 +00:00
|
|
|
|
ops.UseNpgsql(dbstr);
|
|
|
|
|
|
2018-02-20 06:16:30 +00:00
|
|
|
|
// Get all the channels from the db that expired.
|
2018-02-24 06:10:12 +00:00
|
|
|
|
var threshold = DateTime.Now.Subtract(TimeSpan.FromMinutes(60));
|
2018-02-20 05:13:06 +00:00
|
|
|
|
var channel_ids = await
|
2018-02-20 06:16:30 +00:00
|
|
|
|
(new MediaDB(ops.Options)).Channels
|
|
|
|
|
.Where(ch => ch.Refreshed < threshold)
|
|
|
|
|
.Select(ch => ch.YoutubeID)
|
2018-02-20 05:13:06 +00:00
|
|
|
|
.ToListAsync();
|
2018-02-20 04:57:14 +00:00
|
|
|
|
|
|
|
|
|
// For each channel, do an update.
|
2018-02-20 05:13:06 +00:00
|
|
|
|
channel_ids.ForEach(async id => await ChannelUpdate(dbstr, id));
|
2018-02-20 04:57:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update videos for just one channel.
|
|
|
|
|
public static async Task ChannelUpdate(string dbstr, string youtubechannelIDstr) {
|
|
|
|
|
// Get the interface to the database.
|
|
|
|
|
var ops = new DbContextOptionsBuilder<MediaDB>();
|
|
|
|
|
ops.UseNpgsql(dbstr);
|
|
|
|
|
var db = new MediaDB(ops.Options);
|
|
|
|
|
|
|
|
|
|
// Get the channel from the db when including it's videos.
|
|
|
|
|
var channel = await db.Channels
|
|
|
|
|
.Include(c => c.Videos)
|
|
|
|
|
.SingleOrDefaultAsync(ch => ch.YoutubeID == youtubechannelIDstr);
|
|
|
|
|
|
|
|
|
|
// Update the channel if it was found.
|
|
|
|
|
if (channel != null) {
|
|
|
|
|
// Get all the new videos for the channel.
|
|
|
|
|
var Videos = await Get_YTVideos(channel.YoutubeID);
|
|
|
|
|
|
|
|
|
|
// Get all the videos which haven't been put into this channels videos.
|
2018-02-24 04:03:27 +00:00
|
|
|
|
var newvids = Videos
|
|
|
|
|
.Where(nv => !channel.Videos.Any(cv => cv.YoutubeID == nv.YoutubeID));
|
|
|
|
|
|
|
|
|
|
// Say what channel all the videos came from.
|
|
|
|
|
foreach (var v in newvids)
|
2018-02-24 06:10:12 +00:00
|
|
|
|
v.Channel = channel;
|
2018-02-20 04:57:14 +00:00
|
|
|
|
|
2018-02-20 23:00:05 +00:00
|
|
|
|
// Say the channel has been refreshed.
|
|
|
|
|
channel.Refreshed = DateTime.Now;
|
|
|
|
|
|
2018-02-20 04:57:14 +00:00
|
|
|
|
// Add all the videos to the databse.
|
|
|
|
|
await db.Videos.AddRangeAsync(newvids);
|
|
|
|
|
|
|
|
|
|
// Update the videos this channel refers to.
|
|
|
|
|
channel.Videos.AddRange(newvids);
|
|
|
|
|
|
|
|
|
|
// And say the database should be changed.
|
|
|
|
|
await db.SaveChangesAsync();
|
2017-09-01 08:55:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|