Push update
This commit is contained in:
parent
8e5e58168a
commit
96d2a358b4
|
@ -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<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)
|
||||
{
|
||||
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";
|
||||
|
|
|
@ -7,6 +7,7 @@ Resolution res=Resolution.PreMuxed;
|
|||
|
||||
bool verbose=false;
|
||||
bool isSymlink = false;
|
||||
bool isBigExport=false;
|
||||
List<string> _args=new List<string>();
|
||||
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] <Working> <Destination> [<Resolution>]");
|
||||
Console.WriteLine($"usage: {app} [-smaVvg] <Working> <Destination> [<Resolution>]");
|
||||
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<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{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ namespace Tesses.Extensions
|
|||
{
|
||||
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(
|
||||
// $"<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/"))
|
||||
{
|
||||
|
@ -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(
|
||||
$"<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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
public async Task ReplaceList(ServerContext ctx)
|
||||
{
|
||||
|
@ -966,9 +984,7 @@ internal static class B64
|
|||
//Downloader.AddToPersonalPlaylistAsync(name);
|
||||
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
public async Task Everything_Export(ServerContext ctx)
|
||||
{
|
||||
|
@ -1124,9 +1140,7 @@ internal static class B64
|
|||
//Downloader.AddToPersonalPlaylistAsync(name);
|
||||
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
public async Task DeleteFromList(ServerContext ctx)
|
||||
{
|
||||
|
@ -1144,9 +1158,7 @@ internal static class B64
|
|||
}
|
||||
}
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
public async Task SetResolutionInList(ServerContext ctx)
|
||||
{
|
||||
|
@ -1173,9 +1185,7 @@ internal static class B64
|
|||
}
|
||||
}
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
public async Task Subscriptions(ServerContext ctx)
|
||||
{
|
||||
|
@ -1189,9 +1199,7 @@ internal static class B64
|
|||
|
||||
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
public async Task Resubscribe(ServerContext ctx)
|
||||
{
|
||||
|
@ -1222,9 +1230,7 @@ internal static class B64
|
|||
}
|
||||
}
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
|
||||
public async Task Unsubscribe(ServerContext ctx)
|
||||
|
@ -1249,10 +1255,8 @@ internal static class B64
|
|||
}
|
||||
}
|
||||
}
|
||||
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"
|
||||
);
|
||||
}
|
||||
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(
|
||||
$"<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"
|
||||
);
|
||||
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(
|
||||
$"<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.RedirectBackAsync();
|
||||
}
|
||||
}
|
||||
public async Task AddVideo(ServerContext ctx)
|
||||
|
@ -1352,11 +1352,9 @@ internal static class B64
|
|||
await Downloader.AddVideoAsync(id1.Value,resolution);
|
||||
}
|
||||
}
|
||||
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"
|
||||
);
|
||||
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(
|
||||
$"<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.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(
|
||||
$"<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.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(
|
||||
$"<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.RedirectBackAsync();
|
||||
}
|
||||
|
||||
public async Task AddPlaylist(ServerContext ctx)
|
||||
|
@ -1448,9 +1440,7 @@ internal static class B64
|
|||
await Downloader.AddPlaylistAsync(id1.Value,resolution);
|
||||
}
|
||||
}
|
||||
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"
|
||||
);
|
||||
await ctx.RedirectBackAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<PackageId>Tesses.YouTubeDownloader.Server</PackageId>
|
||||
<Author>Mike Nolan</Author>
|
||||
<Company>Tesses</Company>
|
||||
<Version>1.1.5</Version>
|
||||
<AssemblyVersion>1.1.5</AssemblyVersion>
|
||||
<FileVersion>1.1.5</FileVersion>
|
||||
<Version>1.1.6</Version>
|
||||
<AssemblyVersion>1.1.6</AssemblyVersion>
|
||||
<FileVersion>1.1.6</FileVersion>
|
||||
<Description>Adds WebServer to TYTD</Description>
|
||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
||||
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<double> 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace Tesses.YouTubeDownloader
|
|||
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> Continue(string path);
|
||||
|
||||
Task WriteVideoInfoAsync(SavedVideo channel);
|
||||
Task WritePlaylistInfoAsync(SavedPlaylist channel);
|
||||
Task WriteChannelInfoAsync(SavedChannel channel);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -63,6 +63,7 @@ namespace Tesses.YouTubeDownloader
|
|||
video.AuthorTitle=AuthorTitle;
|
||||
video.Description=Description;
|
||||
video.UploadDate = DateTime.Parse(UploadDate);
|
||||
video.Views=Views;
|
||||
return video;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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();
|
||||
public abstract Task<Stream> 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<ConsoleWriteEventArgs> 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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -715,6 +715,11 @@ namespace Tesses.YouTubeDownloader
|
|||
{
|
||||
return await Storage.GetDownloadInfoAsync(url);
|
||||
}
|
||||
|
||||
public void CancelDownload(bool restart = false)
|
||||
{
|
||||
Downloader.CancelDownload(restart);
|
||||
}
|
||||
}
|
||||
|
||||
public class DownloaderMigration
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
<PackageId>Tesses.YouTubeDownloader</PackageId>
|
||||
<Author>Mike Nolan</Author>
|
||||
<Company>Tesses</Company>
|
||||
<Version>1.1.7</Version>
|
||||
<AssemblyVersion>1.1.7</AssemblyVersion>
|
||||
<FileVersion>1.1.7</FileVersion>
|
||||
<Version>1.1.8</Version>
|
||||
<AssemblyVersion>1.1.8</AssemblyVersion>
|
||||
<FileVersion>1.1.8</FileVersion>
|
||||
<Description>A YouTube Downloader</Description>
|
||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
|
|
Loading…
Reference in New Issue