public string ToXml(Uri selfAtom)
{
var xdoc = new XDocument(
new XDeclaration("1.0", "UTF-8", null),
new XElement("rss",
new XAttribute("version", "1.0"),
new XAttribute(XNamespace.Xmlns + "atom", atomNs.NamespaceName),
new XAttribute(XNamespace.Xmlns + "torznab", torznabNs.NamespaceName),
new XElement("channel",
new XElement(atomNs + "link",
new XAttribute("href", selfAtom.ToString()),
new XAttribute("rel", "self"),
new XAttribute("type", "application/rss+xml")
),
new XElement("title", ChannelInfo.Title),
new XElement("description", ChannelInfo.Description),
new XElement("link", ChannelInfo.Link),
new XElement("lanuage", ChannelInfo.Language),
new XElement("category", ChannelInfo.Category),
new XElement("image",
new XElement("url", ChannelInfo.ImageUrl.ToString()),
new XElement("title", ChannelInfo.ImageTitle),
new XElement("link", ChannelInfo.ImageLink.ToString()),
new XElement("description", ChannelInfo.ImageDescription)
),
from r in Releases
select new XElement("item",
new XElement("title", r.Title),
new XElement("guid", r.Guid),
r.Comments == null ? null : new XElement("comments", r.Comments.ToString()),
r.PublishDate == DateTime.MinValue ? null : new XElement("pubDate", xmlDateFormat(r.PublishDate)),
r.Size == null ? null : new XElement("size", r.Size),
r.Files == null ? null : new XElement("files", r.Files),
r.Grabs == null ? null : new XElement("grabs", r.Grabs),
new XElement("description", r.Description),
new XElement("link", r.Link ?? r.MagnetUri),
r.Category == 0 ? null : new XElement("category", r.Category),
new XElement(
"enclosure",
new XAttribute("url", r.Link ?? r.MagnetUri),
r.Size == null ? null : new XAttribute("length", r.Size),
new XAttribute("type", "application/x-bittorrent")
),
getTorznabElement("magneturl", r.MagnetUri),
getTorznabElement("rageid", r.RageID),
getTorznabElement("thetvdb", r.TVDBId),
getTorznabElement("imdb", r.Imdb),
getTorznabElement("seeders", r.Seeders),
getTorznabElement("peers", r.Peers),
getTorznabElement("infohash", r.InfoHash),
getTorznabElement("minimumratio", r.MinimumRatio),
getTorznabElement("minimumseedtime", r.MinimumSeedTime),
getTorznabElement("downloadvolumefactor", r.DownloadVolumeFactor),
getTorznabElement("uploadvolumefactor", r.UploadVolumeFactor)
)
)
)
);
return xdoc.Declaration.ToString() + Environment.NewLine + xdoc.ToString();
}
}
public async Task<HttpResponseMessage> Call(string indexerID) { var indexer = indexerService.GetIndexer(indexerID); var torznabQuery = TorznabQuery.FromHttpQuery(HttpUtility.ParseQueryString(Request.RequestUri.Query)); if (string.Equals(torznabQuery.QueryType, "caps", StringComparison.InvariantCultureIgnoreCase)) { return new HttpResponseMessage() { Content = new StringContent(indexer.TorznabCaps.ToXml(), Encoding.UTF8, "application/rss+xml") }; } torznabQuery.ExpandCatsToSubCats(); var allowBadApiDueToDebug = false; #if DEBUG allowBadApiDueToDebug = Debugger.IsAttached; #endif if (!allowBadApiDueToDebug && !string.Equals(torznabQuery.ApiKey, serverService.Config.APIKey, StringComparison.InvariantCultureIgnoreCase)) { logger.Warn(string.Format("A request from {0} was made with an incorrect API key.", Request.GetOwinContext().Request.RemoteIpAddress)); return Request.CreateResponse(HttpStatusCode.Forbidden, "Incorrect API key"); } if (!indexer.IsConfigured) { logger.Warn(string.Format("Rejected a request to {0} which is unconfigured.", indexer.DisplayName)); return Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer is not configured."); } var releases = await indexer.PerformQuery(torznabQuery); releases = indexer.CleanLinks(releases); // Some trackers do not keep their clocks up to date and can be ~20 minutes out! foreach (var release in releases) { if (release.PublishDate > DateTime.Now) release.PublishDate = DateTime.Now; } // Some trackers do not support multiple category filtering so filter the releases that match manually. var filteredReleases = releases = indexer.FilterResults(torznabQuery, releases); int? newItemCount = null; // Cache non query results if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm)) { newItemCount = cacheService.GetNewItemCount(indexer, filteredReleases); cacheService.CacheRssResults(indexer, releases); } // Log info var logBuilder = new StringBuilder(); if (newItemCount != null) { logBuilder.AppendFormat(string.Format("Found {0} ({1} new) releases from {2}", releases.Count(), newItemCount, indexer.DisplayName)); } else { logBuilder.AppendFormat(string.Format("Found {0} releases from {1}", releases.Count(), indexer.DisplayName)); } if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { logBuilder.AppendFormat(" for: {0}", torznabQuery.GetQueryString()); } logger.Info(logBuilder.ToString()); var serverUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port); var resultPage = new ResultPage(new ChannelInfo { Title = indexer.DisplayName, Description = indexer.DisplayDescription, Link = new Uri(indexer.SiteLink), ImageUrl = new Uri(serverUrl + "logos/" + indexer.ID + ".png"), ImageTitle = indexer.DisplayName, ImageLink = new Uri(indexer.SiteLink), ImageDescription = indexer.DisplayName }); foreach(var result in releases) { var clone = Mapper.Map<ReleaseInfo>(result); clone.Link = serverService.ConvertToProxyLink(clone.Link, serverUrl, indexerID); resultPage.Releases.Add(clone); } var xml = resultPage.ToXml(new Uri(serverUrl)); // Force the return as XML return new HttpResponseMessage() { Content = new StringContent(xml, Encoding.UTF8, "application/rss+xml") }; }