From 7cb2ee057f36dab847ffa04d683940daa2d16020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Do=C4=9Fa=20=C3=96zg=C3=BCr=20Sezer?= Date: Fri, 5 Apr 2024 16:29:34 +0300 Subject: [PATCH] Rss autodiscovery (#134) * Create helm chart for easier deployment in k8s * Add RSS autodiscovery * RSS feed for each channel --- LightTube/Contexts/BaseContext.cs | 11 +++- LightTube/Contexts/ChannelContext.cs | 2 + LightTube/Contexts/HomepageContext.cs | 1 + LightTube/Controllers/FeedController.cs | 72 +++++++++++++++++++++++++ LightTube/Views/Shared/_Layout.cshtml | 4 ++ 5 files changed, 89 insertions(+), 1 deletion(-) diff --git a/LightTube/Contexts/BaseContext.cs b/LightTube/Contexts/BaseContext.cs index 227f2d1b..25a092a5 100644 --- a/LightTube/Contexts/BaseContext.cs +++ b/LightTube/Contexts/BaseContext.cs @@ -10,6 +10,7 @@ public class BaseContext public string Title; public bool IsMobile; public List HeadTags = new(); + public List rssElement = new(); public List EndTags = new(); public bool GuideHidden = false; public HttpContext Context; @@ -38,7 +39,15 @@ public void AddStylesheet(string href) stylesheet.Attributes.Add("href", href + "?v=" + Utils.GetVersion()); HeadTags.Add(stylesheet); } - + public void AddRSSUrl(string href) + { + TagBuilder rss = new("link"); + rss.Attributes.Add("rel", "alternate"); + rss.Attributes.Add("type", "application/rss+xml"); + rss.Attributes.Add("title", "RSS"); + rss.Attributes.Add("href", href); + rssElement.Add(rss); + } public void AddMeta(string property, string content) { TagBuilder stylesheet = new("meta"); diff --git a/LightTube/Contexts/ChannelContext.cs b/LightTube/Contexts/ChannelContext.cs index 61202ca5..c311e05a 100644 --- a/LightTube/Contexts/ChannelContext.cs +++ b/LightTube/Contexts/ChannelContext.cs @@ -43,6 +43,7 @@ public ChannelContext(HttpContext context, ChannelTabs tab, InnerTubeChannelResp AddMeta("og:url", $"{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}{context.Request.QueryString}"); AddMeta("og:image", channel.Header?.Avatars.Last().Url.ToString() ?? ""); AddMeta("twitter:card", channel.Header?.Avatars.Last().Url.ToString() ?? ""); + AddRSSUrl(context.Request.Scheme + "://" + context.Request.Host + "/feed/" + Id + "/rss.xml"); if (channel.Contents.Any(x => x is ChannelVideoPlayerRenderer || x is ItemSectionRenderer isr && isr.Contents.Any(y => y is ChannelVideoPlayerRenderer))) { @@ -85,6 +86,7 @@ public ChannelContext(HttpContext context, ChannelTabs tab, InnerTubeChannelResp AddMeta("og:url", $"{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}{context.Request.QueryString}"); AddMeta("og:image", channel.Header?.Avatars.Last().Url.ToString() ?? ""); AddMeta("twitter:card", channel.Header?.Avatars.Last().Url.ToString() ?? ""); + AddRSSUrl(context.Request.Scheme + "://" + context.Request.Host + "/feed/" + Id + "/rss.xml"); } public ChannelContext(HttpContext context, DatabaseUser? channel, string id) : base(context) diff --git a/LightTube/Contexts/HomepageContext.cs b/LightTube/Contexts/HomepageContext.cs index a66f5b9a..11a6d459 100644 --- a/LightTube/Contexts/HomepageContext.cs +++ b/LightTube/Contexts/HomepageContext.cs @@ -7,6 +7,7 @@ public class HomepageContext : BaseContext public FeedVideo[] Videos; public HomepageContext(HttpContext context) : base(context) { + AddRSSUrl(context.Request.Scheme + "://" + context.Request.Host + "/feed/rss.xml"); if (User != null) { Videos = Task.Run(async () => diff --git a/LightTube/Controllers/FeedController.cs b/LightTube/Controllers/FeedController.cs index 03df4fae..d8e34418 100644 --- a/LightTube/Controllers/FeedController.cs +++ b/LightTube/Controllers/FeedController.cs @@ -20,6 +20,78 @@ public FeedController(InnerTube.InnerTube youtube) _youtube = youtube; } + [Route("channel/{c}/rss.xml")] + [HttpGet] + public async Task ChannelFeed(string c) + { + ChannelFeed ytchannel = await YoutubeRSS.GetChannelFeed(c); + try + { + XmlDocument document = new(); + XmlElement rss = document.CreateElement("rss"); + rss.SetAttribute("version", "2.0"); + + XmlElement channel = document.CreateElement("channel"); + + XmlElement title = document.CreateElement("title"); + title.InnerText = "LightTube channnel RSS feed for " + ytchannel.Name; + channel.AppendChild(title); + + XmlElement description = document.CreateElement("description"); + description.InnerText = $"LightTube channnel RSS feed for {ytchannel.Name}"; + channel.AppendChild(description); + + foreach (FeedVideo video in ytchannel.Videos.Take(15)) + { + XmlElement item = document.CreateElement("item"); + + XmlElement id = document.CreateElement("id"); + id.InnerText = $"id:video:{video.Id}"; + item.AppendChild(id); + + XmlElement vtitle = document.CreateElement("title"); + vtitle.InnerText = video.Title; + item.AppendChild(vtitle); + + XmlElement vdescription = document.CreateElement("description"); + vdescription.InnerText = video.Description; + item.AppendChild(vdescription); + + XmlElement link = document.CreateElement("link"); + link.InnerText = $"https://{Request.Host}/watch?v={video.Id}"; + item.AppendChild(link); + + XmlElement published = document.CreateElement("pubDate"); + published.InnerText = video.PublishedDate.ToString("R"); + item.AppendChild(published); + + XmlElement author = document.CreateElement("author"); + + XmlElement name = document.CreateElement("name"); + name.InnerText = video.ChannelName; + author.AppendChild(name); + + XmlElement uri = document.CreateElement("uri"); + uri.InnerText = $"https://{Request.Host}/channel/{video.ChannelId}"; + author.AppendChild(uri); + + item.AppendChild(author); + channel.AppendChild(item); + } + + rss.AppendChild(channel); + + document.AppendChild(rss); + return File(Encoding.UTF8.GetBytes(document.OuterXml), "application/xml"); + + } + catch (Exception) + { + + throw; + } + } + [Route("subscriptions")] public async Task Subscription() { diff --git a/LightTube/Views/Shared/_Layout.cshtml b/LightTube/Views/Shared/_Layout.cshtml index 69a327e4..9cf8ed25 100644 --- a/LightTube/Views/Shared/_Layout.cshtml +++ b/LightTube/Views/Shared/_Layout.cshtml @@ -17,6 +17,10 @@ + @foreach (IHtmlContent item in Model.rssElement) + { + @item + } @if (Configuration.GetVariable("LIGHTTUBE_CUSTOM_CSS_PATH") != null) {