public async Task TestIndexer(string name) { var indexer = GetIndexer(name); var browseQuery = new TorznabQuery(); var results = await indexer.PerformQuery(browseQuery); results = indexer.CleanLinks(results); logger.Info(string.Format("Found {0} releases from {1}", results.Count(), indexer.DisplayName)); if (results.Count() == 0) { throw new Exception("Found no results while trying to browse this tracker"); } cacheService.CacheRssResults(indexer, results); }
public async Task TestIndexer(string name) { var indexer = GetIndexer(name); var browseQuery = new TorznabQuery(); browseQuery.QueryType = "search"; browseQuery.SearchTerm = ""; browseQuery.IsTest = true; var result = await indexer.ResultsForQuery(browseQuery); logger.Info(string.Format("Found {0} releases from {1}", result.Releases.Count(), indexer.DisplayName)); if (result.Releases.Count() == 0) { throw new Exception("Found no results while trying to browse this tracker"); } cacheService.CacheRssResults(indexer, result.Releases); }
public async Task TestIndexer(string name) { var indexer = GetIndexer(name); var browseQuery = new TorznabQuery { QueryType = "search", SearchTerm = "", IsTest = true }; var result = await indexer.ResultsForQuery(browseQuery); logger.Info($"Found {result.Releases.Count()} releases from {indexer.DisplayName}"); if (!result.Releases.Any()) { throw new Exception("Found no results while trying to browse this tracker"); } cacheService.CacheRssResults(indexer, result.Releases); }
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/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.")); } if (torznabQuery.ImdbID != null) { if (torznabQuery.QueryType != "movie") { logger.Warn(string.Format("A non movie request with an imdbid was made from {0}.", Request.GetOwinContext().Request.RemoteIpAddress)); return(GetErrorXML(201, "Incorrect parameter: only movie-search supports the imdbid parameter")); } if (!string.IsNullOrEmpty(torznabQuery.SearchTerm)) { logger.Warn(string.Format("A movie-search request from {0} was made contining q and imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); return(GetErrorXML(201, "Incorrect parameter: please specify either imdbid or q")); } torznabQuery.ImdbID = ParseUtil.GetFullImdbID(torznabQuery.ImdbID); // normalize ImdbID if (torznabQuery.ImdbID == null) { logger.Warn(string.Format("A movie-search request from {0} was made with an invalid imdbid.", Request.GetOwinContext().Request.RemoteIpAddress)); return(GetErrorXML(201, "Incorrect parameter: invalid imdbid format")); } if (!indexer.TorznabCaps.SupportsImdbSearch) { logger.Warn(string.Format("A movie-search request with imdbid from {0} was made but the indexer {1} doesn't support it.", Request.GetOwinContext().Request.RemoteIpAddress, indexer.DisplayName)); return(GetErrorXML(203, "Function Not Available: imdbid is not supported by this indexer")); } } 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.Where(r => r.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}{3}", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port, serverService.BasePath()); 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, "dl", result.Title + ".torrent"); 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") }); }
public ManualSearchResult Search([FromBody] AdminSearch value) { var results = new List <TrackerCacheResult>(); var query = new TorznabQuery() { SearchTerm = value.Query, Categories = value.Category == 0 ? new int[0] : new int[1] { value.Category } }; query.ExpandCatsToSubCats(); var trackers = indexerService.GetAllIndexers().Where(t => t.IsConfigured).ToList(); if (!string.IsNullOrWhiteSpace(value.Tracker)) { trackers = trackers.Where(t => t.ID == value.Tracker).ToList(); } if (value.Category != 0) { trackers = trackers.Where(t => t.TorznabCaps.Categories.Select(c => c.ID).Contains(value.Category)).ToList(); } Parallel.ForEach(trackers.ToList(), indexer => { try { var searchResults = indexer.PerformQuery(query).Result; searchResults = indexer.CleanLinks(searchResults); cacheService.CacheRssResults(indexer, searchResults); searchResults = indexer.FilterResults(query, searchResults); lock (results) { foreach (var result in searchResults) { var item = Mapper.Map <TrackerCacheResult>(result); item.Tracker = indexer.DisplayName; item.TrackerId = indexer.ID; item.Peers = item.Peers - item.Seeders; // Use peers as leechers results.Add(item); } } } catch (Exception e) { logger.Error(e, "An error occured during manual search on " + indexer.DisplayName + ": " + e.Message); } }); ConfigureCacheResults(results); if (trackers.Count > 1) { results = results.OrderByDescending(d => d.PublishDate).ToList(); } var manualResult = new ManualSearchResult() { Results = results, Indexers = trackers.Select(t => t.DisplayName).ToList() }; if (manualResult.Indexers.Count == 0) { manualResult.Indexers = new List <string>() { "None" } } ; logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", query.GetQueryString(), string.Join(", ", manualResult.Indexers), manualResult.Results.Count)); return(manualResult); } }
public async Task <IActionResult> Results([FromQuery] ApiSearch requestt) { //TODO: Better way to parse querystring ApiSearch request = new ApiSearch(); foreach (var t in Request.Query) { if (t.Key == "Tracker[]") { request.Tracker = t.Value.ToString().Split(','); } if (t.Key == "Category[]") { request.Category = t.Value.ToString().Split(',').Select(Int32.Parse).ToArray(); } if (t.Key == "query") { request.Query = t.Value.ToString(); } } var manualResult = new ManualSearchResult(); var trackers = IndexerService.GetAllIndexers().ToList().Where(t => t.IsConfigured); if (request.Tracker != null) { trackers = trackers.Where(t => request.Tracker.Contains(t.ID)); } trackers = trackers.Where(t => t.CanHandleQuery(CurrentQuery)); var tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList(); try { var aggregateTask = Task.WhenAll(tasks); await aggregateTask; } catch (AggregateException aex) { foreach (var ex in aex.InnerExceptions) { logger.Error(ex); } } catch (Exception ex) { logger.Error(ex); } manualResult.Indexers = tasks.Select(t => { var resultIndexer = new ManualSearchResultIndexer(); IIndexer indexer = null; if (t.Status == TaskStatus.RanToCompletion) { resultIndexer.Status = ManualSearchResultIndexerStatus.OK; resultIndexer.Results = t.Result.Releases.Count(); resultIndexer.Error = null; indexer = t.Result.Indexer; } else if (t.Exception.InnerException is IndexerException) { resultIndexer.Status = ManualSearchResultIndexerStatus.Error; resultIndexer.Results = 0; resultIndexer.Error = ((IndexerException)t.Exception.InnerException).ToString(); indexer = ((IndexerException)t.Exception.InnerException).Indexer; } else { resultIndexer.Status = ManualSearchResultIndexerStatus.Unknown; resultIndexer.Results = 0; resultIndexer.Error = null; } if (indexer != null) { resultIndexer.ID = indexer.ID; resultIndexer.Name = indexer.DisplayName; } return(resultIndexer); }).ToList(); manualResult.Results = tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Where(t => t.Result.Releases.Any()).SelectMany(t => { var searchResults = t.Result.Releases; var indexer = t.Result.Indexer; cacheService.CacheRssResults(indexer, searchResults); return(searchResults.Select(result => { var item = AutoMapper.Mapper.Map <TrackerCacheResult>(result); item.Tracker = indexer.DisplayName; item.TrackerId = indexer.ID; item.Peers = item.Peers - item.Seeders; // Use peers as leechers return item; })); }).OrderByDescending(d => d.PublishDate).ToList(); ConfigureCacheResults(manualResult.Results); logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", CurrentQuery.SanitizedSearchTerm, string.Join(", ", manualResult.Indexers.Select(i => i.ID)), manualResult.Results.Count())); return(Json(manualResult)); }
public async Task <HttpResponseMessage> Call(string indexerID, [FromUri] TorrentPotatoRequest request) { var indexer = indexerService.GetIndexer(indexerID); var allowBadApiDueToDebug = false; #if DEBUG allowBadApiDueToDebug = Debugger.IsAttached; #endif if (!allowBadApiDueToDebug && !string.Equals(request.passkey, 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.")); } if (!indexer.TorznabCaps.Categories.Select(c => c.ID).Any(i => MOVIE_CATS.Contains(i))) { logger.Warn(string.Format("Rejected a request to {0} which does not support searching for movies.", indexer.DisplayName)); return(Request.CreateResponse(HttpStatusCode.Forbidden, "This indexer does not support movies.")); } var year = 0; if (string.IsNullOrWhiteSpace(request.search)) { // We are searching by IMDB id so look up the name var response = await webClient.GetString(new Utils.Clients.WebRequest("http://www.omdbapi.com/?type=movie&i=" + request.imdbid)); if (response.Status == HttpStatusCode.OK) { JObject result = JObject.Parse(response.Content); if (result["Title"] != null) { request.search = result["Title"].ToString(); year = ParseUtil.CoerceInt(result["Year"].ToString()); } } } var torznabQuery = new TorznabQuery() { ApiKey = request.passkey, Categories = MOVIE_CATS, SearchTerm = request.search }; IEnumerable <ReleaseInfo> releases = new List <ReleaseInfo>(); if (!string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { releases = await indexer.PerformQuery(torznabQuery); releases = indexer.CleanLinks(releases); } // Cache non query results if (string.IsNullOrEmpty(torznabQuery.SanitizedSearchTerm)) { cacheService.CacheRssResults(indexer, releases); } releases = indexer.FilterResults(torznabQuery, releases); var serverUrl = string.Format("{0}://{1}:{2}/", Request.RequestUri.Scheme, Request.RequestUri.Host, Request.RequestUri.Port); var potatoResponse = new TorrentPotatoResponse(); releases = TorznabUtil.FilterResultsToTitle(releases, torznabQuery.SanitizedSearchTerm, year); releases = TorznabUtil.FilterResultsToImdb(releases, request.imdbid); foreach (var r in releases) { var release = Mapper.Map <ReleaseInfo>(r); release.Link = serverService.ConvertToProxyLink(release.Link, serverUrl, indexerID); // Only accept torrent links, magnet is not supported if (release.Link != null) { potatoResponse.results.Add(new TorrentPotatoResponseItem() { release_name = release.Title + "[" + indexer.DisplayName + "]", // Suffix the indexer so we can see which tracker we are using in CPS as it just says torrentpotato >.> torrent_id = release.Guid.ToString(), details_url = release.Comments.ToString(), download_url = release.Link.ToString(), imdb_id = release.Imdb.HasValue ? "tt" + release.Imdb : null, freeleech = false, type = "movie", size = (long)release.Size / (1024 * 1024), // This is in MB leechers = (int)release.Peers - (int)release.Seeders, seeders = (int)release.Seeders }); } } // Log info if (string.IsNullOrWhiteSpace(torznabQuery.SanitizedSearchTerm)) { logger.Info(string.Format("Found {0} torrentpotato releases from {1}", releases.Count(), indexer.DisplayName)); } else { logger.Info(string.Format("Found {0} torrentpotato releases from {1} for: {2}", releases.Count(), indexer.DisplayName, torznabQuery.GetQueryString())); } // Force the return as Json return(new HttpResponseMessage() { Content = new JsonContent(potatoResponse) }); }
public ManualSearchResult Search([FromBody] AdminSearch value) { var results = new List <TrackerCacheResult>(); var stringQuery = new TorznabQuery(); var queryStr = value.Query; if (queryStr != null) { var seasonMatch = Regex.Match(queryStr, @"S(\d{2,4})"); if (seasonMatch.Success) { stringQuery.Season = int.Parse(seasonMatch.Groups[1].Value); queryStr = queryStr.Remove(seasonMatch.Index, seasonMatch.Length); } var episodeMatch = Regex.Match(queryStr, @"E(\d{2,4})"); if (episodeMatch.Success) { stringQuery.Episode = episodeMatch.Groups[1].Value; queryStr = queryStr.Remove(episodeMatch.Index, episodeMatch.Length); } queryStr = queryStr.Trim(); } stringQuery.SearchTerm = queryStr; stringQuery.Categories = value.Category == 0 ? new int[0] : new int[1] { value.Category }; stringQuery.ExpandCatsToSubCats(); // try to build an IMDB Query var imdbID = ParseUtil.GetFullImdbID(stringQuery.SanitizedSearchTerm); TorznabQuery imdbQuery = null; if (imdbID != null) { imdbQuery = new TorznabQuery() { ImdbID = imdbID, Categories = stringQuery.Categories, Season = stringQuery.Season, Episode = stringQuery.Episode, }; imdbQuery.ExpandCatsToSubCats(); } var trackers = indexerService.GetAllIndexers().Where(t => t.IsConfigured).ToList(); if (!string.IsNullOrWhiteSpace(value.Tracker)) { trackers = trackers.Where(t => t.ID == value.Tracker).ToList(); } if (value.Category != 0) { trackers = trackers.Where(t => t.TorznabCaps.Categories.Select(c => c.ID).Contains(value.Category)).ToList(); } Parallel.ForEach(trackers.ToList(), indexer => { try { var query = stringQuery; // use imdb Query for trackers which support it if (imdbQuery != null && indexer.TorznabCaps.SupportsImdbSearch) { query = imdbQuery; } var searchResults = indexer.PerformQuery(query).Result; searchResults = indexer.CleanLinks(searchResults); cacheService.CacheRssResults(indexer, searchResults); searchResults = indexer.FilterResults(query, searchResults); lock (results) { foreach (var result in searchResults) { var item = Mapper.Map <TrackerCacheResult>(result); item.Tracker = indexer.DisplayName; item.TrackerId = indexer.ID; item.Peers = item.Peers - item.Seeders; // Use peers as leechers results.Add(item); } } } catch (Exception e) { logger.Error(e, "An error occured during manual search on " + indexer.DisplayName + ": " + e.Message); } }); ConfigureCacheResults(results); if (trackers.Count > 1) { results = results.OrderByDescending(d => d.PublishDate).ToList(); } var manualResult = new ManualSearchResult() { Results = results, Indexers = trackers.Select(t => t.DisplayName).ToList() }; if (manualResult.Indexers.Count == 0) { manualResult.Indexers = new List <string>() { "None" } } ; logger.Info(string.Format("Manual search for \"{0}\" on {1} with {2} results.", stringQuery.GetQueryString(), string.Join(", ", manualResult.Indexers), manualResult.Results.Count)); return(manualResult); } }