using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; using System.Net; 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 Newtonsoft.Json.Linq; using NLog; using WebClient = Jackett.Common.Utils.Clients.WebClient; namespace Jackett.Common.Indexers { [ExcludeFromCodeCoverage] public class Magnetico : BaseWebIndexer { private string SearchURl => SiteLink + "api/v0.1/torrents"; private string TorrentsUrl => SiteLink + "torrents"; private new ConfigurationDataBasicLogin configData => (ConfigurationDataBasicLogin)base.configData; public Magnetico(IIndexerConfigurationService configService, WebClient wc, Logger l, IProtectionService ps, ICacheService cs) : base(id: "magnetico", name: "Magnetico (Local DHT)", description: "Magnetico is a self-hosted BitTorrent DHT search engine", link: "http://127.0.0.1:8080/", caps: new TorznabCapabilities { TvSearchParams = new List { TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep }, MovieSearchParams = new List { MovieSearchParam.Q }, MusicSearchParams = new List { MusicSearchParam.Q }, BookSearchParams = new List { BookSearchParam.Q } }, configService: configService, client: wc, logger: l, p: ps, cacheService: cs, configData: new ConfigurationDataBasicLogin("Configure the URL, username and password from your local magneticow.
" + "Default credentials are: username=username, password=password.
" + "If you have many torrents, it is recommended to use PostgreSQL database to make queries faster. With SQLite, timeouts may occur.")) { Encoding = Encoding.UTF8; Language = "en-US"; Type = "semi-private"; var sort = new ConfigurationData.SingleSelectConfigurationItem("Sort requested from site", new Dictionary { {"DISCOVERED_ON", "discovered"}, {"TOTAL_SIZE", "size"}, {"N_FILES", "files"}, {"RELEVANCE", "relevance"} }) { Value = "discovered" }; configData.AddDynamic("sort", sort); var order = new ConfigurationData.SingleSelectConfigurationItem("Order requested from site", new Dictionary { {"false", "desc"}, {"true", "asc"} }) { Value = "false" }; configData.AddDynamic("order", order); AddCategoryMapping("1", TorznabCatType.Other); } public override async Task ApplyConfiguration(JToken configJson) { LoadValuesFromJson(configJson); await PerformQuery(new TorznabQuery()); // throws exception if there is an error IsConfigured = true; SaveConfig(); return IndexerConfigurationStatus.Completed; } protected override async Task> PerformQuery(TorznabQuery query) { var releases = new List(); var qc = new NameValueCollection { {"query", query.GetQueryString()}, {"orderBy", ((ConfigurationData.SingleSelectConfigurationItem)configData.GetDynamic("sort")).Value}, {"ascending", ((ConfigurationData.SingleSelectConfigurationItem)configData.GetDynamic("order")).Value}, {"limit", "100"} }; var searchUrl = SearchURl + "?" + qc.GetQueryString(); var results = await RequestWithCookiesAsync(searchUrl, headers: GetAuthorizationHeaders()); if (results.Status != HttpStatusCode.OK) throw new Exception($"Error code: {results.Status}"); try { var torrents = JArray.Parse(results.ContentString).ToObject>(); foreach (var torrent in torrents) { var details = new Uri($"{TorrentsUrl}/{torrent.infoHash}"); var publishDate = DateTimeUtil.UnixTimestampToDateTime(torrent.discoveredOn); var release = new ReleaseInfo { Title = torrent.name, Details = new Uri($"{TorrentsUrl}/{torrent.infoHash}"), Guid = details, InfoHash = torrent.infoHash, PublishDate = publishDate, Category = new List { TorznabCatType.Other.ID }, Size = torrent.size, Files = torrent.nFiles, Seeders = 1, Peers = 1, DownloadVolumeFactor = 0, UploadVolumeFactor = 1 }; releases.Add(release); } } catch (Exception ex) { OnParseError(results.ContentString, ex); } return releases; } private Dictionary GetAuthorizationHeaders() { var username = configData.Username.Value; var password = configData.Password.Value; var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password)); var headers = new Dictionary { {"Authorization", "Basic " + encoded} }; return headers; } private class Torrent { public string infoHash { get; set; } public long id { get; set; } public string name { get; set; } public long size { get; set; } public long discoveredOn { get; set; } public long nFiles { get; set; } public long relevance { get; set; } } } }