150 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			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
 | |
|                 }).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 = new List<Models.Tag>();
 | |
|                 else
 | |
|                     vid.Tags = contentdetail.Snippet.Tags.Select(t => new Models.Tag { Name = t }).ToList();
 | |
|             }
 | |
| 
 | |
|             // 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,
 | |
|                 Videos = null
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         // 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();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |