From 96d2a358b44c5669c553380d2691aa3262578414 Mon Sep 17 00:00:00 2001 From: Michael Nolan Date: Sun, 28 Aug 2022 16:40:34 -0500 Subject: [PATCH] Push update --- .../SymlinkGenerator.cs | 86 +++++++++++++++-- .../Program.cs | 58 +++++++++++- Tesses.YouTubeDownloader.Server/Class1.cs | 92 +++++++++---------- .../Tesses.YouTubeDownloader.Server.csproj | 6 +- .../ConsoleWriteEventArgs.cs | 16 ++++ Tesses.YouTubeDownloader/DownloadLoop.cs | 38 ++++++-- Tesses.YouTubeDownloader/IDownloader.cs | 1 + Tesses.YouTubeDownloader/IStorage.cs | 1 + Tesses.YouTubeDownloader/Logging.cs | 23 ++++- Tesses.YouTubeDownloader/SavedVideo.cs | 1 + Tesses.YouTubeDownloader/TYTD.cs | 33 ++++++- Tesses.YouTubeDownloader/TYTDClient.cs | 13 +++ .../TYTDIDownloaderStorageProxy.cs | 5 + .../Tesses.YouTubeDownloader.csproj | 6 +- 14 files changed, 297 insertions(+), 82 deletions(-) create mode 100644 Tesses.YouTubeDownloader/ConsoleWriteEventArgs.cs diff --git a/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.Common/SymlinkGenerator.cs b/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.Common/SymlinkGenerator.cs index 208dfdd..f52bd1e 100644 --- a/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.Common/SymlinkGenerator.cs +++ b/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.Common/SymlinkGenerator.cs @@ -1,6 +1,9 @@ using System.Diagnostics; using System.Runtime.InteropServices; using System; +using YoutubeExplode.Videos; +using Newtonsoft.Json; + namespace Tesses.YouTubeDownloader.Tools.Common { public static class SymlinkGenerator @@ -14,7 +17,8 @@ namespace Tesses.YouTubeDownloader.Tools.Common }else{ using(var p=new Process()) { - + p.StartInfo.UseShellExecute=false; + p.StartInfo.WorkingDirectory="/"; p.StartInfo.FileName = "ln"; p.StartInfo.ArgumentList.Add(srcPath); p.StartInfo.ArgumentList.Add(destPath); @@ -26,11 +30,14 @@ namespace Tesses.YouTubeDownloader.Tools.Common public static async Task GenerateHardLinks(TYTDStorage storage,string dest="GoodFileNames",Resolution res=Resolution.PreMuxed,bool verbose=false) { Directory.CreateDirectory(dest); - await foreach(var item in storage.GetVideosAsync()) + await foreach(var item in storage.GetVideosAsync()) { - if(await item.VideoExistsAsync(storage,res)) + try{ + var v=await BestStreams.GetPathResolution(storage,item,res); + if(storage.FileExists(v)) { - var (path,delete)= await storage.GetRealUrlOrPathAsync(await BestStreams.GetPathResolution(storage,item,res)); + + var (path,delete)= await storage.GetRealUrlOrPathAsync(v); string? ext=Path.GetExtension(path); string defaultExt = res == Resolution.Mux ? ".mkv" : ".mp4"; @@ -55,17 +62,84 @@ namespace Tesses.YouTubeDownloader.Tools.Common Console.WriteLine(item.Title); } } + }catch(Exception ex) + { + Console.WriteLine($"ERROR: {item.Id}"); + Console.WriteLine(ex.ToString()); + } } } + public static async Task VideoExistsAsync(ITYTDBase b,SavedVideo id) + { + var res=await BestStreams.GetPathResolution(b,id,Resolution.PreMuxed); + if(b.FileExists(res)) return true; + await BestStreams.GetPathResolution(b,id,Resolution.Mux); + if(b.FileExists(res)) return true; + await BestStreams.GetPathResolution(b,id,Resolution.VideoOnly); + if(b.FileExists(res)) return true; + await BestStreams.GetPathResolution(b,id,Resolution.AudioOnly); + if(b.FileExists(res)) return true; + + return false; + } + public static async Task GenerateMeta(List items,TYTDStorage storage,string dest="GoodInfos",bool verbose=false) + { + items.Add("Videos"); + if(verbose) + { + Console.WriteLine("[Generating Meta]"); + } + Directory.CreateDirectory(dest); + await foreach(var item in storage.GetVideosAsync()) + { + if(await VideoExistsAsync(storage,item)) + { + string destPathJson=Path.Combine(dest,$"{item.Title.GetSafeFileName()}-{item.Id}.json"); + string destPathText=Path.Combine(dest,$"{item.Title.GetSafeFileName()}-{item.Id}.txt"); + if(!File.Exists(destPathJson)) + File.WriteAllText(destPathJson,JsonConvert.SerializeObject(item,Formatting.Indented)); + if(!File.Exists(destPathText)){ using(var f=new StreamWriter(destPathText)) + { + f.WriteLine($"Title: {item.Title}"); + f.WriteLine($"Id: {item.Id}"); + f.WriteLine($"AuthorTitle: {item.AuthorTitle}"); + f.WriteLine($"AuthorChannelId: {item.AuthorChannelId}"); + f.WriteLine($"Tags: {string.Join(", ",item.Keywords)}"); + + f.WriteLine($"Views: {item.Views}"); + f.WriteLine($"Likes: {item.Likes}"); + f.WriteLine($"Dislikes: {item.Dislikes}"); + + f.WriteLine($"Duration: {item.Duration.ToString()}"); + f.WriteLine($"Upload Date: {item.UploadDate}"); + f.WriteLine($"Add Date: {item.AddDate.ToShortDateString()}"); + + f.WriteLine($"DownloadFrom: {item.DownloadFrom}"); + f.WriteLine($"Legacy Video: {item.LegacyVideo}"); + f.WriteLine($"Downloader Tag: {item.TYTDTag}"); + f.WriteLine($"Video Frozen: {item.VideoFrozen}"); + + f.WriteLine("Description:"); + f.WriteLine($"{item.Description}"); + }} + items.Add($"{item.Title}-{item.Id}"); + if(verbose) + { + Console.WriteLine($"[META] {item.Title}"); + } + } + } + } public static async Task GenerateSymlinks(TYTDBase storage,string dest="GoodFileNames",Resolution res=Resolution.PreMuxed,bool verbose=false) { Directory.CreateDirectory(dest); await foreach(var item in storage.GetVideosAsync()) { - if(await item.VideoExistsAsync(storage,res)) + var v=await BestStreams.GetPathResolution(storage,item,res); + if(storage.FileExists(v)) { - var (path,delete)= await storage.GetRealUrlOrPathAsync(await BestStreams.GetPathResolution(storage,item,res)); + var (path,delete)= await storage.GetRealUrlOrPathAsync(v); string? ext=Path.GetExtension(path); string defaultExt = res == Resolution.Mux ? ".mkv" : ".mp4"; diff --git a/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.LinkCreator/Program.cs b/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.LinkCreator/Program.cs index 8be3e2d..8f9c98e 100644 --- a/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.LinkCreator/Program.cs +++ b/Tesses.YouTubeDownloader.Extras/Tesses.YouTubeDownloader.Tools/Tesses.YouTubeDownloader.Tools.LinkCreator/Program.cs @@ -7,6 +7,7 @@ Resolution res=Resolution.PreMuxed; bool verbose=false; bool isSymlink = false; +bool isBigExport=false; List _args=new List(); foreach(var arg in args) { @@ -16,6 +17,11 @@ foreach(var arg in args) _args.Clear(); break; } + if( (arg.Length >= 2 && arg[1] != '-' && arg[0] == '-' && arg.Contains("g") )|| arg == "--generate-export") + { + any=true; + isBigExport=true; + } if( (arg.Length >= 2 && arg[1] != '-' && arg[0] == '-' && arg.Contains("s") )|| arg == "--symbolic") { any=true; @@ -44,6 +50,7 @@ foreach(var arg in args) verbose=true; } + if(!any) _args.Add(arg); @@ -53,7 +60,7 @@ if(argv.Length < 2) { string app = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]); - Console.WriteLine($"usage: {app} [-smaVv] []"); + Console.WriteLine($"usage: {app} [-smaVvg] []"); Console.WriteLine(); Console.WriteLine("Options:"); Console.WriteLine(" -s, --symbolic make symbolic links instead of hard links"); @@ -62,6 +69,7 @@ if(argv.Length < 2) Console.WriteLine(" -V, --video-only set resolution to VideoOnly"); Console.WriteLine(" -h, --help show this help"); Console.WriteLine(" -v, --verbose print video names"); + Console.WriteLine(" -g, --generate-export Export everything to human readable format"); Console.WriteLine(); Console.WriteLine("Positional Arguments:"); Console.WriteLine(" Working the folder containing the Info Directory for TYTD. (required)"); @@ -76,8 +84,52 @@ TYTDCurrentDirectory currentDirectory=new TYTDCurrentDirectory(); currentDirectory.CanDownload=false; if(isSymlink){ -await SymlinkGenerator.GenerateSymlinks(currentDirectory,argv[1],res,verbose); + if(isBigExport) + { + string outDir = argv[1]; + string sd = Path.Combine(outDir,"PreMuxed"); + string hd = Path.Combine(outDir,"Muxed"); + string vo = Path.Combine(outDir,"VideoOnly"); + string ao = Path.Combine(outDir,"AudioOnly"); + string meta=Path.Combine(outDir,"Meta"); + + List videos=new List(); + try{ + await SymlinkGenerator.GenerateSymlinks(currentDirectory,sd,Resolution.PreMuxed,verbose); + await SymlinkGenerator.GenerateSymlinks(currentDirectory,hd,Resolution.Mux,verbose); + await SymlinkGenerator.GenerateSymlinks(currentDirectory,vo,Resolution.VideoOnly,verbose); + await SymlinkGenerator.GenerateSymlinks(currentDirectory,ao,Resolution.AudioOnly,verbose); + await SymlinkGenerator.GenerateMeta(videos,currentDirectory,meta,verbose); + }catch(Exception ex){ + _=ex; + } + File.WriteAllLines(Path.Combine(outDir,"videos.txt"),videos); + }else{ + await SymlinkGenerator.GenerateSymlinks(currentDirectory,argv[1],res,verbose); + } }else{ -await SymlinkGenerator.GenerateHardLinks(currentDirectory,argv[1],res,verbose); + if(isBigExport) + { + string outDir = argv[1]; + string sd = Path.Combine(outDir,"PreMuxed"); + string hd = Path.Combine(outDir,"Muxed"); + string vo = Path.Combine(outDir,"VideoOnly"); + string ao = Path.Combine(outDir,"AudioOnly"); + string meta=Path.Combine(outDir,"Meta"); + List videos=new List(); + try{ + await SymlinkGenerator.GenerateHardLinks(currentDirectory,sd,Resolution.PreMuxed,verbose); + await SymlinkGenerator.GenerateHardLinks(currentDirectory,hd,Resolution.Mux,verbose); + await SymlinkGenerator.GenerateHardLinks(currentDirectory,vo,Resolution.VideoOnly,verbose); + await SymlinkGenerator.GenerateHardLinks(currentDirectory,ao,Resolution.AudioOnly,verbose); + await SymlinkGenerator.GenerateMeta(videos,currentDirectory,meta,verbose); + File.WriteAllLines(Path.Combine(outDir,"videos.txt"),videos); + }catch(Exception ex){ + _=ex; + } + + }else{ + await SymlinkGenerator.GenerateHardLinks(currentDirectory,argv[1],res,verbose); + } } } diff --git a/Tesses.YouTubeDownloader.Server/Class1.cs b/Tesses.YouTubeDownloader.Server/Class1.cs index 661c5b1..ef43904 100644 --- a/Tesses.YouTubeDownloader.Server/Class1.cs +++ b/Tesses.YouTubeDownloader.Server/Class1.cs @@ -21,6 +21,10 @@ namespace Tesses.Extensions { return value.Substring(str.Length); } + public static async Task RedirectBackAsync(this ServerContext ctx) + { + await ctx.SendTextAsync("\n"); + } } } @@ -165,7 +169,7 @@ internal static class B64 // await ctx.SendTextAsync( // $"

You Will Be Redirected in 5 Sec

\n" //); - await ctx.SendRedirectAsync("/"); + } if(path.StartsWith("/AddItemRes/")) { @@ -252,7 +256,7 @@ internal static class B64 //); } - await ctx.SendRedirectAsync("/"); + await ctx.RedirectBackAsync(); } } internal class ApiStorage : Tesses.WebServer.Server @@ -846,6 +850,7 @@ internal static class B64 public ApiV2Server(IDownloader downloader) { this.Downloader=downloader; + AddBoth("/CancelDownload",Cancel); AddBoth("/Search",Search); AddBoth("/AddItem",AddItem); AddBoth("/AddChannel",AddChannel); @@ -899,6 +904,21 @@ internal static class B64 }*/ } + private async Task Cancel(ServerContext ctx) + { + bool restart=false; + string restartString="false"; + if(ctx.QueryParams.TryGetFirst("restart",out restartString)) + { + if(!bool.TryParse(restartString,out restart)) + { + restart=false; + } + } + Downloader.CancelDownload(restart); + await ctx.RedirectBackAsync(); + } + private async Task Search(ServerContext ctx) { var dl = Downloader as IStorage; @@ -942,9 +962,7 @@ internal static class B64 //Downloader.AddToPersonalPlaylistAsync(name); } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task ReplaceList(ServerContext ctx) { @@ -966,9 +984,7 @@ internal static class B64 //Downloader.AddToPersonalPlaylistAsync(name); } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task Everything_Export(ServerContext ctx) { @@ -1124,9 +1140,7 @@ internal static class B64 //Downloader.AddToPersonalPlaylistAsync(name); } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task DeleteFromList(ServerContext ctx) { @@ -1144,9 +1158,7 @@ internal static class B64 } } } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task SetResolutionInList(ServerContext ctx) { @@ -1173,9 +1185,7 @@ internal static class B64 } } } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task Subscriptions(ServerContext ctx) { @@ -1189,9 +1199,7 @@ internal static class B64 } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task Resubscribe(ServerContext ctx) { @@ -1222,9 +1230,7 @@ internal static class B64 } } } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task Unsubscribe(ServerContext ctx) @@ -1249,10 +1255,8 @@ internal static class B64 } } } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); - } + await ctx.RedirectBackAsync(); + } public async Task Subscribe(ServerContext ctx) { IStorage storage = Downloader as IStorage; @@ -1294,9 +1298,7 @@ internal static class B64 } } } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task QueueList(ServerContext ctx) @@ -1324,9 +1326,7 @@ internal static class B64 } await Downloader.AddFileAsync(url,download); - await ctx.SendTextAsync( - $"

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } } public async Task AddVideo(ServerContext ctx) @@ -1352,11 +1352,9 @@ internal static class B64 await Downloader.AddVideoAsync(id1.Value,resolution); } } - await ctx.SendTextAsync( - $"You Will Be Redirected in 5 Sec

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } - public async Task AddItem(ServerContext ctx) + public async Task AddItem(ServerContext ctx) { string id; if(ctx.QueryParams.TryGetFirst("v",out id)) @@ -1374,11 +1372,9 @@ internal static class B64 await Downloader.AddItemAsync(id,resolution); } - await ctx.SendTextAsync( - $"

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } - public async Task AddUser(ServerContext ctx) + public async Task AddUser(ServerContext ctx) { string id; if(ctx.QueryParams.TryGetFirst("id",out id)) @@ -1398,12 +1394,10 @@ internal static class B64 await Downloader.AddUserAsync(id1.Value,resolution); } } - await ctx.SendTextAsync( - $"

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } - public async Task AddChannel(ServerContext ctx) + public async Task AddChannel(ServerContext ctx) { string id; if(ctx.QueryParams.TryGetFirst("id",out id)) @@ -1423,9 +1417,7 @@ internal static class B64 await Downloader.AddChannelAsync(id1.Value,resolution); } } - await ctx.SendTextAsync( - $"

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } public async Task AddPlaylist(ServerContext ctx) @@ -1448,9 +1440,7 @@ internal static class B64 await Downloader.AddPlaylistAsync(id1.Value,resolution); } } - await ctx.SendTextAsync( - $"

You Will Be Redirected in 5 Sec

\n" - ); + await ctx.RedirectBackAsync(); } } diff --git a/Tesses.YouTubeDownloader.Server/Tesses.YouTubeDownloader.Server.csproj b/Tesses.YouTubeDownloader.Server/Tesses.YouTubeDownloader.Server.csproj index 43f225a..8ebdd86 100644 --- a/Tesses.YouTubeDownloader.Server/Tesses.YouTubeDownloader.Server.csproj +++ b/Tesses.YouTubeDownloader.Server/Tesses.YouTubeDownloader.Server.csproj @@ -15,9 +15,9 @@ Tesses.YouTubeDownloader.Server Mike Nolan Tesses - 1.1.5 - 1.1.5 - 1.1.5 + 1.1.6 + 1.1.6 + 1.1.6 Adds WebServer to TYTD LGPL-3.0-only true diff --git a/Tesses.YouTubeDownloader/ConsoleWriteEventArgs.cs b/Tesses.YouTubeDownloader/ConsoleWriteEventArgs.cs new file mode 100644 index 0000000..a9ef8c6 --- /dev/null +++ b/Tesses.YouTubeDownloader/ConsoleWriteEventArgs.cs @@ -0,0 +1,16 @@ +using System; +namespace Tesses.YouTubeDownloader +{ + public class ConsoleWriteEventArgs : EventArgs + { + /// + ///Use Console.Write(e.Text); not Console.WriteLine(e.Text); + /// + public string Text {get;set;} + + internal ConsoleWriteEventArgs(string e) + { + Text=e; + } + } +} \ No newline at end of file diff --git a/Tesses.YouTubeDownloader/DownloadLoop.cs b/Tesses.YouTubeDownloader/DownloadLoop.cs index c8661cf..fbbeda2 100644 --- a/Tesses.YouTubeDownloader/DownloadLoop.cs +++ b/Tesses.YouTubeDownloader/DownloadLoop.cs @@ -129,6 +129,9 @@ namespace Tesses.YouTubeDownloader private async Task DownloadVideoAsync(SavedVideo video, Resolution resolution, CancellationToken token=default(CancellationToken),IProgress progress=null,bool report=true) { + + begin_download: + try{ if(video.DownloadFrom == "YouTube") { @@ -147,6 +150,7 @@ namespace Tesses.YouTubeDownloader await DownloadVideoOnlyAsync(video,token,progress,report); break; } + }else if(video.DownloadFrom.StartsWith("NormalDownload,Length=")) { await DownloadFileAsync(video,token,progress,report); @@ -160,9 +164,23 @@ namespace Tesses.YouTubeDownloader await GetLogger().WriteAsync(ex); } } - + cancelDownload=false; + if(restartDownload) + { + restartDownload=false; + goto begin_download; + + } } + public bool cancelDownload=false; + public bool restartDownload=false; + public void CancelDownload(bool restart=false) + { + cancelDownload=true; + restartDownload=restart; + } + private async Task DownloadFileAsync(SavedVideo video, CancellationToken token, IProgress progress, bool report) { string incomplete_file_path = $"Download/{B64.Base64UrlEncodes(video.Id)}-incomplete.part"; @@ -371,7 +389,7 @@ namespace Tesses.YouTubeDownloader byte[] buffer=new byte[bufferSize]; do{ read=await src.ReadAsync(buffer,0,buffer.Length,token); - if(token.IsCancellationRequested) + if(token.IsCancellationRequested || restartDownload || cancelDownload) { return false; } @@ -381,8 +399,8 @@ namespace Tesses.YouTubeDownloader { progress.Report(curPos / len); } - }while(read>0 && !token.IsCancellationRequested); - if(token.IsCancellationRequested) + }while(read>0 && !token.IsCancellationRequested && !restartDownload && !cancelDownload); + if(token.IsCancellationRequested || restartDownload || cancelDownload) { return false; } @@ -505,17 +523,17 @@ namespace Tesses.YouTubeDownloader { bool isValid=true; isValid=await DownloadVideoOnlyAsync(video,token,progress,report); - if(token.IsCancellationRequested || !isValid) + if(token.IsCancellationRequested || !isValid || cancelDownload || restartDownload) { return; } isValid = await DownloadAudioOnlyAsync(video,token,progress,report); - if(token.IsCancellationRequested || !isValid) + if(token.IsCancellationRequested || !isValid || cancelDownload || restartDownload) { return; } var streams=await BestStreamInfo.GetBestStreams(this,video.Id,token,false); - if(token.IsCancellationRequested) + if(token.IsCancellationRequested || cancelDownload || restartDownload) { return; } @@ -568,7 +586,7 @@ namespace Tesses.YouTubeDownloader { using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.VideoOnlyStreamInfo,token)) { - if(token.IsCancellationRequested) + if(token.IsCancellationRequested || cancelDownload || restartDownload) { return false; } @@ -670,7 +688,7 @@ namespace Tesses.YouTubeDownloader using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.AudioOnlyStreamInfo,token)) { - if(token.IsCancellationRequested) + if(token.IsCancellationRequested || cancelDownload || restartDownload) { return false; } @@ -722,7 +740,7 @@ namespace Tesses.YouTubeDownloader using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.MuxedStreamInfo,token)) { - if(token.IsCancellationRequested) + if(token.IsCancellationRequested || cancelDownload || restartDownload) { return; } diff --git a/Tesses.YouTubeDownloader/IDownloader.cs b/Tesses.YouTubeDownloader/IDownloader.cs index 966aba6..06554ef 100644 --- a/Tesses.YouTubeDownloader/IDownloader.cs +++ b/Tesses.YouTubeDownloader/IDownloader.cs @@ -12,6 +12,7 @@ namespace Tesses.YouTubeDownloader { public interface IDownloader : IPersonalPlaylistSet { + void CancelDownload(bool restart=false); Task AddVideoAsync(VideoId id,Resolution resolution=Resolution.PreMuxed); Task AddPlaylistAsync(PlaylistId id,Resolution resolution=Resolution.PreMuxed); Task AddChannelAsync(ChannelId id,Resolution resolution=Resolution.PreMuxed); diff --git a/Tesses.YouTubeDownloader/IStorage.cs b/Tesses.YouTubeDownloader/IStorage.cs index 2c4e68e..93ec7eb 100644 --- a/Tesses.YouTubeDownloader/IStorage.cs +++ b/Tesses.YouTubeDownloader/IStorage.cs @@ -20,6 +20,7 @@ namespace Tesses.YouTubeDownloader Task WriteBestStreamInfoAsync(VideoId id,BestStreamInfo.BestStreamsSerialized serialized); Task MuxVideosAsync(SavedVideo video,string videoSrc,string audioSrc,string videoDest,IProgress progress=null,CancellationToken token=default(CancellationToken)); Task Continue(string path); + Task WriteVideoInfoAsync(SavedVideo channel); Task WritePlaylistInfoAsync(SavedPlaylist channel); Task WriteChannelInfoAsync(SavedChannel channel); diff --git a/Tesses.YouTubeDownloader/Logging.cs b/Tesses.YouTubeDownloader/Logging.cs index 3c458cf..4bb6989 100644 --- a/Tesses.YouTubeDownloader/Logging.cs +++ b/Tesses.YouTubeDownloader/Logging.cs @@ -131,17 +131,30 @@ namespace Tesses.YouTubeDownloader } private void WriteStdErr(string message) { - var col=Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; - Console.Error.WriteLine(message); - Console.ForegroundColor = col; + if(TYTDStorage.UseConsole){ + var col=Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; + Console.Error.WriteLine(message); + Console.ForegroundColor = col; + }else{ + _storage.ConsoleWriter.WriteLine($"ERROR: {message}"); + } } private void WriteStd(string message,bool error) { if(error) WriteStdErr(message); - else + else{ + if(TYTDStorage.UseConsole){ + var col=Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(message); + Console.ForegroundColor = col; + }else{ + _storage.ConsoleWriter.WriteLine(message); + } + } + } public async Task WriteAsync(string message,bool writeToConsole=false,bool isError=false,bool log=true) { diff --git a/Tesses.YouTubeDownloader/SavedVideo.cs b/Tesses.YouTubeDownloader/SavedVideo.cs index eb3c582..ad60f47 100644 --- a/Tesses.YouTubeDownloader/SavedVideo.cs +++ b/Tesses.YouTubeDownloader/SavedVideo.cs @@ -63,6 +63,7 @@ namespace Tesses.YouTubeDownloader video.AuthorTitle=AuthorTitle; video.Description=Description; video.UploadDate = DateTime.Parse(UploadDate); + video.Views=Views; return video; } } diff --git a/Tesses.YouTubeDownloader/TYTD.cs b/Tesses.YouTubeDownloader/TYTD.cs index 1990da3..d8b5fbe 100644 --- a/Tesses.YouTubeDownloader/TYTD.cs +++ b/Tesses.YouTubeDownloader/TYTD.cs @@ -10,29 +10,52 @@ using System.IO; using YoutubeExplode.Playlists; using YoutubeExplode.Channels; using Newtonsoft.Json; +using System.Text; namespace Tesses.YouTubeDownloader { + public abstract partial class TYTDStorage : TYTDBase, IStorage { + internal class ConsoleWriterCLS : TextWriter + { + Action cls; + public ConsoleWriterCLS(Action cls) + { + this.cls=cls; + } + + public override Encoding Encoding => Encoding.UTF8; + public override void Write(string value) + { + cls(value); + } + } private static readonly HttpClient _default = new HttpClient(); public abstract Task CreateAsync(string path); public abstract void CreateDirectory(string path); + public static bool UseConsole = true; + public TYTDStorage(HttpClient clt) { HttpClient=clt; YoutubeClient=new YoutubeClient(HttpClient); ExtensionContext=null; - + ConsoleWriter=new ConsoleWriterCLS((e)=>{ + ConsoleWrite?.Invoke(this,new ConsoleWriteEventArgs(e)); + }); } public TYTDStorage() { HttpClient=_default; YoutubeClient=new YoutubeClient(HttpClient); ExtensionContext=null; + ConsoleWriter=new ConsoleWriterCLS((e)=>{ + ConsoleWrite?.Invoke(this,new ConsoleWriteEventArgs(e)); + }); } public async Task WriteAllBytesAsync(string path,byte[] data,CancellationToken token=default(CancellationToken)) { @@ -41,7 +64,14 @@ namespace Tesses.YouTubeDownloader await s.WriteAsync(data,0,data.Length,token); } } + public EventHandler ConsoleWrite; + public TextWriter ConsoleWriter {get; private set;} public static string TYTDTag {get {return _tytd_tag;}} + public static void SetTYTDTag(string tag) + { + //for use on mobile phones + _tytd_tag= tag; + } private static string _tytd_tag=_getTYTDTag(); private static string _getTYTDTag() { @@ -175,6 +205,7 @@ namespace Tesses.YouTubeDownloader CreateDirectoryIfNotExist("FileInfo"); CreateDirectoryIfNotExist("Download"); CreateDirectoryIfNotExist("StreamInfo"); + CreateDirectoryIfNotExist("PersonalPlaylist"); } public void StartLoop(CancellationToken token = default(CancellationToken)) { diff --git a/Tesses.YouTubeDownloader/TYTDClient.cs b/Tesses.YouTubeDownloader/TYTDClient.cs index 1d7694a..7484ba3 100644 --- a/Tesses.YouTubeDownloader/TYTDClient.cs +++ b/Tesses.YouTubeDownloader/TYTDClient.cs @@ -507,5 +507,18 @@ internal class SegmentedHttpStream : Stream _=ex; } } + + public void CancelDownload(bool restart = false) + { + try{ + + + client.GetStringAsync($"{url}api/v2/CancelDownload?restart={restart}").GetAwaiter().GetResult(); + + }catch(Exception ex) + { + _=ex; + } + } } } \ No newline at end of file diff --git a/Tesses.YouTubeDownloader/TYTDIDownloaderStorageProxy.cs b/Tesses.YouTubeDownloader/TYTDIDownloaderStorageProxy.cs index d5c21ff..94d3d43 100644 --- a/Tesses.YouTubeDownloader/TYTDIDownloaderStorageProxy.cs +++ b/Tesses.YouTubeDownloader/TYTDIDownloaderStorageProxy.cs @@ -715,6 +715,11 @@ namespace Tesses.YouTubeDownloader { return await Storage.GetDownloadInfoAsync(url); } + + public void CancelDownload(bool restart = false) + { + Downloader.CancelDownload(restart); + } } public class DownloaderMigration diff --git a/Tesses.YouTubeDownloader/Tesses.YouTubeDownloader.csproj b/Tesses.YouTubeDownloader/Tesses.YouTubeDownloader.csproj index 25745d5..b9f0a81 100644 --- a/Tesses.YouTubeDownloader/Tesses.YouTubeDownloader.csproj +++ b/Tesses.YouTubeDownloader/Tesses.YouTubeDownloader.csproj @@ -7,9 +7,9 @@ Tesses.YouTubeDownloader Mike Nolan Tesses - 1.1.7 - 1.1.7 - 1.1.7 + 1.1.8 + 1.1.8 + 1.1.8 A YouTube Downloader LGPL-3.0-only true