using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Threading.Tasks; using Jackett.Common.Models; using Jackett.Common.Models.IndexerConfig.Bespoke; 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 { [ExcludeFromCodeCoverage] public class MyAnonamouse : IndexerBase { public override string Id => "myanonamouse"; public override string Name => "MyAnonamouse"; public override string Description => "Friendliness, Warmth and Sharing"; public override string SiteLink { get; protected set; } = "https://www.myanonamouse.net/"; public override string Language => "en-US"; public override string Type => "private"; public override bool SupportsPagination => true; public override TorznabCapabilities TorznabCaps => SetCapabilities(); private string SearchUrl => SiteLink + "tor/js/loadSearchJSONbasic.php"; private new ConfigurationDataMyAnonamouse configData => (ConfigurationDataMyAnonamouse)base.configData; public MyAnonamouse(IIndexerConfigurationService configService, WebClient c, Logger l, IProtectionService ps, ICacheService cs) : base(configService: configService, client: c, logger: l, p: ps, cacheService: cs, configData: new ConfigurationDataMyAnonamouse()) { webclient.EmulateBrowser = false; } private TorznabCapabilities SetCapabilities() { var caps = new TorznabCapabilities { BookSearchParams = new List { BookSearchParam.Q } }; caps.Categories.AddCategoryMapping("13", TorznabCatType.AudioAudiobook, "AudioBooks"); caps.Categories.AddCategoryMapping("14", TorznabCatType.BooksEBook, "E-Books"); caps.Categories.AddCategoryMapping("15", TorznabCatType.AudioAudiobook, "Musicology"); caps.Categories.AddCategoryMapping("16", TorznabCatType.AudioAudiobook, "Radio"); caps.Categories.AddCategoryMapping("39", TorznabCatType.AudioAudiobook, "Audiobooks - Action/Adventure"); caps.Categories.AddCategoryMapping("49", TorznabCatType.AudioAudiobook, "Audiobooks - Art"); caps.Categories.AddCategoryMapping("50", TorznabCatType.AudioAudiobook, "Audiobooks - Biographical"); caps.Categories.AddCategoryMapping("83", TorznabCatType.AudioAudiobook, "Audiobooks - Business"); caps.Categories.AddCategoryMapping("51", TorznabCatType.AudioAudiobook, "Audiobooks - Computer/Internet"); caps.Categories.AddCategoryMapping("97", TorznabCatType.AudioAudiobook, "Audiobooks - Crafts"); caps.Categories.AddCategoryMapping("40", TorznabCatType.AudioAudiobook, "Audiobooks - Crime/Thriller"); caps.Categories.AddCategoryMapping("41", TorznabCatType.AudioAudiobook, "Audiobooks - Fantasy"); caps.Categories.AddCategoryMapping("106", TorznabCatType.AudioAudiobook, "Audiobooks - Food"); caps.Categories.AddCategoryMapping("42", TorznabCatType.AudioAudiobook, "Audiobooks - General Fiction"); caps.Categories.AddCategoryMapping("52", TorznabCatType.AudioAudiobook, "Audiobooks - General Non-Fic"); caps.Categories.AddCategoryMapping("98", TorznabCatType.AudioAudiobook, "Audiobooks - Historical Fiction"); caps.Categories.AddCategoryMapping("54", TorznabCatType.AudioAudiobook, "Audiobooks - History"); caps.Categories.AddCategoryMapping("55", TorznabCatType.AudioAudiobook, "Audiobooks - Home/Garden"); caps.Categories.AddCategoryMapping("43", TorznabCatType.AudioAudiobook, "Audiobooks - Horror"); caps.Categories.AddCategoryMapping("99", TorznabCatType.AudioAudiobook, "Audiobooks - Humor"); caps.Categories.AddCategoryMapping("84", TorznabCatType.AudioAudiobook, "Audiobooks - Instructional"); caps.Categories.AddCategoryMapping("44", TorznabCatType.AudioAudiobook, "Audiobooks - Juvenile"); caps.Categories.AddCategoryMapping("56", TorznabCatType.AudioAudiobook, "Audiobooks - Language"); caps.Categories.AddCategoryMapping("45", TorznabCatType.AudioAudiobook, "Audiobooks - Literary Classics"); caps.Categories.AddCategoryMapping("57", TorznabCatType.AudioAudiobook, "Audiobooks - Math/Science/Tech"); caps.Categories.AddCategoryMapping("85", TorznabCatType.AudioAudiobook, "Audiobooks - Medical"); caps.Categories.AddCategoryMapping("87", TorznabCatType.AudioAudiobook, "Audiobooks - Mystery"); caps.Categories.AddCategoryMapping("119", TorznabCatType.AudioAudiobook, "Audiobooks - Nature"); caps.Categories.AddCategoryMapping("88", TorznabCatType.AudioAudiobook, "Audiobooks - Philosophy"); caps.Categories.AddCategoryMapping("58", TorznabCatType.AudioAudiobook, "Audiobooks - Pol/Soc/Relig"); caps.Categories.AddCategoryMapping("59", TorznabCatType.AudioAudiobook, "Audiobooks - Recreation"); caps.Categories.AddCategoryMapping("46", TorznabCatType.AudioAudiobook, "Audiobooks - Romance"); caps.Categories.AddCategoryMapping("47", TorznabCatType.AudioAudiobook, "Audiobooks - Science Fiction"); caps.Categories.AddCategoryMapping("53", TorznabCatType.AudioAudiobook, "Audiobooks - Self-Help"); caps.Categories.AddCategoryMapping("89", TorznabCatType.AudioAudiobook, "Audiobooks - Travel/Adventure"); caps.Categories.AddCategoryMapping("100", TorznabCatType.AudioAudiobook, "Audiobooks - True Crime"); caps.Categories.AddCategoryMapping("108", TorznabCatType.AudioAudiobook, "Audiobooks - Urban Fantasy"); caps.Categories.AddCategoryMapping("48", TorznabCatType.AudioAudiobook, "Audiobooks - Western"); caps.Categories.AddCategoryMapping("111", TorznabCatType.AudioAudiobook, "Audiobooks - Young Adult"); caps.Categories.AddCategoryMapping("60", TorznabCatType.BooksEBook, "Ebooks - Action/Adventure"); caps.Categories.AddCategoryMapping("71", TorznabCatType.BooksEBook, "Ebooks - Art"); caps.Categories.AddCategoryMapping("72", TorznabCatType.BooksEBook, "Ebooks - Biographical"); caps.Categories.AddCategoryMapping("90", TorznabCatType.BooksEBook, "Ebooks - Business"); caps.Categories.AddCategoryMapping("61", TorznabCatType.BooksComics, "Ebooks - Comics/Graphic novels"); caps.Categories.AddCategoryMapping("73", TorznabCatType.BooksEBook, "Ebooks - Computer/Internet"); caps.Categories.AddCategoryMapping("101", TorznabCatType.BooksEBook, "Ebooks - Crafts"); caps.Categories.AddCategoryMapping("62", TorznabCatType.BooksEBook, "Ebooks - Crime/Thriller"); caps.Categories.AddCategoryMapping("63", TorznabCatType.BooksEBook, "Ebooks - Fantasy"); caps.Categories.AddCategoryMapping("107", TorznabCatType.BooksEBook, "Ebooks - Food"); caps.Categories.AddCategoryMapping("64", TorznabCatType.BooksEBook, "Ebooks - General Fiction"); caps.Categories.AddCategoryMapping("74", TorznabCatType.BooksEBook, "Ebooks - General Non-Fiction"); caps.Categories.AddCategoryMapping("102", TorznabCatType.BooksEBook, "Ebooks - Historical Fiction"); caps.Categories.AddCategoryMapping("76", TorznabCatType.BooksEBook, "Ebooks - History"); caps.Categories.AddCategoryMapping("77", TorznabCatType.BooksEBook, "Ebooks - Home/Garden"); caps.Categories.AddCategoryMapping("65", TorznabCatType.BooksEBook, "Ebooks - Horror"); caps.Categories.AddCategoryMapping("103", TorznabCatType.BooksEBook, "Ebooks - Humor"); caps.Categories.AddCategoryMapping("115", TorznabCatType.BooksEBook, "Ebooks - Illusion/Magic"); caps.Categories.AddCategoryMapping("91", TorznabCatType.BooksEBook, "Ebooks - Instructional"); caps.Categories.AddCategoryMapping("66", TorznabCatType.BooksEBook, "Ebooks - Juvenile"); caps.Categories.AddCategoryMapping("78", TorznabCatType.BooksEBook, "Ebooks - Language"); caps.Categories.AddCategoryMapping("67", TorznabCatType.BooksEBook, "Ebooks - Literary Classics"); caps.Categories.AddCategoryMapping("79", TorznabCatType.BooksMags, "Ebooks - Magazines/Newspapers"); caps.Categories.AddCategoryMapping("80", TorznabCatType.BooksTechnical, "Ebooks - Math/Science/Tech"); caps.Categories.AddCategoryMapping("92", TorznabCatType.BooksEBook, "Ebooks - Medical"); caps.Categories.AddCategoryMapping("118", TorznabCatType.BooksEBook, "Ebooks - Mixed Collections"); caps.Categories.AddCategoryMapping("94", TorznabCatType.BooksEBook, "Ebooks - Mystery"); caps.Categories.AddCategoryMapping("120", TorznabCatType.BooksEBook, "Ebooks - Nature"); caps.Categories.AddCategoryMapping("95", TorznabCatType.BooksEBook, "Ebooks - Philosophy"); caps.Categories.AddCategoryMapping("81", TorznabCatType.BooksEBook, "Ebooks - Pol/Soc/Relig"); caps.Categories.AddCategoryMapping("82", TorznabCatType.BooksEBook, "Ebooks - Recreation"); caps.Categories.AddCategoryMapping("68", TorznabCatType.BooksEBook, "Ebooks - Romance"); caps.Categories.AddCategoryMapping("69", TorznabCatType.BooksEBook, "Ebooks - Science Fiction"); caps.Categories.AddCategoryMapping("75", TorznabCatType.BooksEBook, "Ebooks - Self-Help"); caps.Categories.AddCategoryMapping("96", TorznabCatType.BooksEBook, "Ebooks - Travel/Adventure"); caps.Categories.AddCategoryMapping("104", TorznabCatType.BooksEBook, "Ebooks - True Crime"); caps.Categories.AddCategoryMapping("109", TorznabCatType.BooksEBook, "Ebooks - Urban Fantasy"); caps.Categories.AddCategoryMapping("70", TorznabCatType.BooksEBook, "Ebooks - Western"); caps.Categories.AddCategoryMapping("112", TorznabCatType.BooksEBook, "Ebooks - Young Adult"); caps.Categories.AddCategoryMapping("19", TorznabCatType.AudioAudiobook, "Guitar/Bass Tabs"); caps.Categories.AddCategoryMapping("20", TorznabCatType.AudioAudiobook, "Individual Sheet"); caps.Categories.AddCategoryMapping("24", TorznabCatType.AudioAudiobook, "Individual Sheet MP3"); caps.Categories.AddCategoryMapping("126", TorznabCatType.AudioAudiobook, "Instructional Book with Video"); caps.Categories.AddCategoryMapping("22", TorznabCatType.AudioAudiobook, "Instructional Media - Music"); caps.Categories.AddCategoryMapping("113", TorznabCatType.AudioAudiobook, "Lick Library - LTP/Jam With"); caps.Categories.AddCategoryMapping("114", TorznabCatType.AudioAudiobook, "Lick Library - Techniques/QL"); caps.Categories.AddCategoryMapping("17", TorznabCatType.AudioAudiobook, "Music - Complete Editions"); caps.Categories.AddCategoryMapping("26", TorznabCatType.AudioAudiobook, "Music Book"); caps.Categories.AddCategoryMapping("27", TorznabCatType.AudioAudiobook, "Music Book MP3"); caps.Categories.AddCategoryMapping("30", TorznabCatType.AudioAudiobook, "Sheet Collection"); caps.Categories.AddCategoryMapping("31", TorznabCatType.AudioAudiobook, "Sheet Collection MP3"); caps.Categories.AddCategoryMapping("127", TorznabCatType.AudioAudiobook, "Radio - Comedy"); caps.Categories.AddCategoryMapping("130", TorznabCatType.AudioAudiobook, "Radio - Drama"); caps.Categories.AddCategoryMapping("128", TorznabCatType.AudioAudiobook, "Radio - Factual/Documentary"); caps.Categories.AddCategoryMapping("132", TorznabCatType.AudioAudiobook, "Radio - Reading"); return caps; } public override async Task ApplyConfiguration(JToken configJson) { LoadValuesFromJson(configJson); CookieHeader = "mam_id=" + configData.MamId.Value; try { var results = await PerformQuery(new TorznabQuery()); if (!results.Any()) throw new Exception("Your man_id did not work"); IsConfigured = true; SaveConfig(); return IndexerConfigurationStatus.Completed; } catch (Exception e) { IsConfigured = false; throw new Exception("Your man_id did not work: " + e.Message); } } protected override async Task> PerformQuery(TorznabQuery query) { var limit = query.Limit > 0 ? query.Limit : 100; var offset = query.Offset > 0 ? query.Offset : 0; var qParams = new NameValueCollection { {"tor[text]", query.GetQueryString()}, {"tor[searchType]", configData.SearchType.Value}, {"tor[srchIn][title]", "true"}, {"tor[srchIn][author]", "true"}, {"tor[srchIn][narrator]", "true"}, {"tor[searchIn]", "torrents"}, {"tor[sortType]", "default"}, {"tor[perpage]", limit.ToString()}, {"tor[startNumber]", offset.ToString()}, {"thumbnails", "1"}, // gives links for thumbnail sized versions of their posters {"description", "1"} // include the description }; if (configData.SearchInDescription.Value) qParams.Add("tor[srchIn][description]", "true"); if (configData.SearchInSeries.Value) qParams.Add("tor[srchIn][series]", "true"); if (configData.SearchInFilenames.Value) qParams.Add("tor[srchIn][filenames]", "true"); var catList = MapTorznabCapsToTrackers(query); if (catList.Any()) { var index = 0; foreach (var cat in catList) { qParams.Add("tor[cat][" + index + "]", cat); index++; } } else qParams.Add("tor[cat][]", "0"); var urlSearch = SearchUrl; if (qParams.Count > 0) urlSearch += $"?{qParams.GetQueryString()}"; var response = await RequestWithCookiesAndRetryAsync( urlSearch, headers: new Dictionary { {"Accept", "application/json"} }); if (response.ContentString.StartsWith("Error")) throw new Exception(response.ContentString); var releases = new List(); try { var jsonContent = JObject.Parse(response.ContentString); var sitelink = new Uri(SiteLink); var error = jsonContent.Value("error"); if (error != null && error == "Nothing returned, out of 0") return releases; foreach (var item in jsonContent.Value("data")) { var id = item.Value("id"); var link = new Uri(sitelink, "/tor/download.php?tid=" + id); var details = new Uri(sitelink, "/t/" + id); var release = new ReleaseInfo { Guid = details, Title = item.Value("title").Trim(), Description = item.Value("description").Trim(), Link = link, Details = details, Category = MapTrackerCatToNewznab(item.Value("category")), PublishDate = DateTime.ParseExact(item.Value("added"), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).ToLocalTime(), Grabs = item.Value("times_completed"), Files = item.Value("numfiles"), Seeders = item.Value("seeders"), Peers = item.Value("seeders") + item.Value("leechers"), Size = ParseUtil.GetBytes(item.Value("size")), DownloadVolumeFactor = item.Value("free") ? 0 : 1, UploadVolumeFactor = 1, // MinimumRatio = 1, // global MR is 1.0 but torrents must be seeded for 3 days regardless of ratio MinimumSeedTime = 259200 // 72 hours }; var authorInfo = item.Value("author_info"); if (authorInfo != null) try { var authorInfoList = JsonConvert.DeserializeObject>(authorInfo); var author = authorInfoList?.Take(5).Select(v => v.Value).ToList(); if (author != null && author.Any()) release.Title += " by " + string.Join(", ", author); } catch (Exception) { // the JSON on author_info field can be malformed due to double quotes logger.Warn($"{Name} error parsing author_info: {authorInfo}"); } var flags = new List(); var langCode = item.Value("lang_code"); if (!string.IsNullOrEmpty(langCode)) flags.Add(langCode); var filetype = item.Value("filetype"); if (!string.IsNullOrEmpty(filetype)) flags.Add(filetype.ToUpper()); if (flags.Count > 0) release.Title += " [" + string.Join(" / ", flags) + "]"; if (item.Value("vip")) release.Title += " [VIP]"; releases.Add(release); } } catch (Exception ex) { OnParseError(response.ContentString, ex); } return releases; } } }