485 lines
20 KiB
C#
485 lines
20 KiB
C#
using System.Linq;
|
|
using SimpleHttp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.IO.Pipes;
|
|
using System.Reflection;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using TessesYoutubeDownloader.Server.Models;
|
|
using Newtonsoft.Json;
|
|
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using youtube_downloader.Server.Models;
|
|
|
|
namespace youtube_downloader
|
|
{
|
|
public class SSE
|
|
{
|
|
public static SSE ServerSentEventItem = new SSE();
|
|
List<HttpListenerResponse> Streams = new List<HttpListenerResponse>();
|
|
public void RegisterStreamWriter(HttpListenerResponse rp)
|
|
{
|
|
Streams.Add(rp);
|
|
}
|
|
public async Task PushEventAsync(string event_name,object data)
|
|
{
|
|
await PushEventAsync(event_name, JsonConvert.SerializeObject(data));
|
|
}
|
|
public async Task PushEventAsync(string event_name,string data)
|
|
{
|
|
await PushEventRawAsync($"event: {event_name}\ndata: {data}");
|
|
|
|
}
|
|
public async Task PushEventRawAsync(string raw_data)
|
|
{
|
|
foreach (var items in Streams)
|
|
{
|
|
try
|
|
{
|
|
var bytes = Encoding.UTF8.GetBytes(raw_data + "\n\n");
|
|
await items.OutputStream.WriteAsync(bytes, 0, bytes.Length);
|
|
await items.OutputStream.FlushAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_ = ex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class Program
|
|
{
|
|
static string webSitePath;
|
|
static void Main(string[] arg)
|
|
{
|
|
|
|
Thread t = new Thread(new ThreadStart(() => {
|
|
Server.Functions.Downloader.DL.DownloadThread().GetAwaiter().GetResult();
|
|
}));
|
|
t.Start();
|
|
Thread t2 = new Thread(new ThreadStart(() => {
|
|
Server.Functions.Downloader.DL.ListenForQueueItem().GetAwaiter().GetResult();
|
|
}));
|
|
t2.Start();
|
|
|
|
|
|
// we need to get our app name so that
|
|
// we can create unique names for our mutex and our pipe
|
|
webSitePath = Server.Functions.Downloader.DL.GetPath(true, "WebSite");
|
|
|
|
Route.Before += Route_Before;
|
|
|
|
|
|
/* Generic */
|
|
Route.Add("/api/AddItems", (HttpAction)AddItems, "POST");
|
|
Route.Add("/api/AddFile/{Url}", (HttpAction)AddFile);
|
|
Route.Add("/api/AddCaptions/{Id}", (HttpAction)AddCaptions);
|
|
|
|
/* Videos */
|
|
Route.Add("/api/AddVideoInfo/{Id}", (HttpAction)AddVideoInfo);
|
|
Route.Add("/api/AddVideo/{Id}", (HttpAction)AddVideo);
|
|
Route.Add("/api/AddVideoRes/{R}/{Id}", (HttpAction)AddVideoRes);
|
|
Route.Add("/api/Redownload", (HttpAction)Redownload);
|
|
Route.Add("/api/Redownload/{R}", (HttpAction)RedownloadRes);
|
|
Route.Add("/api/Watch/{VideoId}", (HttpAction)Watch);
|
|
|
|
/* Playlist */
|
|
Route.Add("/api/AddPlaylistOnly/{Id}", (HttpAction)AddPlaylistOnly);
|
|
Route.Add("/api/AddPlaylist/{Id}", (HttpAction)AddPlaylist);
|
|
Route.Add("/api/AddPlaylistRes/{R}/{Id}", (HttpAction)AddPlaylistRes);
|
|
|
|
/* Search */
|
|
Route.Add("/api/SearchOnly/{text}", (HttpAction)SearchOnly);
|
|
Route.Add("/api/Search/{text}", (HttpAction)Search);
|
|
|
|
/* Channel */
|
|
Route.Add("/api/AddChannelOnly/{Id}", (HttpAction)AddChannelOnly);
|
|
Route.Add("/api/AddChannel/{Id}", (HttpAction)AddChannel);
|
|
Route.Add("/api/AddChannelRes/{R}/{Id}", (HttpAction)AddChannelRes);
|
|
|
|
/* User */
|
|
Route.Add("/api/AddUserOnly/{Id}", (HttpAction)AddUserOnly);
|
|
Route.Add("/api/AddUser/{Id}", (HttpAction)AddUser);
|
|
Route.Add("/api/AddUserRes/{R}/{Id}", (HttpAction)AddUserRes);
|
|
|
|
/* Queue and Progress */
|
|
Route.Add("/api/QueueList", (HttpAction)QueueList);
|
|
Route.Add("/api/QueueMove/{From}/{To}", (HttpAction)QueueMove);
|
|
Route.Add("/api/QueueMove2/{To}/{Id}", (HttpAction)QueueMove2);
|
|
Route.Add("/api/Progress", (HttpAction)VideoProgress);
|
|
Route.Add("/api/SSE", (HttpAction)ServerSentEvents);
|
|
|
|
/* Storage */
|
|
Route.Add("/api/Storage/GetDirectories/{Path}", (HttpAction)StorageGetDirectories);
|
|
Route.Add("/api/Storage/GetFiles/{Path}", (HttpAction)StorageGetFiles);
|
|
Route.Add("/api/Storage/DirectoryExists/{Path}", (HttpAction)StorageDirectoryExists);
|
|
Route.Add("/api/Storage/FileExists/{Path}", (HttpAction)StorageFileExists);
|
|
Route.Add("/api/Storage/File/{Path}", (HttpAction)StorageFile);
|
|
Route.Add("/api/Storage/Video/{Id}",(HttpAction)Video);
|
|
Route.Add("/api/Storage/VideoRes/{Res}/{Id}",(HttpAction)VideoRes);
|
|
Route.Add("/api/upload/", (HttpAction)UploadFiles, "POST");
|
|
|
|
|
|
/* Other */
|
|
Route.Add("/", (HttpAction)Index);
|
|
Route.Add("/{Path}", (HttpAction)RootPath);
|
|
Console.WriteLine("Almost Ready To Listen");
|
|
|
|
if (arg.Length > 0)
|
|
{
|
|
|
|
HttpServer.ListenAsync(arg[0], CancellationToken.None, Route.OnHttpRequestAsync).Wait();
|
|
|
|
}
|
|
else
|
|
{
|
|
HttpServer.ListenAsync(3250, CancellationToken.None, Route.OnHttpRequestAsync).Wait();
|
|
}
|
|
}
|
|
|
|
#region Generic
|
|
private static void AddItems(HttpListenerRequest request, HttpListenerResponse response, Dictionary<string, string> arguments)
|
|
{
|
|
var f = request.ParseBody(arguments);
|
|
foreach (var file in f.Values)
|
|
{
|
|
|
|
using (var req = new StreamReader(file.Value))
|
|
{
|
|
List<IDResolutionTypeTriplet> tripletlst = JsonConvert.DeserializeObject<List<IDResolutionTypeTriplet>>(req.ReadToEnd());
|
|
Server.Functions.Downloader.DownloadItems(tripletlst);
|
|
response.Redirect("/");
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
public static void AddFile(HttpListenerRequest request, HttpListenerResponse response, Dictionary<string, string> arguments)
|
|
{
|
|
Server.Functions.Downloader.DownloadFile(arguments["Url"]);
|
|
}
|
|
public static void AddCaptions(HttpListenerRequest request, HttpListenerResponse response, Dictionary<string, string> arguments)
|
|
{
|
|
Server.Functions.Downloader.DownloadCaptions(arguments["Id"]);
|
|
}
|
|
#endregion
|
|
#region Video
|
|
public static void AddVideoInfo(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadVideoInfo(System.Web.HttpUtility.UrlDecode(args["Id"]), Resolution.NoConvert);
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddVideo(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadVideo(System.Web.HttpUtility.UrlDecode(args["Id"]));
|
|
|
|
rp.AsRedirect("/");
|
|
}
|
|
|
|
public static void AddVideoRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadVideo(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"]));
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void Redownload(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
foreach (var item in Directory.GetFiles(Server.Functions.Downloader.DL.GetPath(true, "Info"), "*.json"))
|
|
{
|
|
string id = System.IO.Path.GetFileNameWithoutExtension(item);
|
|
Server.Functions.Downloader.DownloadVideo(id, Resolution.NoConvert);
|
|
}
|
|
rp.AsRedirect("/");
|
|
}
|
|
|
|
public static void RedownloadRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
foreach (var item in Directory.GetFiles(Server.Functions.Downloader.DL.GetPath(true, "Info"), "*.json"))
|
|
{
|
|
string id = System.IO.Path.GetFileNameWithoutExtension(item);
|
|
Server.Functions.Downloader.DownloadVideo(id, (Resolution)int.Parse(args["R"]));
|
|
}
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void Watch(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
var txt = Templating.RenderFile(Path.Combine(webSitePath, "watch_page.thtml"), args); //populate template
|
|
rp.AsText(txt);
|
|
}
|
|
#endregion
|
|
#region Playlist
|
|
public static void AddPlaylistOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadPlaylistOnly(System.Web.HttpUtility.UrlDecode(args["Id"]), Resolution.NoConvert);
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddPlaylist(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadPlaylist(System.Web.HttpUtility.UrlDecode(args["Id"]));
|
|
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddPlaylistRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadPlaylist(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"]));
|
|
rp.AsRedirect("/");
|
|
}
|
|
#endregion
|
|
#region Search
|
|
public static void SearchOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string search = System.Web.HttpUtility.UrlDecode(args["text"]);
|
|
string json = JsonConvert.SerializeObject(Server.Functions.Downloader.Search(search, false));
|
|
rp.AsText(json, "application/json");
|
|
|
|
}
|
|
public static void Search(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string search = System.Web.HttpUtility.UrlDecode(args["text"]);
|
|
string json = JsonConvert.SerializeObject(Server.Functions.Downloader.Search(search));
|
|
rp.AsText(json, "application/json");
|
|
|
|
}
|
|
#endregion
|
|
#region Channel
|
|
public static void AddChannelOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadChannelOnly(System.Web.HttpUtility.UrlDecode(args["Id"]));
|
|
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddChannel(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadChannel(System.Web.HttpUtility.UrlDecode(args["Id"]));
|
|
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddChannelRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadChannel(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"]));
|
|
rp.AsRedirect("/");
|
|
}
|
|
#endregion
|
|
#region User
|
|
public static void AddUserOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadUserOnly(System.Web.HttpUtility.UrlDecode(args["Id"]));
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddUser(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadUser(System.Web.HttpUtility.UrlDecode(args["Id"]));
|
|
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void AddUserRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.DownloadUser(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"]));
|
|
rp.AsRedirect("/");
|
|
}
|
|
#endregion
|
|
#region Queue And Progress
|
|
public static void QueueList(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string json = Server.Functions.Downloader.GetQueue();
|
|
rp.AsText(json, "application/json");
|
|
}
|
|
public static void QueueMove(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
Server.Functions.Downloader.ModQueue(args["To"], args["From"]);
|
|
rp.AsRedirect("/");
|
|
}
|
|
public static void QueueMove2(HttpListenerRequest request, HttpListenerResponse response, Dictionary<string, string> arguments)
|
|
{
|
|
Server.Functions.Downloader.ModQueue2(arguments["To"], arguments["Id"]);
|
|
response.AsRedirect("/");
|
|
}
|
|
public static void VideoProgress(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string json = JsonConvert.SerializeObject(Server.Functions.Downloader.GetProgress());
|
|
rp.AsText(json, "application/json");
|
|
}
|
|
public static void ServerSentEvents(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
rp.AddHeader("Cache-Control", "no-cache");
|
|
rp.ContentType = "text/event-stream";
|
|
rp.WithCode();
|
|
rp.ContentEncoding = Encoding.UTF8;
|
|
|
|
SSE.ServerSentEventItem.RegisterResponse(rp);
|
|
|
|
|
|
|
|
}
|
|
#endregion
|
|
#region Storage
|
|
public static void StorageGetDirectories(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, args["Path"]);
|
|
|
|
if (Directory.Exists(path))
|
|
{
|
|
string json = Newtonsoft.Json.JsonConvert.SerializeObject(Directory.EnumerateDirectories(path).Select<string, string>((o) => { return Path.GetFileName(o); }));
|
|
rp.AsText(json, "application/json");
|
|
}
|
|
else
|
|
{
|
|
rp.AsText("[]", "application/json");
|
|
}
|
|
}
|
|
public static void StorageGetFiles(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, args["Path"]);
|
|
|
|
if (Directory.Exists(path))
|
|
{
|
|
string json = Newtonsoft.Json.JsonConvert.SerializeObject(Directory.EnumerateFiles(path).Select<string, string>((o) => { return Path.GetFileName(o); }));
|
|
rp.AsText(json, "application/json");
|
|
}
|
|
else
|
|
{
|
|
rp.AsText("[]", "application/json");
|
|
}
|
|
}
|
|
public static void StorageDirectoryExists(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, args["Path"]);
|
|
string json = Directory.Exists(path) ? "true" : "false";
|
|
rp.AsText(json, "text/plain");
|
|
|
|
}
|
|
public static void StorageFileExists(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, args["Path"]);
|
|
string json = File.Exists(path) ? "true" : "false";
|
|
rp.AsText(json, "text/plain");
|
|
|
|
}
|
|
public static void StorageFile(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
if (args["Path"].StartsWith("config/"))
|
|
{
|
|
rp.AsText("Access denied");
|
|
}
|
|
else
|
|
{
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, args["Path"]);
|
|
|
|
rp.AsFile(rq, path);
|
|
}
|
|
}
|
|
public static void Video(HttpListenerRequest rq,HttpListenerResponse rp,Dictionary<string,string> args)
|
|
{
|
|
YoutubeExplode.Videos.VideoId? vid = YoutubeExplode.Videos.VideoId.TryParse(args["Id"]);
|
|
if (vid.HasValue)
|
|
{
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, "NotConverted",vid.Value +".mp4");
|
|
rp.AddHeader("Content-Disposition", GetVideoContentDisposition(vid.Value).ToString());
|
|
rp.AsFile(rq, path);
|
|
}
|
|
else
|
|
{
|
|
rp.WithCode(HttpStatusCode.BadRequest);
|
|
rp.AsText("Invalid Video ID or URL", "text/plain");
|
|
}
|
|
}
|
|
public static void VideoRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
YoutubeExplode.Videos.VideoId? vid = YoutubeExplode.Videos.VideoId.TryParse(args["Id"]);
|
|
if (vid.HasValue)
|
|
{
|
|
int res;
|
|
if(int.TryParse(args["Res"],out res))
|
|
{
|
|
if (res > 2 || res < 0)
|
|
{
|
|
rp.WithCode(HttpStatusCode.BadRequest);
|
|
rp.AsText($"Invalid Resolution Number must be either 0, 1 or 2", "text/plain");
|
|
}
|
|
else
|
|
{
|
|
string[] m = new string[] { "Converted", "NotConverted", "Audio" };
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, m[res], vid.Value + ".mp4");
|
|
rp.AddHeader("Content-Disposition", GetVideoContentDisposition(vid.Value).ToString());
|
|
rp.AsFile(rq, path);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
rp.WithCode(HttpStatusCode.BadRequest);
|
|
rp.AsText("Res is not a number", "text/plain");
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
rp.WithCode(HttpStatusCode.BadRequest);
|
|
rp.AsText("Invalid Video ID or URL", "text/plain");
|
|
}
|
|
}
|
|
public static System.Net.Mime.ContentDisposition GetVideoContentDisposition(string id)
|
|
{
|
|
var cd = new System.Net.Mime.ContentDisposition();
|
|
string filename = GetVideoName(id);
|
|
cd.FileName = filename;
|
|
|
|
return cd;
|
|
}
|
|
public static string GetVideoName(string id)
|
|
{
|
|
string name = id + ".mp4";
|
|
string path = Server.Functions.Downloader.DL.GetPath(true, "Info", id + ".json");
|
|
if (File.Exists(path))
|
|
{
|
|
string info=File.ReadAllText(path);
|
|
name= JsonConvert.DeserializeObject<SavedVideo>(info).Title + ".mp4";
|
|
}
|
|
|
|
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 static void UploadFiles(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
var files = rq.ParseBody(args);
|
|
foreach (var f in files.Values)
|
|
f.Save(Path.Combine(webSitePath, f.FileName));
|
|
rp.AsText("uploaded", "text/plain");
|
|
}
|
|
#endregion
|
|
#region Other
|
|
public static void Index(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
rp.AsFile(rq, Path.Combine(webSitePath, "index.html"));
|
|
}
|
|
public static void RootPath(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary<string, string> args)
|
|
{
|
|
string path = Path.Combine(webSitePath, args["Path"].Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]);
|
|
|
|
rp.AsFile(rq, path);
|
|
}
|
|
#endregion
|
|
|
|
public static bool Route_Before(HttpListenerRequest request, HttpListenerResponse response)
|
|
{
|
|
response.WithCORS();
|
|
return false;
|
|
}
|
|
|
|
}
|
|
}
|