diff --git a/.vs/youtube-downloader/xs/UserPrefs.xml b/.vs/youtube-downloader/xs/UserPrefs.xml
index f152ceb..9d9f3fa 100644
--- a/.vs/youtube-downloader/xs/UserPrefs.xml
+++ b/.vs/youtube-downloader/xs/UserPrefs.xml
@@ -7,7 +7,7 @@
-
+
@@ -37,7 +37,7 @@
-
+
diff --git a/Program.cs b/Program.cs
index 449ec85..480d8b7 100644
--- a/Program.cs
+++ b/Program.cs
@@ -99,11 +99,14 @@ namespace TYTD
Route.Add("/api/Storage/VideoRes/{Res}/{Id}",(HttpAction)VideoRes);
Route.Add("/api/upload/", (HttpAction)UploadFiles, "POST");
+ Route.Add("/api/endpoint", (HttpAction)Endpoint,"POST");
+
ApiLoader.Init();
/* Other */
Route.Add("/", (HttpAction)Index);
Route.Add("/extensions.html", (HttpAction)Extensions);
Route.Add("/{Path}", (HttpAction)RootPath);
+ Route.Add("/{Path}",(HttpAction)UploadFilePut,"PUT");
Console.CancelKeyPress += (sender, e) => { ApiLoader.Dispose();var date = DateTime.Now.ToString("yyyyMMdd_HHmmss");File.WriteAllText(Path.Combine("config","queues-close",$"{date}.json"), Downloader.GetQueue()); return; };
@@ -121,6 +124,8 @@ namespace TYTD
}
}
+
+
private static async Task GetManifest(YoutubeClient arg1, VideoId arg2)
{
return await arg1.Videos.Streams.GetManifestAndFixStreamUrlsAsync(arg2);
@@ -186,7 +191,7 @@ namespace TYTD
{
foreach (var item in Directory.GetFiles(Downloader.DL.GetPath(true, "Info"), "*.json"))
{
- string id = System.IO.Path.GetFileNameWithoutExtension(item);
+ string id =Path.GetFileNameWithoutExtension(item);
Downloader.DownloadVideo(id, Resolution.NoConvert);
}
rp.AsRedirect("/");
@@ -301,14 +306,21 @@ namespace TYTD
}
public static void Redo(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args)
{
- Downloader.RedownloadIt = true;
- Downloader.DownloadIt = false;
+ lock (Downloader.DL.cancelSrc)
+ {
+ Downloader.RedownloadIt = true;
+ Downloader.DL.cancelSrc.Item.Cancel();
+ }
}
public static void Cancel(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args)
{
- Downloader.RedownloadIt = false;
- Downloader.DownloadIt = false;
+
+ lock (Downloader.DL.cancelSrc)
+ {
+ Downloader.RedownloadIt = false;
+ Downloader.DL.cancelSrc.Item.Cancel();
+ }
}
#endregion
@@ -364,9 +376,49 @@ namespace TYTD
else
{
string path = Downloader.DL.GetPath(true, args["Path"]);
+ if (Directory.Exists(path))
+ {
+ string indexHtml = Path.Combine(path, "index.html");
+ if (File.Exists(indexHtml))
+ {
+ path = indexHtml;
+ }
+ else
+ {
+ string dir = Path.Combine(webSitePath, "err", "dir.html");
+ StringBuilder b = new StringBuilder();
+ var f = Directory.GetLastWriteTime(Path.GetDirectoryName(path));
+ string parentModified = $"{f.ToShortDateString()} {f.ToShortTimeString()}";
+ b.Append($"Up | {parentModified} | DIR |
");
+ foreach (var file in Directory.GetDirectories(path))
+ {
+ string name = Path.GetFileName(file);
+ string nameUrled = System.Web.HttpUtility.UrlEncode(name);
+ string nameHtmled = System.Web.HttpUtility.HtmlEncode(name);
+ f = Directory.GetLastWriteTime(file);
+ string dateModifed = $"{f.ToShortDateString()} {f.ToShortTimeString()}";
+ b.Append($"{nameHtmled} | {dateModifed} | DIR |
");
+ }
+ foreach (var file in Directory.GetFiles(path))
+ {
+ string name = Path.GetFileName(file);
+ string nameUrled = System.Web.HttpUtility.UrlEncode(name);
+ string nameHtmled = System.Web.HttpUtility.HtmlEncode(name);
+ f = File.GetLastWriteTime(file);
+ string dateModifed = $"{f.ToShortDateString()} {f.ToShortTimeString()}";
+ b.Append($"{nameHtmled} | {dateModifed} | FILE |
");
+ }
+ Dictionary templating = new Dictionary();
+ templating.Add("Items", b.ToString());
+ rp.AsText(Templating.RenderFile(dir, templating));
+
+ return;
+ }
+ }
rp.AsFile(rq, path);
}
+
}
public static void Video(HttpListenerRequest rq,HttpListenerResponse rp,Dictionary args)
{
@@ -385,7 +437,7 @@ namespace TYTD
}
public static void VideoRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args)
{
- YoutubeExplode.Videos.VideoId? vid = YoutubeExplode.Videos.VideoId.TryParse(args["Id"]);
+ VideoId? vid = VideoId.TryParse(args["Id"]);
if (vid.HasValue)
{
int res;
@@ -466,9 +518,218 @@ namespace TYTD
{
rp.AsText(ApiLoader.Page);
}
+ private static void UploadFilePut(HttpListenerRequest request, HttpListenerResponse response, Dictionary arguments)
+ {
+ string p = arguments["Path"].Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0];
+ string path = Path.Combine(webSitePath, p);
+ bool exists = File.Exists(path);
+ using (var instr = request.InputStream)
+ {
+ using (var outStr = File.Create(path))
+ {
+ instr.CopyTo(outStr);
+ }
+ }
+ if (exists)
+ {
+ response.WithCode(HttpStatusCode.NoContent);
+ }
+ else
+ {
+ response.WithCode(HttpStatusCode.Created);
+ }
+ }
+
+ private static void Endpoint(HttpListenerRequest request, HttpListenerResponse response, Dictionary arguments)
+ {
+ request.ParseBody(arguments);
+ List print = new List();
+ bool hasOtherResponse=false;
+ bool success = true;
+ if(arguments.ContainsKey("operation"))
+ {
+ if (arguments["operation"] == "server_download")
+ {
+ if (arguments.ContainsKey("url"))
+ {
+ string myUrl = arguments["url"];
+ if (arguments.ContainsKey("resolution"))
+ {
+ uint res;
+ if (uint.TryParse(arguments["resolution"], out res) && res <= 2)
+ {
+ Downloader.DownloadItem(myUrl, (Resolution)res);
+ }
+ else
+ {
+ print.Add("WARNING: argument resolution shall not be greater than 3 or less than 0");
+ Downloader.DownloadItem(myUrl);
+ }
+ }
+ else
+ {
+ Downloader.DownloadItem(myUrl);
+ }
+ }
+ }
+ else if (arguments["operation"] == "download")
+ {
+ if (arguments.ContainsKey("url"))
+ {
+ VideoId? vid = VideoId.TryParse(arguments["url"]);
+ if (vid.HasValue)
+ {
+ if (arguments.ContainsKey("resolution"))
+ {
+ int res;
+ if (int.TryParse(arguments["resolution"], out res))
+ {
+ if (res > 2 || res < 0)
+ {
+
+ print.Add("Invalid Resolution Number must be either 0, 1 or 2");
+ }
+ else
+ {
+ string[] m = new string[] { "Converted", "NotConverted", "Audio" };
+ string path = Downloader.DL.GetPath(true, m[res], vid.Value + ".mp4");
+ response.AddHeader("Content-Disposition", GetVideoContentDisposition(vid.Value).ToString());
+ response.AsFile(request, path);
+ hasOtherResponse = true;
+ }
+ }
+
+ else
+ {
+
+ print.Add("Res is not a number");
+ }
+ }
+ else
+ {
+
+ string path = Downloader.DL.GetPath(true, "NotConverted", vid.Value + ".mp4");
+ response.AddHeader("Content-Disposition", GetVideoContentDisposition(vid.Value).ToString());
+ response.AsFile(request, path);
+ hasOtherResponse = true;
+
+ }
+ }
+ else
+ {
+
+ success = false;
+ print.Add("Invalid Video ID or URL");
+
+ }
+ }
+ }
+ else if (arguments["operation"] == "enumerate_queue")
+ {
+ string json = Downloader.GetQueue();
+ response.AsText(json, "application/json");
+ hasOtherResponse = true;
+
+ }
+ else if (arguments["operation"] == "progress")
+ {
+ string json = JsonConvert.SerializeObject(Downloader.GetProgress());
+ response.AsText(json, "application/json");
+ hasOtherResponse = true;
+
+ }
+ else if(arguments["operation"] == "queue_move")
+ {
+ bool containsId = arguments.ContainsKey("id");
+ bool containsIndex = arguments.ContainsKey("index");
+ if (containsId ^ containsIndex)
+ {
+ success = false;
+ print.Add("You cant use both id and index");
+ }
+ else
+ {
+ if (arguments.ContainsKey("to"))
+ {
+ string to_loc = arguments["to"];
+ if(containsId)
+ Downloader.ModQueue2(to_loc, arguments["id"]);
+
+ if (containsIndex)
+ Downloader.ModQueue(to_loc, arguments["index"]);
+ }
+ else
+ {
+ success = false;
+ print.Add("You must have the "to" variable set");
+ }
+ }
+ }
+ else
+ {
+ success = false;
+ }
+
+ }
+ if(success)
+ {
+ print.Add("Your request was delt with successfully");
+ }
+ else if(!hasOtherResponse)
+ {
+ response.WithCode(HttpStatusCode.BadRequest);
+ }
+ if (!hasOtherResponse)
+ {
+ response.AsText(string.Join("
", print));
+ }
+ }
public static void RootPath(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args)
{
- string path = Path.Combine(webSitePath, args["Path"].Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]);
+ string p = args["Path"].Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0];
+ string path = Path.Combine(webSitePath, p);
+ if (Directory.Exists(path))
+ {
+ string indexHtml = Path.Combine(path, "index.html");
+ if(File.Exists(indexHtml))
+ {
+ path = indexHtml;
+ }
+ else
+ {
+ string dir = Path.Combine(webSitePath,"err", "dir.html");
+ StringBuilder b = new StringBuilder();
+ var f= Directory.GetLastWriteTime(Path.GetDirectoryName(path));
+ string parentModified = $"{f.ToShortDateString()} {f.ToShortTimeString()}";
+ b.Append($"Up | {parentModified} | DIR |
");
+ foreach (var file in Directory.GetDirectories(path))
+ {
+ string name = Path.GetFileName(file);
+ string nameUrled = System.Web.HttpUtility.UrlEncode(name);
+ string nameHtmled = System.Web.HttpUtility.HtmlEncode(name);
+ f= Directory.GetLastWriteTime(file);
+ string dateModifed =$"{f.ToShortDateString()} {f.ToShortTimeString()}";
+ b.Append($"{nameHtmled} | {dateModifed} | DIR |
");
+ }
+ foreach (var file in Directory.GetFiles(path))
+ {
+ string name = Path.GetFileName(file);
+ string nameUrled = System.Web.HttpUtility.UrlEncode(name);
+ string nameHtmled = System.Web.HttpUtility.HtmlEncode(name);
+ f = File.GetLastWriteTime(file);
+
+ string dateModifed = $"{f.ToShortDateString()} {f.ToShortTimeString()}";
+ b.Append($"{nameHtmled} | {dateModifed} | FILE |
");
+ }
+ Dictionary templating = new Dictionary();
+ templating.Add("Items", b.ToString());
+ rp.AsText(Templating.RenderFile(dir, templating));
+
+ return;
+ }
+ }
+
+
rp.AsFile(rq, path);
}
diff --git a/TYTD.Api/Server/Functions/Downloader.cs b/TYTD.Api/Server/Functions/Downloader.cs
index 005fce1..cae3898 100644
--- a/TYTD.Api/Server/Functions/Downloader.cs
+++ b/TYTD.Api/Server/Functions/Downloader.cs
@@ -15,19 +15,36 @@ using YoutubeExplode.Channels;
using YoutubeExplode.Playlists;
using Dasync.Collections;
-
+using System.Threading;
namespace TYTD.Server.Functions
{
public class Downloader
{
- public Downloader()
+
+ public class Lockable
{
- // TessesYoutubeDownloader.Server.Functions.Downloader.DL.DownloadThread().GetAwaiter().GetResult();
+ public Lockable(Func recreate)
+ {
+ _recreate = recreate;
+ }
+ Func _recreate;
+ public void Recreate()
+ {
+ Item = _recreate();
+ }
+ public T Item { get; set; }
+ public void Change(T item)
+ {
+ Item = item;
+ }
+ public static implicit operator T(Lockable item)
+ {
+ return item.Item;
+ }
}
- public static bool DownloadIt = true;
public static bool RedownloadIt = false;
public List infoQueue = new List();
public static YoutubeClient CreateYoutubeClient()
@@ -401,352 +418,620 @@ namespace TYTD.Server.Functions
nameDest= Path.Combine(Path.GetDirectoryName(nameSrc), $"{Path.GetFileNameWithoutExtension(nameSrc)} ({i}){Path.GetExtension(nameSrc)}");
return File.Exists(nameDest);
}
+ public Lockable cancelSrc = new Lockable(()=> { return new CancellationTokenSource(); });
public static Func> GetManifest;
+ private async Task DownloadHDVideo(SavedVideoObject v,CancellationToken token)
+ {
+ string mypath = GetPath(true, "Converted", v.Video.Id + "-vidonly.bkp");
+ string mypathaudio = GetPath(true, "Audio", v.Video.Id + "incomplete.mp4");
+ string mypathCompleteAudio = GetPath(true, "Audio", v.Video.Id + ".mp4");
+ string mypathComplete = GetPath(true, "Converted", v.Video.Id + ".mp4");
+ string mypathIncompleteConverting = GetPath(true, "Converted", "conv.mkv");
+
+ if (Continue(mypathComplete))
+ {
+
+ var s3 = await GetManifest(ytc, v.Video.Id);
+ var best2 = s3.GetAudioOnlyStreams().GetWithHighestBitrate();
+
+
+
+ var best = s3.GetVideoOnlyStreams().GetWithHighestVideoQuality();
+
+ P.Length = best.Size.Bytes + best2.Size.Bytes;
+ ProgressTwo p = new ProgressTwo(best.Size.Bytes, best2.Size.Bytes, DownloadP);
+
+
+ using (var destStrm = File.Open(mypath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ {
+ long pos = 0;
+ long len = 0;
+ using (var srcStrm = await ytc.Videos.Streams.GetAsync(best,token))
+ {
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadHDVideo(v, token);
+ }
+ return;
+ }
+ len = srcStrm.Length;
+ pos = destStrm.Length;
+ IProgress myProgress = p.Video;
+ if (pos >= len)
+ {
+
+ myProgress.Report(1);
+
+ }
+ /* This is why videos get corrupted */
+ srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ byte[] buffer = new byte[4096];
+ int read = 0;
+ do
+ {
+ read = await srcStrm.ReadAsync(buffer, 0, buffer.Length,token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadHDVideo(v, token);
+ }
+ return;
+ }
+ await destStrm.WriteAsync(buffer, 0, read,token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadHDVideo(v, token);
+ }
+ return;
+ }
+ pos += read;
+ double myP = (double)pos / (double)len;
+ myProgress.Report(myP);
+ }
+ while (read > 0 );
+
+ }
+
+ }
+
+ IProgress pv = p.Video;
+ pv.Report(1);
+ if (Continue(mypathCompleteAudio))
+ {
+ long pos = 0;
+ long len = 0;
+ using (var destStrm = File.Open(mypathaudio, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ {
+ using (var srcStrm = await ytc.Videos.Streams.GetAsync(best2,token))
+ {
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadHDVideo(v, token);
+ }
+ return;
+ }
+ len = srcStrm.Length;
+ pos = destStrm.Length;
+ IProgress myProgress = p.Audio;
+ if (pos >= len)
+ {
+
+ myProgress.Report(1);
+
+ }
+ /* This is why videos get corrupted */
+ srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+
+ byte[] buffer = new byte[4096];
+ int read = 0;
+ do
+ {
+ read = await srcStrm.ReadAsync(buffer, 0, buffer.Length,token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadHDVideo(v, token);
+ }
+ return;
+ }
+ await destStrm.WriteAsync(buffer, 0, read,token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadHDVideo(v, token);
+ }
+ return;
+ }
+ pos += read;
+ double myP = (double)pos / (double)len;
+ myProgress.Report(myP);
+ }
+ while (read > 0);
+ }
+
+ }
+
+ File.Move(mypathaudio, mypathCompleteAudio);
+
+
+ }
+ IProgress pa = p.Video;
+
+ pa.Report(1);
+ ffmpeg.mux(mypath, mypathCompleteAudio, mypathIncompleteConverting);
+
+
+ File.Move(mypathIncompleteConverting, mypathComplete);
+ }
+
+ }
+ private async Task DownloadSDVideo(SavedVideoObject v, CancellationToken token)
+ {
+ string mypath2 = GetPath(true, "NotConverted", v.Video.Id + "incomplete.mp4");
+ string mypath2Complete = GetPath(true, "NotConverted", v.Video.Id + ".mp4");
+
+ if (Continue(mypath2Complete))
+ {
+ var s = await GetManifest(ytc, v.Video.Id);
+ var best = s.GetMuxedStreams().GetWithHighestVideoQuality();
+ P.Length = best.Size.Bytes;
+ long pos = 0;
+ long len = 0;
+ using (var destStrm = File.Open(mypath2, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ {
+ using (var srcStrm = await ytc.Videos.Streams.GetAsync(best, token))
+ {
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadSDVideo(v, token);
+ }
+ return;
+ }
+ len = srcStrm.Length;
+ pos = destStrm.Length;
+ IProgress myProgress = DownloadP;
+ if (pos >= len)
+ {
+
+ myProgress.Report(1);
+
+ }
+ /* This is why videos get corrupted */
+ srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ byte[] buffer = new byte[4096];
+ int read = 0;
+ do
+ {
+ read = await srcStrm.ReadAsync(buffer, 0, buffer.Length, token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadSDVideo(v, token);
+ }
+ return;
+ }
+ await destStrm.WriteAsync(buffer, 0, read, token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadSDVideo(v, token);
+ }
+ return;
+ }
+
+ pos += read;
+ double myP = (double)pos / (double)len;
+ myProgress.Report(myP);
+ }
+ while (read > 0);
+ }
+
+ }
+
+
+ File.Move(mypath2, mypath2Complete);
+
+
+
+ }
+ }
+ private async Task DownloadAudio(SavedVideoObject v, CancellationToken token)
+ {
+ string mypath3 = GetPath(true, "Audio", v.Video.Id + "incomplete.mp4");
+ string mypath3Complete = GetPath(true, "Audio", v.Video.Id + ".mp4");
+ if (Continue(mypath3Complete))
+ {
+ var s2 = await GetManifest(ytc, v.Video.Id);
+ var best2 = s2.GetAudioOnlyStreams().GetWithHighestBitrate();
+ P.Length = best2.Size.Bytes;
+ long pos = 0;
+ long len = 0;
+ using (var destStrm = File.Open(mypath3, FileMode.OpenOrCreate, FileAccess.ReadWrite))
+ {
+ using (var srcStrm = await ytc.Videos.Streams.GetAsync(best2,token))
+ {
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadAudio(v, token);
+ }
+ return;
+ }
+ len = srcStrm.Length;
+
+ pos = destStrm.Length;
+ IProgress myProgress = DownloadP;
+ if (pos >= len)
+ {
+
+ myProgress.Report(1);
+
+ }
+ /* This is why videos get corrupted */
+ srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
+ byte[] buffer = new byte[4096];
+ int read = 0;
+ do
+ {
+ read = await srcStrm.ReadAsync(buffer, 0, buffer.Length,token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadAudio(v, token);
+ }
+ return;
+ }
+ await destStrm.WriteAsync(buffer, 0, read,token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcStrm.Dispose();
+ destStrm.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadAudio(v, token);
+ }
+ return;
+ }
+ pos += read;
+ double myP = (double)pos / (double)len;
+ myProgress.Report(myP);
+ }
+ while (read > 0);
+ }
+
+ }
+
+
+ File.Move(mypath3, mypath3Complete);
+
+ }
+ }
+ private async Task DownloadFileAsync(SavedVideoObject v,CancellationToken token)
+ {
+ var req = await Http.GetAsync(v.Video.Id, token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadFileAsync(v, token);
+ }
+ return;
+ }
+ long? Len = req.Content.Headers.ContentLength;
+ Uri u = new Uri(v.Video.Id);
+ string abs = u.AbsolutePath;
+ string name = "file.bin";
+ if (abs.Contains("/"))
+ {
+ name = abs.Substring(abs.LastIndexOf('/') + 1);
+ }
+ if (req.Content.Headers.Contains("Content-Disposition"))
+ {
+ name = req.Content.Headers.ContentDisposition.FileName;
+ }
+ int fileI = 1;
+ P.Saved.Title = name;
+ name = GetPath(true, "Download", name);
+ string filename = name;
+ while (FileExists(name, ref filename, ref fileI)) { }
+ long Len2 = long.MaxValue;
+ if (Len.HasValue)
+ {
+ if (Len.Value > 0)
+ {
+ Len2 = Len.Value;
+ }
+ }
+
+ P.Length = Len2;
+ long Pos = 0;
+ byte[] buffer = new byte[4096];
+ int Cycles = 0;
+ IProgress p = DownloadP;
+ int CYCLES_BETWEEN_REPORT = 1;
+ using (var srcFile = await req.Content.ReadAsStreamAsync())
+ {
+ using (var destFile = File.Create(filename))
+ {
+ int read;
+ do
+ {
+ read = await srcFile.ReadAsync(buffer, 0, buffer.Length, token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcFile.Dispose();
+ destFile.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadFileAsync(v, token);
+ }
+ return;
+ }
+ await destFile.WriteAsync(buffer, 0, read, token);
+ if (token.IsCancellationRequested)
+ {
+ cancelSrc.Item.Dispose();
+ cancelSrc.Recreate();
+ if (RedownloadIt)
+ {
+ srcFile.Dispose();
+ destFile.Dispose();
+ lock (cancelSrc)
+ {
+
+ token = cancelSrc.Item.Token;
+ }
+ await DownloadFileAsync(v, token);
+ }
+ return;
+ }
+ Pos += read;
+ Cycles++;
+ if (Cycles > CYCLES_BETWEEN_REPORT)
+ {
+ Cycles = 0;
+ p.Report(Pos / Len2);
+ }
+ } while (read > 0);
+ }
+ }
+ p.Report(1);
+ }
+ private async Task DownloadItem(CancellationToken token)
+ {
+ P.Progress = 0;
+ P.ProgressRaw = 0;
+ await Task.Delay(2000);
+ bool canDownload = false;
+ SavedVideoObject v;
+ lock (Queue)
+ {
+ canDownload = Queue.Count > 0;
+ if (canDownload)
+ {
+ v = Queue[0];
+ Queue.RemoveAt(0);
+ P.Saved = v.Video;
+ if (v.RegularFile)
+ {
+ Console.WriteLine($"Download: {v.Video.Id}");
+ }
+ else
+ {
+ Console.WriteLine($"Download: {v.Video.Title}");
+ }
+
+
+ }
+ else
+ {
+ v = null;
+ }
+ }
+
+ if (canDownload)
+ {
+ DownloadStartEventArgs evt = new DownloadStartEventArgs();
+ evt.Cancel = false;
+ evt.RegularFile = v.RegularFile;
+ evt.Video = v.Video;
+
+ ApiLoader.DownloadStarted(this, evt);
+ if (evt.Cancel)
+ {
+ return;
+
+ }
+
+ try
+ {
+ if (v.RegularFile)
+ {
+ await DownloadFileAsync(v, token);
+ }
+ else
+ {
+ switch (v.Resolution)
+ {
+ case Resolution.Convert:
+ await DownloadHDVideo(v, token);
+
+ break;
+ case Resolution.NoConvert:
+
+ await DownloadSDVideo(v, token);
+
+ break;
+ case Resolution.Audio:
+ await DownloadAudio(v, token);
+ break;
+ }
+ DownloadCompleteEventArgs evt2 = new DownloadCompleteEventArgs();
+
+ evt2.RegularFile = v.RegularFile;
+ evt2.Video = v.Video;
+
+ ApiLoader.DownloadComplete(this, evt2);
+ ffmpeg.on_video_done(v.Video.Id, (int)v.Resolution);
+
+
+ }
+
+
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+
+ }
public async Task DownloadThread()
{
do
{
- bool canDownload = false;
- SavedVideoObject v;
- lock (Queue)
- {
- canDownload = Queue.Count > 0;
- if (canDownload)
- {
- v = Queue[0];
- Queue.RemoveAt(0);
- P.Saved = v.Video;
- if (v.RegularFile)
- {
- Console.WriteLine($"Download: {v.Video.Id}");
- }
- else
- {
- Console.WriteLine($"Download: {v.Video.Title}");
- }
-
- }
- else
- {
- v = null;
- }
- }
-
- if (canDownload)
- {
- DownloadStartEventArgs evt = new DownloadStartEventArgs();
- evt.Cancel = false;
- evt.RegularFile = v.RegularFile;
- evt.Video = v.Video;
-
- ApiLoader.DownloadStarted(this, evt);
- if(evt.Cancel)
- {
- DownloadIt = true;
- goto nope;
- }
- redownload:
- try
- {
- if (v.RegularFile) {
- var req=await Http.GetAsync(v.Video.Id);
- long? Len=req.Content.Headers.ContentLength;
- Uri u = new Uri(v.Video.Id);
- string abs = u.AbsolutePath;
- string name = "file.bin";
- if(abs.Contains("/"))
- {
- name=abs.Substring(abs.LastIndexOf('/') + 1);
- }
- if (req.Content.Headers.Contains("Content-Disposition"))
- {
- name=req.Content.Headers.ContentDisposition.FileName;
- }
- int fileI=1;
- P.Saved.Title = name;
- name=GetPath(true, "Download", name);
- string filename=name;
- while (FileExists(name, ref filename, ref fileI)) ;
- long Len2 = long.MaxValue;
- if(Len.HasValue)
- {
- if(Len.Value > 0)
- {
- Len2 = Len.Value;
- }
- }
-
- P.Length = Len2;
- long Pos = 0;
- byte[] buffer = new byte[4096];
- int Cycles = 0;
- IProgress p = DownloadP;
- int CYCLES_BETWEEN_REPORT = 1;
- using (var srcFile = await req.Content.ReadAsStreamAsync())
- {
- using (var destFile = File.Create(filename))
- {
- int read;
- do
- {
- read = await srcFile.ReadAsync(buffer, 0, buffer.Length);
- await destFile.WriteAsync(buffer, 0, read);
- Pos += read;
- Cycles++;
- if (Cycles > CYCLES_BETWEEN_REPORT)
- {
- Cycles = 0;
- p.Report(Pos / Len2);
- }
- } while (read > 0 && DownloadIt);
- }
- }
- p.Report(1);
- }
- else
- {
- switch (v.Resolution)
- {
- case Resolution.Convert:
-
- string mypath = GetPath(true, "Converted", v.Video.Id + "-vidonly.bkp");
- string mypathaudio = GetPath(true, "Audio", v.Video.Id + "incomplete.mp4");
- string mypathCompleteAudio = GetPath(true, "Audio", v.Video.Id + ".mp4");
- string mypathComplete = GetPath(true, "Converted", v.Video.Id + ".mp4");
- string mypathIncompleteConverting = GetPath(true, "Converted", "conv.mkv");
-
- if (Continue(mypathComplete))
- {
-
- var s3 = await GetManifest(ytc,v.Video.Id);
- var best2 = s3.GetAudioOnlyStreams().GetWithHighestBitrate();
-
-
-
- var best = s3.GetVideoOnlyStreams().GetWithHighestVideoQuality();
-
- P.Length = best.Size.Bytes + best2.Size.Bytes;
- ProgressTwo p = new ProgressTwo(best.Size.Bytes, best2.Size.Bytes, DownloadP);
-
-
- using (var destStrm = System.IO.File.Open(mypath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
- {
- long pos = 0;
- long len = 0;
- using (var srcStrm = await ytc.Videos.Streams.GetAsync(best))
- {
- len = srcStrm.Length;
- pos = destStrm.Length;
- IProgress myProgress = p.Video;
- if (pos >= len)
- {
-
- myProgress.Report(1);
-
- }
- /* This is why videos get corrupted */
- srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- byte[] buffer = new byte[4096];
- int read = 0;
- do
- {
- read = srcStrm.Read(buffer, 0, buffer.Length);
- destStrm.Write(buffer, 0, read);
-
- pos += read;
- double myP = (double)pos / (double)len;
- myProgress.Report(myP);
- }
- while (read > 0 && DownloadIt ) ;
-
- }
-
- }
-
- IProgress pv = p.Video;
- pv.Report(1);
- if (Continue(mypathCompleteAudio))
- {
- long pos = 0;
- long len = 0;
- using (var destStrm = File.Open(mypathaudio, FileMode.OpenOrCreate, FileAccess.ReadWrite))
- {
- using (var srcStrm = await ytc.Videos.Streams.GetAsync(best2))
- {
- len = srcStrm.Length;
- pos = destStrm.Length;
- IProgress myProgress = p.Audio;
- if (pos >= len)
- {
-
- myProgress.Report(1);
-
- }
- /* This is why videos get corrupted */
- srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
-
- byte[] buffer = new byte[4096];
- int read = 0;
- do
- {
- read = srcStrm.Read(buffer, 0, buffer.Length);
- destStrm.Write(buffer, 0, read);
-
- pos += read;
- double myP = (double)pos / (double)len;
- myProgress.Report(myP);
- }
- while (read > 0 && DownloadIt);
- }
-
- }
- if(DownloadIt)
- {
- File.Move(mypathaudio, mypathCompleteAudio);
- }
-
- }
- IProgress pa = p.Video;
- if (DownloadIt)
- {
- pa.Report(1);
- ffmpeg.mux(mypath, mypathCompleteAudio, mypathIncompleteConverting);
-
-
- File.Move(mypathIncompleteConverting, mypathComplete);
- }
- }
- break;
- case Resolution.NoConvert:
- string mypath2 = GetPath(true, "NotConverted", v.Video.Id + "incomplete.mp4");
- string mypath2Complete = GetPath(true, "NotConverted", v.Video.Id + ".mp4");
-
- if (Continue(mypath2Complete))
- {
- var s = await GetManifest(ytc,v.Video.Id);
- var best = s.GetMuxedStreams().GetWithHighestVideoQuality();
- P.Length = best.Size.Bytes;
- long pos = 0;
- long len = 0;
- using (var destStrm = System.IO.File.Open(mypath2, FileMode.OpenOrCreate, FileAccess.ReadWrite))
- {
- using (var srcStrm = await ytc.Videos.Streams.GetAsync(best))
- {
- len = srcStrm.Length;
- pos = destStrm.Length;
- IProgress myProgress = DownloadP;
- if (pos >= len)
- {
-
- myProgress.Report(1);
-
- }
- /* This is why videos get corrupted */
- srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- byte[] buffer = new byte[4096];
- int read = 0;
- do
- {
- read = srcStrm.Read(buffer, 0, buffer.Length);
- destStrm.Write(buffer, 0, read);
-
- pos += read;
- double myP = (double)pos / (double)len;
- myProgress.Report(myP);
- }
- while (read > 0 && DownloadIt);
- }
-
- }
- if (DownloadIt)
- {
- File.Move(mypath2, mypath2Complete);
-
- }
-
- }
-
-
- break;
- case Resolution.Audio:
- string mypath3 = GetPath(true, "Audio", v.Video.Id + "incomplete.mp4");
- string mypath3Complete = GetPath(true, "Audio", v.Video.Id + ".mp4");
- if (Continue(mypath3Complete))
- {
- var s2 = await GetManifest(ytc,v.Video.Id);
- var best2 = s2.GetAudioOnlyStreams().GetWithHighestBitrate();
- P.Length = best2.Size.Bytes;
- long pos = 0;
- long len = 0;
- using (var destStrm = System.IO.File.Open(mypath3, FileMode.OpenOrCreate, FileAccess.ReadWrite))
- {
- using (var srcStrm = await ytc.Videos.Streams.GetAsync(best2))
- {
- len = srcStrm.Length;
- pos = destStrm.Length;
- IProgress myProgress = DownloadP;
- if (pos >= len)
- {
-
- myProgress.Report(1);
-
- }
- /* This is why videos get corrupted */
- srcStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- destStrm.Seek(destStrm.Length, SeekOrigin.Begin);
- byte[] buffer = new byte[4096];
- int read = 0;
- do
- {
- read = srcStrm.Read(buffer, 0, buffer.Length);
- destStrm.Write(buffer, 0, read);
-
- pos += read;
- double myP = (double)pos / (double)len;
- myProgress.Report(myP);
- }
- while (read > 0 && DownloadIt);
- }
-
- }
- if (DownloadIt)
- {
- File.Move(mypath3, mypath3Complete);
- }
- }
- break;
- }
- if (DownloadIt)
- {
- DownloadCompleteEventArgs evt2 = new DownloadCompleteEventArgs();
-
- evt2.RegularFile = v.RegularFile;
- evt2.Video = v.Video;
-
- ApiLoader.DownloadComplete(this, evt2);
- ffmpeg.on_video_done(v.Video.Id, (int)v.Resolution);
- }
-
- }
-
- if (RedownloadIt && !DownloadIt)
- {
- DownloadIt = true;
- goto redownload;
- }
-
-
- DownloadIt = true;
- } catch (Exception ex)
- {
- Console.WriteLine(ex.Message);
- }
- }
- nope: System.Threading.Thread.Sleep(2000);
+ await DownloadItem(cancelSrc.Item.Token);
}
while (true);
@@ -1018,7 +1303,7 @@ namespace TYTD.Server.Functions
string[] array2 = new string[_path.Length + 1];
array2[0] = StorageLocation;
Array.Copy(_path, 0, array2, 1,_path.Length);
- return System.IO.Path.Combine(array2);
+ return Path.Combine(array2);
}
public static Downloader DL = new Downloader();
diff --git a/TYTD.Api/bin/Release/TYTD.Api.dll b/TYTD.Api/bin/Release/TYTD.Api.dll
index e8d4db5..004b47d 100644
Binary files a/TYTD.Api/bin/Release/TYTD.Api.dll and b/TYTD.Api/bin/Release/TYTD.Api.dll differ
diff --git a/TYTD.Api/obj/Release/TYTD.Api.csproj.CoreCompileInputs.cache b/TYTD.Api/obj/Release/TYTD.Api.csproj.CoreCompileInputs.cache
index 0fe2453..3358e15 100644
--- a/TYTD.Api/obj/Release/TYTD.Api.csproj.CoreCompileInputs.cache
+++ b/TYTD.Api/obj/Release/TYTD.Api.csproj.CoreCompileInputs.cache
@@ -1 +1 @@
-bd5555531ad345fded2f6956d4df232b6cc12a0e
+90e7df0901031d53badd1ff52afc81b857770db7
diff --git a/TYTD.Api/obj/Release/TYTD.Api.csproj.FileListAbsolute.txt b/TYTD.Api/obj/Release/TYTD.Api.csproj.FileListAbsolute.txt
index e2a055a..6ff7e1b 100644
--- a/TYTD.Api/obj/Release/TYTD.Api.csproj.FileListAbsolute.txt
+++ b/TYTD.Api/obj/Release/TYTD.Api.csproj.FileListAbsolute.txt
@@ -129,3 +129,134 @@
/home/ddlovato/tytd/site/TYTD.Api/bin/Release/MimeTypesMap.dll
/home/ddlovato/tytd/site/TYTD.Api/bin/Release/SimpleHTTP.dll
/home/ddlovato/tytd/site/TYTD.Api/bin/Release/SimpleHTTP.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/TYTD.Api.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.InteropServices.RuntimeInformation.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Cryptography.Algorithms.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.ValueTuple.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/Microsoft.Win32.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/netstandard.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.AppContext.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Collections.Concurrent.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Collections.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Collections.NonGeneric.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Collections.Specialized.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.ComponentModel.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.ComponentModel.EventBasedAsync.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.ComponentModel.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.ComponentModel.TypeConverter.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Console.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Data.Common.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.Contracts.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.Debug.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.FileVersionInfo.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.Process.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.StackTrace.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.TextWriterTraceListener.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.Tools.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.TraceSource.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Diagnostics.Tracing.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Drawing.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Dynamic.Runtime.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Globalization.Calendars.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Globalization.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Globalization.Extensions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.Compression.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.Compression.ZipFile.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.FileSystem.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.FileSystem.DriveInfo.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.FileSystem.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.FileSystem.Watcher.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.IsolatedStorage.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.MemoryMappedFiles.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.Pipes.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.IO.UnmanagedMemoryStream.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Linq.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Linq.Expressions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Linq.Parallel.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Linq.Queryable.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.Http.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.NameResolution.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.NetworkInformation.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.Ping.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.Requests.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.Security.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.Sockets.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.WebHeaderCollection.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.WebSockets.Client.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Net.WebSockets.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.ObjectModel.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Reflection.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Reflection.Extensions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Reflection.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Resources.Reader.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Resources.ResourceManager.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Resources.Writer.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.CompilerServices.VisualC.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Extensions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Handles.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.InteropServices.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Numerics.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Serialization.Formatters.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Serialization.Json.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Serialization.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.Serialization.Xml.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Claims.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Cryptography.Csp.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Cryptography.Encoding.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Cryptography.Primitives.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Cryptography.X509Certificates.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.Principal.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Security.SecureString.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Encoding.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Encoding.Extensions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.RegularExpressions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Overlapped.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Tasks.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Tasks.Parallel.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Thread.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.ThreadPool.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Timer.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Xml.ReaderWriter.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Xml.XDocument.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Xml.XmlDocument.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Xml.XmlSerializer.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Xml.XPath.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Xml.XPath.XDocument.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/AngleSharp.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/AsyncEnumerable.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/CookiesTxtParser.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/Microsoft.Bcl.AsyncInterfaces.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/MimeTypesMap.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/Newtonsoft.Json.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/SimpleHTTP.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Buffers.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Memory.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Numerics.Vectors.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.CompilerServices.Unsafe.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Encoding.CodePages.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Encodings.Web.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Json.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Tasks.Extensions.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/YoutubeExplode.dll
+/home/mike/Git/site/TYTD.Api/bin/Release/Newtonsoft.Json.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Buffers.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Numerics.Vectors.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Runtime.CompilerServices.Unsafe.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Memory.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Encoding.CodePages.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/AngleSharp.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Encodings.Web.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Threading.Tasks.Extensions.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/Microsoft.Bcl.AsyncInterfaces.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/System.Text.Json.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/YoutubeExplode.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/AsyncEnumerable.xml
+/home/mike/Git/site/TYTD.Api/bin/Release/SimpleHTTP.xml
+/home/mike/Git/site/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache
+/home/mike/Git/site/TYTD.Api/obj/Release/TYTD.Api.csproj.CoreCompileInputs.cache
+/home/mike/Git/site/TYTD.Api/obj/Release/TYTD.Api.csproj.CopyComplete
+/home/mike/Git/site/TYTD.Api/obj/Release/TYTD.Api.dll
diff --git a/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache b/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache
index 1d4fce0..1f6ccd6 100644
Binary files a/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache and b/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache differ
diff --git a/TYTD.Api/obj/Release/TYTD.Api.dll b/TYTD.Api/obj/Release/TYTD.Api.dll
index e8d4db5..004b47d 100644
Binary files a/TYTD.Api/obj/Release/TYTD.Api.dll and b/TYTD.Api/obj/Release/TYTD.Api.dll differ
diff --git a/bin/Release/TYTD.Api.dll b/bin/Release/TYTD.Api.dll
index e8d4db5..004b47d 100644
Binary files a/bin/Release/TYTD.Api.dll and b/bin/Release/TYTD.Api.dll differ
diff --git a/bin/Release/youtube-downloader.exe b/bin/Release/youtube-downloader.exe
index ca039a3..09f945d 100644
Binary files a/bin/Release/youtube-downloader.exe and b/bin/Release/youtube-downloader.exe differ
diff --git a/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache b/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache
index 1c65f72..80970e0 100644
--- a/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache
+++ b/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache
@@ -1 +1 @@
-f8ed00aa95ccbdf3db94f6dfd910ae2b01d175fa
+0420bdbd734151f93ed246c2e88d675d01ee774e
diff --git a/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt b/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt
index e63209a..4f6b31a 100644
--- a/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt
+++ b/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt
@@ -424,3 +424,150 @@
/home/ddlovato/tytd/site/bin/Release/Jurassic.xml
/home/ddlovato/tytd/site/bin/Release/Flurl.pdb
/home/ddlovato/tytd/site/bin/Release/Flurl.xml
+/home/mike/Git/site/bin/Release/youtube-downloader.exe
+/home/mike/Git/site/bin/Release/System.Runtime.InteropServices.RuntimeInformation.dll
+/home/mike/Git/site/bin/Release/System.Security.Cryptography.Algorithms.dll
+/home/mike/Git/site/bin/Release/System.ValueTuple.dll
+/home/mike/Git/site/bin/Release/Microsoft.Win32.Primitives.dll
+/home/mike/Git/site/bin/Release/netstandard.dll
+/home/mike/Git/site/bin/Release/System.AppContext.dll
+/home/mike/Git/site/bin/Release/System.Collections.Concurrent.dll
+/home/mike/Git/site/bin/Release/System.Collections.dll
+/home/mike/Git/site/bin/Release/System.Collections.NonGeneric.dll
+/home/mike/Git/site/bin/Release/System.Collections.Specialized.dll
+/home/mike/Git/site/bin/Release/System.ComponentModel.dll
+/home/mike/Git/site/bin/Release/System.ComponentModel.EventBasedAsync.dll
+/home/mike/Git/site/bin/Release/System.ComponentModel.Primitives.dll
+/home/mike/Git/site/bin/Release/System.ComponentModel.TypeConverter.dll
+/home/mike/Git/site/bin/Release/System.Console.dll
+/home/mike/Git/site/bin/Release/System.Data.Common.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.Contracts.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.Debug.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.FileVersionInfo.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.Process.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.StackTrace.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.TextWriterTraceListener.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.Tools.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.TraceSource.dll
+/home/mike/Git/site/bin/Release/System.Diagnostics.Tracing.dll
+/home/mike/Git/site/bin/Release/System.Drawing.Primitives.dll
+/home/mike/Git/site/bin/Release/System.Dynamic.Runtime.dll
+/home/mike/Git/site/bin/Release/System.Globalization.Calendars.dll
+/home/mike/Git/site/bin/Release/System.Globalization.dll
+/home/mike/Git/site/bin/Release/System.Globalization.Extensions.dll
+/home/mike/Git/site/bin/Release/System.IO.Compression.dll
+/home/mike/Git/site/bin/Release/System.IO.Compression.ZipFile.dll
+/home/mike/Git/site/bin/Release/System.IO.dll
+/home/mike/Git/site/bin/Release/System.IO.FileSystem.dll
+/home/mike/Git/site/bin/Release/System.IO.FileSystem.DriveInfo.dll
+/home/mike/Git/site/bin/Release/System.IO.FileSystem.Primitives.dll
+/home/mike/Git/site/bin/Release/System.IO.FileSystem.Watcher.dll
+/home/mike/Git/site/bin/Release/System.IO.IsolatedStorage.dll
+/home/mike/Git/site/bin/Release/System.IO.MemoryMappedFiles.dll
+/home/mike/Git/site/bin/Release/System.IO.Pipes.dll
+/home/mike/Git/site/bin/Release/System.IO.UnmanagedMemoryStream.dll
+/home/mike/Git/site/bin/Release/System.Linq.dll
+/home/mike/Git/site/bin/Release/System.Linq.Expressions.dll
+/home/mike/Git/site/bin/Release/System.Linq.Parallel.dll
+/home/mike/Git/site/bin/Release/System.Linq.Queryable.dll
+/home/mike/Git/site/bin/Release/System.Net.Http.dll
+/home/mike/Git/site/bin/Release/System.Net.NameResolution.dll
+/home/mike/Git/site/bin/Release/System.Net.NetworkInformation.dll
+/home/mike/Git/site/bin/Release/System.Net.Ping.dll
+/home/mike/Git/site/bin/Release/System.Net.Primitives.dll
+/home/mike/Git/site/bin/Release/System.Net.Requests.dll
+/home/mike/Git/site/bin/Release/System.Net.Security.dll
+/home/mike/Git/site/bin/Release/System.Net.Sockets.dll
+/home/mike/Git/site/bin/Release/System.Net.WebHeaderCollection.dll
+/home/mike/Git/site/bin/Release/System.Net.WebSockets.Client.dll
+/home/mike/Git/site/bin/Release/System.Net.WebSockets.dll
+/home/mike/Git/site/bin/Release/System.ObjectModel.dll
+/home/mike/Git/site/bin/Release/System.Reflection.dll
+/home/mike/Git/site/bin/Release/System.Reflection.Extensions.dll
+/home/mike/Git/site/bin/Release/System.Reflection.Primitives.dll
+/home/mike/Git/site/bin/Release/System.Resources.Reader.dll
+/home/mike/Git/site/bin/Release/System.Resources.ResourceManager.dll
+/home/mike/Git/site/bin/Release/System.Resources.Writer.dll
+/home/mike/Git/site/bin/Release/System.Runtime.CompilerServices.VisualC.dll
+/home/mike/Git/site/bin/Release/System.Runtime.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Extensions.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Handles.dll
+/home/mike/Git/site/bin/Release/System.Runtime.InteropServices.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Numerics.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Serialization.Formatters.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Serialization.Json.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Serialization.Primitives.dll
+/home/mike/Git/site/bin/Release/System.Runtime.Serialization.Xml.dll
+/home/mike/Git/site/bin/Release/System.Security.Claims.dll
+/home/mike/Git/site/bin/Release/System.Security.Cryptography.Csp.dll
+/home/mike/Git/site/bin/Release/System.Security.Cryptography.Encoding.dll
+/home/mike/Git/site/bin/Release/System.Security.Cryptography.Primitives.dll
+/home/mike/Git/site/bin/Release/System.Security.Cryptography.X509Certificates.dll
+/home/mike/Git/site/bin/Release/System.Security.Principal.dll
+/home/mike/Git/site/bin/Release/System.Security.SecureString.dll
+/home/mike/Git/site/bin/Release/System.Text.Encoding.dll
+/home/mike/Git/site/bin/Release/System.Text.Encoding.Extensions.dll
+/home/mike/Git/site/bin/Release/System.Text.RegularExpressions.dll
+/home/mike/Git/site/bin/Release/System.Threading.dll
+/home/mike/Git/site/bin/Release/System.Threading.Overlapped.dll
+/home/mike/Git/site/bin/Release/System.Threading.Tasks.dll
+/home/mike/Git/site/bin/Release/System.Threading.Tasks.Parallel.dll
+/home/mike/Git/site/bin/Release/System.Threading.Thread.dll
+/home/mike/Git/site/bin/Release/System.Threading.ThreadPool.dll
+/home/mike/Git/site/bin/Release/System.Threading.Timer.dll
+/home/mike/Git/site/bin/Release/System.Xml.ReaderWriter.dll
+/home/mike/Git/site/bin/Release/System.Xml.XDocument.dll
+/home/mike/Git/site/bin/Release/System.Xml.XmlDocument.dll
+/home/mike/Git/site/bin/Release/System.Xml.XmlSerializer.dll
+/home/mike/Git/site/bin/Release/System.Xml.XPath.dll
+/home/mike/Git/site/bin/Release/System.Xml.XPath.XDocument.dll
+/home/mike/Git/site/bin/Release/AngleSharp.dll
+/home/mike/Git/site/bin/Release/AsyncEnumerable.dll
+/home/mike/Git/site/bin/Release/Common.Logging.Core.dll
+/home/mike/Git/site/bin/Release/Common.Logging.dll
+/home/mike/Git/site/bin/Release/CookiesTxtParser.dll
+/home/mike/Git/site/bin/Release/ExposedObject.dll
+/home/mike/Git/site/bin/Release/Flurl.dll
+/home/mike/Git/site/bin/Release/Jurassic.dll
+/home/mike/Git/site/bin/Release/Microsoft.Bcl.AsyncInterfaces.dll
+/home/mike/Git/site/bin/Release/MimeTypesMap.dll
+/home/mike/Git/site/bin/Release/Newtonsoft.Json.dll
+/home/mike/Git/site/bin/Release/SimpleBase.dll
+/home/mike/Git/site/bin/Release/SimpleHTTP.dll
+/home/mike/Git/site/bin/Release/Stef.Validation.dll
+/home/mike/Git/site/bin/Release/System.Buffers.dll
+/home/mike/Git/site/bin/Release/System.Memory.dll
+/home/mike/Git/site/bin/Release/System.Numerics.Vectors.dll
+/home/mike/Git/site/bin/Release/System.Runtime.CompilerServices.Unsafe.dll
+/home/mike/Git/site/bin/Release/System.Text.Encoding.CodePages.dll
+/home/mike/Git/site/bin/Release/System.Text.Encodings.Web.dll
+/home/mike/Git/site/bin/Release/System.Text.Json.dll
+/home/mike/Git/site/bin/Release/System.Threading.Tasks.Extensions.dll
+/home/mike/Git/site/bin/Release/TYTD.Api.dll
+/home/mike/Git/site/bin/Release/YoutubeExplode.dll
+/home/mike/Git/site/bin/Release/YoutubeExplode.Extensions.dll
+/home/mike/Git/site/bin/Release/Newtonsoft.Json.xml
+/home/mike/Git/site/bin/Release/System.Buffers.xml
+/home/mike/Git/site/bin/Release/System.Numerics.Vectors.xml
+/home/mike/Git/site/bin/Release/System.Runtime.CompilerServices.Unsafe.xml
+/home/mike/Git/site/bin/Release/System.Memory.xml
+/home/mike/Git/site/bin/Release/AngleSharp.xml
+/home/mike/Git/site/bin/Release/System.Text.Encodings.Web.xml
+/home/mike/Git/site/bin/Release/System.Threading.Tasks.Extensions.xml
+/home/mike/Git/site/bin/Release/Microsoft.Bcl.AsyncInterfaces.xml
+/home/mike/Git/site/bin/Release/System.Text.Json.xml
+/home/mike/Git/site/bin/Release/YoutubeExplode.xml
+/home/mike/Git/site/bin/Release/SimpleHTTP.xml
+/home/mike/Git/site/bin/Release/AsyncEnumerable.xml
+/home/mike/Git/site/bin/Release/Common.Logging.Core.pdb
+/home/mike/Git/site/bin/Release/Common.Logging.pdb
+/home/mike/Git/site/bin/Release/Common.Logging.xml
+/home/mike/Git/site/bin/Release/SimpleBase.pdb
+/home/mike/Git/site/bin/Release/ExposedObject.pdb
+/home/mike/Git/site/bin/Release/Jurassic.xml
+/home/mike/Git/site/bin/Release/Flurl.pdb
+/home/mike/Git/site/bin/Release/Flurl.xml
+/home/mike/Git/site/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache
+/home/mike/Git/site/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache
+/home/mike/Git/site/obj/x86/Release/youtube-downloader.csproj.CopyComplete
+/home/mike/Git/site/obj/x86/Release/youtube-downloader.exe
diff --git a/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache b/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache
index 3d9564e..10cd1a2 100644
Binary files a/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache and b/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache differ
diff --git a/obj/x86/Release/youtube-downloader.exe b/obj/x86/Release/youtube-downloader.exe
index ca039a3..09f945d 100644
Binary files a/obj/x86/Release/youtube-downloader.exe and b/obj/x86/Release/youtube-downloader.exe differ