tytd-server/Server/Functions/Downloader.cs

418 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YoutubeExplode.Videos;
using YoutubeExplode;
using System.Net.Http;
using System.Net;
using System.IO;
using TessesYoutubeDownloader.Server.Models;
using Newtonsoft.Json;
using YoutubeExplode.Videos.Streams;
using YoutubeExplode.Channels;
using YoutubeExplode.Playlists;
namespace youtube_downloader.Server.Functions
{
public class Downloader
{
public Downloader()
{
// TessesYoutubeDownloader.Server.Functions.Downloader.DL.DownloadThread().GetAwaiter().GetResult();
}
public static YoutubeClient CreateYoutubeClient()
{
ServicePointManager
.ServerCertificateValidationCallback +=
(sender, cert, chain, sslPolicyErrors) => true;
HttpClientHandler handler = new HttpClientHandler();
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
Http = new HttpClient(handler);
return new YoutubeExplode.YoutubeClient(Http);
}
internal static VideoDownloadProgress GetProgress()
{
return P;
}
static HttpClient Http;
YoutubeClient ytc = CreateYoutubeClient();
static VideoDownloadProgress P=new VideoDownloadProgress();
Progress<double> DownloadP =new Progress<double>( (e)=> { P.Progress = (int)(e * 100.0); });
List<SavedVideoObject> Queue = new List<SavedVideoObject>();
internal static string GetQueue()
{
string q;
lock (DL.Queue)
{
q = JsonConvert.SerializeObject(DL.Queue.Select<SavedVideoObject, SavedVideo>(o => o.Video)) ;
}
return q;
}
internal 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)
{
_ = ex;
}
}
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 (System.IO.File.Exists("loc.txt"))
{
string loc=System.IO.File.ReadAllText("loc.txt");
try
{
System.IO.Directory.CreateDirectory(loc);
if (System.IO.Directory.Exists(loc))
{
return loc;
}
}catch(Exception ex)
{
}
}
return Environment.CurrentDirectory;
}
public string StorageLocation { get { return gStorageLocation(); } }
private async Task _DownloadVideo(VideoId videoId,Resolution res)
{ string infpath= GetPath(true, "Info", videoId + ".json");
SavedVideoObject sv;
bool exist = File.Exists(videoId);
if (exist)
{
sv = new SavedVideoObject();
sv.Resolution = res;
sv.Video = Newtonsoft.Json.JsonConvert.DeserializeObject<SavedVideo>(File.ReadAllText(infpath));
}
else
{
var vinfo = await ytc.Videos.GetAsync(videoId);
sv = SavedVideo.CreateFrom(res, vinfo, _DownloadThumbnail);
}
if (!exist)
{
File.WriteAllText(infpath, JsonConvert.SerializeObject(sv.Video));
}
lock (Queue)
{
Queue.Insert(0,sv); //new elements get added to begining
}
}
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;
Console.WriteLine($"Download: {v.Video.Title}");
}
else
{
v = null;
}
}
if (canDownload)
{
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 ytc.Videos.Streams.GetManifestAsync(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);
await ytc.Videos.Streams.DownloadAsync(best,mypath, p.Video);
IProgress<double> pv = p.Video;
pv.Report(1);
if (Continue(mypathCompleteAudio))
{
await ytc.Videos.Streams.DownloadAsync(best2, mypathaudio,p.Audio);
File.Move(mypathaudio, mypathCompleteAudio);
}
IProgress<double> pa = p.Video;
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 ytc.Videos.Streams.GetManifestAsync(v.Video.Id);
var best = s.GetMuxedStreams().GetWithHighestVideoQuality();
P.Length = best.Size.Bytes;
await ytc.Videos.Streams.DownloadAsync(best, mypath2, DownloadP);
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 ytc.Videos.Streams.GetManifestAsync(v.Video.Id);
var best2 = s2.GetAudioOnlyStreams().GetWithHighestBitrate();
P.Length = best2.Size.Bytes;
await ytc.Videos.Streams.DownloadAsync(best2, mypath3, DownloadP);
File.Move(mypath3, mypath3Complete);
}
break;
}
}
System.Threading.Thread.Sleep(1);
}
while (true);
}
private 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)
{
_ = ex;
}
}
internal static List<SavedVideoObject> GetQueueItems()
{
return DL.Queue;
}
private async Task _DownloadChannel(ChannelId id,Resolution res)
{
var c=await ytc.Channels.GetAsync(id);
SavedChannel c2 = SavedChannel.FromChannel(c, _DownloadThumbnail);
string infpath = GetPath(true, "Channel", id + ".json");
File.WriteAllText(infpath, JsonConvert.SerializeObject(c2));
var cvids = ytc.Channels.GetUploadsAsync(id).GetAsyncEnumerator();
while (await cvids.MoveNextAsync())
{
await _DownloadVideo(cvids.Current.Id, res);
}
}
private async Task _DownloadPlaylist(PlaylistId id,Resolution res)
{
SavedPlaylist pl =await SavedPlaylist.FromPlaylistId(res, ytc, id, DownloadVideo, _DownloadThumbnail);
string infpath = GetPath(true, "Playlist", id + ".json");
File.WriteAllText(infpath, JsonConvert.SerializeObject(pl));
}
private async Task _DownloadUser(UserName name, Resolution res)
{
var c = await ytc.Channels.GetByUserAsync(name);
SavedChannel c2 = SavedChannel.FromChannel(c, _DownloadThumbnail);
string infpath = GetPath(true, "Channels", c.Id + ".json");
File.WriteAllText(infpath, JsonConvert.SerializeObject(c2));
var cvids = ytc.Channels.GetUploadsAsync(c.Id).GetAsyncEnumerator();
while (await cvids.MoveNextAsync())
{
await _DownloadVideo(cvids.Current.Id, res);
}
}
public static void DownloadVideo(VideoId v,Resolution res)
{
DL._DownloadVideo(v, res).GetAwaiter().GetResult();
}
public static void DownloadVideo(VideoId v)
{
DownloadVideo(v, Resolution.NoConvert);
}
public static void DownloadPlaylist(PlaylistId id,Resolution res)
{
DL._DownloadPlaylist(id, res).GetAwaiter().GetResult();
}
public static void DownloadPlaylist(PlaylistId id)
{
DownloadPlaylist(id, Resolution.NoConvert);
}
public static void DownloadChannel(ChannelId id,Resolution res)
{
DL._DownloadChannel(id, res).GetAwaiter().GetResult();
}
public static void DownloadChannel(ChannelId id)
{
DownloadChannel(id, Resolution.NoConvert);
}
public static void DownloadUser(UserName name, Resolution res)
{
DL._DownloadUser(name, res).GetAwaiter().GetResult();
}
public static void DownloadUser(UserName 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)
{
_ = 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 System.IO.Path.Combine(array2);
}
public static Downloader DL = new Downloader();
}
}