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.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";

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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>

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)
{
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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

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

View File

@ -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))
{

View File

@ -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;
}
}
}
}

View File

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

View File

@ -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>