using SimpleHttp; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using TYTD; using Newtonsoft.Json; using System.IO; using YoutubeExplode.Channels; using Hyperlinq; namespace Autofetch_YT { public class RSSState { public RSSState() { ReqDuration = new TimeSpan(0,30, 0); } public Dictionary VideoRSS { get; set; } public TimeSpan ReqDuration { get; set; } } public class AutofetchYT : Api { RSSState state; public override void OnStart() { Route.Add("/api/Extensions/AutofetchYT/", (HttpAction)Autofetch); Route.Add("/api/Extensions/AutofetchYT/change", (HttpAction)AutofetchChange, "POST"); Load(); SetTimer(state.ReqDuration); } public override IEnumerable> GetUrls() { yield return new KeyValuePair("AutoFetch", "api/Extensions/AutofetchYT/"); } protected override void TimerElapsed() { foreach(var item in state.VideoRSS) { item.Value.Scan(); } } public HElement GetSite() { return H.html( H.head( H.meta(e => e.charset("UTF8")), H.meta(e => e.http_equiv("X-UA-Compatible").content("IE=edge")), H.meta(e => e.name("viewport").content("width=device-width, initial-scale=1.0")), H.title("Autofetch YT"), H.link(e => e.href("https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css").rel("stylesheet")), H.script(e => e.src("https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js")), H.script(e => e.src("https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js")), H.link(e => e.href("../../favicon.ico").rel("shortcut icon").type("image/x-icon").Custom("crossorigin","use-credentials")) ), H.body( H.div(e=>e.css("container"), H.h1("Autofetch YT"), H.ul(e=>e.css("nav nav-tabs"), H.li(e=>e.css("active"), H.a(e=>e.Custom("data-toggle","tab").href("#addchannel"),"Add") ), H.li( H.a(e=> e.Custom("data-toggle", "tab").href("#channels"),"Channels") ), H.li( H.a(e => e.Custom("data-toggle", "tab").href("#more"), "More") ) ), H.div(e=>e.css("tab-content"), H.div(e=>e.id("addchannel").css("tab-pane fad in active"), H.br(), H.div(e=>e.css("container"), H.form(e=>e.action("change").method("POST"), H.input(e=>e.type("hidden").name("operation").value("add")), H.input(e=>e.type("text").placeholder("Name").name("key")), H.br(),H.br(), H.input(e=>e.type("text").placeholder("Channel ID or URL").name("value")), H.br(),H.br(), H.input(e=>e.type("submit").value("Add Channel").css("btn btn-primary")) ) ) ), H.div(e=>e.id("channels").css("tab-pane fade"), H.br(), H.div(e=>e.css("container"), H.table(e=>e.css("table table-striped"), H.thead( H.tr( H.th("Name"), H.th("Channel Url"), H.th("Delete") ) ), H.tbody( from item in state.VideoRSS select RSSTr(item) ) ) ) ), H.div(e => e.id("more").css("tab-pane fade"), H.br(), H.div(e => e.css("container"), H.form(e=>e.action("change").method("POST"), H.h1("Clear All Channels"), H.input(e=>e.type("hidden").name("operation").value("clear")), H.input(e=>e.type("submit").value("Clear").css("btn btn-danger")) ), H.form(e => e.action("change").method("POST"), H.h1("Interval"), H.input(e=>e.type("hidden").name("operation").value("setinterval")), H.input(e=>e.type("text").name("interval").value(state.ReqDuration.ToString())), H.br(),H.br(), H.input(e=>e.type("submit").value("Set Interval").css("btn btn-primary")) ) ) ) ) ) )); } public HElement RSSTr(KeyValuePair item) { string url = $"https://www.youtube.com/channel/{item.Value.ID}"; return H.tr( H.td(item.Key), H.td(H.A(url, url)), H.td( H.form( H.input(e => e.type("submit").css("btn-danger").value("X")), H.input(e => e.type("hidden").name("operation").value("delete")), H.input(e => e.type("hidden").name("key").value(item.Value.ID) ) ))); } public void Autofetch(HttpListenerRequest req, HttpListenerResponse resp, Dictionary args) { resp.AsText(GetSite().ToString()); } public void AutofetchChange(HttpListenerRequest req, HttpListenerResponse resp, Dictionary args) { TimerEnabled = false; req.ParseBody(args); if (args.ContainsKey("operation")) { string operation = args["operation"]; switch (operation) { case "add": if(args.ContainsKey("key") && args.ContainsKey("value")) { string key = args["key"]; string value = args["value"]; ChannelId? id = ChannelId.TryParse(value); if(id.HasValue) { state.VideoRSS.Add(key, new YoutubeRSS(this, id.Value)); } } break; case "delete": if (args.ContainsKey("key")) { string key = args["key"]; if(state.VideoRSS.ContainsKey(key)) { state.VideoRSS.Remove(key); } } break; case "clear": state.VideoRSS.Clear(); break; case "setinterval": if (args.ContainsKey("interval")) { TimeSpan span; if (TimeSpan.TryParse(args["interval"], out span)) { state.ReqDuration = span; } } break; } } Save(); resp.AsText(""); } public void Save() { string videoInfo = Path.Combine(StorageLocation, "autofetch.json"); File.WriteAllText(videoInfo, JsonConvert.SerializeObject(state)); SetTimer(state.ReqDuration); } public void Load() { string videoInfo = Path.Combine(StorageLocation, "autofetch.json"); if (File.Exists(videoInfo)) { state = JsonConvert.DeserializeObject(File.ReadAllText(videoInfo)); foreach(var item in state.VideoRSS) { item.Value.SetApi(this); } } else { state = new RSSState(); state.VideoRSS = new Dictionary(); } } } public class YoutubeRSS { Api api; public string ID { get; set; } public YoutubeRSS(Api api,string id) { this.api = api; this.ID = id; // UCZkURf9tDolFOeuw_4RD7XQ } public YoutubeRSS() { } public void SetApi(Api api) { this.api = api; } public void Scan() { var xml = System.Xml.XmlReader.Create("https://www.youtube.com/feeds/videos.xml?channel_id=" + this.ID); var feed = System.ServiceModel.Syndication.SyndicationFeed.Load(xml); foreach (var item in feed.Items) { string id = item.Id; api.AddItem(id.Substring("yt:videoId".Length - 1)); } } } }