using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Jackett.Common.Models; using Jackett.Common.Models.IndexerConfig; using Jackett.Common.Services.Interfaces; using Jackett.Common.Utils; using Jackett.Common.Utils.Clients; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; namespace Jackett.Common.Indexers { public class BroadcastTheNet : BaseWebIndexer { // Docs at http://apidocs.broadcasthe.net/docs.php private string APIBASE = "https://api.broadcasthe.net"; private new ConfigurationDataAPIKey configData { get { return (ConfigurationDataAPIKey)base.configData; } set { base.configData = value; } } public BroadcastTheNet(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps) : base(name: "BroadcastTheNet", description: "Broadcasthe.net (BTN) is an invite-only torrent tracker focused on TV shows", link: "https://broadcasthe.net/", caps: new TorznabCapabilities(), configService: configService, client: wc, logger: l, p: ps, configData: new ConfigurationDataAPIKey()) { Encoding = Encoding.UTF8; Language = "en-us"; Type = "private"; TorznabCaps.LimitsDefault = 100; TorznabCaps.LimitsMax = 1000; AddCategoryMapping("SD", TorznabCatType.TVSD, "SD"); AddCategoryMapping("720p", TorznabCatType.TVHD, "720p"); AddCategoryMapping("1080p", TorznabCatType.TVHD, "1080p"); AddCategoryMapping("1080i", TorznabCatType.TVHD, "1080i"); AddCategoryMapping("2160p", TorznabCatType.TVHD, "2160p"); AddCategoryMapping("Portable Device", TorznabCatType.TVSD, "Portable Device"); } public override async Task ApplyConfiguration(JToken configJson) { LoadValuesFromJson(configJson); IsConfigured = false; try { var results = await PerformQuery(new TorznabQuery()); if (results.Count() == 0) throw new Exception("Testing returned no results!"); IsConfigured = true; SaveConfig(); } catch (Exception e) { throw new ExceptionWithConfigData(e.Message, configData); } return IndexerConfigurationStatus.Completed; } private string JsonRPCRequest(string method, JArray parameters) { dynamic request = new JObject(); request["jsonrpc"] = "2.0"; request["method"] = method; request["params"] = parameters; request["id"] = Guid.NewGuid().ToString().Substring(0, 8); return request.ToString(); } protected override async Task> PerformQuery(TorznabQuery query) { var searchString = query.GetQueryString(); var btnResults = query.Limit; if (btnResults == 0) btnResults = (int)TorznabCaps.LimitsDefault; var btnOffset = query.Offset; var releases = new List(); var parameters = new JArray(); parameters.Add(new JValue(configData.Key.Value)); parameters.Add(new JValue(searchString.Trim())); parameters.Add(new JValue(btnResults)); parameters.Add(new JValue(btnOffset)); var response = await PostDataWithCookiesAndRetry(APIBASE, null, null, null, new Dictionary() { { "Accept", "application/json-rpc, application/json"}, {"Content-Type", "application/json-rpc"} }, JsonRPCRequest("getTorrents", parameters), false); try { var btnResponse = JsonConvert.DeserializeObject(response.Content); if (btnResponse != null && btnResponse.Result != null && btnResponse.Result.Torrents != null) { foreach (var itemKey in btnResponse.Result.Torrents) { var descriptions = new List(); var btnResult = itemKey.Value; var item = new ReleaseInfo(); if (!string.IsNullOrEmpty(btnResult.SeriesBanner)) item.BannerUrl = new Uri(btnResult.SeriesBanner); item.Category = MapTrackerCatToNewznab(btnResult.Resolution); if (item.Category.Count == 0) // default to TV item.Category.Add(TorznabCatType.TV.ID); item.Comments = new Uri($"{SiteLink}torrents.php?id={btnResult.GroupID}&torrentid={btnResult.TorrentID}"); item.Guid = new Uri(btnResult.DownloadURL); if (!string.IsNullOrWhiteSpace(btnResult.ImdbID)) item.Imdb = ParseUtil.CoerceLong(btnResult.ImdbID); item.Link = new Uri(btnResult.DownloadURL); item.MinimumRatio = 1; item.PublishDate = DateTimeUtil.UnixTimestampToDateTime(btnResult.Time); item.RageID = btnResult.TvrageID; item.Seeders = btnResult.Seeders; item.Peers = btnResult.Seeders + btnResult.Leechers; item.Size = btnResult.Size; item.TVDBId = btnResult.TvdbID; item.Title = btnResult.ReleaseName; item.UploadVolumeFactor = 1; item.DownloadVolumeFactor = 0; // ratioless item.Grabs = btnResult.Snatched; if (!string.IsNullOrWhiteSpace(btnResult.Series)) descriptions.Add("Series: " + btnResult.Series); if (!string.IsNullOrWhiteSpace(btnResult.GroupName)) descriptions.Add("Group Name: " + btnResult.GroupName); if (!string.IsNullOrWhiteSpace(btnResult.Source)) descriptions.Add("Source: " + btnResult.Source); if (!string.IsNullOrWhiteSpace(btnResult.Container)) descriptions.Add("Container: " + btnResult.Container); if (!string.IsNullOrWhiteSpace(btnResult.Codec)) descriptions.Add("Codec: " + btnResult.Codec); if (!string.IsNullOrWhiteSpace(btnResult.Resolution)) descriptions.Add("Resolution: " + btnResult.Resolution); if (!string.IsNullOrWhiteSpace(btnResult.Origin)) descriptions.Add("Origin: " + btnResult.Origin); if (!string.IsNullOrWhiteSpace(btnResult.Series)) descriptions.Add("Youtube Trailer: " + btnResult.YoutubeTrailer + ""); item.Description = string.Join("
\n", descriptions); releases.Add(item); } } } catch (Exception ex) { OnParseError(response.Content, ex); } return releases; } public class BTNRPCResponse { public string Id { get; set; } public BTNResultPage Result { get; set; } } public class BTNResultPage { public Dictionary Torrents { get; set; } } public class BTNResultItem { public int TorrentID { get; set; } public string DownloadURL { get; set; } public string GroupName { get; set; } public int GroupID { get; set; } public int SeriesID { get; set; } public string Series { get; set; } public string SeriesBanner { get; set; } public string SeriesPoster { get; set; } public string YoutubeTrailer { get; set; } public string Category { get; set; } public int? Snatched { get; set; } public int? Seeders { get; set; } public int? Leechers { get; set; } public string Source { get; set; } public string Container { get; set; } public string Codec { get; set; } public string Resolution { get; set; } public string Origin { get; set; } public string ReleaseName { get; set; } public long Size { get; set; } public long Time { get; set; } public int? TvdbID { get; set; } public int? TvrageID { get; set; } public string ImdbID { get; set; } public string InfoHash { get; set; } } } }