public ActionResult <SearchResource> GrabReleases(List <SearchResource> releases) { var source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); var host = Request.GetHostName(); var groupedReleases = releases.GroupBy(r => r.IndexerId); foreach (var indexerReleases in groupedReleases) { var indexerDef = _indexerFactory.Get(indexerReleases.Key); foreach (var release in indexerReleases) { ValidateResource(release); var releaseInfo = _remoteReleaseCache.Find(GetCacheKey(release)); try { _downloadService.SendReportToClient(releaseInfo, source, host, indexerDef.Redirect); } catch (ReleaseDownloadException ex) { _logger.Error(ex, "Getting release from indexer failed"); } } } return(Ok(releases)); }
public async Task <object> GetDownload(int id, string link, string file) { var indexerDef = _indexerFactory.Get(id); var indexer = _indexerFactory.GetInstance(indexerDef); if (_indexerLimitService.AtDownloadLimit(indexerDef)) { throw new BadRequestException("Grab limit reached"); } if (link.IsNullOrWhiteSpace() || file.IsNullOrWhiteSpace()) { throw new BadRequestException("Invalid Prowlarr link"); } file = WebUtility.UrlDecode(file); if (indexerDef == null) { throw new NotFoundException("Indexer Not Found"); } var source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); var host = Request.GetHostName(); var unprotectedlLink = _downloadMappingService.ConvertToNormalLink(link); // If Indexer is set to download via Redirect then just redirect to the link if (indexer.SupportsRedirect && indexerDef.Redirect) { _downloadService.RecordRedirect(unprotectedlLink, id, source, host, file); return(RedirectPermanent(unprotectedlLink)); } var downloadBytes = Array.Empty <byte>(); downloadBytes = await _downloadService.DownloadReport(unprotectedlLink, id, source, host, file); // handle magnet URLs if (downloadBytes.Length >= 7 && downloadBytes[0] == 0x6d && downloadBytes[1] == 0x61 && downloadBytes[2] == 0x67 && downloadBytes[3] == 0x6e && downloadBytes[4] == 0x65 && downloadBytes[5] == 0x74 && downloadBytes[6] == 0x3a) { var magnetUrl = Encoding.UTF8.GetString(downloadBytes); return(RedirectPermanent(magnetUrl)); } var contentType = indexer.Protocol == DownloadProtocol.Torrent ? "application/x-bittorrent" : "application/x-nzb"; var extension = indexer.Protocol == DownloadProtocol.Torrent ? "torrent" : "nzb"; var filename = $"{file}.{extension}"; return(File(downloadBytes, contentType, filename)); }
public ActionResult <SearchResource> GrabRelease(SearchResource release) { ValidateResource(release); var releaseInfo = _remoteReleaseCache.Find(GetCacheKey(release)); var indexerDef = _indexerFactory.Get(release.IndexerId); var source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); var host = Request.GetHostName(); try { _downloadService.SendReportToClient(releaseInfo, source, host, indexerDef.Redirect); } catch (ReleaseDownloadException ex) { _logger.Error(ex, "Getting release from indexer failed"); throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed"); } return(Ok(release)); }
public void should_parse_user_agent(string userAgent, string parsedAgent) { UserAgentParser.ParseSource(userAgent).Should().Be(parsedAgent); }
public async Task <IActionResult> GetNewznabResponse(int id, [FromQuery] NewznabRequest request) { var requestType = request.t; request.source = UserAgentParser.ParseSource(Request.Headers["User-Agent"]); request.server = Request.GetServerUrl(); request.host = Request.GetHostName(); if (requestType.IsNullOrWhiteSpace()) { return(Content(CreateErrorXML(200, "Missing parameter (t)"), "application/rss+xml")); } request.imdbid = request.imdbid?.TrimStart('t') ?? null; if (request.imdbid.IsNotNullOrWhiteSpace()) { if (!int.TryParse(request.imdbid, out var imdb) || imdb == 0) { return(Content(CreateErrorXML(201, "Incorrect parameter (imdbid)"), "application/rss+xml")); } } if (id == 0) { switch (requestType) { case "caps": var caps = new IndexerCapabilities { TvSearchParams = new List <TvSearchParam> { TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep }, MovieSearchParams = new List <MovieSearchParam> { MovieSearchParam.Q }, MusicSearchParams = new List <MusicSearchParam> { MusicSearchParam.Q }, BookSearchParams = new List <BookSearchParam> { BookSearchParam.Q } }; foreach (var cat in NewznabStandardCategory.AllCats) { caps.Categories.AddCategoryMapping(1, cat); } return(Content(caps.ToXml(), "application/rss+xml")); case "search": case "tvsearch": case "music": case "book": case "movie": var results = new NewznabResults(); results.Releases = new List <ReleaseInfo> { new ReleaseInfo { Title = "Test Release", Guid = "https://prowlarr.com", DownloadUrl = "https://prowlarr.com", PublishDate = DateTime.Now } }; return(Content(results.ToXml(DownloadProtocol.Usenet), "application/rss+xml")); } } var indexerDef = _indexerFactory.Get(id); if (indexerDef == null) { throw new NotFoundException("Indexer Not Found"); } var indexer = _indexerFactory.GetInstance(indexerDef); //TODO Optimize this so it's not called here and in NzbSearchService (for manual search) if (_indexerLimitService.AtQueryLimit(indexerDef)) { return(Content(CreateErrorXML(500, $"Request limit reached ({((IIndexerSettings)indexer.Definition.Settings).BaseSettings.QueryLimit})"), "application/rss+xml")); } switch (requestType) { case "caps": var caps = indexer.GetCapabilities(); return(Content(caps.ToXml(), "application/rss+xml")); case "search": case "tvsearch": case "music": case "book": case "movie": var results = await _nzbSearchService.Search(request, new List <int> { indexerDef.Id }, false); foreach (var result in results.Releases) { result.DownloadUrl = result.DownloadUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(result.DownloadUrl), request.server, indexerDef.Id, result.Title).AbsoluteUri : null; if (result.DownloadProtocol == DownloadProtocol.Torrent) { ((TorrentInfo)result).MagnetUrl = ((TorrentInfo)result).MagnetUrl.IsNotNullOrWhiteSpace() ? _downloadMappingService.ConvertToProxyLink(new Uri(((TorrentInfo)result).MagnetUrl), request.server, indexerDef.Id, result.Title).AbsoluteUri : null; } } return(Content(results.ToXml(indexer.Protocol), "application/rss+xml")); default: return(Content(CreateErrorXML(202, $"No such function ({requestType})"), "application/rss+xml")); } }