tytd-server/TYTD.Api/Server/Functions/Downloader.cs

1421 lines
50 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using YoutubeExplode.Videos;
using YoutubeExplode;
using System.Net.Http;
using System.Net;
using System.IO;
using TYTD.Server.Models;
using Newtonsoft.Json;
using YoutubeExplode.Videos.Streams;
using YoutubeExplode.Channels;
using YoutubeExplode.Playlists;
using Dasync.Collections;
using System.Threading;
using SimpleHttp;
using System.Text;
namespace TYTD.Server.Functions
{
public class Downloader
{
private static string HandleDescription(string desc)
{
StringBuilder builder = new StringBuilder();
foreach(var ln in desc.Split('\n'))
{
builder.Append($"&nbsp;&nbsp;&nbsp;&nbsp;{ln}<br>");
}
return builder.ToString();
}
public static Dictionary<string, List<(string Path, string Description, string Method)>> Endpoints = new Dictionary<string, List<(string Path, string Description, string Method)>>();
/// <summary>
/// Adds route while adding it to list for documentation
/// </summary>
/// <param name="path">Path.</param>
/// <param name="group">Group.</param>
/// <param name="description">Description. (you have to use WebUtility.HtmlEncode())</param>
/// <param name="act">action to call</param>
/// <param name="method">HTTP Method</param>
public static void RouteAdd(string path, string group, string description, HttpActionAsync act, string method = "GET")
{
Endpoints.AddToList(group, (WebUtility.HtmlEncode(path), HandleDescription(description), method));
//_endpoint.((WebUtility.HtmlEncode(path),description));
Route.Add(path, act, method);
}
/// <summary>
/// Adds route while adding it to list for documentation
/// </summary>
/// <param name="path">Path.</param>
/// <param name="group">Group.</param>
/// <param name="description">Description. (you have to use WebUtility.HtmlEncode())</param>
/// <param name="act">action to call</param>
/// <param name="method">HTTP Method</param>
public static void RouteAdd(string path, string group, string description, HttpAction act, string method = "GET")
{
Endpoints.AddToList(group, (WebUtility.HtmlEncode(path), HandleDescription(description), method));
Route.Add(path, act, method);
}
public static List<SavedVideo> SearchFor(string str)
{
Func<SavedVideo,bool> add = (e) =>
{
if(string.IsNullOrWhiteSpace(str))
{
return true;
}
if(str=="*")
{
return true;
}
if(str.StartsWith("v/",StringComparison.Ordinal))
{
return str.Substring(2) == e.Id;
}
if(str.StartsWith("c/",StringComparison.Ordinal))
{
string r = str.Substring(2);
return r == e.AuthorChannelId || r==e.AuthorTitle;
}
if(str.StartsWith("longer/",StringComparison.Ordinal))
{
string r = str.Substring(7);
TimeSpan ts;
long n;
if(TimeSpan.TryParse(str,out ts))
{
return ts.TotalSeconds > e.Duration;
}
if(long.TryParse(str,out n))
{
return n > e.Duration;
}
}
if (str.StartsWith("shorter/", StringComparison.Ordinal))
{
string r = str.Substring(8);
TimeSpan ts;
long n;
if (TimeSpan.TryParse(str, out ts))
{
return ts.TotalSeconds < e.Duration;
}
if (long.TryParse(str, out n))
{
return n < e.Duration;
}
return false;
}
if (e.Title.Length < str.Length)
{
return false;
}
return e.Title.Remove(str.Length) == str;
};
List<SavedVideo> videos = new List<SavedVideo>();
foreach (var video in Directory.GetFiles("Info", ".json"))
{
var val=JsonConvert.DeserializeObject<SavedVideo>(File.ReadAllText(video));
if(add(val))
{
videos.Add(val);
}
}
return videos;
}
public class Lockable<T>
{
public Lockable(Func<T> recreate)
{
_recreate = recreate;
Item = recreate();
}
Func<T> _recreate;
public void Recreate()
{
Item = _recreate();
}
public T Item { get; set; }
public void Change(T item)
{
Item = item;
}
public static implicit operator T(Lockable<T> item)
{
return item.Item;
}
}
public static bool RedownloadIt = false;
public List<InfomationQueueItem> infoQueue = new List<InfomationQueueItem>();
public static YoutubeClient CreateYoutubeClient()
{
ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
Directory.CreateDirectory("config");
string cookiesFile = Path.Combine("config", "cookies.txt");
if (File.Exists(cookiesFile))
{
var cookies = CookiesTxt.Parser.ParseFileAsCookieCollection(cookiesFile);
handler.CookieContainer.Add(cookies);
}
Http = new HttpClient(handler);
return new YoutubeClient(Http);
}
public static VideoDownloadProgress GetProgress()
{
return P;
}
static HttpClient Http;
internal YoutubeClient ytc = CreateYoutubeClient();
public static YoutubeClient GetClient()
{
return DL.ytc;
}
static VideoDownloadProgress P = new VideoDownloadProgress();
const int NUM_WAITS = 5;
static int WAITS = 0;
public static void SendProgress(double p)
{
WAITS++;
if (WAITS <= NUM_WAITS)
return;
WAITS = 0;
ApiLoader.SetProgress(p);
}
Progress<double> DownloadP = new Progress<double>((e) => { P.Progress = (int)(e * 100.0); P.ProgressRaw = e; SendProgress(e); });
public List<SavedVideoObject> Queue = new List<SavedVideoObject>();
public static string GetQueue()
{
string q;
lock (DL.Queue)
{
q = JsonConvert.SerializeObject(DL.Queue.Select<SavedVideoObject, SavedVideo>(o => o.Video));
}
return q;
}
public async Task ListenForQueueItem()
{
do
{
InfomationQueueItem item;
bool canAdd = false;
lock (infoQueue)
{
canAdd = infoQueue.Count > 0;
if (canAdd)
{
item = infoQueue[0];
infoQueue.RemoveAt(0);
}
else
{
item = null;
}
}
if (canAdd)
{
try
{
var items = await item.DownloadData();
if (item.DownloadActualDataAfterwards)
{
_DownloadVideos(items);
}
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
}
} while (true);
}
public static void ModQueue2(string mvto, string index)
{
try
{
//?mv=up|down|top|bottom|remove,int&i=videoId;URL
lock (DL.Queue)
{
int index2 = -1;
for(int i=0;i<DL.Queue.Count;i++)
{
if(DL.Queue[i].Video.Id == index)
{
index2 = i;
break;
}
}
if(index2 < 0)
{
return;
}
if (mvto == "top")
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Insert(0, v);
}
else if (mvto == "bottom")
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Add(v);
}
else if (mvto == "remove")
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
}
else if (mvto == "up")
{
if (index2 > 0)
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Insert(index2 - 1, v);
}
}
else if (mvto == "down")
{
if (index2 < DL.Queue.Count - 1)
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Insert(index2 + 1, v);
}
}
else
{
int n1;
if (int.TryParse(mvto, out n1))
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
if (n1 > index2)
{
DL.Queue.Insert(n1 - 1, v);
}
else
{
DL.Queue.Insert(n1, v);
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
}
public static void ModQueue(string mvto, string index)
{
try
{
//?mv=up|down|top|bottom|remove,int&i=0,last
lock (DL.Queue)
{
int index2 = 0;
if (index == "last")
{
index2 = DL.Queue.Count - 1;
}
else
{
if (!int.TryParse(index, out index2))
{
index2 = 0;
}
}
if (index2 >= DL.Queue.Count)
{
index2 = DL.Queue.Count - 1;
}
if (mvto == "top")
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Insert(0, v);
}
else if (mvto == "bottom")
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Add(v);
}
else if (mvto == "remove")
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
}
else if (mvto == "up")
{
if (index2 > 0)
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Insert(index2 - 1, v);
}
}
else if (mvto == "down")
{
if (index2 < DL.Queue.Count - 1)
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
DL.Queue.Insert(index2 + 1, v);
}
}
else
{
int n1;
if (int.TryParse(mvto, out n1))
{
var v = DL.Queue[index2];
DL.Queue.Remove(v);
if (n1 > index2)
{
DL.Queue.Insert(n1 - 1, v);
}
else
{
DL.Queue.Insert(n1, v);
}
}
}
}
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
}
public static async Task DownloadChannelOnly(string id)
{
ChannelId? v = ChannelId.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, Resolution.NoConvert, false);
await item.DownloadData();
}
}
public static void DownloadItems(List<IDResolutionTypeTriplet> id)
{
List<InfomationQueueItem> items = new List<InfomationQueueItem>();
foreach (var item in id)
{
var iqi = item.ToInfomationQueueItem();
if (iqi != null)
{
items.Add(iqi);
}
}
if (items.Count > 0)
{
lock (DL.infoQueue)
{
DL.infoQueue.InsertRange(0, items);
}
}
}
public static async Task DownloadUserOnly(string id)
{
UserName? v = UserName.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, Resolution.NoConvert, false);
await item.DownloadData();
}
}
public bool Continue(string v)
{
if (File.Exists(v))
{
using (var f = File.OpenRead(v))
{
return f.Length == 0;
}
}
return true;
}
private string gStorageLocation()
{
if (File.Exists("loc.txt"))
{
string loc = File.ReadAllText("loc.txt");
try
{
Directory.CreateDirectory(loc);
if (Directory.Exists(loc))
{
return loc;
}
} catch (Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
}
return Environment.CurrentDirectory;
}
public string StorageLocation { get { return gStorageLocation(); } }
private void _DownloadVideos(SavedVideoObject[] items)
{
lock (Queue)
{
foreach (var item in items)
{
Queue.Insert(0, item);
//new elements get added to begining
}
}
}
public bool FileExists(string nameSrc,ref string nameDest,ref int i)
{
if(i == 1)
{
i++;
return File.Exists(nameSrc);
}
i++;
nameDest= Path.Combine(Path.GetDirectoryName(nameSrc), $"{Path.GetFileNameWithoutExtension(nameSrc)} ({i}){Path.GetExtension(nameSrc)}");
return File.Exists(nameDest);
}
public Lockable<CancellationTokenSource> cancelSrc = new Lockable<CancellationTokenSource>(()=> { return new CancellationTokenSource(); });
public static Func<YoutubeClient,VideoId, Task<StreamManifest>> 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<double> 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<double> 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<double> 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<double> 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<double> 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<double> 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<double> 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
{
await DownloadItem(cancelSrc.Item.Token);
}
while (true);
}
internal void _DownloadThumbnail(int w, int h, string id, string tnail)
{
try
{
string p = GetPath(true, "Thumbnails", w.ToString() + 'x' + h.ToString(), id + ".jpg");
if (!File.Exists(p))
{
ffmpeg.download_thumbnail(tnail, p);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
}
internal void _DownloadThumbnail2(int w, int h, string id, string tnail)
{
try
{
string p = GetPath(true, "Thumbnails", w.ToString() + 'x' + h.ToString(), id + ".jpg");
if (!File.Exists(p))
{
using (var f = File.Create(p))
{
Http.GetStreamAsync(tnail);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
}
public static async Task<List<SavedMedia>> Search(string text, bool downloadThumbs = true)
{
List<SavedMedia> media = new List<SavedMedia>();
try
{
await DL.ytc.Search.GetVideosAsync(text).ForEachAsync((e) =>
{
if (downloadThumbs)
{
foreach (var t in e.Thumbnails)
{
DL._DownloadThumbnail2(t.Resolution.Width, t.Resolution.Height, e.Id, t.Url);
}
}
media.Add(new SavedMedia() { Title = e.Title, Id = e.Id, Kind = InfoType.Video });
});
await DL.ytc.Search.GetPlaylistsAsync(text).ForEachAsync((e) => {
if (downloadThumbs)
{
foreach (var t in e.Thumbnails)
{
DL._DownloadThumbnail2(t.Resolution.Width, t.Resolution.Height, e.Id, t.Url);
}
}
media.Add(new SavedMedia() { Title = e.Title, Id = e.Id, Kind = InfoType.Playlist });
});
await DL.ytc.Search.GetChannelsAsync(text).ForEachAsync((e) => {
if (downloadThumbs)
{
foreach (var t in e.Thumbnails)
{
DL._DownloadThumbnail2(t.Resolution.Width, t.Resolution.Height, e.Id, t.Url);
}
}
media.Add(new SavedMedia() { Title = e.Title, Id = e.Id, Kind = InfoType.Channel });
});
} catch (Exception ex)
{
_ = ex;
}
return media;
}
public static List<SavedVideoObject> GetQueueItems()
{
return DL.Queue;
}
public static void DownloadFile(string id)
{
InfomationQueueItem item = new InfomationQueueItem(new Uri(id));
lock (DL.infoQueue)
{
DL.infoQueue.Insert(0, item);
}
}
public static void DownloadVideo(string id, Resolution res)
{
VideoId? v = VideoId.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, res, true);
lock (DL.infoQueue)
{
DL.infoQueue.Insert(0, item);
}
}
}
public static async Task DownloadVideoInfo(string id, Resolution res)
{
VideoId? v = VideoId.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, res, false);
await item.DownloadData();
}
}
public static void DownloadVideo(string v)
{
DownloadVideo(v, Resolution.NoConvert);
}
public static void DownloadCaptions(string id)
{
VideoId? v = VideoId.TryParse(id);
if(v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value);
lock (DL.infoQueue)
{
DL.infoQueue.Insert(0, item);
}
}
}
public static void DownloadPlaylist(string id,Resolution res)
{
PlaylistId? v = PlaylistId.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, res, true);
lock (DL.infoQueue)
{
DL.infoQueue.Insert(0, item);
}
}
}
public static async Task DownloadPlaylistOnly(string id, Resolution res)
{
PlaylistId? v = PlaylistId.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, res, false);
await item.DownloadData();
}
}
public static void DownloadPlaylist(string id)
{
DownloadPlaylist(id, Resolution.NoConvert);
}
public static void DownloadChannel(string id,Resolution res)
{
ChannelId? v = ChannelId.TryParse(id);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, res, true);
lock (DL.infoQueue)
{
DL.infoQueue.Insert(0, item);
}
}
}
public static void DownloadChannel(string id)
{
DownloadChannel(id, Resolution.NoConvert);
}
public static void DownloadItem(string id)
{
DownloadItem(id, Resolution.NoConvert);
}
public static void DownloadItem(string id,Resolution res)
{
VideoId? vid = VideoId.TryParse(id);
PlaylistId? pid = PlaylistId.TryParse(id);
ChannelId? cid = ChannelId.TryParse(id);
UserName? user = UserName.TryParse(id);
if (id.Length == 11)
{
if (vid.HasValue)
{
DownloadVideo(vid.Value, res); //shall we download video
}
}
else
{
if (pid.HasValue)
{
DownloadPlaylist(pid.Value, res);
}
else if (vid.HasValue)
{
DownloadVideo(vid.Value, res);
}
else if (cid.HasValue)
{
DownloadChannel(cid.Value, res);
}
else if (user.HasValue)
{
DownloadUser(user.Value, res);
}
}
}
public static void DownloadUser(string name, Resolution res)
{
UserName? v=UserName.TryParse(name);
if (v.HasValue)
{
InfomationQueueItem item = new InfomationQueueItem(v.Value, res, true);
lock (DL.infoQueue)
{
DL.infoQueue.Insert(0, item);
}
}
}
public static void DownloadUser(string name)
{
DownloadUser(name, Resolution.NoConvert);
}
public string GetPath(bool createParent,params string[] _path)
{
if (createParent)
{
string dir = GetPath(_path);
try
{
Directory.CreateDirectory(Path.GetDirectoryName(dir));
}catch(Exception ex)
{
Console.WriteLine(ex.Message);
_ = ex;
}
return dir;
}
else
{
return GetPath(_path);
}
}
private string GetPath(params string[] _path)
{
string[] array2 = new string[_path.Length + 1];
array2[0] = StorageLocation;
Array.Copy(_path, 0, array2, 1,_path.Length);
return Path.Combine(array2);
}
public static Downloader DL = new Downloader();
}
}