Push update

This commit is contained in:
Michael Nolan 2022-08-28 16:40:34 -05:00
parent 8e5e58168a
commit 96d2a358b4
14 changed files with 297 additions and 82 deletions

View File

@ -1,6 +1,9 @@
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System; using System;
using YoutubeExplode.Videos;
using Newtonsoft.Json;
namespace Tesses.YouTubeDownloader.Tools.Common namespace Tesses.YouTubeDownloader.Tools.Common
{ {
public static class SymlinkGenerator public static class SymlinkGenerator
@ -14,7 +17,8 @@ namespace Tesses.YouTubeDownloader.Tools.Common
}else{ }else{
using(var p=new Process()) using(var p=new Process())
{ {
p.StartInfo.UseShellExecute=false;
p.StartInfo.WorkingDirectory="/";
p.StartInfo.FileName = "ln"; p.StartInfo.FileName = "ln";
p.StartInfo.ArgumentList.Add(srcPath); p.StartInfo.ArgumentList.Add(srcPath);
p.StartInfo.ArgumentList.Add(destPath); 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) public static async Task GenerateHardLinks(TYTDStorage storage,string dest="GoodFileNames",Resolution res=Resolution.PreMuxed,bool verbose=false)
{ {
Directory.CreateDirectory(dest); 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? ext=Path.GetExtension(path);
string defaultExt = res == Resolution.Mux ? ".mkv" : ".mp4"; string defaultExt = res == Resolution.Mux ? ".mkv" : ".mp4";
@ -55,17 +62,84 @@ namespace Tesses.YouTubeDownloader.Tools.Common
Console.WriteLine(item.Title); Console.WriteLine(item.Title);
} }
} }
}catch(Exception ex)
{
Console.WriteLine($"ERROR: {item.Id}");
Console.WriteLine(ex.ToString());
}
} }
} }
public static async Task<bool> 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<string> 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) public static async Task GenerateSymlinks(TYTDBase storage,string dest="GoodFileNames",Resolution res=Resolution.PreMuxed,bool verbose=false)
{ {
Directory.CreateDirectory(dest); Directory.CreateDirectory(dest);
await foreach(var item in storage.GetVideosAsync()) 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? ext=Path.GetExtension(path);
string defaultExt = res == Resolution.Mux ? ".mkv" : ".mp4"; string defaultExt = res == Resolution.Mux ? ".mkv" : ".mp4";

View File

@ -7,6 +7,7 @@ Resolution res=Resolution.PreMuxed;
bool verbose=false; bool verbose=false;
bool isSymlink = false; bool isSymlink = false;
bool isBigExport=false;
List<string> _args=new List<string>(); List<string> _args=new List<string>();
foreach(var arg in args) foreach(var arg in args)
{ {
@ -16,6 +17,11 @@ foreach(var arg in args)
_args.Clear(); _args.Clear();
break; 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") if( (arg.Length >= 2 && arg[1] != '-' && arg[0] == '-' && arg.Contains("s") )|| arg == "--symbolic")
{ {
any=true; any=true;
@ -44,6 +50,7 @@ foreach(var arg in args)
verbose=true; verbose=true;
} }
if(!any) if(!any)
_args.Add(arg); _args.Add(arg);
@ -53,7 +60,7 @@ if(argv.Length < 2)
{ {
string app = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]); string app = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
Console.WriteLine($"usage: {app} [-smaVv] <Working> <Destination> [<Resolution>]"); Console.WriteLine($"usage: {app} [-smaVvg] <Working> <Destination> [<Resolution>]");
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Options:"); Console.WriteLine("Options:");
Console.WriteLine(" -s, --symbolic make symbolic links instead of hard links"); 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(" -V, --video-only set resolution to VideoOnly");
Console.WriteLine(" -h, --help show this help"); Console.WriteLine(" -h, --help show this help");
Console.WriteLine(" -v, --verbose print video names"); Console.WriteLine(" -v, --verbose print video names");
Console.WriteLine(" -g, --generate-export Export everything to human readable format");
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Positional Arguments:"); Console.WriteLine("Positional Arguments:");
Console.WriteLine(" Working the folder containing the Info Directory for TYTD. (required)"); Console.WriteLine(" Working the folder containing the Info Directory for TYTD. (required)");
@ -76,8 +84,52 @@ TYTDCurrentDirectory currentDirectory=new TYTDCurrentDirectory();
currentDirectory.CanDownload=false; currentDirectory.CanDownload=false;
if(isSymlink){ 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<string> videos=new List<string>();
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{ }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<string> videos=new List<string>();
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);
}
} }
} }

View File

@ -21,6 +21,10 @@ namespace Tesses.Extensions
{ {
return value.Substring(str.Length); return value.Substring(str.Length);
} }
public static async Task RedirectBackAsync(this ServerContext ctx)
{
await ctx.SendTextAsync("<script>history.back()</script>\n");
}
} }
} }
@ -165,7 +169,7 @@ internal static class B64
// 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><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"
//); //);
await ctx.SendRedirectAsync("/");
} }
if(path.StartsWith("/AddItemRes/")) if(path.StartsWith("/AddItemRes/"))
{ {
@ -252,7 +256,7 @@ internal static class B64
//); //);
} }
await ctx.SendRedirectAsync("/"); await ctx.RedirectBackAsync();
} }
} }
internal class ApiStorage : Tesses.WebServer.Server internal class ApiStorage : Tesses.WebServer.Server
@ -846,6 +850,7 @@ internal static class B64
public ApiV2Server(IDownloader downloader) public ApiV2Server(IDownloader downloader)
{ {
this.Downloader=downloader; this.Downloader=downloader;
AddBoth("/CancelDownload",Cancel);
AddBoth("/Search",Search); AddBoth("/Search",Search);
AddBoth("/AddItem",AddItem); AddBoth("/AddItem",AddItem);
AddBoth("/AddChannel",AddChannel); 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) private async Task Search(ServerContext ctx)
{ {
var dl = Downloader as IStorage; var dl = Downloader as IStorage;
@ -942,9 +962,7 @@ internal static class B64
//Downloader.AddToPersonalPlaylistAsync(name); //Downloader.AddToPersonalPlaylistAsync(name);
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 ReplaceList(ServerContext ctx) public async Task ReplaceList(ServerContext ctx)
{ {
@ -966,9 +984,7 @@ internal static class B64
//Downloader.AddToPersonalPlaylistAsync(name); //Downloader.AddToPersonalPlaylistAsync(name);
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 Everything_Export(ServerContext ctx) public async Task Everything_Export(ServerContext ctx)
{ {
@ -1124,9 +1140,7 @@ internal static class B64
//Downloader.AddToPersonalPlaylistAsync(name); //Downloader.AddToPersonalPlaylistAsync(name);
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 DeleteFromList(ServerContext ctx) public async Task DeleteFromList(ServerContext ctx)
{ {
@ -1144,9 +1158,7 @@ internal static class B64
} }
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 SetResolutionInList(ServerContext ctx) public async Task SetResolutionInList(ServerContext ctx)
{ {
@ -1173,9 +1185,7 @@ internal static class B64
} }
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 Subscriptions(ServerContext ctx) public async Task Subscriptions(ServerContext ctx)
{ {
@ -1189,9 +1199,7 @@ internal static class B64
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 Resubscribe(ServerContext ctx) public async Task Resubscribe(ServerContext ctx)
{ {
@ -1222,9 +1230,7 @@ internal static class B64
} }
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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 Unsubscribe(ServerContext ctx) public async Task Unsubscribe(ServerContext ctx)
@ -1249,10 +1255,8 @@ internal static class B64
} }
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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) public async Task Subscribe(ServerContext ctx)
{ {
IStorage storage = Downloader as IStorage; IStorage storage = Downloader as IStorage;
@ -1294,9 +1298,7 @@ internal static class B64
} }
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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)
@ -1324,9 +1326,7 @@ internal static class B64
} }
await Downloader.AddFileAsync(url,download); await Downloader.AddFileAsync(url,download);
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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"
);
} }
} }
public async Task AddVideo(ServerContext ctx) public async Task AddVideo(ServerContext ctx)
@ -1352,11 +1352,9 @@ internal static class B64
await Downloader.AddVideoAsync(id1.Value,resolution); await Downloader.AddVideoAsync(id1.Value,resolution);
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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)
{ {
string id; string id;
if(ctx.QueryParams.TryGetFirst("v",out id)) if(ctx.QueryParams.TryGetFirst("v",out id))
@ -1374,11 +1372,9 @@ internal static class B64
await Downloader.AddItemAsync(id,resolution); await Downloader.AddItemAsync(id,resolution);
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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"
);
} }
public async Task AddUser(ServerContext ctx) public async Task AddUser(ServerContext ctx)
{ {
string id; string id;
if(ctx.QueryParams.TryGetFirst("id",out id)) if(ctx.QueryParams.TryGetFirst("id",out id))
@ -1398,12 +1394,10 @@ internal static class B64
await Downloader.AddUserAsync(id1.Value,resolution); await Downloader.AddUserAsync(id1.Value,resolution);
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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"
);
} }
public async Task AddChannel(ServerContext ctx) public async Task AddChannel(ServerContext ctx)
{ {
string id; string id;
if(ctx.QueryParams.TryGetFirst("id",out id)) if(ctx.QueryParams.TryGetFirst("id",out id))
@ -1423,9 +1417,7 @@ internal static class B64
await Downloader.AddChannelAsync(id1.Value,resolution); await Downloader.AddChannelAsync(id1.Value,resolution);
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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"
);
} }
public async Task AddPlaylist(ServerContext ctx) public async Task AddPlaylist(ServerContext ctx)
@ -1448,9 +1440,7 @@ internal static class B64
await Downloader.AddPlaylistAsync(id1.Value,resolution); await Downloader.AddPlaylistAsync(id1.Value,resolution);
} }
} }
await ctx.SendTextAsync( await ctx.RedirectBackAsync();
$"<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"
);
} }
} }

View File

@ -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.1.5</Version> <Version>1.1.6</Version>
<AssemblyVersion>1.1.5</AssemblyVersion> <AssemblyVersion>1.1.6</AssemblyVersion>
<FileVersion>1.1.5</FileVersion> <FileVersion>1.1.6</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>

View File

@ -0,0 +1,16 @@
using System;
namespace Tesses.YouTubeDownloader
{
public class ConsoleWriteEventArgs : EventArgs
{
///<summary>
///Use Console.Write(e.Text); not Console.WriteLine(e.Text);
///</summary>
public string Text {get;set;}
internal ConsoleWriteEventArgs(string e)
{
Text=e;
}
}
}

View File

@ -129,6 +129,9 @@ namespace Tesses.YouTubeDownloader
private async Task DownloadVideoAsync(SavedVideo video, Resolution resolution, CancellationToken token=default(CancellationToken),IProgress<double> progress=null,bool report=true) private async Task DownloadVideoAsync(SavedVideo video, Resolution resolution, CancellationToken token=default(CancellationToken),IProgress<double> progress=null,bool report=true)
{ {
begin_download:
try{ try{
if(video.DownloadFrom == "YouTube") if(video.DownloadFrom == "YouTube")
{ {
@ -147,6 +150,7 @@ namespace Tesses.YouTubeDownloader
await DownloadVideoOnlyAsync(video,token,progress,report); await DownloadVideoOnlyAsync(video,token,progress,report);
break; break;
} }
}else if(video.DownloadFrom.StartsWith("NormalDownload,Length=")) }else if(video.DownloadFrom.StartsWith("NormalDownload,Length="))
{ {
await DownloadFileAsync(video,token,progress,report); await DownloadFileAsync(video,token,progress,report);
@ -160,7 +164,21 @@ namespace Tesses.YouTubeDownloader
await GetLogger().WriteAsync(ex); 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<double> progress, bool report) private async Task DownloadFileAsync(SavedVideo video, CancellationToken token, IProgress<double> progress, bool report)
@ -371,7 +389,7 @@ namespace Tesses.YouTubeDownloader
byte[] buffer=new byte[bufferSize]; byte[] buffer=new byte[bufferSize];
do{ do{
read=await src.ReadAsync(buffer,0,buffer.Length,token); read=await src.ReadAsync(buffer,0,buffer.Length,token);
if(token.IsCancellationRequested) if(token.IsCancellationRequested || restartDownload || cancelDownload)
{ {
return false; return false;
} }
@ -381,8 +399,8 @@ namespace Tesses.YouTubeDownloader
{ {
progress.Report(curPos / len); progress.Report(curPos / len);
} }
}while(read>0 && !token.IsCancellationRequested); }while(read>0 && !token.IsCancellationRequested && !restartDownload && !cancelDownload);
if(token.IsCancellationRequested) if(token.IsCancellationRequested || restartDownload || cancelDownload)
{ {
return false; return false;
} }
@ -505,17 +523,17 @@ namespace Tesses.YouTubeDownloader
{ {
bool isValid=true; bool isValid=true;
isValid=await DownloadVideoOnlyAsync(video,token,progress,report); isValid=await DownloadVideoOnlyAsync(video,token,progress,report);
if(token.IsCancellationRequested || !isValid) if(token.IsCancellationRequested || !isValid || cancelDownload || restartDownload)
{ {
return; return;
} }
isValid = await DownloadAudioOnlyAsync(video,token,progress,report); isValid = await DownloadAudioOnlyAsync(video,token,progress,report);
if(token.IsCancellationRequested || !isValid) if(token.IsCancellationRequested || !isValid || cancelDownload || restartDownload)
{ {
return; return;
} }
var streams=await BestStreamInfo.GetBestStreams(this,video.Id,token,false); var streams=await BestStreamInfo.GetBestStreams(this,video.Id,token,false);
if(token.IsCancellationRequested) if(token.IsCancellationRequested || cancelDownload || restartDownload)
{ {
return; return;
} }
@ -568,7 +586,7 @@ namespace Tesses.YouTubeDownloader
{ {
using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.VideoOnlyStreamInfo,token)) using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.VideoOnlyStreamInfo,token))
{ {
if(token.IsCancellationRequested) if(token.IsCancellationRequested || cancelDownload || restartDownload)
{ {
return false; return false;
} }
@ -670,7 +688,7 @@ namespace Tesses.YouTubeDownloader
using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.AudioOnlyStreamInfo,token)) using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.AudioOnlyStreamInfo,token))
{ {
if(token.IsCancellationRequested) if(token.IsCancellationRequested || cancelDownload || restartDownload)
{ {
return false; return false;
} }
@ -722,7 +740,7 @@ namespace Tesses.YouTubeDownloader
using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.MuxedStreamInfo,token)) using(var strm = await YoutubeClient.Videos.Streams.GetAsync(streams.MuxedStreamInfo,token))
{ {
if(token.IsCancellationRequested) if(token.IsCancellationRequested || cancelDownload || restartDownload)
{ {
return; return;
} }

View File

@ -12,6 +12,7 @@ namespace Tesses.YouTubeDownloader
{ {
public interface IDownloader : IPersonalPlaylistSet public interface IDownloader : IPersonalPlaylistSet
{ {
void CancelDownload(bool restart=false);
Task AddVideoAsync(VideoId id,Resolution resolution=Resolution.PreMuxed); Task AddVideoAsync(VideoId id,Resolution resolution=Resolution.PreMuxed);
Task AddPlaylistAsync(PlaylistId id,Resolution resolution=Resolution.PreMuxed); Task AddPlaylistAsync(PlaylistId id,Resolution resolution=Resolution.PreMuxed);
Task AddChannelAsync(ChannelId id,Resolution resolution=Resolution.PreMuxed); Task AddChannelAsync(ChannelId id,Resolution resolution=Resolution.PreMuxed);

View File

@ -20,6 +20,7 @@ namespace Tesses.YouTubeDownloader
Task WriteBestStreamInfoAsync(VideoId id,BestStreamInfo.BestStreamsSerialized serialized); Task WriteBestStreamInfoAsync(VideoId id,BestStreamInfo.BestStreamsSerialized serialized);
Task<bool> MuxVideosAsync(SavedVideo video,string videoSrc,string audioSrc,string videoDest,IProgress<double> progress=null,CancellationToken token=default(CancellationToken)); Task<bool> MuxVideosAsync(SavedVideo video,string videoSrc,string audioSrc,string videoDest,IProgress<double> progress=null,CancellationToken token=default(CancellationToken));
Task<bool> Continue(string path); Task<bool> Continue(string path);
Task WriteVideoInfoAsync(SavedVideo channel); Task WriteVideoInfoAsync(SavedVideo channel);
Task WritePlaylistInfoAsync(SavedPlaylist channel); Task WritePlaylistInfoAsync(SavedPlaylist channel);
Task WriteChannelInfoAsync(SavedChannel channel); Task WriteChannelInfoAsync(SavedChannel channel);

View File

@ -131,17 +131,30 @@ namespace Tesses.YouTubeDownloader
} }
private void WriteStdErr(string message) private void WriteStdErr(string message)
{ {
var col=Console.ForegroundColor; if(TYTDStorage.UseConsole){
Console.ForegroundColor = ConsoleColor.Red; var col=Console.ForegroundColor;
Console.Error.WriteLine(message); Console.ForegroundColor = ConsoleColor.Red;
Console.ForegroundColor = col; Console.Error.WriteLine(message);
Console.ForegroundColor = col;
}else{
_storage.ConsoleWriter.WriteLine($"ERROR: {message}");
}
} }
private void WriteStd(string message,bool error) private void WriteStd(string message,bool error)
{ {
if(error) if(error)
WriteStdErr(message); WriteStdErr(message);
else else{
if(TYTDStorage.UseConsole){
var col=Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(message); 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) public async Task WriteAsync(string message,bool writeToConsole=false,bool isError=false,bool log=true)
{ {

View File

@ -63,6 +63,7 @@ namespace Tesses.YouTubeDownloader
video.AuthorTitle=AuthorTitle; video.AuthorTitle=AuthorTitle;
video.Description=Description; video.Description=Description;
video.UploadDate = DateTime.Parse(UploadDate); video.UploadDate = DateTime.Parse(UploadDate);
video.Views=Views;
return video; return video;
} }
} }

View File

@ -10,29 +10,52 @@ using System.IO;
using YoutubeExplode.Playlists; using YoutubeExplode.Playlists;
using YoutubeExplode.Channels; using YoutubeExplode.Channels;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Text;
namespace Tesses.YouTubeDownloader namespace Tesses.YouTubeDownloader
{ {
public abstract partial class TYTDStorage : TYTDBase, IStorage public abstract partial class TYTDStorage : TYTDBase, IStorage
{ {
internal class ConsoleWriterCLS : TextWriter
{
Action<string> cls;
public ConsoleWriterCLS(Action<string> 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(); private static readonly HttpClient _default = new HttpClient();
public abstract Task<Stream> CreateAsync(string path); public abstract Task<Stream> CreateAsync(string path);
public abstract void CreateDirectory(string path); public abstract void CreateDirectory(string path);
public static bool UseConsole = true;
public TYTDStorage(HttpClient clt) public TYTDStorage(HttpClient clt)
{ {
HttpClient=clt; HttpClient=clt;
YoutubeClient=new YoutubeClient(HttpClient); YoutubeClient=new YoutubeClient(HttpClient);
ExtensionContext=null; ExtensionContext=null;
ConsoleWriter=new ConsoleWriterCLS((e)=>{
ConsoleWrite?.Invoke(this,new ConsoleWriteEventArgs(e));
});
} }
public TYTDStorage() public TYTDStorage()
{ {
HttpClient=_default; HttpClient=_default;
YoutubeClient=new YoutubeClient(HttpClient); YoutubeClient=new YoutubeClient(HttpClient);
ExtensionContext=null; ExtensionContext=null;
ConsoleWriter=new ConsoleWriterCLS((e)=>{
ConsoleWrite?.Invoke(this,new ConsoleWriteEventArgs(e));
});
} }
public async Task WriteAllBytesAsync(string path,byte[] data,CancellationToken token=default(CancellationToken)) 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); await s.WriteAsync(data,0,data.Length,token);
} }
} }
public EventHandler<ConsoleWriteEventArgs> ConsoleWrite;
public TextWriter ConsoleWriter {get; private set;}
public static string TYTDTag {get {return _tytd_tag;}} 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 _tytd_tag=_getTYTDTag();
private static string _getTYTDTag() private static string _getTYTDTag()
{ {
@ -175,6 +205,7 @@ namespace Tesses.YouTubeDownloader
CreateDirectoryIfNotExist("FileInfo"); CreateDirectoryIfNotExist("FileInfo");
CreateDirectoryIfNotExist("Download"); CreateDirectoryIfNotExist("Download");
CreateDirectoryIfNotExist("StreamInfo"); CreateDirectoryIfNotExist("StreamInfo");
CreateDirectoryIfNotExist("PersonalPlaylist");
} }
public void StartLoop(CancellationToken token = default(CancellationToken)) public void StartLoop(CancellationToken token = default(CancellationToken))
{ {

View File

@ -507,5 +507,18 @@ internal class SegmentedHttpStream : Stream
_=ex; _=ex;
} }
} }
public void CancelDownload(bool restart = false)
{
try{
client.GetStringAsync($"{url}api/v2/CancelDownload?restart={restart}").GetAwaiter().GetResult();
}catch(Exception ex)
{
_=ex;
}
}
} }
} }

View File

@ -715,6 +715,11 @@ namespace Tesses.YouTubeDownloader
{ {
return await Storage.GetDownloadInfoAsync(url); return await Storage.GetDownloadInfoAsync(url);
} }
public void CancelDownload(bool restart = false)
{
Downloader.CancelDownload(restart);
}
} }
public class DownloaderMigration public class DownloaderMigration

View File

@ -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.1.7</Version> <Version>1.1.8</Version>
<AssemblyVersion>1.1.7</AssemblyVersion> <AssemblyVersion>1.1.8</AssemblyVersion>
<FileVersion>1.1.7</FileVersion> <FileVersion>1.1.8</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>