tytd/Tesses.YouTubeDownloader.Se.../Class1.cs

1731 lines
81 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Tesses.WebServer;
using System.Net;
using YoutubeExplode.Videos;
using System.Linq;
using System.IO;
using System.Text;
using YoutubeExplode.Playlists;
using YoutubeExplode.Channels;
using Tesses.Extensions;
using YoutubeExplode.Videos.Streams;
using Tesses.WebServer.Swagme;
namespace Tesses.Extensions
{
public static class Extensions
{
public static string Substring(this string value,string str)
{
return value.Substring(str.Length);
}
public static async Task RedirectBackAsync(this ServerContext ctx)
{
await ctx.SendTextAsync("<script>history.back()</script>\n");
}
}
}
namespace Tesses.YouTubeDownloader.Server
{
using Tesses.YouTubeDownloader;
internal class EventSender
{
DateTime lastScan = DateTime.Now;
TimeSpan ts;
public EventSender(TimeSpan interval)
{
this.ts = interval;
}
public bool CanScan
{
get{
return DateTime.Now - lastScan >= ts;
}
}
public void SendEvent(Action action)
{
if(CanScan)
{
lastScan = DateTime.Now;
action();
}
}
public void Sent()
{
lastScan = DateTime.Now;
}
}
internal static class B64
{
public static string Base64UrlEncodes(string arg)
{
return Base64UrlEncode(System.Text.Encoding.UTF8.GetBytes(arg));
}
public static string Base64Encode(byte[] arg)
{
return Convert.ToBase64String(arg);
}
public static byte[] Base64Decode(string arg)
{
return Convert.FromBase64String(arg);
}
public static string Base64Encodes(string arg)
{
return Base64Encode(System.Text.Encoding.UTF8.GetBytes(arg));
}
public static string Base64UrlEncode(byte[] arg)
{
string s = Convert.ToBase64String(arg); // Regular base64 encoder
s = s.Split('=')[0]; // Remove any trailing '='s
s = s.Replace('+', '-'); // 62nd char of encoding
s = s.Replace('/', '_'); // 63rd char of encoding
return s;
}
public static string Base64Decodes(string arg)
{
return System.Text.Encoding.UTF8.GetString(Base64Decode(arg));
}
public static string Base64UrlDecodes(string arg)
{
return System.Text.Encoding.UTF8.GetString(Base64UrlDecode(arg));
}
public static byte[] Base64UrlDecode(string arg)
{
string s = arg;
s = s.Replace('-', '+'); // 62nd char of encoding
s = s.Replace('_', '/'); // 63rd char of encoding
switch (s.Length % 4) // Pad with trailing '='s
{
case 0: break; // No pad chars in this case
case 2: s += "=="; break; // Two pad chars
case 3: s += "="; break; // One pad char
default: throw new System.Exception(
"Illegal base64url string!");
}
return Convert.FromBase64String(s); // Standard base64 decoder
}
}
internal class ApiV1Server : Tesses.WebServer.Server
{
IDownloader downloader1;
public ApiV1Server(IDownloader dl)
{
downloader1=dl;
}
public override async Task GetAsync(ServerContext ctx)
{
string path=ctx.UrlAndQuery;
if(path.StartsWith("/AddPlaylistRes/"))
{ string id_res=path.Substring(16);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
await downloader1.AddPlaylistAsync(id_res_split[1],(Resolution)num);
}
}
}
if(path.StartsWith("/AddChannelRes/"))
{ string id_res=path.Substring(15);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
await downloader1.AddChannelAsync(id_res_split[1],(Resolution)num);
}
}
}
if(path.StartsWith("/AddChannel/"))
{
await downloader1.AddChannelAsync(path.Substring(12),Resolution.PreMuxed);
}
if(path.StartsWith("/AddPlaylist/"))
{
await downloader1.AddPlaylistAsync(path.Substring(13),Resolution.PreMuxed);
}
if(path.StartsWith("/AddVideoRes/"))
{ string id_res=path.Substring(13);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
await downloader1.AddVideoAsync(id_res_split[1],(Resolution)num);
}
}
}
if(path.StartsWith("/AddVideo/"))
{
//string id_res=path.Substring(12);
//string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
//if(id_res_split.Length ==2)
//{
await downloader1.AddVideoAsync(path.Substring(10),Resolution.PreMuxed);
// }
// await ctx.SendTextAsync(
// $"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
//);
}
if(path.StartsWith("/AddItemRes/"))
{
string id_res=path.Substring(12);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
await downloader1.AddItemAsync(id_res_split[1],(Resolution)num);
}
}
// await ctx.SendTextAsync(
// $"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
//);
}
if(path.StartsWith("/AddItem/"))
{
//string id_res=path.Substring(12);
//string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
//if(id_res_split.Length ==2)
//{
await downloader1.AddItemAsync(path.Substring(9),Resolution.PreMuxed);
// }
// await ctx.SendTextAsync(
// $"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
//);
}
if(path.StartsWith("/AddUserRes/"))
{
string id_res=path.Substring(12);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
await downloader1.AddUserAsync(id_res_split[1],(Resolution)num);
}
}
// await ctx.SendTextAsync(
// $"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
//);
}
if(path.StartsWith("/AddUser/"))
{
//string id_res=path.Substring(12);
//string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
//if(id_res_split.Length ==2)
//{
await downloader1.AddUserAsync(path.Substring(9),Resolution.PreMuxed);
// }
// await ctx.SendTextAsync(
// $"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
//);
}
if(path.StartsWith("/AddFile/"))
{
//string id_res=path.Substring(12);
//string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
//if(id_res_split.Length ==2)
//{
await downloader1.AddFileAsync(path.Substring(9));
// }
// await ctx.SendTextAsync(
// $"<html><head><titleYou Will Be Redirected in 5 Sec</title><meta http-equiv=\"Refresh\" content=\"5; url='../'\" /></head><body><h1>You Will Be Redirected in 5 Sec</h1></body></html>\n"
//);
}
await ctx.RedirectBackAsync();
}
}
internal class ApiStorage : Tesses.WebServer.Server
{
ITYTDBase baseCtl;
public ApiStorage(ITYTDBase baseCtl)
{
this.baseCtl=baseCtl;
}
public static System.Net.Mime.ContentDisposition GetVideoContentDisposition(string name)
{
var cd = new System.Net.Mime.ContentDisposition();
string filename = GetVideoName(name);
cd.FileName = filename;
cd.DispositionType = System.Net.Mime.DispositionTypeNames.Inline;
return cd;
}
public static string GetVideoName(string name)
{
string asAscii = Encoding.ASCII.GetString(
Encoding.Convert(
Encoding.UTF8,
Encoding.GetEncoding(
Encoding.ASCII.EncodingName,
new EncoderReplacementFallback(string.Empty),
new DecoderExceptionFallback()
),
Encoding.UTF8.GetBytes(name)
)
);
return asAscii;
}
public override async Task GetAsync(ServerContext ctx)
{
string path=ctx.UrlAndQuery;
/*if(path.StartsWith("/File/NotConverted/"))
{
// redirect to new
// /File/NotConverted/xxxxxxxxxxx.mp4
string idmp4=WebUtility.UrlDecode(path.Substring(19));
if(idmp4.Length == 15)
{
string id=Path.GetFileNameWithoutExtension(idmp4);
string path2 = $"Info/{id}.json";
if(!await baseCtl.FileExistsAsync(path2))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
} var data= await baseCtl.ReadAllTextAsync(path2);
var data2=JsonConvert.DeserializeObject<SavedVideo>(data);
var loc= await BestStreams.GetPathResolution(baseCtl,data2,Resolution.PreMuxed);
if(!await baseCtl.FileExistsAsync(loc))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
}
using(var s = await baseCtl.OpenReadAsyncWithLength(loc))
{
await ctx.SendStreamAsync(s,HeyRed.Mime.MimeTypesMap.GetMimeType(loc));
}
}
}
else if(path.StartsWith("/File/Converted/"))
{
// redirect to new
// /File/NotConverted/xxxxxxxxxxx.mp4
string idmp4=WebUtility.UrlDecode(path.Substring(16));
if(idmp4.Length == 15)
{
string id=Path.GetFileNameWithoutExtension(idmp4);
string path2 = $"Info/{id}.json";
if(!await baseCtl.FileExistsAsync(path2))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
} var data= await baseCtl.ReadAllTextAsync(path2);
var data2=JsonConvert.DeserializeObject<SavedVideo>(data);
var loc= await BestStreams.GetPathResolution(baseCtl,data2,Resolution.Mux);
if(!await baseCtl.FileExistsAsync(loc))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
}
using(var s = await baseCtl.OpenReadAsyncWithLength(loc))
{
await ctx.SendStreamAsync(s,HeyRed.Mime.MimeTypesMap.GetMimeType(loc));
}
}
}
else if(path.StartsWith("/File/Audio/"))
{
// redirect to new
// /File/NotConverted/xxxxxxxxxxx.mp4
string idmp4=WebUtility.UrlDecode(path.Substring(12));
if(idmp4.Length == 15)
{
string id=Path.GetFileNameWithoutExtension(idmp4);
string path2 = $"Info/{id}.json";
if(!await baseCtl.FileExistsAsync(path2))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
} var data= await baseCtl.ReadAllTextAsync(path2);
var data2=JsonConvert.DeserializeObject<SavedVideo>(data);
var loc= await BestStreams.GetPathResolution(baseCtl,data2,Resolution.AudioOnly);
if(!await baseCtl.FileExistsAsync(loc))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
}
using(var s = await baseCtl.OpenReadAsyncWithLength(loc))
{
await ctx.SendStreamAsync(s,HeyRed.Mime.MimeTypesMap.GetMimeType(loc));
}
}
}
else if(path.StartsWith("/File/Info/"))
{
string idjson=WebUtility.UrlDecode(path.Substring(11));
string path2 = $"Info/{idjson}";
if(!await baseCtl.FileExistsAsync(path2))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
}
var data= await baseCtl.ReadAllTextAsync(path2);
var data2=JsonConvert.DeserializeObject<SavedVideo>(data);
await ctx.SendJsonAsync(data2.ToLegacy());
}
else*/
if(path.StartsWith("/File/DownloadsInfo/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/File/DownloadsInfo/")));
string url = B64.Base64UrlDecodes(file);
if(baseCtl.DownloadExists(url))
{
var obj=await baseCtl.GetDownloadInfoAsync(url);
await ctx.SendJsonAsync(obj);
}else{
ctx.StatusCode = 404;
ctx.NetworkStream.Close();
}
}
else if(path.StartsWith("/File/FileInfo/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/File/FileInfo/")));
string url = B64.Base64UrlDecodes(file);
if(baseCtl.DownloadExists(url))
{
var obj=await baseCtl.GetDownloadInfoAsync(url);
await ctx.SendJsonAsync(obj);
}else{
ctx.StatusCode = 404;
ctx.NetworkStream.Close();
}
}
else if(path.StartsWith("/File/Info/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/File/Info/")));
VideoId? id =VideoId.TryParse(file);
if(id.HasValue && baseCtl.VideoInfoExists(id.Value))
{
var obj=await baseCtl.GetVideoInfoAsync(id.Value);
await ctx.SendJsonAsync(obj);
}else{
ctx.StatusCode = 404;
ctx.NetworkStream.Close();
}
}else if(path.StartsWith("/File/Playlist/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/File/Playlist/")));
PlaylistId? id =PlaylistId.TryParse(file);
if(id.HasValue && baseCtl.PlaylistInfoExists(id.Value))
{
var obj=await baseCtl.GetPlaylistInfoAsync(id.Value);
await ctx.SendJsonAsync(obj);
}else{
ctx.StatusCode = 404;
ctx.NetworkStream.Close();
}
}else if(path.StartsWith("/File/Channel/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/File/Channel/")));
ChannelId? id =ChannelId.TryParse(file);
if(id.HasValue && baseCtl.ChannelInfoExists(id.Value))
{
var obj=await baseCtl.GetChannelInfoAsync(id.Value);
await ctx.SendJsonAsync(obj);
}else{
ctx.StatusCode = 404;
ctx.NetworkStream.Close();
}
}else if(path.StartsWith("/File/StreamInfo/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/File/Info/")));
VideoId? id =VideoId.TryParse(file);
if(id.HasValue && baseCtl.BestStreamInfoExists(id.Value))
{
var obj=await baseCtl.GetBestStreamInfoAsync(id.Value);
await ctx.SendJsonAsync(obj);
}else{
ctx.StatusCode = 404;
ctx.NetworkStream.Close();
}
}
else if(path.StartsWith("/File/"))
{
string file=WebUtility.UrlDecode(path.Substring(6));
if(!await baseCtl.FileExistsAsync(file))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
}
using(var s = await baseCtl.OpenReadAsync(file))
{
await ctx.SendStreamAsync(s);
}
}/*else if(path.StartsWith("/File-v2/"))
{
string file=WebUtility.UrlDecode(path.Substring(9));
if(!await baseCtl.FileExistsAsync(file))
{
await NotFoundServer.ServerNull.GetAsync(ctx);
return;
}
using(var s = await baseCtl.OpenReadAsyncWithLength(file))
{
await ctx.SendStreamAsync(s);
}
}*/
if(path.StartsWith("/GetFiles/DownloadsInfo") || path.StartsWith("/GetFiles/DownloadsInfo/"))
{
List<string> urls=new List<string>();
await foreach(var url in baseCtl.GetDownloadUrlsAsync())
{
urls.Add($"{TYTDBase.HashDownloadUrl(url)}.json");
}
await ctx.SendJsonAsync(urls);
}
else if(path.StartsWith("/GetFiles/FileInfo") || path.StartsWith("/GetFiles/FileInfo/"))
{
List<string> urls=new List<string>();
await foreach(var url in baseCtl.GetDownloadUrlsAsync())
{
urls.Add($"{B64.Base64UrlEncodes(url)}.json");
}
await ctx.SendJsonAsync(urls);
}
else if(path.StartsWith("/GetFiles/Info") || path.StartsWith("/GetFiles/Info/") || path.StartsWith("/GetFiles/StreamInfo") || path.StartsWith("/GetFiles/StreamInfo/"))
{
bool containsStrmInfo=path.Contains("StreamInfo");
List<string> items=new List<string>();
await foreach(var vid in baseCtl.GetVideoIdsAsync())
{
var vid2=VideoId.TryParse(vid);
if(!containsStrmInfo || (vid2.HasValue && baseCtl.BestStreamInfoExists(vid2.Value))){
items.Add($"{vid}.json");
}
}
await ctx.SendJsonAsync(items);
}else if(path.StartsWith("/GetFiles/Playlist") || path.StartsWith("/GetFiles/Playlist/"))
{
List<string> items=new List<string>();
await foreach(var vid in baseCtl.GetPlaylistIdsAsync())
{
items.Add($"{vid}.json");
}
await ctx.SendJsonAsync(items);
}else if(path.StartsWith("/GetFiles/Channel") || path.StartsWith("/GetFiles/Channel/"))
{
List<string> items=new List<string>();
await foreach(var vid in baseCtl.GetChannelIdsAsync())
{
items.Add($"{vid}.json");
}
await ctx.SendJsonAsync(items);
}
else if(path.StartsWith("/GetFiles/"))
{
await ctx.SendJsonAsync(baseCtl.EnumerateFiles( WebUtility.UrlDecode(path.Substring(10))).ToList());
}
else if(path.StartsWith("/GetDirectories/"))
{
await ctx.SendJsonAsync(baseCtl.EnumerateDirectories( WebUtility.UrlDecode(path.Substring(16))).ToList());
}
else if(path.StartsWith("/FileExists/StreamInfo/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/FileExists/StreamInfo/")));
VideoId? id =VideoId.TryParse(file);
if(id.HasValue && baseCtl.BestStreamInfoExists(id.Value))
{
await ctx.SendTextAsync( "true","text/plain");
}else{
await ctx.SendTextAsync( "false","text/plain");
}
}
else if(path.StartsWith("/FileExists/DownloadsInfo/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/FileExists/DownloadsInfo/")));
await foreach(var item in baseCtl.GetDownloadUrlsAsync())
{
if(TYTDBase.HashDownloadUrl(item) == file)
{
await ctx.SendTextAsync( "true","text/plain");
return;
}
}
await ctx.SendTextAsync( "false","text/plain");
}
else if(path.StartsWith("/FileExists/FileInfo/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/FileExists/FileInfo/")));
string url = B64.Base64Decodes(file);
if(baseCtl.DownloadExists(url))
{
await ctx.SendTextAsync( "true","text/plain");
}else{
await ctx.SendTextAsync( "false","text/plain");
}
}
else if(path.StartsWith("/FileExists/Info/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/FileExists/Info/")));
VideoId? id =VideoId.TryParse(file);
if(id.HasValue && baseCtl.VideoInfoExists(id.Value))
{
await ctx.SendTextAsync( "true","text/plain");
}else{
await ctx.SendTextAsync( "false","text/plain");
}
} else if(path.StartsWith("/FileExists/Playlist/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/FileExists/Playlist/")));
PlaylistId? id =PlaylistId.TryParse(file);
if(id.HasValue && baseCtl.PlaylistInfoExists(id.Value))
{
await ctx.SendTextAsync( "true","text/plain");
}else{
await ctx.SendTextAsync( "false","text/plain");
}
}else if(path.StartsWith("/FileExists/Channel/"))
{
string file = Path.GetFileNameWithoutExtension(WebUtility.UrlDecode(path.Substring("/FileExists/Channel/")));
ChannelId? id =ChannelId.TryParse(file);
if(id.HasValue && baseCtl.ChannelInfoExists(id.Value))
{
await ctx.SendTextAsync( "true","text/plain");
}else{
await ctx.SendTextAsync( "false","text/plain");
}
}
else if(path.StartsWith("/FileExists/"))
{
await ctx.SendTextAsync(baseCtl.FileExists(WebUtility.UrlDecode(path.Substring(12))) ? "true" : "false","text/plain");
}else if(path.StartsWith("/DirectoryExists/"))
{
await ctx.SendTextAsync(baseCtl.DirectoryExists(WebUtility.UrlDecode(path.Substring(17))) ? "true" : "false","text/plain");
}else if(path.StartsWith("/Download/"))
{
string url = path.Substring("/Download/");
if(baseCtl.DownloadExists(url) && baseCtl.DownloadFileExists(url))
{
var v = await baseCtl.GetDownloadInfoAsync(url);
string header=GetVideoContentDisposition(v.Title).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
using(var strm = await baseCtl.OpenReadAsync(baseCtl.GetDownloadFile(url)))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(v.Title));
}
}
}
else if(path.StartsWith("/Video/"))
{
string id=path.Substring(7);
VideoId? id1=VideoId.TryParse(id);
if(id1.HasValue){
if(baseCtl.VideoInfoExists(id1.Value))
{
//Console.WriteLine("Id exists");
SavedVideo v = await baseCtl.GetVideoInfoAsync(id1.Value);
string path0= await BestStreams.GetPathResolution(baseCtl,v,Resolution.PreMuxed);
if(!string.IsNullOrWhiteSpace(path0))
{
//Console.WriteLine("F is not null");
string filename = $"{v.Title}-{Path.GetFileName(path0)}";
string header=GetVideoContentDisposition(filename).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
using(var strm = await baseCtl.OpenReadAsync(path0))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(filename));
}
}
}
}
}
else if(path.StartsWith("/VideoRes/"))
{
string id_res=path.Substring(10);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
VideoId? id1=VideoId.TryParse(id_res_split[1]);
if(id1.HasValue){
if(baseCtl.VideoInfoExists(id1.Value))
{
//Console.WriteLine("Id exists");
SavedVideo v = await baseCtl.GetVideoInfoAsync(id1.Value);
string path0= await BestStreams.GetPathResolution(baseCtl,v,(Resolution)num);
if(!string.IsNullOrWhiteSpace(path0))
{
//Console.WriteLine("F is not null");
string filename = $"{v.Title}-{Path.GetFileName(path0)}";
string header=GetVideoContentDisposition(filename).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
using(var strm = await baseCtl.OpenReadAsync(path0))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(filename));
}
}
}
}
}
}
}
else if(path.StartsWith("/Watch/"))
{
string id=path.Substring(7);
VideoId? id1=VideoId.TryParse(id);
if(id1.HasValue){
int i=0;
alt:
if(i>= 10)
{
ctx.StatusCode=500;
return;
}
if(baseCtl.VideoInfoExists(id1.Value))
{
//Console.WriteLine("Id exists");
SavedVideo v = await baseCtl.GetVideoInfoAsync(id1.Value);
var res= await BestStreamInfo.GetBestStreams(baseCtl,id1.Value);
string path0= await BestStreams.GetPathResolution(baseCtl,v,Resolution.PreMuxed);
if(!string.IsNullOrWhiteSpace(path0) && baseCtl.VideoInfoExists(id1.Value))
{
//Console.WriteLine("F is not null");
string filename = $"{v.Title}-{Path.GetFileName(path0)}";
string header=GetVideoContentDisposition(filename).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
using(var strm = await baseCtl.OpenReadAsync(path0))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(filename));
}
}else{
//stream to browser
string url=res.MuxedStreamInfo.Url;
var b = baseCtl as TYTDStorage;
if(b != null)
{
string filename = $"{v.Title}-{Path.GetFileName(path0)}";
string header=GetVideoContentDisposition(filename).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
using( var strm=await b.YoutubeClient.Videos.Streams.GetAsync(res.MuxedStreamInfo))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(filename));
}
}else{
ctx.StatusCode=500;
return;
}
}
}else{
var b = baseCtl as TYTDStorage;
if(b != null)
{
var videoInfo=await b.YoutubeClient.Videos.GetAsync(id1.Value);
await b.WriteVideoInfoAsync(new SavedVideo(videoInfo));
}else{
ctx.StatusCode=500;
return;
}
i++;
goto alt;
}
}
}
else if(path.StartsWith("/WatchRes/"))
{
string id_res=path.Substring(10);
string[] id_res_split = id_res.Split(new char[] {'/'},2,StringSplitOptions.RemoveEmptyEntries);
if(id_res_split.Length ==2)
{
int num;
if(int.TryParse(id_res_split[0],out num))
{
if(num < 0) num=1;
if(num > 3) num=1;
VideoId? id1=VideoId.TryParse(id_res_split[1]);
if(id1.HasValue){
int i=0;
alt:
if(i>= 10)
{
ctx.StatusCode=500;
return;
}
if(baseCtl.VideoInfoExists(id1.Value))
{
//Console.WriteLine("Id exists");
SavedVideo v = await baseCtl.GetVideoInfoAsync(id1.Value);
var res= await BestStreamInfo.GetBestStreams(baseCtl,id1.Value);
string path0= await BestStreams.GetPathResolution(baseCtl,v,(Resolution)num);
if(!string.IsNullOrWhiteSpace(path0) && baseCtl.VideoInfoExists(id1.Value))
{
//Console.WriteLine("F is not null");
string filename = $"{v.Title}-{Path.GetFileName(path0)}";
string header=GetVideoContentDisposition(filename).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
using(var strm = await baseCtl.OpenReadAsync(path0))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(filename));
}
}else{
//stream to browser
var b = baseCtl as TYTDStorage;
if(b != null)
{
string filename = $"{v.Title}-{Path.GetFileName(path0)}";
string header=GetVideoContentDisposition(filename).ToString();
ctx.ResponseHeaders.Add("Content-Disposition",header);
IStreamInfo info=res.MuxedStreamInfo;
if(num == 2)
{
info = res.AudioOnlyStreamInfo;
}else if(num == 3){
info = res.VideoOnlyStreamInfo;
}
using( var strm=await b.YoutubeClient.Videos.Streams.GetAsync(info))
{
await ctx.SendStreamAsync(strm,HeyRed.Mime.MimeTypesMap.GetMimeType(filename));
}
}else{
ctx.StatusCode=500;
return;
}
}
}else{
var b = baseCtl as TYTDStorage;
if(b != null)
{
var videoInfo=await b.YoutubeClient.Videos.GetAsync(id1.Value);
await b.WriteVideoInfoAsync(new SavedVideo(videoInfo));
}else{
ctx.StatusCode=500;
return;
}
i++;
goto alt;
}
}
}
}
}
else{
await NotFoundServer.ServerNull.GetAsync(ctx);
}
}
}
internal class ApiV2Server
{
public SwagmeServer Swagme {get;private set;}=new SwagmeServer();
IDownloader Downloader;
public ApiV2Server(IDownloader downloader)
{
Swagme.AbsoluteUrl=true;
this.Downloader=downloader;
/*Adding items*/
AddBoth("/AddVideo",AddVideo,new SwagmeDocumentation("/AddVideo?v=jNQXAC9IVRw&res=PreMuxed","Add youtube video","v: Video Id Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddPlaylist",AddPlaylist,new SwagmeDocumentation("/AddPlaylist?id=PLgXAgLm6Kre7M3c8G2OlQTG-PETLHs4Vd&res=PreMuxed","Add youtube playlist","id: Playlist Id Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddChannel",AddChannel,new SwagmeDocumentation("/AddChannel?id=UC4QobU6STFB0P71PMvOGN5A&res=PreMuxed","Add youtube channel","id: YouTube Channel Id Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddUser",AddUser,new SwagmeDocumentation("/AddUser?id=jawed&res=PreMuxed","Add youtube user","id: YouTube Channel Name Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddSlug",AddSlug,new SwagmeDocumentation("/AddSlug?id=https%3A%2F%2Fwww.youtube.com%2Fc%2FLinusTechTips&res=PreMuxed","Add youtube channel by slug","id: YouTube Channel with slug Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddHandle",AddHandle,new SwagmeDocumentation("/AddHandle?id=@tesses50&res=PreMuxed","Add youtube channel by handle","id: YouTube Channel with handle Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddItem",AddItem,new SwagmeDocumentation("/AddItem?v=jNQXAC9IVRw&res=PreMuxed","Add any type of item","v: Media Id Or encodeUriComponent Url<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Adding items");
AddBoth("/AddFile",AddFile,new SwagmeDocumentation("/AddFile?url=https%3A%2F%2Ftesses.cf%2Fimages%2Frvl.jpg&download=true","Add normal file download","url: Url to file<br>download: whether to download file"),"Adding items");
/*Getting status*/
AddBoth("/event",Event,new SwagmeDocumentation("Server sent events","Returns events with json"),"Getting status");
AddBoth("/Progress",ProgressFunc,new SwagmeDocumentation("Get video progress","<a href=\"https://tesses.net/apps/tytd/2022/progress.php\">More Info</a>"),"Getting status");
AddBoth("/QueueList",QueueList,new SwagmeDocumentation("Get items in Queue","<a href=\"https://tesses.net/apps/tytd/2022/queuels.php\">More Info</a>"),"Getting status");
/*Subscriptions*/
AddBoth("/Subscribe",Subscribe,new SwagmeDocumentation("/Subscribe?id=UC4QobU6STFB0P71PMvOGN5A&conf=NotifyAndDownload","Subscribe to youtuber","id: Channel Id<br>conf: DoNothing=Disable, GetInfo=Just Get info, Notify=Bell event, Download=Download video no bell event, NotifyAndDownload=Download video with bell event"),"Subscriptions");
AddBoth("/subscribe",Subscribe,new SwagmeDocumentation("/subscribe?id=UC4QobU6STFB0P71PMvOGN5A&conf=NotifyAndDownload","Subscribe to youtuber","id: Channel Id<br>conf: DoNothing=Disable, GetInfo=Just Get info, Notify=Bell event, Download=Download video no bell event, NotifyAndDownload=Download video with bell event"),"Subscriptions");
AddBoth("/Resubscribe",Resubscribe,new SwagmeDocumentation("/Resubscribe?id=UC4QobU6STFB0P71PMvOGN5A&conf=Download","Change subscription settings","id: Channel Id<br>conf: DoNothing=Disable, GetInfo=Just Get info, Notify=Bell event, Download=Download video no bell event, NotifyAndDownload=Download video with bell event"),"Subscriptions");
AddBoth("/resubscribe",Resubscribe,new SwagmeDocumentation("/resubscribe?id=UC4QobU6STFB0P71PMvOGN5A&conf=Download","Change subscription settings","id: Channel Id<br>conf: DoNothing=Disable, GetInfo=Just Get info, Notify=Bell event, Download=Download video no bell event, NotifyAndDownload=Download video with bell event"),"Subscriptions");
AddBoth("/Unsubscribe",Unsubscribe,new SwagmeDocumentation("/Unsubscribe?id=UC4QobU6STFB0P71PMvOGN5A","Unsubscribe from youtuber","id: Channel Id"),"Subscriptions");
AddBoth("/unsubscribe",Unsubscribe,new SwagmeDocumentation("/unsubscribe?id=UC4QobU6STFB0P71PMvOGN5A","Unsubscribe from youtuber","id: Channel Id"),"Subscriptions");
AddBoth("/Subscriptions",Subscriptions,new SwagmeDocumentation("Get subscriptions","Returned Json array<br>&emsp;Id: Channel Id<br>&emsp;BellInfo: 0=DoNothing, 1=GetInfo, 3=Notify, 5=Download, 7=NotifyAndDownload"),"Subscriptions");
AddBoth("/subscriptions",Subscriptions,new SwagmeDocumentation("Get subscriptions","Returned Json array<br>&emsp;Id: Channel Id<br>&emsp;BellInfo: 0=DoNothing, 1=GetInfo, 3=Notify, 5=Download, 7=NotifyAndDownload"),"Subscriptions");
/*Personal Lists*/
AddBoth("/AddToList",AddToList,new SwagmeDocumentation("/AddToList?name=SomeList&v=jNQXAC9IVRw&res=PreMuxed","Add item to personal list","NOTE, this will create list if not created<br>name: Name of personal list<br><b>Works on GET and POST</b><hr>v: VideoId<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only<br><b>Works only on POST</b><hr>data: Json Array with objects with entries:<br>&emsp;Id: VideoId<br>&emsp;Resolution: -1=NoDownload, 0=Mux, 1=PreMuxed, 2=AudioOnly, 3=VideoOnly"),"Personal Lists");
Swagme.Add("/ReplaceList",ReplaceList,new SwagmeDocumentation("/ReplaceList","Replace personal list's contents","name: Name of personal playlist<br>data: Json Array with objects with entries:<br>&emsp;Id: VideoId<br>&emsp;Resolution: -1=NoDownload, 0=Mux, 1=PreMuxed, 2=AudioOnly, 3=VideoOnly"),"POST","Personal Lists");
AddBoth("/SetResolutionInList",SetResolutionInList,new SwagmeDocumentation("/SetResolutionInList?name=SomeList&v=jNQXAC9IVRw&res=Mux","Set resolution for item in personal list","name: Name of personal playlist<br>name: Name of personal list<br>v: VideoId<br>res: NoDownload=Do not download clip but just info, Mux=Requires conversion, PreMuxed=Does not require conversion, AudioOnly=Best audio only, VideoOnly=Best video only"),"Personal Lists");
AddBoth("/DeleteFromList",DeleteFromList,new SwagmeDocumentation("/DeleteFromList?name=SomeList&v=jNQXAC9IVRw","Remove item from personal list","name: Name of personal list<br>id: Video Id"),"Personal Lists");
AddBoth("/DeleteList",DeleteList,new SwagmeDocumentation("/DeleteList?name=SomeList","Remove personal list","name: Name of personal playlist"),"Personal Lists");
/*Searching*/
AddBoth("/Search",Search,new SwagmeDocumentation("/Search?q=Demi%20Lovato","Search youtube","q: search query<br>getinfo: whether to fetch info as well"),"Searching");
/*Exporting*/
Swagme.Add("/export/everything.json",Everything_Export,new SwagmeDocumentation("Everything","<a href=\"https://tesses.net/apps/tytd/2022/export/everything.php\">More Info</a>"),"GET","Exporting");
Swagme.Add("/export/videos.json",VideosExport,new SwagmeDocumentation("Videos","<a href=\"https://tesses.net/apps/tytd/2022/export/videos.php\">More Info</a>"),"GET","Exporting");
Swagme.Add("/export/playlists.json",PlaylistsExport,new SwagmeDocumentation("Playlists","<a href=\"https://tesses.net/apps/tytd/2022/export/playlists.php\">More Info</a>"),"GET","Exporting");
Swagme.Add("/export/channels.json",ChannelsExport,new SwagmeDocumentation("Channels","<a href=\"https://tesses.net/apps/tytd/2022/export/channels.php\">More Info</a>"),"GET","Exporting");
Swagme.Add("/export/filedownloads.json",FilesExport,new SwagmeDocumentation("File Downloads","<a href=\"https://tesses.net/apps/tytd/2022/export/filedownloads.php\">More Info</a>"),"GET","Exporting");
Swagme.Add("/export/subscriptions.json",SubscriptionsExport,new SwagmeDocumentation("Subscriptions","<a href=\"https://tesses.net/apps/tytd/2022/export/subscriptions.php\">More Info</a>"),"GET","Exporting");
Swagme.Add("/export/personal_lists.json",PersonalListsExport,new SwagmeDocumentation("Personal Lists","<a href=\"https://tesses.net/apps/tytd/2022/export/personallists.php\">More Info</a>"),"GET","Exporting");
/*Other*/
AddBoth("/extra_data.json",ExtraData,new SwagmeDocumentation("Get extra info about downloader","Get extra data such as TYTD Tag, item count in queue and tytd version"));
AddBoth("/CancelDownload",Cancel,new SwagmeDocumentation("/CancelDownload?restart=true","Cancel or Restart download","restart:<br>&emsp;true: Restart download<br>&emsp;false: Cancel Download"));
AddBoth("/Thumbnail",Thumbnail,new SwagmeDocumentation("/Thumbnail?v=PzUKeGZiEl0&res=maxresdefault","Get Thumbnail for video","v: Video Id<br>res: YouTube Thumbnail Resolution <a href=\"https://www.binarymoon.co.uk/2014/03/using-youtube-thumbnails/\">List of resolutions</a>"),"Other");
/*
public async Task AddToPersonalPlaylistAsync(string name, IEnumerable<(VideoId Id, Resolution Resolution)> items)
{
throw new NotImplementedException();
}
public async Task ReplacePersonalPlaylistAsync(string name, IEnumerable<(VideoId Id, Resolution Resolution)> items)
{
throw new NotImplementedException();
}
public async Task RemoveItemFromPersonalPlaylistAsync(string name, VideoId id)
{
throw new NotImplementedException();
}
public async Task SetResolutionForItemInPersonalPlaylistAsync(string name, VideoId id, Resolution resolution)
{
throw new NotImplementedException();
}*/
}
public async Task Thumbnail(ServerContext ctx)
{
string v="";
string res="";
VideoId? id=null;
ITYTDBase baseCtl = Downloader as ITYTDBase;
if(ctx.QueryParams.TryGetFirst("v",out v) && ctx.QueryParams.TryGetFirst("res",out res) && (id=VideoId.TryParse(v)).HasValue && baseCtl != null)
{
await ctx.SendBytesAsync(await baseCtl.ReadThumbnailAsync(id.Value,res),"image/jpg");
}else{
await ctx.SendTextAsync("Expected v=YouTubeVideoId\r\nres=a youtube thumbnail resolution\r\nAnd Downloader must implement ITYTDBase","text/plain");
}
}
public async Task ExtraData(ServerContext ctx)
{
var twebserverVersion = ctx.GetType().Assembly.GetName().Version.ToString();
var tytdserverversion= this.GetType().Assembly.GetName().Version.ToString();
ExtraData data=Downloader.GetExtraData();
data.TessesWebServerVersion=twebserverVersion;
data.TYTDServerVersion=tytdserverversion;
await ctx.SendJsonAsync(data);
}
public async Task Event(ServerContext ctx)
{
double interval=0;
string intervalStr;
if(ctx.QueryParams.TryGetFirst("interval",out intervalStr))
{
if(!double.TryParse(intervalStr,out interval)) interval=0;
}
IStorage storage=Downloader as IStorage;
if(storage != null){
var _p=Downloader.GetProgress();
long len = _p.Length;
bool first=true;
SendEvents evts=new SendEvents();
storage.VideoStarted += (sender,e)=>
{
len=e.EstimatedLength;
ProgressItem p=new ProgressItem();
p.StartEvent=true;
p.StopEvent=false;
p.BellEvent=false;
p.ErrorEvent=false;
p.Length=e.EstimatedLength;
p.Percent=0;
p.Video=e.VideoInfo;
evts.SendEvent(p);
};
EventSender s = new EventSender(TimeSpan.FromSeconds(interval));
storage.VideoProgress += (sender,e)=>{
bool wasFirst= first;
ProgressItem p=new ProgressItem();
p.StartEvent=false;
p.StopEvent=false;
p.Length=len;
p.Percent=e.Progress;
p.BellEvent=false;
p.ErrorEvent=false;
if(first)
p.Video=e.VideoInfo;
first=false;
if(wasFirst || s.CanScan)
{
s.Sent();
evts.SendEvent(p);
}
};
storage.VideoFinished +=(sender,e)=>{
ProgressItem p=new ProgressItem();
p.StartEvent=false;
p.StopEvent=true;
p.BellEvent=false;
p.ErrorEvent=false;
p.Length=len;
p.Percent=1;
p.Video=e.VideoInfo;
evts.SendEvent(p);
};
storage.Error += (sender,e)=>{
ProgressItem p=new ProgressItem();
p.StartEvent=false;
p.StopEvent=false;
p.BellEvent=false;
p.ErrorEvent=true;
p.Length=0;
p.Percent=0;
p.Error=e.Exception.ToString();
p.Message = e.Exception.Message;
p.Id = e.Id;
p.ExceptionName = e.Exception.GetType().FullName;
evts.SendEvent(p);
};
storage.Bell += (sender,e)=>{
ProgressItem p=new ProgressItem();
p.StartEvent=false;
p.StopEvent=false;
p.BellEvent=true;
p.ErrorEvent=false;
p.Length=0;
p.Percent=0;
p.Id=e.Id.Value;
evts.SendEvent(p);
};
ctx.ServerSentEvents(evts);
}else{
await ctx.SendTextAsync("Error no IStorage");
}
}
private async Task Cancel(ServerContext ctx)
{
bool restart=false;
string restartString="false";
if(ctx.QueryParams.TryGetFirst("restart",out restartString))
{
if(!bool.TryParse(restartString,out restart))
{
restart=false;
}
}
Downloader.CancelDownload(restart);
await ctx.RedirectBackAsync();
}
private async Task Search(ServerContext ctx)
{
var dl = Downloader as IStorage;
string q;
if(ctx.QueryParams.TryGetFirst("q",out q))
{
bool getInfoBool=false;
string getInfo;
if(ctx.QueryParams.TryGetFirst("getinfo",out getInfo))
{
if(!bool.TryParse(getInfo,out getInfoBool)) getInfoBool=false;
}
List<SearchResult> results=new List<SearchResult>();
await foreach(var vid in dl.SearchYouTubeAsync(q,getInfoBool))
{
results.Add(vid);
}
if(getInfoBool)
{
dl.WaitTillMediaContentQueueEmpty();
}
await ctx.SendJsonAsync(results);
}
}
private void AddBoth(string url,HttpActionAsync action,SwagmeDocumentation documentation,string group="Other")
{
Swagme.Add(url,action,documentation,method:"GET",group:group);
Swagme.Add(url,async(evt)=>{
evt.ParseBody();
await action(evt);
},documentation,method:"POST",group:group);
}
public async Task DeleteList(ServerContext ctx)
{
//this is for personal playlists
string name;
if(ctx.QueryParams.TryGetFirst("name",out name)){
Downloader.DeletePersonalPlaylist(name);
//Downloader.AddToPersonalPlaylistAsync(name);
}
await ctx.RedirectBackAsync();
}
public async Task ReplaceList(ServerContext ctx)
{
ctx.ParseBody();
//this is for personal playlists
string name;
if(ctx.QueryParams.TryGetFirst("name",out name)){
string jsonData;
List<ListContentItem> itemList;
if(ctx.QueryParams.TryGetFirst("data",out jsonData))
{
itemList = JsonConvert.DeserializeObject<List<ListContentItem>>(jsonData);
await Downloader.ReplacePersonalPlaylistAsync(name,itemList);
}
//Downloader.AddToPersonalPlaylistAsync(name);
}
await ctx.RedirectBackAsync();
}
public async Task Everything_Export(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportEverythingAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task VideosExport(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportVideosAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task PlaylistsExport(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportPlaylistsAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task ChannelsExport(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportChannelsAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task FilesExport(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportDownloadsAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task SubscriptionsExport(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportSubscriptionsAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task PersonalListsExport(ServerContext ctx)
{
var storage = Downloader as TYTDStorage;
if(storage != null)
{
if(storage.GetLoggerProperties().AllowExport)
{
TYTDExporter exporter=new TYTDExporter(storage);
var res=await exporter.ExportPersonalPlaylistsAsync();
await ctx.SendJsonAsync(res);
}else{
ctx.StatusCode=403;
await ctx.SendTextAsync("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>Can't Export, Access Denied</title></head><body><h1>Can't Export, Access Denied</h1><p>Call the TYTD adminstrator if you are not the administrator to edit the following</p><hr><p>In file: <i><b>config/tytdprop.json</b></i>, unless overriden in code<br>Change <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">false</font> with <font color=\"#ce9178\">&quot;AllowExport&quot;</font>:<font color=\"#569cd6\">true</font></p></body></html>");
}
}
}
public async Task AddToList(ServerContext ctx)
{
//this is for personal playlists
string name;
if(ctx.QueryParams.TryGetFirst("name",out name)){
string jsonData;
List<ListContentItem> itemList;
if(ctx.Method == "POST" && ctx.QueryParams.TryGetFirst("data",out jsonData))
{
itemList = JsonConvert.DeserializeObject<List<ListContentItem>>(jsonData);
}else{
itemList=new List<ListContentItem>();
string id;
if(ctx.QueryParams.TryGetFirst("v",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
VideoId? id1=VideoId.TryParse(id);
if(id1.HasValue)
{
itemList.Add(new ListContentItem(id1,resolution));
}
}
}
await Downloader.AddToPersonalPlaylistAsync(name,itemList);
//Downloader.AddToPersonalPlaylistAsync(name);
}
await ctx.RedirectBackAsync();
}
public async Task DeleteFromList(ServerContext ctx)
{
//this is for personal playlists
string name;
if(ctx.QueryParams.TryGetFirst("name",out name)){
string id;
if(ctx.QueryParams.TryGetFirst("v",out id))
{
VideoId? id1=VideoId.TryParse(id);
if(id1.HasValue)
{
await Downloader.RemoveItemFromPersonalPlaylistAsync(name,id1.Value);
}
}
}
await ctx.RedirectBackAsync();
}
public async Task SetResolutionInList(ServerContext ctx)
{
//this is for personal playlists
string name;
if(ctx.QueryParams.TryGetFirst("name",out name)){
string id;
if(ctx.QueryParams.TryGetFirst("v",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
VideoId? id1=VideoId.TryParse(id);
if(id1.HasValue)
{
await Downloader.SetResolutionForItemInPersonalPlaylistAsync(name,id1.Value,resolution);
}
}
}
await ctx.RedirectBackAsync();
}
public async Task Subscriptions(ServerContext ctx)
{
IStorage storage = Downloader as IStorage;
if(storage != null)
{
var sub=storage.GetLoadedSubscriptions();
await ctx.SendJsonAsync(sub);
}
await ctx.RedirectBackAsync();
}
public async Task Resubscribe(ServerContext ctx)
{
IStorage storage = Downloader as IStorage;
if(storage != null)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
string confstr;
ChannelBellInfo conf=ChannelBellInfo.NotifyAndDownload;
if(ctx.QueryParams.TryGetFirst("conf",out confstr))
{
if(!Enum.TryParse<ChannelBellInfo>(confstr,out conf))
{
conf = ChannelBellInfo.NotifyAndDownload;
}
}
ChannelId? cid=ChannelId.TryParse(id);
if(cid.HasValue)
{
await storage.ResubscribeAsync(cid.Value,conf);
}
}
}
await ctx.RedirectBackAsync();
}
public async Task Unsubscribe(ServerContext ctx)
{
IStorage storage = Downloader as IStorage;
if(storage != null)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
ChannelId? cid=ChannelId.TryParse(id);
if(cid.HasValue)
{
storage.Unsubscribe(cid.Value);
}
}
}
await ctx.RedirectBackAsync();
}
public async Task Subscribe(ServerContext ctx)
{
IStorage storage = Downloader as IStorage;
if(storage != null)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
string confstr;
ChannelBellInfo conf=ChannelBellInfo.NotifyAndDownload;
if(ctx.QueryParams.TryGetFirst("conf",out confstr))
{
if(!Enum.TryParse<ChannelBellInfo>(confstr,out conf))
{
conf = ChannelBellInfo.NotifyAndDownload;
}
}
ChannelId? cid=ChannelId.TryParse(id);
if(cid.HasValue)
{
await storage.SubscribeAsync(cid.Value,conf);
}else{
UserName? uname=UserName.TryParse(id);
await storage.SubscribeAsync(uname.Value,conf);
}
}
}
await ctx.RedirectBackAsync();
}
public async Task QueueList(ServerContext ctx)
{
await ctx.SendJsonAsync(Downloader.GetQueueList());
}
public async Task ProgressFunc(ServerContext ctx)
{
await ctx.SendJsonAsync(Downloader.GetProgress());
}
public async Task AddFile(ServerContext ctx)
{
string url;
string downloadStr;
bool download=true;
if(ctx.QueryParams.TryGetFirst("url",out url))
{
if(ctx.QueryParams.TryGetFirst("download",out downloadStr))
{
bool dl;
if(bool.TryParse(downloadStr,out dl))
{
download=dl;
}
}
await Downloader.AddFileAsync(url,download);
await ctx.RedirectBackAsync();
}
}
public async Task AddVideo(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("v",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
VideoId? id1=VideoId.TryParse(id);
if(id1.HasValue)
{
await Downloader.AddVideoAsync(id1.Value,resolution);
}
}
await ctx.RedirectBackAsync();
}
public async Task AddItem(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("v",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
await Downloader.AddItemAsync(id,resolution);
}
await ctx.RedirectBackAsync();
}
public async Task AddUser(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
UserName? id1=UserName.TryParse(id);
if(id1.HasValue)
{
await Downloader.AddUserAsync(id1.Value,resolution);
}
}
await ctx.RedirectBackAsync();
}
public async Task AddHandle(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
ChannelHandle? id1=ChannelHandle.TryParse(id);
if(id1.HasValue)
{
await Downloader.AddHandleAsync(id1.Value,resolution);
}
}
await ctx.RedirectBackAsync();
}
public async Task AddSlug(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
ChannelSlug? id1=ChannelSlug.TryParse(id);
if(id1.HasValue)
{
await Downloader.AddSlugAsync(id1.Value,resolution);
}
}
await ctx.RedirectBackAsync();
}
public async Task AddChannel(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
ChannelId? id1=ChannelId.TryParse(id);
if(id1.HasValue)
{
await Downloader.AddChannelAsync(id1.Value,resolution);
}
}
await ctx.RedirectBackAsync();
}
public async Task AddPlaylist(ServerContext ctx)
{
string id;
if(ctx.QueryParams.TryGetFirst("id",out id))
{
Resolution resolution=Resolution.PreMuxed;
string res;
if(ctx.QueryParams.TryGetFirst("res",out res))
{
if(!Enum.TryParse<Resolution>(res,out resolution))
{
resolution=Resolution.PreMuxed;
}
}
PlaylistId? id1=PlaylistId.TryParse(id);
if(id1.HasValue)
{
await Downloader.AddPlaylistAsync(id1.Value,resolution);
}
}
await ctx.RedirectBackAsync();
}
}
public class TYTDServer
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="baseCtl">TYTD context</param>
public TYTDServer(ITYTDBase baseCtl)
{
ExtensionsServer=new ChangeableServer();
RootServer=new ChangeableServer();
MountableServer mountableServer=new MountableServer(RootServer);
IDownloader downloader=baseCtl as IDownloader;
if(downloader != null)
{
mountableServer.Mount("/api/",new ApiV1Server(downloader));
mountableServer.Mount("/api/v2/",new ApiV2Server(downloader).Swagme);
}
mountableServer.Mount("/api/v2/Extensions/",ExtensionsServer);
mountableServer.Mount("/api/Storage/",new ApiStorage(baseCtl));
InnerServer=mountableServer;
}
/// <summary>
/// To provide to tesses.webserver
/// </summary>
public IServer InnerServer {get; private set;}
/// <summary>
/// Set by Nuget Package Tesses.YouTubeDownloader.ExtensionLoader
/// </summary>
public ChangeableServer ExtensionsServer {get; private set;}
/// <summary>
/// An optional static website (recomendeded)
/// </summary>
public ChangeableServer RootServer {get;private set;}
}
}