Added Subscriptions
This commit is contained in:
parent
a87aad366b
commit
ebcc4cda54
|
@ -10,7 +10,7 @@ namespace Tesses.YouTubeDownloader.Net6
|
|||
TYTDCurrentDirectory currentDirectory=new TYTDCurrentDirectory(new HttpClient());
|
||||
TYTDServer server=new TYTDServer(currentDirectory);
|
||||
server.RootServer.Server=new StaticServer("WebSite");
|
||||
HttpServerListener listener=new HttpServerListener(server.InnerServer);
|
||||
HttpServerListener listener=new HttpServerListener(new System.Net.IPEndPoint(System.Net.IPAddress.Any,42440),server.InnerServer);
|
||||
currentDirectory.StartLoop();
|
||||
TYTDStorage.FFmpeg ="/usr/bin/ffmpeg";
|
||||
Console.WriteLine("Almost Ready to Listen");
|
||||
|
|
|
@ -325,6 +325,7 @@ namespace Tesses.YouTubeDownloader.Server
|
|||
public ApiV2Server(IDownloader downloader)
|
||||
{
|
||||
this.Downloader=downloader;
|
||||
|
||||
Add("/AddItem",AddItem);
|
||||
Add("/AddChannel",AddChannel);
|
||||
Add("/AddUser",AddUser);
|
||||
|
@ -332,7 +333,94 @@ namespace Tesses.YouTubeDownloader.Server
|
|||
Add("/AddVideo",AddVideo);
|
||||
Add("/Progress",ProgressFunc);
|
||||
Add("/QueueList",QueueList);
|
||||
Add("/subscribe",Subscribe);
|
||||
Add("/resubscribe",Resubscribe);
|
||||
|
||||
}
|
||||
public async Task Resubscribe(ServerContext ctx)
|
||||
{
|
||||
TYTDStorage storage = Downloader as TYTDStorage;
|
||||
if(storage != null)
|
||||
{
|
||||
string id;
|
||||
|
||||
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||
{
|
||||
|
||||
string confstr;
|
||||
ChannelBellInfo conf=ChannelBellInfo.NotifyAndDownload;
|
||||
if(ctx.QueryParams.TryGetFirst("conf",out confstr))
|
||||
{
|
||||
if(!Enum.TryParse<ChannelBellInfo>(confstr,out conf))
|
||||
{
|
||||
conf = ChannelBellInfo.NotifyAndDownload;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelId? cid=ChannelId.TryParse(WebUtility.UrlDecode(id));
|
||||
|
||||
if(cid.HasValue)
|
||||
{
|
||||
|
||||
var sub=storage.GetSubscription(cid.Value);
|
||||
if(sub != null)
|
||||
{
|
||||
sub.BellInfo = conf;
|
||||
await storage.SaveSubscription(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await ctx.SendTextAsync(
|
||||
$"<html><head><title>You Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
|
||||
);
|
||||
}
|
||||
public async Task Subscribe(ServerContext ctx)
|
||||
{
|
||||
TYTDStorage storage = Downloader as TYTDStorage;
|
||||
if(storage != null)
|
||||
{
|
||||
string id;
|
||||
|
||||
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||
{
|
||||
string getinfostr;
|
||||
bool getinfo=true;
|
||||
if(ctx.QueryParams.TryGetFirst("getinfo",out getinfostr))
|
||||
{
|
||||
if(getinfostr == "false")
|
||||
{
|
||||
getinfo=false;
|
||||
}
|
||||
}
|
||||
string confstr;
|
||||
ChannelBellInfo conf=ChannelBellInfo.NotifyAndDownload;
|
||||
if(ctx.QueryParams.TryGetFirst("conf",out confstr))
|
||||
{
|
||||
if(!Enum.TryParse<ChannelBellInfo>(confstr,out conf))
|
||||
{
|
||||
conf = ChannelBellInfo.NotifyAndDownload;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelId? cid=ChannelId.TryParse(WebUtility.UrlDecode(id));
|
||||
|
||||
if(cid.HasValue)
|
||||
{
|
||||
|
||||
await storage.Subscribe(cid.Value,getinfo,conf);
|
||||
}else{
|
||||
UserName? uname=UserName.TryParse(WebUtility.UrlDecode(id));
|
||||
await storage.Subscribe(uname.Value,conf);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
await ctx.SendTextAsync(
|
||||
$"<html><head><title>You Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
|
||||
);
|
||||
}
|
||||
|
||||
public async Task QueueList(ServerContext ctx)
|
||||
{
|
||||
await ctx.SendJsonAsync(Downloader.GetQueueList());
|
||||
|
@ -362,7 +450,7 @@ namespace Tesses.YouTubeDownloader.Server
|
|||
}
|
||||
}
|
||||
await ctx.SendTextAsync(
|
||||
$"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
|
||||
$"<html><head><title>You Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
|
||||
);
|
||||
}
|
||||
public async Task AddItem(ServerContext ctx)
|
||||
|
@ -390,7 +478,7 @@ namespace Tesses.YouTubeDownloader.Server
|
|||
public async Task AddUser(ServerContext ctx)
|
||||
{
|
||||
string id;
|
||||
if(ctx.QueryParams.TryGetFirst("v",out id))
|
||||
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||
{
|
||||
Resolution resolution=Resolution.PreMuxed;
|
||||
string res;
|
||||
|
@ -415,7 +503,7 @@ namespace Tesses.YouTubeDownloader.Server
|
|||
public async Task AddChannel(ServerContext ctx)
|
||||
{
|
||||
string id;
|
||||
if(ctx.QueryParams.TryGetFirst("v",out id))
|
||||
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||
{
|
||||
Resolution resolution=Resolution.PreMuxed;
|
||||
string res;
|
||||
|
@ -440,7 +528,7 @@ namespace Tesses.YouTubeDownloader.Server
|
|||
public async Task AddPlaylist(ServerContext ctx)
|
||||
{
|
||||
string id;
|
||||
if(ctx.QueryParams.TryGetFirst("v",out id))
|
||||
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||
{
|
||||
Resolution resolution=Resolution.PreMuxed;
|
||||
string res;
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<PackageId>Tesses.YouTubeDownloader.Server</PackageId>
|
||||
<Author>Mike Nolan</Author>
|
||||
<Company>Tesses</Company>
|
||||
<Version>1.0.1.0</Version>
|
||||
<AssemblyVersion>1.0.1.0</AssemblyVersion>
|
||||
<FileVersion>1.0.1.0</FileVersion>
|
||||
<Version>1.0.2.0</Version>
|
||||
<AssemblyVersion>1.0.2.0</AssemblyVersion>
|
||||
<FileVersion>1.0.2.0</FileVersion>
|
||||
<Description>Adds WebServer to TYTD</Description>
|
||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
|
|
|
@ -27,7 +27,11 @@ namespace Tesses.YouTubeDownloader
|
|||
var (Video, Resolution) = Dequeue(out hasAny);
|
||||
if (hasAny)
|
||||
{
|
||||
await DownloadVideoAsync(Video, Resolution, token,new Progress<double>(ReportProgress),true);
|
||||
await DownloadVideoAsync(Video, Resolution, token,new Progress<double>(
|
||||
async (e)=>{
|
||||
await ReportProgress(e);
|
||||
}
|
||||
),true);
|
||||
}
|
||||
|
||||
}catch(Exception ex)
|
||||
|
@ -38,7 +42,7 @@ namespace Tesses.YouTubeDownloader
|
|||
}
|
||||
|
||||
public readonly SavedVideoProgress Progress = new SavedVideoProgress();
|
||||
private void ReportProgress(double progress)
|
||||
private async Task ReportProgress(double progress)
|
||||
{
|
||||
Progress.Progress = (int)(progress * 100);
|
||||
Progress.ProgressRaw = progress;
|
||||
|
@ -47,11 +51,19 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
foreach (var ext in ExtensionContext.Extensions)
|
||||
{
|
||||
ext.VideoProgress(Progress.Video, progress);
|
||||
await ext.VideoProgress(Progress.Video, progress);
|
||||
}
|
||||
}
|
||||
|
||||
VideoProgressEventArgs args=new VideoProgressEventArgs();
|
||||
args.VideoInfo=Progress.Video;
|
||||
args.Progress=progress;
|
||||
|
||||
|
||||
VideoProgress?.Invoke(this,args);
|
||||
|
||||
}
|
||||
private void ReportStartVideo(SavedVideo video, Resolution resolution, long length)
|
||||
private async Task ReportStartVideo(SavedVideo video, Resolution resolution, long length)
|
||||
{
|
||||
GetLogger().WriteAsync(video).Wait();
|
||||
Progress.Video = video;
|
||||
|
@ -63,11 +75,17 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
foreach (var item in ExtensionContext.Extensions)
|
||||
{
|
||||
item.VideoStarted(video, resolution, length);
|
||||
await item.VideoStarted(video, resolution, length);
|
||||
}
|
||||
}
|
||||
VideoStartedEventArgs args=new VideoStartedEventArgs();
|
||||
args.VideoInfo=video;
|
||||
args.Resolution=resolution;
|
||||
args.EstimatedLength=length;
|
||||
|
||||
VideoStarted?.Invoke(this,args);
|
||||
}
|
||||
private void ReportEndVideo(SavedVideo video, Resolution resolution)
|
||||
private async Task ReportEndVideo(SavedVideo video, Resolution resolution)
|
||||
{
|
||||
Progress.Progress = 100;
|
||||
Progress.ProgressRaw = 1;
|
||||
|
@ -77,10 +95,15 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
foreach (var item in ExtensionContext.Extensions)
|
||||
{
|
||||
item.VideoFinished(video, resolution);
|
||||
await item.VideoFinished(video, resolution);
|
||||
}
|
||||
}
|
||||
VideoFinishedEventArgs args=new VideoFinishedEventArgs();
|
||||
args.VideoInfo=video;
|
||||
args.Resolution = resolution;
|
||||
VideoFinished?.Invoke(this,args);
|
||||
}
|
||||
|
||||
public async Task DownloadNoQueue(SavedVideo info,Resolution resolution=Resolution.Mux,CancellationToken token=default(CancellationToken),IProgress<double> progress=null)
|
||||
{
|
||||
|
||||
|
@ -399,7 +422,7 @@ namespace Tesses.YouTubeDownloader
|
|||
return;
|
||||
}
|
||||
if(report)
|
||||
ReportStartVideo(video,Resolution.Mux,0);
|
||||
await ReportStartVideo(video,Resolution.Mux,0);
|
||||
string complete = $"Muxed/{video.Id}.mkv";
|
||||
string incomplete = $"Muxed/{video.Id}incomplete.mkv";
|
||||
string complete_vidonly = $"VideoOnly/{video.Id}.{streams.VideoOnlyStreamInfo.Container}";
|
||||
|
@ -414,7 +437,7 @@ namespace Tesses.YouTubeDownloader
|
|||
}
|
||||
}
|
||||
if(report)
|
||||
ReportEndVideo(video,Resolution.Mux);
|
||||
await ReportEndVideo(video,Resolution.Mux);
|
||||
}
|
||||
private void DeleteIfExists(string path)
|
||||
{
|
||||
|
@ -447,7 +470,7 @@ namespace Tesses.YouTubeDownloader
|
|||
return false;
|
||||
}
|
||||
if(report)
|
||||
ReportStartVideo(video, Resolution.VideoOnly,streams.VideoOnlyStreamInfo.Size.Bytes);
|
||||
await ReportStartVideo(video, Resolution.VideoOnly,streams.VideoOnlyStreamInfo.Size.Bytes);
|
||||
long len=await GetLengthAsync(incomplete);
|
||||
|
||||
using(var dest = await OpenOrCreateAsync(incomplete))
|
||||
|
@ -458,7 +481,7 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
RenameFile(incomplete,complete);
|
||||
if(report)
|
||||
ReportEndVideo(video, Resolution.VideoOnly);
|
||||
await ReportEndVideo(video, Resolution.VideoOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -543,7 +566,7 @@ namespace Tesses.YouTubeDownloader
|
|||
return false;
|
||||
}
|
||||
if(report)
|
||||
ReportStartVideo(video, Resolution.AudioOnly,streams.AudioOnlyStreamInfo.Size.Bytes);
|
||||
await ReportStartVideo(video, Resolution.AudioOnly,streams.AudioOnlyStreamInfo.Size.Bytes);
|
||||
long len=await GetLengthAsync(incomplete);
|
||||
|
||||
using(var dest = await OpenOrCreateAsync(incomplete))
|
||||
|
@ -554,7 +577,7 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
RenameFile(incomplete,complete);
|
||||
if(report)
|
||||
ReportEndVideo(video, Resolution.AudioOnly);
|
||||
await ReportEndVideo(video, Resolution.AudioOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,7 +614,7 @@ namespace Tesses.YouTubeDownloader
|
|||
return;
|
||||
}
|
||||
if(report)
|
||||
ReportStartVideo(video,Resolution.PreMuxed,streams.MuxedStreamInfo.Size.Bytes);
|
||||
await ReportStartVideo(video,Resolution.PreMuxed,streams.MuxedStreamInfo.Size.Bytes);
|
||||
long len=await GetLengthAsync(incomplete);
|
||||
bool ret;
|
||||
using(var dest = await OpenOrCreateAsync(incomplete))
|
||||
|
@ -603,7 +626,7 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
RenameFile(incomplete,complete);
|
||||
if(report)
|
||||
ReportEndVideo(video, Resolution.PreMuxed);
|
||||
await ReportEndVideo(video, Resolution.PreMuxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,36 @@ namespace Tesses.YouTubeDownloader
|
|||
}
|
||||
public partial class TYTDStorage
|
||||
{
|
||||
internal LoggerProperties Properties {get;set;}
|
||||
public LoggerProperties GetProperties()
|
||||
{
|
||||
CreateDirectoryIfNotExist("config");
|
||||
CreateDirectoryIfNotExist("config/logs");
|
||||
|
||||
if(FileExists("config/tytdprop.json"))
|
||||
{
|
||||
string data=ReadAllTextAsync("config/tytdprop.json").GetAwaiter().GetResult();
|
||||
return JsonConvert.DeserializeObject<LoggerProperties>(data);
|
||||
}else{
|
||||
LoggerProperties prop=new LoggerProperties();
|
||||
prop.AddDateInLog=true;
|
||||
prop.LogVideoIds=true;
|
||||
prop.PrintErrors =false;
|
||||
prop.PrintVideoIds=true;
|
||||
prop.UseLogs=true;
|
||||
prop.SubscriptionInterval=TimeSpan.FromHours(1);
|
||||
prop.AlwaysDownloadChannel = false;
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
public LoggerProperties GetLoggerProperties()
|
||||
{
|
||||
if(Properties == null)
|
||||
{
|
||||
Properties=GetProperties();
|
||||
}
|
||||
return Properties;
|
||||
}
|
||||
internal static LockObj o=new LockObj();
|
||||
|
||||
private Logger _log=null;
|
||||
|
@ -41,6 +71,9 @@ namespace Tesses.YouTubeDownloader
|
|||
}
|
||||
public class LoggerProperties
|
||||
{
|
||||
public bool AlwaysDownloadChannel {get;set;}
|
||||
public TimeSpan SubscriptionInterval {get;set;}
|
||||
|
||||
public bool UseLogs {get;set;}
|
||||
|
||||
public bool PrintVideoIds {get;set;}
|
||||
|
@ -58,29 +91,11 @@ namespace Tesses.YouTubeDownloader
|
|||
private string _filename;
|
||||
private TYTDStorage _storage;
|
||||
|
||||
public LoggerProperties Properties {get;set;}
|
||||
|
||||
private LoggerProperties GetProperties(TYTDStorage storage)
|
||||
|
||||
internal Logger(TYTDStorage storage)
|
||||
{
|
||||
if(storage.FileExists("config/logger.json"))
|
||||
{
|
||||
string data=storage.ReadAllTextAsync("config/lggger.json").GetAwaiter().GetResult();
|
||||
return JsonConvert.DeserializeObject<LoggerProperties>(data);
|
||||
}else{
|
||||
LoggerProperties prop=new LoggerProperties();
|
||||
prop.AddDateInLog=true;
|
||||
prop.LogVideoIds=true;
|
||||
prop.PrintErrors =false;
|
||||
prop.PrintVideoIds=true;
|
||||
prop.UseLogs=true;
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
internal Logger(TYTDStorage storage)
|
||||
{
|
||||
storage.CreateDirectoryIfNotExist("config");
|
||||
storage.CreateDirectoryIfNotExist("config/logs");
|
||||
Properties = GetProperties(storage);
|
||||
|
||||
_storage=storage;
|
||||
|
||||
string dateTime = DateTime.Now.ToString("yyyyMMdd_hhmmss");
|
||||
|
@ -110,11 +125,11 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
|
||||
if(writeToConsole) WriteStd(message,isError);
|
||||
if(!log || !Properties.UseLogs) return;
|
||||
if(!log || !_storage.GetLoggerProperties().UseLogs) return;
|
||||
|
||||
// DateTime time = DateTime.Now;
|
||||
var msg= new StringBuilder();
|
||||
if(Properties.AddDateInLog)
|
||||
if(_storage.GetLoggerProperties().AddDateInLog)
|
||||
{
|
||||
var dat=DateTime.Now;
|
||||
msg.AppendLine($"{dat.ToShortDateString()} at {dat.ToShortTimeString()}:");
|
||||
|
@ -142,11 +157,11 @@ namespace Tesses.YouTubeDownloader
|
|||
|
||||
public async Task WriteAsync(Exception ex)
|
||||
{
|
||||
await WriteAsync($"Exception Catched:\n{ex.ToString()}",Properties.PrintErrors,true);
|
||||
await WriteAsync($"Exception Catched:\n{ex.ToString()}",_storage.GetLoggerProperties().PrintErrors,true);
|
||||
}
|
||||
public async Task WriteAsync(SavedVideo video)
|
||||
{
|
||||
await WriteAsync($"Download: {video.Title} with Id: {video.Id}",Properties.PrintVideoIds,false,Properties.LogVideoIds);
|
||||
await WriteAsync($"Download: {video.Title} with Id: {video.Id}",_storage.GetLoggerProperties().PrintVideoIds,false,_storage.GetLoggerProperties().LogVideoIds);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,6 +110,7 @@ namespace Tesses.YouTubeDownloader
|
|||
}
|
||||
public async Task FillQueue(TYTDStorage storage, List<(SavedVideo video, Resolution resolution)> Queue)
|
||||
{
|
||||
|
||||
string path=$"Playlist/{Id}.json";
|
||||
List<IVideo> videos=new List<IVideo>();
|
||||
await foreach(var vid in storage.YoutubeClient.Playlists.GetVideosAsync(Id))
|
||||
|
@ -117,6 +118,13 @@ namespace Tesses.YouTubeDownloader
|
|||
videos.Add(vid);
|
||||
}
|
||||
var p=new SavedPlaylist(await storage.YoutubeClient.Playlists.GetAsync(Id),videos);
|
||||
if(storage.GetLoggerProperties().AlwaysDownloadChannel)
|
||||
{
|
||||
var c=ChannelId.Parse(p.AuthorChannelId);
|
||||
ChannelMediaContext cmc=new ChannelMediaContext(c,Resolution.NoDownload);
|
||||
await cmc.GetChannel(storage);
|
||||
|
||||
}
|
||||
await storage.WriteAllTextAsync(path,JsonConvert.SerializeObject(p));
|
||||
if(Resolution == Resolution.NoDownload) return;
|
||||
foreach(var item in videos)
|
||||
|
@ -146,6 +154,8 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
try{
|
||||
video = new SavedVideo(await storage.YoutubeClient.Videos.GetAsync(Id));
|
||||
|
||||
storage.SendBeforeSaveInfo(video);
|
||||
await storage.WriteAllTextAsync(path,JsonConvert.SerializeObject(video));
|
||||
await video.DownloadThumbnails(storage);
|
||||
}catch(Exception ex)
|
||||
|
@ -157,6 +167,13 @@ namespace Tesses.YouTubeDownloader
|
|||
}else{
|
||||
video = JsonConvert.DeserializeObject<SavedVideo>(await storage.ReadAllTextAsync(path));
|
||||
}
|
||||
if(storage.GetLoggerProperties().AlwaysDownloadChannel)
|
||||
{
|
||||
var c=ChannelId.Parse(video.AuthorChannelId);
|
||||
ChannelMediaContext cmc=new ChannelMediaContext(c,Resolution.NoDownload);
|
||||
await cmc.GetChannel(storage);
|
||||
|
||||
}
|
||||
if(resolution == Resolution.NoDownload) return;
|
||||
lock(queue)
|
||||
{
|
||||
|
|
|
@ -231,14 +231,14 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
StringBuilder b=new StringBuilder();
|
||||
b.AppendLine($"Title: {Title}");
|
||||
b.AppendLine($"💁 {AuthorTitle}");
|
||||
b.AppendLine($"AuthorTitle: {AuthorTitle}");
|
||||
DateTime date=UploadDate;
|
||||
|
||||
b.AppendLine($"📅 {date.ToShortDateString()}");
|
||||
b.AppendLine($"Upload Date: {date.ToShortDateString()}");
|
||||
|
||||
b.AppendLine($"👍 {Likes}, 👎 {Dislikes}, 👁 {Views}");
|
||||
b.AppendLine($"🕒 {Duration.ToString()}");
|
||||
b.AppendLine($"🔑 {string.Join(", ",Keywords)}");
|
||||
b.AppendLine($"Likes: {Likes}, Dislikes: {Dislikes}, Views: {Views}");
|
||||
b.AppendLine($"Duration: {Duration.ToString()}");
|
||||
b.AppendLine($"Tags: {string.Join(", ",Keywords)}");
|
||||
b.AppendLine("Description:");
|
||||
b.AppendLine(Description);
|
||||
return b.ToString();
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Newtonsoft.Json;
|
||||
using YoutubeExplode.Channels;
|
||||
using YoutubeExplode.Videos;
|
||||
|
||||
namespace Tesses.YouTubeDownloader
|
||||
{
|
||||
|
||||
public class BellEventArgs : EventArgs
|
||||
{
|
||||
public VideoId Id {get;set;}
|
||||
}
|
||||
public class VideoProgressEventArgs : EventArgs
|
||||
{
|
||||
public SavedVideo VideoInfo {get;set;}
|
||||
|
||||
public double Progress {get;set;}
|
||||
}
|
||||
public class BeforeSaveInfoEventArgs : EventArgs
|
||||
{
|
||||
public SavedVideo VideoInfo {get;set;}
|
||||
|
||||
}
|
||||
public class VideoStartedEventArgs : EventArgs
|
||||
{
|
||||
public SavedVideo VideoInfo {get;set;}
|
||||
public Resolution Resolution {get;set;}
|
||||
public long EstimatedLength {get;set;}
|
||||
}
|
||||
|
||||
public class VideoFinishedEventArgs : EventArgs
|
||||
{
|
||||
public SavedVideo VideoInfo {get;set;}
|
||||
public Resolution Resolution {get;set;}
|
||||
}
|
||||
|
||||
public abstract partial class TYTDStorage
|
||||
{
|
||||
///<summary>
|
||||
///For Notifications Like Bell on YouTube
|
||||
///</summary>
|
||||
|
||||
public event EventHandler<BellEventArgs> Bell;
|
||||
public event EventHandler<VideoStartedEventArgs> VideoStarted;
|
||||
|
||||
public event EventHandler<BeforeSaveInfoEventArgs> BeforeSaveInfo;
|
||||
|
||||
public event EventHandler<VideoProgressEventArgs> VideoProgress;
|
||||
|
||||
public event EventHandler<VideoFinishedEventArgs> VideoFinished;
|
||||
|
||||
internal void SendBeforeSaveInfo(SavedVideo video)
|
||||
{
|
||||
BeforeSaveInfo?.Invoke(this,new BeforeSaveInfoEventArgs() {VideoInfo=video});
|
||||
}
|
||||
internal void SendBell(VideoId i)
|
||||
{
|
||||
|
||||
Bell?.Invoke(this,new BellEventArgs() {Id=i});
|
||||
|
||||
}
|
||||
|
||||
|
||||
public DateTime LastSubscriptionTime = DateTime.MinValue;
|
||||
public async Task HandleSubscriptions()
|
||||
{
|
||||
var date=DateTime.Now;
|
||||
var interval=GetLoggerProperties().SubscriptionInterval;
|
||||
if(date - interval < LastSubscriptionTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach(var sub in Subscriptions)
|
||||
{
|
||||
await sub.LookOnYouTube();
|
||||
}
|
||||
LastSubscriptionTime=date;
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<Subscription> GetSubscriptionsAsync()
|
||||
{
|
||||
|
||||
await foreach(var item in EnumerateFilesAsync("Subscriptions"))
|
||||
{
|
||||
if(Path.GetExtension(item).Equals(".json"))
|
||||
{
|
||||
var sub=JsonConvert.DeserializeObject<Subscription>(item);
|
||||
sub.Base=this;
|
||||
yield return await Task.FromResult(sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Subscribe to creator
|
||||
/// </summary>
|
||||
public async Task Subscribe(ChannelId id, bool downloadChannelInfo=false,ChannelBellInfo bellInfo = ChannelBellInfo.NotifyAndDownload)
|
||||
{
|
||||
if(downloadChannelInfo)
|
||||
{
|
||||
ChannelMediaContext context=new ChannelMediaContext(id,Resolution.NoDownload);
|
||||
var c=await context.GetChannel(this);
|
||||
}
|
||||
Subscription sub=new Subscription();
|
||||
sub.BellInfo = bellInfo;
|
||||
sub.Base=this;
|
||||
sub.Id=id.Value;
|
||||
Subscriptions.Add(sub);
|
||||
await SaveSubscription(sub);
|
||||
}
|
||||
public async Task SaveSubscription(Subscription sub)
|
||||
{
|
||||
await WriteAllTextAsync($"Subscriptions/{sub.Id}",JsonConvert.SerializeObject(sub));
|
||||
}
|
||||
public async Task Subscribe(UserName name,ChannelBellInfo bellInfo=ChannelBellInfo.NotifyAndDownload)
|
||||
{
|
||||
ChannelMediaContext context=new ChannelMediaContext(name,Resolution.NoDownload);
|
||||
var c=await context.GetChannel(this);
|
||||
await Subscribe(ChannelId.Parse(c.Id),false,bellInfo);
|
||||
}
|
||||
public void Unsubscribe(ChannelId id)
|
||||
{
|
||||
Subscription sub= Subscriptions.FirstOrDefault(e=>e.Id==id.Value);
|
||||
if(sub != null)
|
||||
{
|
||||
Subscriptions.Remove(sub);
|
||||
}
|
||||
DeleteFile($"Subscriptions/{sub.Id}.json");
|
||||
}
|
||||
|
||||
public Subscription GetSubscription(ChannelId id)
|
||||
{
|
||||
return Subscriptions.FirstOrDefault(e=>e.Id==id.Value);
|
||||
}
|
||||
|
||||
}
|
||||
[Flags]
|
||||
public enum ChannelBellInfo
|
||||
{
|
||||
DoNothing=0,
|
||||
GetInfo=1,
|
||||
|
||||
Notify=2,
|
||||
|
||||
Download=3,
|
||||
|
||||
NotifyAndDownload=Notify|Download
|
||||
}
|
||||
|
||||
public class Subscription
|
||||
{
|
||||
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public TYTDStorage Base {get;set;}
|
||||
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
public DateTime LastCheckTime = DateTime.Now;
|
||||
|
||||
public string Id {get;set;}
|
||||
|
||||
public ChannelBellInfo BellInfo {get;set;}
|
||||
|
||||
public async Task<SavedChannel> GetChannelInfo()
|
||||
{
|
||||
if(await Base.FileExistsAsync($"Channel/{Id}.json"))
|
||||
{
|
||||
return await Base.GetChannelInfoAsync(Id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task LookOnYouTube()
|
||||
{
|
||||
try{
|
||||
List<(string Id,DateTime Time)> items=new List<(string Id, DateTime Time)>();
|
||||
XmlDocument doc=new XmlDocument();
|
||||
doc.LoadXml(await Base.HttpClient.GetStringAsync($"https://www.youtube.com/feeds/videos.xml?channel_id={Id}"));
|
||||
foreach(XmlNode item in doc.GetElementsByTagName("entry"))
|
||||
{
|
||||
string Id="";
|
||||
DateTime Time=LastCheckTime-TimeSpan.FromMinutes(1);
|
||||
|
||||
foreach(XmlNode item2 in item.ChildNodes)
|
||||
{
|
||||
if(item2.Name == "yt:videoId")
|
||||
{
|
||||
if(BellInfo.HasFlag(ChannelBellInfo.Download))
|
||||
{
|
||||
await Base.AddVideoAsync(item2.InnerText);
|
||||
}
|
||||
|
||||
Id=item2.InnerText;
|
||||
}
|
||||
if(item2.Name == "published")
|
||||
{
|
||||
Time = DateTime.Parse(item2.InnerText);
|
||||
}
|
||||
}
|
||||
items.Add((Id,Time));
|
||||
}
|
||||
if(BellInfo.HasFlag(ChannelBellInfo.Notify) )
|
||||
{
|
||||
foreach(var item in items)
|
||||
{
|
||||
if(item.Time > LastCheckTime)
|
||||
{
|
||||
Base.SendBell(item.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
LastCheckTime=DateTime.Now;
|
||||
}catch(Exception ex)
|
||||
{
|
||||
await Base.GetLogger().WriteAsync(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -115,6 +115,7 @@ namespace Tesses.YouTubeDownloader
|
|||
}
|
||||
public void CreateDirectories()
|
||||
{
|
||||
CreateDirectoryIfNotExist("Subscriptions");
|
||||
CreateDirectoryIfNotExist("VideoOnly");
|
||||
CreateDirectoryIfNotExist("AudioOnly");
|
||||
CreateDirectoryIfNotExist("Muxed");
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
<PackageId>Tesses.YouTubeDownloader</PackageId>
|
||||
<Author>Mike Nolan</Author>
|
||||
<Company>Tesses</Company>
|
||||
<Version>1.0.2.4</Version>
|
||||
<AssemblyVersion>1.0.2.4</AssemblyVersion>
|
||||
<FileVersion>1.0.2.4</FileVersion>
|
||||
<Version>1.0.3.0</Version>
|
||||
<AssemblyVersion>1.0.3.0</AssemblyVersion>
|
||||
<FileVersion>1.0.3.0</FileVersion>
|
||||
<Description>A YouTube Downloader</Description>
|
||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
|
|
|
@ -32,13 +32,26 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
return Progress;
|
||||
}
|
||||
List<Subscription> Subscriptions {get;set;}
|
||||
List<(SavedVideo Video, Resolution Resolution)> QueueList = new List<(SavedVideo Video, Resolution Resolution)>();
|
||||
List<IMediaContext> Temporary =new List<IMediaContext>();
|
||||
private async Task QueueLoop(CancellationToken token)
|
||||
{
|
||||
|
||||
try{
|
||||
|
||||
Subscriptions=new List<Subscription>();
|
||||
await foreach(var sub in GetSubscriptionsAsync())
|
||||
{
|
||||
Subscriptions.Add(sub);
|
||||
}
|
||||
}catch(Exception ex)
|
||||
{
|
||||
await GetLogger().WriteAsync(ex);
|
||||
}
|
||||
while(!token.IsCancellationRequested)
|
||||
{ try{
|
||||
|
||||
IMediaContext context;
|
||||
lock(Temporary)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue