diff --git a/.vs/youtube-downloader/xs/UserPrefs.xml b/.vs/youtube-downloader/xs/UserPrefs.xml index 03b0483..dfbced6 100644 --- a/.vs/youtube-downloader/xs/UserPrefs.xml +++ b/.vs/youtube-downloader/xs/UserPrefs.xml @@ -1,19 +1,21 @@  - + - + - + + + diff --git a/Program.cs b/Program.cs index b8f557b..b96b17c 100644 --- a/Program.cs +++ b/Program.cs @@ -17,12 +17,23 @@ using TYTD.Server.Functions; using YoutubeExplode.Videos; using YoutubeExplode; using YoutubeExplode.Videos.Streams; - +using PlaylistsNET; +using PlaylistsNET.Content; +using PlaylistsNET.Models; +using PlaylistsNET.Utils; namespace TYTD { - class Program + static class Program { + public static void RemoveRange(this List list,IEnumerable items) + { + foreach(var item in items) + { + list.Remove(item); + } + } + static string webSitePath; static void Main(string[] arg) { @@ -65,7 +76,9 @@ namespace TYTD Route.Add("/api/AddPlaylistOnly/{Id}", (HttpAction)AddPlaylistOnly); Route.Add("/api/AddPlaylist/{Id}", (HttpAction)AddPlaylist); Route.Add("/api/AddPlaylistRes/{R}/{Id}", (HttpAction)AddPlaylistRes); - + Route.Add("/api/PersonalPlaylist/{PlaylistName}",(HttpAction)PersonalPlaylist); + Route.Add("/api/CreatePlaylist/{Ids}/playlist.{extension}", (HttpAction)CreatePlaylist); + Route.Add("/api/CreatePlaylistRes/{Ids}/playlist.{extension}", (HttpAction)CreatePlaylistRes); /* Search */ Route.Add("/api/SearchOnly/{text}", (HttpAction)SearchOnly); Route.Add("/api/Search/{text}", (HttpAction)Search); @@ -99,14 +112,14 @@ namespace TYTD Route.Add("/api/upload/", (HttpAction)UploadFiles, "POST"); Route.Add("/api/endpoint", (HttpAction)Endpoint,"POST"); - + ApiLoader.Init(); /* Other */ Route.Add("/", (HttpAction)Index); Route.Add("/extensions.html", (HttpAction)Extensions); Route.Add("/{Path}", (HttpAction)RootPath); Route.Add("/{Path}",(HttpAction)UploadFilePut,"PUT"); - Console.CancelKeyPress += (sender, e) => { ApiLoader.Dispose();var date = DateTime.Now.ToString("yyyyMMdd_HHmmss");File.WriteAllText(Path.Combine("config","queues-close",$"{date}.json"), Downloader.GetQueue()); return; }; + Console.CancelKeyPress += (sender, e) => { ApiLoader.Dispose();var date = DateTime.Now.ToString("yyyyMMdd_HHmmss");File.WriteAllText(Path.Combine("config","queues-close",$"{date}.json"), Downloader.GetQueue()); e.Cancel = false; }; Console.WriteLine("Almost Ready To Listen"); @@ -151,13 +164,13 @@ namespace TYTD { Downloader.DownloadItem(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddItemRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadItem(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddFile(HttpListenerRequest request, HttpListenerResponse response, Dictionary arguments) { @@ -172,19 +185,19 @@ namespace TYTD public static void AddVideoInfo(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadVideoInfo(System.Web.HttpUtility.UrlDecode(args["Id"]), Resolution.NoConvert); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddVideo(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadVideo(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddVideoRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadVideo(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void Redownload(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { @@ -193,7 +206,7 @@ namespace TYTD string id =Path.GetFileNameWithoutExtension(item); Downloader.DownloadVideo(id, Resolution.NoConvert); } - rp.AsRedirect("/"); + rp.AsText(""); } public static void RedownloadRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) @@ -203,7 +216,7 @@ namespace TYTD string id = System.IO.Path.GetFileNameWithoutExtension(item); Downloader.DownloadVideo(id, (Resolution)int.Parse(args["R"])); } - rp.AsRedirect("/"); + rp.AsText(""); } public static void Watch(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { @@ -215,19 +228,146 @@ namespace TYTD public static void AddPlaylistOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadPlaylistOnly(System.Web.HttpUtility.UrlDecode(args["Id"]), Resolution.NoConvert); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddPlaylist(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadPlaylist(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddPlaylistRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadPlaylist(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"])); - rp.AsRedirect("/"); + rp.AsText(""); } + public static void PersonalPlaylist(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) + { + string playlistName=System.Web.HttpUtility.UrlDecode(args["PlaylistName"]); + string playlistNameWithoutExtension =Path.GetFileNameWithoutExtension(playlistName); + string path= Path.Combine("PersonalPlaylist", $"{playlistNameWithoutExtension}.json"); + string extension = Path.GetExtension(playlistName); + List<(string Id, Resolution Resolution)> list = JsonConvert.DeserializeObject>(File.ReadAllText(path)); + string mimeType; + rp.AsText(CreatePlaylistString(rq, list, extension, out mimeType),mimeType); + } + public static void CreatePlaylist(HttpListenerRequest rq,HttpListenerResponse rp,Dictionary args) + { + // Route.Add("/api/PersonalPlaylist/{PlaylistName}", (HttpAction)PersonalPlaylist); + //Route.Add("/api/CreatePlaylist/{Ids}/playlist.{extension}", (HttpAction)CreatePlaylist); + //Route.Add("/api/CreatePlaylistRes/{Ids}/playlist.{extension}", (HttpAction)CreatePlaylistRes); + + string[] ids= System.Web.HttpUtility.UrlDecode(args["Ids"]).Split(','); + var list = new List<(string Id, Resolution Resolution)>(); + foreach (var id in ids) + { + list.Add((id, Resolution.NoConvert)); + } + string mimeType; + rp.AsText(CreatePlaylistString(rq, list, args["extension"],out mimeType),mimeType); + } + public static void CreatePlaylistRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) + { + string[] ids = System.Web.HttpUtility.UrlDecode(args["Ids"]).Split(','); + var list = new List<(string Id, Resolution Resolution)>(); + for (int i=0;i videoIds, string ext,out string mimeType) + { + string[] _res = { "Converted", "NotConverted", "Audio" }; + string UrlBegin = GetServerRoot(req); + string ext2 = ext.TrimStart('.'); + if (ext2 == "m3u" || ext2 == "m3u8") + { + M3uPlaylist playlist = new M3uPlaylist(); + playlist.IsExtended = true; + + foreach (var item in videoIds) + { + + M3uPlaylistEntry entry = new M3uPlaylistEntry(); + entry.Path = UrlBegin.TrimEnd('/') + $"/api/Storage/File/{_res[(int)item.Resolution]}/{item.Id}.mp4"; + var video = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine("Info", $"{item.Id}.json"))); + entry.Title = video.Title; + entry.AlbumArtist = video.AuthorTitle; + entry.Duration = TimeSpan.FromSeconds(video.Duration); + playlist.PlaylistEntries.Add(entry); + } + + M3uContent content = new M3uContent(); + mimeType = "audio/x-mpegurl"; + return content.ToText(playlist); + } else if (ext2 == "wpl") + { + WplPlaylist playlist = new WplPlaylist(); + + + foreach (var item in videoIds) + { + + WplPlaylistEntry entry = new WplPlaylistEntry(); + entry.Path = UrlBegin.TrimEnd('/') + $"/api/Storage/File/{_res[(int)item.Resolution]}/{item.Id}.mp4"; + var video = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine("Info", $"{item.Id}.json"))); + entry.TrackTitle = video.Title; + entry.TrackArtist = video.AuthorTitle; + entry.Duration = TimeSpan.FromSeconds(video.Duration); + playlist.PlaylistEntries.Add(entry); + } + + WplContent content = new WplContent(); + mimeType = "application/vnd.ms-wpl"; + return content.ToText(playlist); + } else if (ext2 == "pls") + { + PlsPlaylist playlist = new PlsPlaylist(); + + int i = 1; + foreach (var item in videoIds) + { + + PlsPlaylistEntry entry = new PlsPlaylistEntry(); + entry.Path = UrlBegin.TrimEnd('/') + $"/api/Storage/File/{_res[(int)item.Resolution]}/{item.Id}.mp4"; + var video = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine("Info", $"{item.Id}.json"))); + entry.Title = video.Title; + entry.Nr = i++; + + playlist.PlaylistEntries.Add(entry); + } + mimeType = "audio/x-scpls"; + PlsContent content = new PlsContent(); + return content.ToText(playlist); + } else if (ext2 == "zpl") + { + ZplPlaylist playlist = new ZplPlaylist(); + + + foreach (var item in videoIds) + { + + ZplPlaylistEntry entry = new ZplPlaylistEntry(); + entry.Path = UrlBegin.TrimEnd('/') + $"/api/Storage/File/{_res[(int)item.Resolution]}/{item.Id}.mp4"; + var video = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine("Info", $"{item.Id}.json"))); + entry.TrackTitle = video.Title; + entry.TrackArtist = video.AuthorTitle; + entry.Duration = TimeSpan.FromSeconds(video.Duration); + + playlist.PlaylistEntries.Add(entry); + } + mimeType = "application/vnd.ms-zpl"; + ZplContent content = new ZplContent(); + return content.ToText(playlist); + } + mimeType = "text/plain"; + return "Invalid"; + } + #endregion #region Search public static void SearchOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) @@ -250,36 +390,36 @@ namespace TYTD { Downloader.DownloadChannelOnly(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddChannel(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadChannel(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddChannelRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadChannel(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"])); - rp.AsRedirect("/"); + rp.AsText(""); } #endregion #region User public static void AddUserOnly(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadUserOnly(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddUser(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadUser(System.Web.HttpUtility.UrlDecode(args["Id"])); - rp.AsRedirect("/"); + rp.AsText(""); } public static void AddUserRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.DownloadUser(System.Web.HttpUtility.UrlDecode(args["Id"]), (Resolution)int.Parse(args["R"])); - rp.AsRedirect("/"); + rp.AsText(""); } #endregion #region Queue And Progress @@ -291,7 +431,7 @@ namespace TYTD public static void QueueMove(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { Downloader.ModQueue(args["To"], args["From"]); - rp.AsRedirect("/"); + rp.AsText(""); } public static void QueueMove2(HttpListenerRequest request, HttpListenerResponse response, Dictionary arguments) { @@ -326,7 +466,7 @@ namespace TYTD #region Storage public static void StorageGetDirectories(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { - string path = Downloader.DL.GetPath(true, args["Path"]); + string path = Downloader.DL.GetPath(true, System.Web.HttpUtility.UrlDecode(args["Path"])); if (Directory.Exists(path)) { @@ -340,7 +480,7 @@ namespace TYTD } public static void StorageGetFiles(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { - string path = Downloader.DL.GetPath(true, args["Path"]); + string path = Downloader.DL.GetPath(true, System.Web.HttpUtility.UrlDecode(args["Path"])); if (Directory.Exists(path)) { @@ -354,14 +494,14 @@ namespace TYTD } public static void StorageDirectoryExists(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { - string path = Downloader.DL.GetPath(true, args["Path"]); + string path = Downloader.DL.GetPath(true, System.Web.HttpUtility.UrlDecode(args["Path"])); string json = Directory.Exists(path) ? "true" : "false"; rp.AsText(json, "text/plain"); } public static void StorageFileExists(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { - string path = Downloader.DL.GetPath(true, args["Path"]); + string path = Downloader.DL.GetPath(true, System.Web.HttpUtility.UrlDecode(args["Path"])); string json = File.Exists(path) ? "true" : "false"; rp.AsText(json, "text/plain"); @@ -374,7 +514,7 @@ namespace TYTD } else { - string path = Downloader.DL.GetPath(true, args["Path"]); + string path = Downloader.DL.GetPath(true, System.Web.HttpUtility.UrlDecode(args["Path"])); if (Directory.Exists(path)) { string indexHtml = Path.Combine(path, "index.html"); @@ -421,7 +561,7 @@ namespace TYTD } public static void Video(HttpListenerRequest rq,HttpListenerResponse rp,Dictionary args) { - YoutubeExplode.Videos.VideoId? vid = YoutubeExplode.Videos.VideoId.TryParse(args["Id"]); + VideoId? vid = VideoId.TryParse(System.Web.HttpUtility.UrlDecode(args["Id"])); if (vid.HasValue) { string path = Downloader.DL.GetPath(true, "NotConverted",vid.Value +".mp4"); @@ -436,7 +576,7 @@ namespace TYTD } public static void VideoRes(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { - VideoId? vid = VideoId.TryParse(args["Id"]); + VideoId? vid = VideoId.TryParse(System.Web.HttpUtility.UrlDecode(args["Id"])); if (vid.HasValue) { int res; @@ -519,7 +659,7 @@ namespace TYTD } private static void UploadFilePut(HttpListenerRequest request, HttpListenerResponse response, Dictionary arguments) { - string p = arguments["Path"].Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]; + string p = System.Web.HttpUtility.UrlDecode(arguments["Path"]).Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]; string path = Path.Combine(webSitePath, p); bool exists = File.Exists(path); using (var instr = request.InputStream) @@ -541,13 +681,132 @@ namespace TYTD private static void Endpoint(HttpListenerRequest request, HttpListenerResponse response, Dictionary arguments) { + //MultiDictionary multi = new MultiDictionary(); request.ParseBody(arguments); List print = new List(); bool hasOtherResponse=false; bool success = true; if(arguments.ContainsKey("operation")) { - if (arguments["operation"] == "server_download") + if (arguments["operation"] == "create_personal_playlist") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = new List<(string Id, Resolution Resolution)>(); + list.AddRange(ids.Select(e => (e, Resolution.NoConvert))); + + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + } + else if (arguments["operation"] == "create_personal_playlist_res") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = new List<(string Id, Resolution Resolution)>(); + + for (int i = 0; i < list.Count; i += 2) + { + string id = ids[i]; + string res = ids[i + 1]; + list.Add((id, (Resolution)int.Parse(res))); + } + + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + + } + else if (arguments["operation"] == "add_to_personal_playlist") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = JsonConvert.DeserializeObject>(File.ReadAllText(path)); + + + list.AddRange(ids.Select(e => (e, Resolution.NoConvert))); + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + } + else if (arguments["operation"] == "add_to_personal_playlist_res") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = JsonConvert.DeserializeObject>(File.ReadAllText(path)); + + for (int i = 0; i < list.Count; i += 2) + { + string id = ids[i]; + string res = ids[i + 1]; + list.Add((id, (Resolution)int.Parse(res))); + } + + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + } + else if (arguments["operation"] == "insert_to_personal_playlist") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = JsonConvert.DeserializeObject>(File.ReadAllText(path)); + int offset = 0; + if (arguments.ContainsKey("offset")) + { + if (!int.TryParse(arguments["offset"], out offset)) + { + offset = 0; + } + } + list.InsertRange(offset, ids.Select(e => (e, Resolution.NoConvert))); + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + } + else if (arguments["operation"] == "remove_from_personal_playlist") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = JsonConvert.DeserializeObject>(File.ReadAllText(path)); + List<(string, Resolution)> todel = new List<(string, Resolution)>(); + foreach(var item in list) + { + if(ids.Contains(item.Id)) + { + todel.Add(item); + } + } + list.RemoveRange(todel); + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + } + else if (arguments["operation"] == "insert_to_personal_playlist_res") + { + string myName = arguments["name"]; + string path = Downloader.DL.GetPath(true, "PersonalPlaylist", $"{myName}.json"); + + string[] ids = System.Web.HttpUtility.UrlDecode(arguments["ids"]).Split(','); + var list = JsonConvert.DeserializeObject>(File.ReadAllText(path)); + int offset = 0; + if (arguments.ContainsKey("offset")) + { + if (!int.TryParse(arguments["offset"], out offset)) + { + offset = 0; + } + } + for (int i = 0; i < list.Count; i += 2) + { + string id = ids[i]; + string res = ids[i + 1]; + list.Insert(offset++,(id, (Resolution)int.Parse(res))); + } + + File.WriteAllText(path, JsonConvert.SerializeObject(list)); + } + else if (arguments["operation"] == "server_download") { if (arguments.ContainsKey("url")) { @@ -637,7 +896,7 @@ namespace TYTD hasOtherResponse = true; } - else if(arguments["operation"] == "queue_move") + else if (arguments["operation"] == "queue_move") { bool containsId = arguments.ContainsKey("id"); bool containsIndex = arguments.ContainsKey("index"); @@ -651,7 +910,7 @@ namespace TYTD if (arguments.ContainsKey("to")) { string to_loc = arguments["to"]; - if(containsId) + if (containsId) Downloader.ModQueue2(to_loc, arguments["id"]); if (containsIndex) @@ -685,7 +944,7 @@ namespace TYTD } public static void RootPath(HttpListenerRequest rq, HttpListenerResponse rp, Dictionary args) { - string p = args["Path"].Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]; + string p = System.Web.HttpUtility.UrlDecode(args["Path"]).Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries)[0]; string path = Path.Combine(webSitePath, p); if (Directory.Exists(path)) { @@ -739,6 +998,18 @@ namespace TYTD response.WithCORS(); return false; } + public static string GetServerRoot(HttpListenerRequest req) + { + if(req.Headers.AllKeys.Contains("ServerRoot")) + { + return req.Headers["ServerRoot"]; + } + else + { + return $"http://{req.LocalEndPoint.ToString()}/"; + } + + } } } diff --git a/TYTD.Api/Server/Models/IEnumerator.cs b/TYTD.Api/Server/Models/IEnumerator.cs new file mode 100644 index 0000000..fca7a8a --- /dev/null +++ b/TYTD.Api/Server/Models/IEnumerator.cs @@ -0,0 +1,6 @@ +namespace TYTD.Server.Models +{ + internal interface IEnumerator + { + } +} \ No newline at end of file diff --git a/TYTD.Api/Server/Models/InfoType.cs b/TYTD.Api/Server/Models/InfoType.cs index ff5c51e..6003e66 100644 --- a/TYTD.Api/Server/Models/InfoType.cs +++ b/TYTD.Api/Server/Models/InfoType.cs @@ -1,6 +1,10 @@ using YoutubeExplode.Channels; using YoutubeExplode.Playlists; using YoutubeExplode.Videos; +using System.Collections.Generic; +using System.Collections; +using System.Linq; +using System.Collections.ObjectModel; namespace TYTD.Server.Models { @@ -13,6 +17,129 @@ namespace TYTD.Server.Models ClosedCaptions=4, FileDownload=5 } + public class MultiDictionary : IDictionary + { + Dictionary> _dict= new Dictionary>(); + + public IReadOnlyDictionary> Dictionary { get { return _dict; } } + + public T2 this[T1 key] { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + + public ICollection Keys => _dict.Keys; + + public ICollection Values => new Collection( _dict.Values.Select, T2>(e => e.First()).ToList()); + + public int Count => _dict.Count; + + public bool IsReadOnly => false; + + public void Add(T1 key, T2 value) + { + if(!_dict.ContainsKey(key)) + { + _dict.Add(key, new List()); + } + _dict[key].Add(value); + } + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + _dict.Clear(); + } + + public bool Contains(KeyValuePair item) + { + if(_dict.ContainsKey(item.Key)) + { + return _dict[item.Key].Contains(item.Value); + + } + return false; + } + + public bool ContainsKey(T1 key) + { + return _dict.ContainsKey(key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + int i = arrayIndex; + foreach(var item in _dict) + { + var v = new KeyValuePair(item.Key,item.Value.First()); + + array[i++]=v; + } + } + + public IEnumerator> GetEnumerator() + { + return new TEnumerator(_dict.GetEnumerator()); + } + private class TEnumerator : IEnumerator> + { + public TEnumerator(IEnumerator>> dict) + { + _enum = dict; + } + IEnumerator>> _enum; + public object Current => new KeyValuePair(_enum.Current.Key, _enum.Current.Value.First()); + + KeyValuePair IEnumerator>.Current => new KeyValuePair(_enum.Current.Key, _enum.Current.Value.First()); + + public void Dispose() + { + _enum.Dispose(); + } + + public bool MoveNext() + { + return _enum.MoveNext(); + } + + public void Reset() + { + _enum.Reset(); + } + } + public bool Remove(T1 key) + { + return _dict.Remove(key); + } + + public bool Remove(KeyValuePair item) + { + if(_dict.ContainsKey(item.Key)) + { + return _dict[item.Key].Remove(item.Value); + + } + return false; + } + + public bool TryGetValue(T1 key, out T2 value) + { + List value0; + if(_dict.TryGetValue(key,out value0)) + { + value = value0.First(); + return true; + } + value = default(T2); + return false; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new TEnumerator(_dict.GetEnumerator()); + } + } public class IDResolutionTypeTriplet { public string Id { get; set; } diff --git a/TYTD.Api/Server/Models/VideoDownloadProgress.cs b/TYTD.Api/Server/Models/VideoDownloadProgress.cs index 7f08eaa..eba2a09 100644 --- a/TYTD.Api/Server/Models/VideoDownloadProgress.cs +++ b/TYTD.Api/Server/Models/VideoDownloadProgress.cs @@ -10,4 +10,5 @@ namespace TYTD.Server.Models public int Progress { get; set; } public double ProgressRaw { get; set; } } + } \ No newline at end of file diff --git a/TYTD.Api/bin/Release/TYTD.Api.dll b/TYTD.Api/bin/Release/TYTD.Api.dll index db0e032..91ca257 100644 Binary files a/TYTD.Api/bin/Release/TYTD.Api.dll and b/TYTD.Api/bin/Release/TYTD.Api.dll differ diff --git a/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache b/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache index afdeebc..57bfcff 100644 Binary files a/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache and b/TYTD.Api/obj/Release/TYTD.Api.csprojAssemblyReference.cache differ diff --git a/TYTD.Api/obj/Release/TYTD.Api.dll b/TYTD.Api/obj/Release/TYTD.Api.dll index db0e032..91ca257 100644 Binary files a/TYTD.Api/obj/Release/TYTD.Api.dll and b/TYTD.Api/obj/Release/TYTD.Api.dll differ diff --git a/bin/Release/PlaylistsNET.dll b/bin/Release/PlaylistsNET.dll new file mode 100755 index 0000000..db4502a Binary files /dev/null and b/bin/Release/PlaylistsNET.dll differ diff --git a/bin/Release/TYTD.Api.dll b/bin/Release/TYTD.Api.dll index db0e032..91ca257 100644 Binary files a/bin/Release/TYTD.Api.dll and b/bin/Release/TYTD.Api.dll differ diff --git a/bin/Release/youtube-downloader.exe b/bin/Release/youtube-downloader.exe index 35c1f04..ef726d9 100644 Binary files a/bin/Release/youtube-downloader.exe and b/bin/Release/youtube-downloader.exe differ diff --git a/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache b/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache index 76c7083..a674724 100644 --- a/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache +++ b/obj/x86/Release/youtube-downloader.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -86258721c083b2dc3445d3e49869600975273fa0 +3a0ad01444a7c622c3bd15b537d0dc7e888f6685 diff --git a/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt b/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt index 8c01165..f13c524 100644 --- a/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt +++ b/obj/x86/Release/youtube-downloader.csproj.FileListAbsolute.txt @@ -705,3 +705,4 @@ /home/mike/tytd-server/obj/x86/Release/youtube-downloader.csproj.CopyComplete /home/mike/tytd-server/obj/x86/Release/youtube-downloader.exe /home/mike/tytd-server/bin/Release/System.Text.Encoding.CodePages.xml +/home/mike/tytd-server/bin/Release/PlaylistsNET.dll diff --git a/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache b/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache index 1ad8a52..fef4da8 100644 Binary files a/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache and b/obj/x86/Release/youtube-downloader.csprojAssemblyReference.cache differ diff --git a/obj/x86/Release/youtube-downloader.exe b/obj/x86/Release/youtube-downloader.exe index 35c1f04..ef726d9 100644 Binary files a/obj/x86/Release/youtube-downloader.exe and b/obj/x86/Release/youtube-downloader.exe differ diff --git a/packages.config b/packages.config index 8047221..3cdeb66 100644 --- a/packages.config +++ b/packages.config @@ -7,6 +7,7 @@ + diff --git a/packages/PlaylistsNET.1.1.3/.signature.p7s b/packages/PlaylistsNET.1.1.3/.signature.p7s new file mode 100755 index 0000000..ca43082 Binary files /dev/null and b/packages/PlaylistsNET.1.1.3/.signature.p7s differ diff --git a/packages/PlaylistsNET.1.1.3/PlaylistsNET.1.1.3.nupkg b/packages/PlaylistsNET.1.1.3/PlaylistsNET.1.1.3.nupkg new file mode 100755 index 0000000..fb79cc4 Binary files /dev/null and b/packages/PlaylistsNET.1.1.3/PlaylistsNET.1.1.3.nupkg differ diff --git a/packages/PlaylistsNET.1.1.3/lib/net45/PlaylistsNET.dll b/packages/PlaylistsNET.1.1.3/lib/net45/PlaylistsNET.dll new file mode 100755 index 0000000..db4502a Binary files /dev/null and b/packages/PlaylistsNET.1.1.3/lib/net45/PlaylistsNET.dll differ diff --git a/packages/PlaylistsNET.1.1.3/lib/netstandard1.4/PlaylistsNET.dll b/packages/PlaylistsNET.1.1.3/lib/netstandard1.4/PlaylistsNET.dll new file mode 100755 index 0000000..dcec528 Binary files /dev/null and b/packages/PlaylistsNET.1.1.3/lib/netstandard1.4/PlaylistsNET.dll differ diff --git a/packages/PlaylistsNET.1.1.3/lib/netstandard2.0/PlaylistsNET.dll b/packages/PlaylistsNET.1.1.3/lib/netstandard2.0/PlaylistsNET.dll new file mode 100755 index 0000000..e04fa09 Binary files /dev/null and b/packages/PlaylistsNET.1.1.3/lib/netstandard2.0/PlaylistsNET.dll differ diff --git a/youtube-downloader.csproj b/youtube-downloader.csproj index 7773b66..46d806e 100644 --- a/youtube-downloader.csproj +++ b/youtube-downloader.csproj @@ -112,6 +112,9 @@ packages\CookiesTxtParser.1.0.1\lib\netstandard2.0\CookiesTxtParser.dll + + packages\PlaylistsNET.1.1.3\lib\net45\PlaylistsNET.dll +