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());
|
TYTDCurrentDirectory currentDirectory=new TYTDCurrentDirectory(new HttpClient());
|
||||||
TYTDServer server=new TYTDServer(currentDirectory);
|
TYTDServer server=new TYTDServer(currentDirectory);
|
||||||
server.RootServer.Server=new StaticServer("WebSite");
|
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();
|
currentDirectory.StartLoop();
|
||||||
TYTDStorage.FFmpeg ="/usr/bin/ffmpeg";
|
TYTDStorage.FFmpeg ="/usr/bin/ffmpeg";
|
||||||
Console.WriteLine("Almost Ready to Listen");
|
Console.WriteLine("Almost Ready to Listen");
|
||||||
|
|
|
@ -325,6 +325,7 @@ namespace Tesses.YouTubeDownloader.Server
|
||||||
public ApiV2Server(IDownloader downloader)
|
public ApiV2Server(IDownloader downloader)
|
||||||
{
|
{
|
||||||
this.Downloader=downloader;
|
this.Downloader=downloader;
|
||||||
|
|
||||||
Add("/AddItem",AddItem);
|
Add("/AddItem",AddItem);
|
||||||
Add("/AddChannel",AddChannel);
|
Add("/AddChannel",AddChannel);
|
||||||
Add("/AddUser",AddUser);
|
Add("/AddUser",AddUser);
|
||||||
|
@ -332,7 +333,94 @@ namespace Tesses.YouTubeDownloader.Server
|
||||||
Add("/AddVideo",AddVideo);
|
Add("/AddVideo",AddVideo);
|
||||||
Add("/Progress",ProgressFunc);
|
Add("/Progress",ProgressFunc);
|
||||||
Add("/QueueList",QueueList);
|
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)
|
public async Task QueueList(ServerContext ctx)
|
||||||
{
|
{
|
||||||
await ctx.SendJsonAsync(Downloader.GetQueueList());
|
await ctx.SendJsonAsync(Downloader.GetQueueList());
|
||||||
|
@ -362,7 +450,7 @@ namespace Tesses.YouTubeDownloader.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await ctx.SendTextAsync(
|
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)
|
public async Task AddItem(ServerContext ctx)
|
||||||
|
@ -390,7 +478,7 @@ namespace Tesses.YouTubeDownloader.Server
|
||||||
public async Task AddUser(ServerContext ctx)
|
public async Task AddUser(ServerContext ctx)
|
||||||
{
|
{
|
||||||
string id;
|
string id;
|
||||||
if(ctx.QueryParams.TryGetFirst("v",out id))
|
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||||
{
|
{
|
||||||
Resolution resolution=Resolution.PreMuxed;
|
Resolution resolution=Resolution.PreMuxed;
|
||||||
string res;
|
string res;
|
||||||
|
@ -415,7 +503,7 @@ namespace Tesses.YouTubeDownloader.Server
|
||||||
public async Task AddChannel(ServerContext ctx)
|
public async Task AddChannel(ServerContext ctx)
|
||||||
{
|
{
|
||||||
string id;
|
string id;
|
||||||
if(ctx.QueryParams.TryGetFirst("v",out id))
|
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||||
{
|
{
|
||||||
Resolution resolution=Resolution.PreMuxed;
|
Resolution resolution=Resolution.PreMuxed;
|
||||||
string res;
|
string res;
|
||||||
|
@ -440,7 +528,7 @@ namespace Tesses.YouTubeDownloader.Server
|
||||||
public async Task AddPlaylist(ServerContext ctx)
|
public async Task AddPlaylist(ServerContext ctx)
|
||||||
{
|
{
|
||||||
string id;
|
string id;
|
||||||
if(ctx.QueryParams.TryGetFirst("v",out id))
|
if(ctx.QueryParams.TryGetFirst("id",out id))
|
||||||
{
|
{
|
||||||
Resolution resolution=Resolution.PreMuxed;
|
Resolution resolution=Resolution.PreMuxed;
|
||||||
string res;
|
string res;
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
<PackageId>Tesses.YouTubeDownloader.Server</PackageId>
|
<PackageId>Tesses.YouTubeDownloader.Server</PackageId>
|
||||||
<Author>Mike Nolan</Author>
|
<Author>Mike Nolan</Author>
|
||||||
<Company>Tesses</Company>
|
<Company>Tesses</Company>
|
||||||
<Version>1.0.1.0</Version>
|
<Version>1.0.2.0</Version>
|
||||||
<AssemblyVersion>1.0.1.0</AssemblyVersion>
|
<AssemblyVersion>1.0.2.0</AssemblyVersion>
|
||||||
<FileVersion>1.0.1.0</FileVersion>
|
<FileVersion>1.0.2.0</FileVersion>
|
||||||
<Description>Adds WebServer to TYTD</Description>
|
<Description>Adds WebServer to TYTD</Description>
|
||||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
|
|
|
@ -27,7 +27,11 @@ namespace Tesses.YouTubeDownloader
|
||||||
var (Video, Resolution) = Dequeue(out hasAny);
|
var (Video, Resolution) = Dequeue(out hasAny);
|
||||||
if (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)
|
}catch(Exception ex)
|
||||||
|
@ -38,7 +42,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly SavedVideoProgress Progress = new SavedVideoProgress();
|
public readonly SavedVideoProgress Progress = new SavedVideoProgress();
|
||||||
private void ReportProgress(double progress)
|
private async Task ReportProgress(double progress)
|
||||||
{
|
{
|
||||||
Progress.Progress = (int)(progress * 100);
|
Progress.Progress = (int)(progress * 100);
|
||||||
Progress.ProgressRaw = progress;
|
Progress.ProgressRaw = progress;
|
||||||
|
@ -47,11 +51,19 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
foreach (var ext in ExtensionContext.Extensions)
|
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();
|
GetLogger().WriteAsync(video).Wait();
|
||||||
Progress.Video = video;
|
Progress.Video = video;
|
||||||
|
@ -63,11 +75,17 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
foreach (var item in ExtensionContext.Extensions)
|
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.Progress = 100;
|
||||||
Progress.ProgressRaw = 1;
|
Progress.ProgressRaw = 1;
|
||||||
|
@ -77,10 +95,15 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
foreach (var item in ExtensionContext.Extensions)
|
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)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if(report)
|
if(report)
|
||||||
ReportStartVideo(video,Resolution.Mux,0);
|
await ReportStartVideo(video,Resolution.Mux,0);
|
||||||
string complete = $"Muxed/{video.Id}.mkv";
|
string complete = $"Muxed/{video.Id}.mkv";
|
||||||
string incomplete = $"Muxed/{video.Id}incomplete.mkv";
|
string incomplete = $"Muxed/{video.Id}incomplete.mkv";
|
||||||
string complete_vidonly = $"VideoOnly/{video.Id}.{streams.VideoOnlyStreamInfo.Container}";
|
string complete_vidonly = $"VideoOnly/{video.Id}.{streams.VideoOnlyStreamInfo.Container}";
|
||||||
|
@ -414,7 +437,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(report)
|
if(report)
|
||||||
ReportEndVideo(video,Resolution.Mux);
|
await ReportEndVideo(video,Resolution.Mux);
|
||||||
}
|
}
|
||||||
private void DeleteIfExists(string path)
|
private void DeleteIfExists(string path)
|
||||||
{
|
{
|
||||||
|
@ -447,7 +470,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(report)
|
if(report)
|
||||||
ReportStartVideo(video, Resolution.VideoOnly,streams.VideoOnlyStreamInfo.Size.Bytes);
|
await ReportStartVideo(video, Resolution.VideoOnly,streams.VideoOnlyStreamInfo.Size.Bytes);
|
||||||
long len=await GetLengthAsync(incomplete);
|
long len=await GetLengthAsync(incomplete);
|
||||||
|
|
||||||
using(var dest = await OpenOrCreateAsync(incomplete))
|
using(var dest = await OpenOrCreateAsync(incomplete))
|
||||||
|
@ -458,7 +481,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
RenameFile(incomplete,complete);
|
RenameFile(incomplete,complete);
|
||||||
if(report)
|
if(report)
|
||||||
ReportEndVideo(video, Resolution.VideoOnly);
|
await ReportEndVideo(video, Resolution.VideoOnly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -543,7 +566,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(report)
|
if(report)
|
||||||
ReportStartVideo(video, Resolution.AudioOnly,streams.AudioOnlyStreamInfo.Size.Bytes);
|
await ReportStartVideo(video, Resolution.AudioOnly,streams.AudioOnlyStreamInfo.Size.Bytes);
|
||||||
long len=await GetLengthAsync(incomplete);
|
long len=await GetLengthAsync(incomplete);
|
||||||
|
|
||||||
using(var dest = await OpenOrCreateAsync(incomplete))
|
using(var dest = await OpenOrCreateAsync(incomplete))
|
||||||
|
@ -554,7 +577,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
RenameFile(incomplete,complete);
|
RenameFile(incomplete,complete);
|
||||||
if(report)
|
if(report)
|
||||||
ReportEndVideo(video, Resolution.AudioOnly);
|
await ReportEndVideo(video, Resolution.AudioOnly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -591,7 +614,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(report)
|
if(report)
|
||||||
ReportStartVideo(video,Resolution.PreMuxed,streams.MuxedStreamInfo.Size.Bytes);
|
await ReportStartVideo(video,Resolution.PreMuxed,streams.MuxedStreamInfo.Size.Bytes);
|
||||||
long len=await GetLengthAsync(incomplete);
|
long len=await GetLengthAsync(incomplete);
|
||||||
bool ret;
|
bool ret;
|
||||||
using(var dest = await OpenOrCreateAsync(incomplete))
|
using(var dest = await OpenOrCreateAsync(incomplete))
|
||||||
|
@ -603,7 +626,7 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
RenameFile(incomplete,complete);
|
RenameFile(incomplete,complete);
|
||||||
if(report)
|
if(report)
|
||||||
ReportEndVideo(video, Resolution.PreMuxed);
|
await ReportEndVideo(video, Resolution.PreMuxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,36 @@ namespace Tesses.YouTubeDownloader
|
||||||
}
|
}
|
||||||
public partial class TYTDStorage
|
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();
|
internal static LockObj o=new LockObj();
|
||||||
|
|
||||||
private Logger _log=null;
|
private Logger _log=null;
|
||||||
|
@ -41,6 +71,9 @@ namespace Tesses.YouTubeDownloader
|
||||||
}
|
}
|
||||||
public class LoggerProperties
|
public class LoggerProperties
|
||||||
{
|
{
|
||||||
|
public bool AlwaysDownloadChannel {get;set;}
|
||||||
|
public TimeSpan SubscriptionInterval {get;set;}
|
||||||
|
|
||||||
public bool UseLogs {get;set;}
|
public bool UseLogs {get;set;}
|
||||||
|
|
||||||
public bool PrintVideoIds {get;set;}
|
public bool PrintVideoIds {get;set;}
|
||||||
|
@ -58,29 +91,11 @@ namespace Tesses.YouTubeDownloader
|
||||||
private string _filename;
|
private string _filename;
|
||||||
private TYTDStorage _storage;
|
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;
|
_storage=storage;
|
||||||
|
|
||||||
string dateTime = DateTime.Now.ToString("yyyyMMdd_hhmmss");
|
string dateTime = DateTime.Now.ToString("yyyyMMdd_hhmmss");
|
||||||
|
@ -110,11 +125,11 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
|
|
||||||
if(writeToConsole) WriteStd(message,isError);
|
if(writeToConsole) WriteStd(message,isError);
|
||||||
if(!log || !Properties.UseLogs) return;
|
if(!log || !_storage.GetLoggerProperties().UseLogs) return;
|
||||||
|
|
||||||
// DateTime time = DateTime.Now;
|
// DateTime time = DateTime.Now;
|
||||||
var msg= new StringBuilder();
|
var msg= new StringBuilder();
|
||||||
if(Properties.AddDateInLog)
|
if(_storage.GetLoggerProperties().AddDateInLog)
|
||||||
{
|
{
|
||||||
var dat=DateTime.Now;
|
var dat=DateTime.Now;
|
||||||
msg.AppendLine($"{dat.ToShortDateString()} at {dat.ToShortTimeString()}:");
|
msg.AppendLine($"{dat.ToShortDateString()} at {dat.ToShortTimeString()}:");
|
||||||
|
@ -142,11 +157,11 @@ namespace Tesses.YouTubeDownloader
|
||||||
|
|
||||||
public async Task WriteAsync(Exception ex)
|
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)
|
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)
|
public async Task FillQueue(TYTDStorage storage, List<(SavedVideo video, Resolution resolution)> Queue)
|
||||||
{
|
{
|
||||||
|
|
||||||
string path=$"Playlist/{Id}.json";
|
string path=$"Playlist/{Id}.json";
|
||||||
List<IVideo> videos=new List<IVideo>();
|
List<IVideo> videos=new List<IVideo>();
|
||||||
await foreach(var vid in storage.YoutubeClient.Playlists.GetVideosAsync(Id))
|
await foreach(var vid in storage.YoutubeClient.Playlists.GetVideosAsync(Id))
|
||||||
|
@ -117,6 +118,13 @@ namespace Tesses.YouTubeDownloader
|
||||||
videos.Add(vid);
|
videos.Add(vid);
|
||||||
}
|
}
|
||||||
var p=new SavedPlaylist(await storage.YoutubeClient.Playlists.GetAsync(Id),videos);
|
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));
|
await storage.WriteAllTextAsync(path,JsonConvert.SerializeObject(p));
|
||||||
if(Resolution == Resolution.NoDownload) return;
|
if(Resolution == Resolution.NoDownload) return;
|
||||||
foreach(var item in videos)
|
foreach(var item in videos)
|
||||||
|
@ -146,6 +154,8 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
video = new SavedVideo(await storage.YoutubeClient.Videos.GetAsync(Id));
|
video = new SavedVideo(await storage.YoutubeClient.Videos.GetAsync(Id));
|
||||||
|
|
||||||
|
storage.SendBeforeSaveInfo(video);
|
||||||
await storage.WriteAllTextAsync(path,JsonConvert.SerializeObject(video));
|
await storage.WriteAllTextAsync(path,JsonConvert.SerializeObject(video));
|
||||||
await video.DownloadThumbnails(storage);
|
await video.DownloadThumbnails(storage);
|
||||||
}catch(Exception ex)
|
}catch(Exception ex)
|
||||||
|
@ -157,6 +167,13 @@ namespace Tesses.YouTubeDownloader
|
||||||
}else{
|
}else{
|
||||||
video = JsonConvert.DeserializeObject<SavedVideo>(await storage.ReadAllTextAsync(path));
|
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;
|
if(resolution == Resolution.NoDownload) return;
|
||||||
lock(queue)
|
lock(queue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,14 +231,14 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
StringBuilder b=new StringBuilder();
|
StringBuilder b=new StringBuilder();
|
||||||
b.AppendLine($"Title: {Title}");
|
b.AppendLine($"Title: {Title}");
|
||||||
b.AppendLine($"💁 {AuthorTitle}");
|
b.AppendLine($"AuthorTitle: {AuthorTitle}");
|
||||||
DateTime date=UploadDate;
|
DateTime date=UploadDate;
|
||||||
|
|
||||||
b.AppendLine($"📅 {date.ToShortDateString()}");
|
b.AppendLine($"Upload Date: {date.ToShortDateString()}");
|
||||||
|
|
||||||
b.AppendLine($"👍 {Likes}, 👎 {Dislikes}, 👁 {Views}");
|
b.AppendLine($"Likes: {Likes}, Dislikes: {Dislikes}, Views: {Views}");
|
||||||
b.AppendLine($"🕒 {Duration.ToString()}");
|
b.AppendLine($"Duration: {Duration.ToString()}");
|
||||||
b.AppendLine($"🔑 {string.Join(", ",Keywords)}");
|
b.AppendLine($"Tags: {string.Join(", ",Keywords)}");
|
||||||
b.AppendLine("Description:");
|
b.AppendLine("Description:");
|
||||||
b.AppendLine(Description);
|
b.AppendLine(Description);
|
||||||
return b.ToString();
|
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()
|
public void CreateDirectories()
|
||||||
{
|
{
|
||||||
|
CreateDirectoryIfNotExist("Subscriptions");
|
||||||
CreateDirectoryIfNotExist("VideoOnly");
|
CreateDirectoryIfNotExist("VideoOnly");
|
||||||
CreateDirectoryIfNotExist("AudioOnly");
|
CreateDirectoryIfNotExist("AudioOnly");
|
||||||
CreateDirectoryIfNotExist("Muxed");
|
CreateDirectoryIfNotExist("Muxed");
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
<PackageId>Tesses.YouTubeDownloader</PackageId>
|
<PackageId>Tesses.YouTubeDownloader</PackageId>
|
||||||
<Author>Mike Nolan</Author>
|
<Author>Mike Nolan</Author>
|
||||||
<Company>Tesses</Company>
|
<Company>Tesses</Company>
|
||||||
<Version>1.0.2.4</Version>
|
<Version>1.0.3.0</Version>
|
||||||
<AssemblyVersion>1.0.2.4</AssemblyVersion>
|
<AssemblyVersion>1.0.3.0</AssemblyVersion>
|
||||||
<FileVersion>1.0.2.4</FileVersion>
|
<FileVersion>1.0.3.0</FileVersion>
|
||||||
<Description>A YouTube Downloader</Description>
|
<Description>A YouTube Downloader</Description>
|
||||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
|
|
|
@ -32,13 +32,26 @@ namespace Tesses.YouTubeDownloader
|
||||||
{
|
{
|
||||||
return Progress;
|
return Progress;
|
||||||
}
|
}
|
||||||
|
List<Subscription> Subscriptions {get;set;}
|
||||||
List<(SavedVideo Video, Resolution Resolution)> QueueList = new List<(SavedVideo Video, Resolution Resolution)>();
|
List<(SavedVideo Video, Resolution Resolution)> QueueList = new List<(SavedVideo Video, Resolution Resolution)>();
|
||||||
List<IMediaContext> Temporary =new List<IMediaContext>();
|
List<IMediaContext> Temporary =new List<IMediaContext>();
|
||||||
private async Task QueueLoop(CancellationToken token)
|
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)
|
while(!token.IsCancellationRequested)
|
||||||
{ try{
|
{ try{
|
||||||
|
|
||||||
IMediaContext context;
|
IMediaContext context;
|
||||||
lock(Temporary)
|
lock(Temporary)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue