public StructureRss(Logger logger, string dbUrl) { this.logger = logger; // API only available to authenticated users BeforeAsync = async(p, c) => await c.EnsureIsAuthenticatedAsync(); var cache = new Utils.Cache <List <Rss> >(400, TimeSpan.FromMinutes(20), async(string key) => { logger.Log(LogLevel.Info, $"Load RSS: {key}"); var items = new List <Rss>(); try { var settings = new XmlReaderSettings { IgnoreComments = true, DtdProcessing = DtdProcessing.Ignore }; var uri = new Uri(key); var doc = await LoadXmlAsync(uri); XElement root = doc.Root; XNamespace ns = doc.Root.Name.Namespace; var contentns = "http://purl.org/rss/1.0/modules/content/"; var dcns = "http://purl.org/dc/elements/1.1/"; // RSS 2.0 if (root.Name.LocalName == "rss") { foreach (XElement item in root.Element("channel").Elements("item")) { var rss = new Rss(); var title = item.Element("title"); if (title != null) { rss.title = title.Value; } var content = item.Element("description"); if (content != null) { rss.content = content.Value; } var link = item.Element("link"); if (link != null) { rss.link = link.Value; } var date = item.Element("pubDate"); if (date == null) { date = item.Element(XName.Get("date", dcns)); } if (date != null) { rss.pubDate = DateTime.Parse(date.Value); } var encoded = item.Element(XName.Get("encoded", contentns)); if (encoded != null) { var imageUrl = GetImageFromHtml(encoded.Value); if (imageUrl != null) { rss.image = imageUrl; } } items.Add(rss); } } // ATOM else if (root.Name.LocalName == "feed") { var atomns = "http://www.w3.org/2005/Atom"; foreach (XElement item in root.Elements(XName.Get("entry", atomns))) { var rss = new Rss(); var title = item.Element(XName.Get("title", atomns)); if (title != null) { rss.title = title.Value; } var summary = item.Element(XName.Get("summary", atomns)); if (summary != null) { rss.content = summary.Value; } var content = item.Element(XName.Get("content", atomns)); if (content != null) { var type = "text"; if (content.Attribute("type") != null) { type = content.Attribute("type").Value; } var textContent = content.Value; if (type == "html") { textContent = GetTextFromHtml(content.Value); var imageUrl = GetImageFromHtml(content.Value); if (imageUrl != null) { rss.image = imageUrl; } } if (rss.content == null) { rss.content = textContent; } } var link = item.Element(XName.Get("link", atomns)); if (link != null) { rss.link = link.Attribute("href").Value; } var updated = item.Element(XName.Get("updated", atomns)); if (updated != null) { rss.pubDate = DateTime.Parse(updated.Value); } items.Add(rss); } } // RSS 1.0 else if (root.Name.LocalName == "RDF") { var rss10ns = "http://purl.org/rss/1.0/"; foreach (XElement item in root.Elements(XName.Get("item", rss10ns))) { var rss = new Rss(); var title = item.Element(XName.Get("title", rss10ns)); if (title != null) { rss.title = title.Value; } var content = item.Element(XName.Get("description", rss10ns)); if (content != null) { rss.content = content.Value; } var link = item.Element(XName.Get("link", rss10ns)); if (link != null) { rss.link = link.Value; } var date = item.Element(XName.Get("date", dcns)); if (date != null) { rss.pubDate = DateTime.Parse(date.Value); } var encoded = item.Element(XName.Get("encoded", contentns)); if (encoded != null) { var imageUrl = GetImageFromHtml(encoded.Value); if (imageUrl != null) { rss.image = imageUrl; } } items.Add(rss); } } } catch (Exception e) { logger.Log(LogLevel.Error, $"invalid RSS feed '{key}'. Exception: {e}"); items = null; } return(items); }, true); GetAsync["/{uai}/rss"] = async(p, c) => { var structure = new Structure { id = (string)p["uai"] }; using (DB db = await DB.CreateAsync(dbUrl)) { if (await structure.LoadAsync(db)) { await c.EnsureHasRightsOnStructureAsync(structure, true, false, false); await structure.LoadExpandFieldAsync(db, nameof(structure.flux)); var infos = new ModelList <Rss>(); // parallel loading var tasks = structure.flux.Select((flux) => cache.GetAsync(flux.url)); await Task.WhenAll(tasks); tasks.ForEach((t) => { if (t.Result != null) { infos.AddRange(t.Result); } }); c.Response.StatusCode = 200; c.Response.Content = infos.Filter(c); } } }; }