2021-06-24 01:10:20 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
2021-06-24 03:41:34 +00:00
|
|
|
|
public Downloader()
|
|
|
|
|
{
|
|
|
|
|
// TessesYoutubeDownloader.Server.Functions.Downloader.DL.DownloadThread().GetAwaiter().GetResult();
|
|
|
|
|
|
|
|
|
|
}
|
2021-06-24 01:10:20 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
_ = ex;
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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));
|
2021-06-24 04:05:21 +00:00
|
|
|
|
var cvids = await ytc.Channels.GetUploadsAsync(id).ToListAsync();
|
|
|
|
|
foreach(var v in cvids)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
await _DownloadVideo(v.Id, res);
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
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));
|
2021-06-24 04:05:21 +00:00
|
|
|
|
var cvids = await ytc.Channels.GetUploadsAsync(c2.Id).ToListAsync();
|
|
|
|
|
foreach (var v in cvids)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
await _DownloadVideo(v.Id, res);
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadVideo(string id,Resolution res)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
VideoId? v = VideoId.TryParse(id);
|
|
|
|
|
if (v.HasValue)
|
|
|
|
|
{
|
|
|
|
|
DL._DownloadVideo(v.Value, res).GetAwaiter().GetResult();
|
|
|
|
|
}
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadVideo(string v)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
|
|
|
|
DownloadVideo(v, Resolution.NoConvert);
|
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadPlaylist(string id,Resolution res)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
PlaylistId? v = PlaylistId.TryParse(id);
|
|
|
|
|
if (v.HasValue)
|
|
|
|
|
{
|
|
|
|
|
DL._DownloadPlaylist(v.Value, res).GetAwaiter().GetResult();
|
|
|
|
|
}
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadPlaylist(string id)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
|
|
|
|
DownloadPlaylist(id, Resolution.NoConvert);
|
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadChannel(string id,Resolution res)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
ChannelId? v = ChannelId.TryParse(id);
|
|
|
|
|
if (v.HasValue)
|
|
|
|
|
{
|
|
|
|
|
DL._DownloadChannel(v.Value, res).GetAwaiter().GetResult();
|
|
|
|
|
}
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadChannel(string id)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
|
|
|
|
DownloadChannel(id, Resolution.NoConvert);
|
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadUser(string name, Resolution res)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
2021-06-24 04:05:21 +00:00
|
|
|
|
UserName? v=UserName.TryParse(name);
|
|
|
|
|
if (v.HasValue)
|
|
|
|
|
{
|
|
|
|
|
DL._DownloadUser(v.Value, res).GetAwaiter().GetResult();
|
|
|
|
|
}
|
2021-06-24 01:10:20 +00:00
|
|
|
|
}
|
2021-06-24 04:05:21 +00:00
|
|
|
|
public static void DownloadUser(string name)
|
2021-06-24 01:10:20 +00:00
|
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|