From f5592d04e2d749f8387341edf080c4dc5c8fc0b1 Mon Sep 17 00:00:00 2001 From: Ben Houshmand Date: Sat, 22 Jul 2017 19:12:12 -0400 Subject: [PATCH] Added yts.ag as an indexer. (#1579) --- src/Jackett/Indexers/yts.cs | 220 ++++++++++++++++++++++++++++++++++++ src/Jackett/Jackett.csproj | 3 +- 2 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 src/Jackett/Indexers/yts.cs diff --git a/src/Jackett/Indexers/yts.cs b/src/Jackett/Indexers/yts.cs new file mode 100644 index 000000000..bd9220908 --- /dev/null +++ b/src/Jackett/Indexers/yts.cs @@ -0,0 +1,220 @@ +using Jackett.Models; +using Jackett.Models.IndexerConfig; +using Jackett.Services; +using Jackett.Utils; +using Jackett.Utils.Clients; +using Newtonsoft.Json.Linq; +using NLog; +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using System.Text; +using System.Web; + +namespace Jackett.Indexers +{ + public class Yts : BaseWebIndexer + { + readonly static string defaultSiteLink = "https://yts.ag/"; + + private Uri BaseUri + { + get { return new Uri(configData.Url.Value); } + set { configData.Url.Value = value.ToString(); } + } + + private string ApiEndpoint { get { return BaseUri + "api/v2/list_movies.json"; } } + + new ConfigurationDataUrl configData + { + get { return (ConfigurationDataUrl)base.configData; } + set { base.configData = value; } + } + + public Yts(IIndexerConfigurationService configService, IWebClient wc, Logger l, IProtectionService ps) + : base(name: "YTS", + description: null, + link: "https://yts.ag/", + caps: new TorznabCapabilities(), + configService: configService, + client: wc, + logger: l, + p: ps, + configData: new ConfigurationDataUrl(defaultSiteLink)) + { + Encoding = Encoding.GetEncoding("windows-1252"); + Language = "en-us"; + Type = "public"; + + TorznabCaps.SupportsImdbSearch = true; + + webclient.requestDelay = 2.5; // 0.5 requests per second (2 causes problems) + + AddCategoryMapping(45, TorznabCatType.MoviesHD, "Movies/x264/720"); + AddCategoryMapping(44, TorznabCatType.MoviesHD, "Movies/x264/1080"); + AddCategoryMapping(47, TorznabCatType.Movies3D, "Movies/x264/3D"); + } + + public override async Task ApplyConfiguration(JToken configJson) + { + configData.LoadValuesFromJson(configJson); + var releases = await PerformQuery(new TorznabQuery()); + + await ConfigureIfOK(string.Empty, releases.Count() > 0, () => + { + throw new Exception("Could not find releases from this URL"); + }); + + return IndexerConfigurationStatus.Completed; + } + + protected override async Task> PerformQuery(TorznabQuery query) + { + return await PerformQuery(query, 0); + } + + public async Task> PerformQuery(TorznabQuery query, int attempts) + { + var releases = new List(); + var searchString = query.GetQueryString(); + + var queryCollection = new NameValueCollection(); + + if (query.ImdbID != null) + { + queryCollection.Add("query_term", query.ImdbID); + } + else if (!string.IsNullOrWhiteSpace(searchString)) + { + searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model) + queryCollection.Add("query_term", searchString); + } + + // This API does not seem to be working for quality=720p or quality=1080p + // Only quality=3D seems to return a proper result? + //var cats = string.Join(";", MapTorznabCapsToTrackers(query)); + //if (!string.IsNullOrEmpty(cats)) + //{ + // if (cats == "45") + // { + // queryCollection.Add("quality", "720p"); + // } + // if (cats == "44") + // { + // queryCollection.Add("quality", "1080p"); + // } + // if (cats == "2050") + // { + // queryCollection.Add("quality", "3D"); + // } + //} + + var searchUrl = ApiEndpoint + "?" + queryCollection.GetQueryString(); + var response = await RequestStringWithCookiesAndRetry(searchUrl, string.Empty); + + try + { + var jsonContent = JObject.Parse(response.Content); + + string result = jsonContent.Value("status"); + if (result != "ok") // query was not successful + { + return releases.ToArray(); + } + + var data_items = jsonContent.Value("data"); + int movie_count = data_items.Value("movie_count"); + if (movie_count < 1) // no results found in query + { + return releases.ToArray(); + } + + foreach (var movie_item in data_items.Value("movies")) + { + foreach (var torrent_info in movie_item.Value("torrents")) + { + var release = new ReleaseInfo(); + + // Append the quality to the title because thats how radarr seems to be determining the quality? + release.Title = movie_item.Value("title_long") + " " + torrent_info.Value("quality"); + var imdb = movie_item.Value("imdb_code"); + release.Imdb = ParseUtil.GetImdbID(imdb); + + // API does not provide magnet link, so, construct it + string magnet_uri = "magnet:?xt=urn:btih:" + torrent_info.Value("hash") + + "&dn=" + movie_item.Value("slug") + + "&tr=udp://open.demonii.com:1337/announce" + + "&tr=udp://tracker.openbittorrent.com:80" + + "&tr=udp://tracker.coppersurfer.tk:6969" + + "&tr=udp://glotorrents.pw:6969/announce" + + "&tr=udp://tracker.opentrackr.org:1337/announce" + + "&tr=udp://torrent.gresille.org:80/announce" + + "&tr=udp://p4p.arenabg.com:1337&tr=udp://tracker.leechers-paradise.org:6969"; + + release.MagnetUri = new Uri(magnet_uri); + release.InfoHash = torrent_info.Value("hash"); + + // ex: 2015-08-16 21:25:08 +0000 + var dateStr = torrent_info.Value("date_uploaded"); + var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime(); + release.Link = new Uri(torrent_info.Value("url")); + release.Seeders = torrent_info.Value("seeds"); + release.Peers = torrent_info.Value("peers") + release.Seeders; + release.Size = torrent_info.Value("size_bytes"); + release.DownloadVolumeFactor = 0; + release.UploadVolumeFactor = 1; + + release.Comments = release.Link; + release.Guid = release.Comments; + + // Hack to prevent adding non-specified catogery, since API doesn't seem to be working + string categories = string.Join(";", MapTorznabCapsToTrackers(query)); + + if (!string.IsNullOrEmpty(categories)) + { + if (categories.Contains("45") || categories.Contains("2040")) + { + if (torrent_info.Value("quality") == "720p") + { + release.Category = MapTrackerCatToNewznab("45"); + releases.Add(release); + } + } + if (categories.Contains("44") || categories.Contains("2040")) + { + if (torrent_info.Value("quality") == "1080p") + { + release.Category = MapTrackerCatToNewznab("44"); + releases.Add(release); + } + } + if (categories.Contains("47")) + { + if (torrent_info.Value("quality") == "3D") + { + release.Category = MapTrackerCatToNewznab("47"); + releases.Add(release); + } + } + } + else + { + release.Category = MapTrackerCatToNewznab("45"); + releases.Add(release); + } + } + } + } + catch (Exception ex) + { + OnParseError(response.Content, ex); + } + + return releases; + } + } +} \ No newline at end of file diff --git a/src/Jackett/Jackett.csproj b/src/Jackett/Jackett.csproj index fd9442772..998564ac4 100644 --- a/src/Jackett/Jackett.csproj +++ b/src/Jackett/Jackett.csproj @@ -183,6 +183,7 @@ + @@ -597,4 +598,4 @@ - + \ No newline at end of file