From 09d227a845448f1adca88e89a0aa7425ce76c431 Mon Sep 17 00:00:00 2001 From: Audionut Date: Sat, 23 Sep 2023 07:34:47 +0000 Subject: [PATCH] PTP: Added back (#14710) --- README.md | 1 + src/Jackett.Common/Indexers/PassThePopcorn.cs | 277 ++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 src/Jackett.Common/Indexers/PassThePopcorn.cs diff --git a/README.md b/README.md index c97d90749..3f60351d9 100644 --- a/README.md +++ b/README.md @@ -465,6 +465,7 @@ A third-party Golang SDK for Jackett is available from [webtor-io/go-jackett](ht * P2PBG * Panda * Party-Tracker + * PassThePopcorn (PTP) * Peeratiko * Peers.FM * PigNetwork diff --git a/src/Jackett.Common/Indexers/PassThePopcorn.cs b/src/Jackett.Common/Indexers/PassThePopcorn.cs new file mode 100644 index 000000000..ec00fee2a --- /dev/null +++ b/src/Jackett.Common/Indexers/PassThePopcorn.cs @@ -0,0 +1,277 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Jackett.Common.Models; +using Jackett.Common.Models.IndexerConfig; +using Jackett.Common.Services.Interfaces; +using Jackett.Common.Utils; +using Newtonsoft.Json.Linq; +using NLog; + +namespace Jackett.Common.Indexers +{ + [ExcludeFromCodeCoverage] + public class PassThePopcorn : IndexerBase + { + public override string Id => "passthepopcorn"; + public override string Name => "PassThePopcorn"; + public override string Description => "PassThePopcorn is a Private site for MOVIES / TV"; + public override string SiteLink { get; protected set; } = "https://passthepopcorn.me/"; + public override string Language => "en-US"; + public override string Type => "private"; + + public override TorznabCapabilities TorznabCaps => SetCapabilities(); + + private static string SearchUrl => "https://passthepopcorn.me/torrents.php"; + private string AuthKey { get; set; } + private string PassKey { get; set; } + + // TODO: merge ConfigurationDataAPILoginWithUserAndPasskeyAndFilter class with with ConfigurationDataUserPasskey + private new ConfigurationDataAPILoginWithUserAndPasskeyAndFilter configData + { + get => (ConfigurationDataAPILoginWithUserAndPasskeyAndFilter)base.configData; + set => base.configData = value; + } + + public PassThePopcorn(IIndexerConfigurationService configService, Utils.Clients.WebClient c, Logger l, + IProtectionService ps, ICacheService cs) + : base(configService: configService, + client: c, + logger: l, + p: ps, + cacheService: cs, + configData: new ConfigurationDataAPILoginWithUserAndPasskeyAndFilter(@"Enter filter options below to restrict search results. + Separate options with a space if using more than one option.
Filter options available: +
GoldenPopcorn
Scene
Checked
Free")) + { + webclient.requestDelay = 2; // 0.5 requests per second + } + + private TorznabCapabilities SetCapabilities() + { + var caps = new TorznabCapabilities + { + TvSearchParams = new List + { + TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep + }, + MovieSearchParams = new List + { + MovieSearchParam.Q, MovieSearchParam.ImdbId + } + }; + + caps.Categories.AddCategoryMapping(1, TorznabCatType.Movies, "Feature Film"); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesForeign); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesOther); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesSD); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesHD); + caps.Categories.AddCategoryMapping(1, TorznabCatType.Movies3D); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesBluRay); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesDVD); + caps.Categories.AddCategoryMapping(1, TorznabCatType.MoviesWEBDL); + caps.Categories.AddCategoryMapping(2, TorznabCatType.Movies, "Short Film"); + caps.Categories.AddCategoryMapping(3, TorznabCatType.TV, "Miniseries"); + caps.Categories.AddCategoryMapping(4, TorznabCatType.TV, "Stand-up Comedy"); + caps.Categories.AddCategoryMapping(5, TorznabCatType.TV, "Live Performance"); + + return caps; + } + + public override async Task ApplyConfiguration(JToken configJson) + { + LoadValuesFromJson(configJson); + + IsConfigured = false; + try + { + var results = await PerformQuery(new TorznabQuery()); + if (!results.Any()) + throw new Exception("Testing returned no results!"); + IsConfigured = true; + SaveConfig(); + } + catch (Exception e) + { + throw new ExceptionWithConfigData(e.Message, configData); + } + + return IndexerConfigurationStatus.Completed; + } + + protected override async Task> PerformQuery(TorznabQuery query) + { + var releases = new List(); + var configGoldenPopcornOnly = configData.FilterString.Value.ToLowerInvariant().Contains("goldenpopcorn"); + var configSceneOnly = configData.FilterString.Value.ToLowerInvariant().Contains("scene"); + var configCheckedOnly = configData.FilterString.Value.ToLowerInvariant().Contains("checked"); + var configFreeOnly = configData.FilterString.Value.ToLowerInvariant().Contains("free"); + + + var movieListSearchUrl = SearchUrl; + var queryCollection = new NameValueCollection { { "json", "noredirect" } }; + + if (!string.IsNullOrEmpty(query.ImdbID)) + queryCollection.Add("searchstr", query.ImdbID); + else if (!string.IsNullOrEmpty(query.GetQueryString())) + queryCollection.Add("searchstr", query.GetQueryString()); + if (configFreeOnly) + queryCollection.Add("freetorrent", "1"); + + movieListSearchUrl += "?" + queryCollection.GetQueryString(); + + var authHeaders = new Dictionary + { + { "ApiUser", configData.User.Value }, + { "ApiKey", configData.Key.Value } + }; + + var results = await RequestWithCookiesAndRetryAsync(movieListSearchUrl, headers: authHeaders); + if (results.IsRedirect) // untested + results = await RequestWithCookiesAndRetryAsync(movieListSearchUrl, headers: authHeaders); + try + { + //Iterate over the releases for each movie + var jsResults = JObject.Parse(results.ContentString); + + AuthKey = (string)jsResults["AuthKey"]; + PassKey = (string)jsResults["PassKey"]; + + foreach (var movie in jsResults["Movies"]) + { + var movieTitle = (string)movie["Title"]; + var year = (string)movie["Year"]; + var movieImdbIdStr = (string)movie["ImdbId"]; + var posterStr = (string)movie["Cover"]; + var poster = !string.IsNullOrEmpty(posterStr) ? new Uri(posterStr) : null; + var movieImdbId = !string.IsNullOrEmpty(movieImdbIdStr) ? (long?)long.Parse(movieImdbIdStr) : null; + var movieGroupId = (string)movie["GroupId"]; + foreach (var torrent in movie["Torrents"]) + { + var releaseName = (string)torrent["ReleaseName"]; + var torrentId = (string)torrent["Id"]; + + var releaseLinkQuery = new NameValueCollection + { + {"action", "download"}, + {"id", torrentId}, + {"authkey", AuthKey}, + {"torrent_pass", PassKey} + }; + var free = !(torrent["FreeleechType"] is null); + + bool.TryParse((string)torrent["GoldenPopcorn"], out var golden); + bool.TryParse((string)torrent["Scene"], out var scene); + bool.TryParse((string)torrent["Checked"], out var check); + + if (configGoldenPopcornOnly && !golden) + continue; //Skip release if user only wants GoldenPopcorn + if (configSceneOnly && !scene) + continue; //Skip release if user only wants Scene + if (configCheckedOnly && !check) + continue; //Skip release if user only wants Checked + if (configFreeOnly && !free) + continue; + var link = new Uri($"{SearchUrl}?{releaseLinkQuery.GetQueryString()}"); + var seeders = int.Parse((string)torrent["Seeders"]); + var details = new Uri($"{SearchUrl}?id={WebUtility.UrlEncode(movieGroupId)}&torrentid={WebUtility.UrlEncode(torrentId)}"); + var size = long.Parse((string)torrent["Size"]); + var grabs = long.Parse((string)torrent["Snatched"]); + var publishDate = DateTime.ParseExact((string)torrent["UploadTime"], + "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) + .ToLocalTime(); + var leechers = int.Parse((string)torrent["Leechers"]); + var release = new ReleaseInfo + { + Title = releaseName, + Description = $"Title: {movieTitle}", + Poster = poster, + Imdb = movieImdbId, + Details = details, + Size = size, + Grabs = grabs, + Seeders = seeders, + Peers = seeders + leechers, + PublishDate = publishDate, + Link = link, + Guid = link, + MinimumRatio = 1, + MinimumSeedTime = 345600, + DownloadVolumeFactor = free ? 0 : 1, + UploadVolumeFactor = 1, + Category = new List { TorznabCatType.Movies.ID } + }; + + + var titleTags = new List(); + var quality = (string)torrent["Quality"]; + var container = (string)torrent["Container"]; + var codec = (string)torrent["Codec"]; + var resolution = (string)torrent["Resolution"]; + var source = (string)torrent["Source"]; + var otherTags = (string)torrent["RemasterTitle"]; + + if (year != null) + release.Description += $"
\nYear: {year}"; + if (quality != null) + release.Description += $"
\nQuality: {quality}"; + if (resolution != null) + { + titleTags.Add(resolution); + release.Description += $"
\nResolution: {resolution}"; + } + if (source != null) + { + titleTags.Add(source); + release.Description += $"
\nSource: {source}"; + } + if (codec != null) + { + titleTags.Add(codec); + release.Description += $"
\nCodec: {codec}"; + } + if (container != null) + { + titleTags.Add(container); + release.Description += $"
\nContainer: {container}"; + } + if (scene) + { + titleTags.Add("Scene"); + release.Description += "
\nScene"; + } + if (check) + { + titleTags.Add("Checked"); + release.Description += "
\nChecked"; + } + if (golden) + { + titleTags.Add("Golden Popcorn"); + release.Description += "
\nGolden Popcorn"; + } + + if (otherTags != null) + titleTags.Add(otherTags); + + if (titleTags.Any()) + release.Title += " [" + string.Join(" / ", titleTags) + "]"; + + releases.Add(release); + } + } + } + catch (Exception ex) + { + OnParseError(results.ContentString, ex); + } + + return releases; + } + } +}