BackEnd/Tasks/FetchVideos.cs

150 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Apis.YouTube.v3;
using Microsoft.EntityFrameworkCore;
namespace YTManager.Tasks {
public class FetchVideos {
// Get a bunch of videos from youtube that the channel generated.
public static async Task<List<Models.Video>> Get_YTVideos(string channelID, int max = 50) {
// YT API access key
var youtubeService = new YouTubeService(new Google.Apis.Services.BaseClientService.Initializer()
{
ApiKey = "AIzaSyCuIYkMc5SktlnXRXNaDf2ObX-fQvtWCnQ",
ApplicationName = "testingapppp"
});
// Max cannot be larger than 50, so clamp it.
max = max > 50 ? 50 : max;
// Search youtube for all the relevant data of the channel.
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();
// Convert the response into models.
var videos = videos_response.Items?
.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,
ThumbnailURL = newvid.Snippet.Thumbnails.Medium.Url,
Tags = new string[] {}
}).ToList();
// 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.
if (contentdetail.Snippet.Tags != null)
vid.Tags = contentdetail.Snippet.Tags.Select(t => t.ToLower()).ToArray();
}
// Send back the parsed vids.
return videos;
}
// Gets some info about a youtube channel.
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,
AddedtoDB = DateTime.Now,
Refreshed = DateTime.MinValue,
UserTags = new string[]{},
Videos = { }
};
}
// Update videos for all our channels.
public static async Task MassUpdate(string dbstr) {
// Get the interface to the database.
var ops = new DbContextOptionsBuilder<MediaDB>();
ops.UseNpgsql(dbstr);
// Get all the channels from the db that expired.
var threshold = DateTime.Now.Subtract(TimeSpan.FromMinutes(60));
var channel_ids = await
(new MediaDB(ops.Options)).Channels
.Where(ch => ch.Refreshed < threshold)
.Select(ch => ch.YoutubeID)
.ToListAsync();
// For each channel, do an update.
channel_ids.ForEach(async id => await ChannelUpdate(dbstr, id));
}
// 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.
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)
v.Channel = channel;
// Say the channel has been refreshed.
channel.Refreshed = DateTime.Now;
// 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();
}
}
}
}