parent
f87aa820c7
commit
1a71375c3f
@ -0,0 +1,56 @@
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(017)]
|
||||
public class indexer_cleanup : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
//Remove v3 yml transfers
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "Aither" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "Anilibria" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "AnimeWorld" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "LatTeam" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "Blutopia" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "DanishBytes" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "DesiTorrents" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "DigitalCore" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "InternetArchive" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "Milkie" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "ShareIsland" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "SuperBits" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "ThePirateBay" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "TorrentLeech" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "TorrentSeeds" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "TorrentParadiseMI" });
|
||||
Delete.FromTable("Indexers").Row(new { Implementation = "YTS" });
|
||||
|
||||
//Change settings to shared classes
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "Animedia" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "Shizaproject" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "ShowRSS" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "SubsPlease" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "NoAuthTorrentBaseSettings" }).Where(new { Implementation = "TorrentsCSV" });
|
||||
|
||||
//Change settings to shared classes
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "Anidub" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "AnimeTorrents" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "Anthelion" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "BB" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "HDSpace" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "HDTorrents" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "ImmortalSeed" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "RevolutionTT" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "SpeedCD" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "TVVault" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "UserPassTorrentBaseSettings" }).Where(new { Implementation = "ZonaQ" });
|
||||
|
||||
//Change settings to shared classes
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "CookieTorrentBaseSettings" }).Where(new { Implementation = "TorrentDay" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "CookieTorrentBaseSettings" }).Where(new { Implementation = "MoreThanTV" });
|
||||
Update.Table("Indexers").Set(new { ConfigContract = "CookieTorrentBaseSettings" }).Where(new { Implementation = "BitHDTV" });
|
||||
}
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class Aither : Unit3dBase
|
||||
{
|
||||
public override string Name => "Aither";
|
||||
public override string[] IndexerUrls => new string[] { "https://aither.cc/" };
|
||||
public override string Description => "Aither is a Private Torrent Tracker for HD MOVIES / TV";
|
||||
public override string Language => "en-US";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public Aither(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "Games");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXX, "XXX");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVSport, "Sport");
|
||||
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.PC, "Software/Apps");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.BooksEBook, "Ebooks/Magazines");
|
||||
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.AudioAudiobook, "AudioBooks");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.Other, "Education");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class AnimeWorld : Unit3dBase
|
||||
{
|
||||
public override string Name => "AnimeWorld";
|
||||
public override string[] IndexerUrls => new string[] { "https://animeworld.cx/" };
|
||||
public override string Description => "AnimeWorld (AW) is a GERMAN Private site for ANIME / MANGA / HENTAI";
|
||||
public override string Language => "de-DE";
|
||||
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public AnimeWorld(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Anime Movie");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TVAnime, "Anime Series");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Anime Musik/OST");
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.PCGames, "Anime Spiele");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.XXX, "Anime Hentai");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Software");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.Other, "Sonstiges");
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.Movies, "Filme");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TV, "Serien");
|
||||
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.PCGames, "Spiele");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Audio, "Musik");
|
||||
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.BooksComics, "Mangas");
|
||||
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Movies, "Cartoon Filme");
|
||||
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TV, "Cartoon Serie");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.XXX, "H-Manga / Doujinshi");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class Blutopia : Unit3dBase
|
||||
{
|
||||
public override string Name => "Blutopia";
|
||||
public override string[] IndexerUrls => new string[] { "https://blutopia.xyz/" };
|
||||
public override string Description => "Blutopia (BLU) is a Private Torrent Tracker for HD MOVIES / TV";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public Blutopia(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV Show");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesOther, "FANRES");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.MoviesOther, "Trailer");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,342 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML")]
|
||||
public class DanishBytes : TorrentIndexerBase<DanishBytesSettings>
|
||||
{
|
||||
public override string Name => "DanishBytes";
|
||||
public override string[] IndexerUrls => new string[] { "https://danishbytes.club/", "https://danishbytes2.org/" };
|
||||
public override string Description => "DanishBytes is a Private Danish Tracker";
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public DanishBytes(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new DanishBytesRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new DanishBytesParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping("1", NewznabStandardCategory.Movies, "Movies");
|
||||
caps.Categories.AddCategoryMapping("2", NewznabStandardCategory.TV, "TV");
|
||||
caps.Categories.AddCategoryMapping("3", NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping("4", NewznabStandardCategory.PCGames, "Games");
|
||||
caps.Categories.AddCategoryMapping("5", NewznabStandardCategory.PC0day, "Appz");
|
||||
caps.Categories.AddCategoryMapping("8", NewznabStandardCategory.Books, "Bookz");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class DanishBytesRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public DanishBytesSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public DanishBytesRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null, int tmdbId = 0, int tvdbId = 0)
|
||||
{
|
||||
var qc = new NameValueCollection
|
||||
{
|
||||
{ "search", term },
|
||||
{ "api_token", Settings.ApiKey },
|
||||
};
|
||||
|
||||
if (imdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
qc.Add("imdb", imdbId);
|
||||
}
|
||||
|
||||
if (tmdbId > 0)
|
||||
{
|
||||
qc.Add("tmdb", tmdbId.ToString());
|
||||
}
|
||||
|
||||
if (tvdbId > 0)
|
||||
{
|
||||
qc.Add("tvdb", tvdbId.ToString());
|
||||
}
|
||||
|
||||
var searchUrl = string.Format("{0}/api/torrents/v2/filter?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString());
|
||||
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories))
|
||||
{
|
||||
searchUrl += $"&categories[]={cat}";
|
||||
}
|
||||
|
||||
var request = new HttpRequest(searchUrl, HttpAccept.Json);
|
||||
|
||||
var indexerRequest = new IndexerRequest(request);
|
||||
|
||||
yield return indexerRequest;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId, searchCriteria.TmdbId.GetValueOrDefault(0)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId, 0, searchCriteria.TvdbId.GetValueOrDefault(0)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class DanishBytesParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly DanishBytesSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public DanishBytesParser(DanishBytesSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<TorrentInfo>();
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
|
||||
}
|
||||
|
||||
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
||||
}
|
||||
|
||||
var jsonResponse = new HttpResponse<DanishBytesResponse>(indexerResponse.HttpResponse);
|
||||
|
||||
foreach (var row in jsonResponse.Resource.Torrents)
|
||||
{
|
||||
var infoUrl = $"{_settings.BaseUrl}torrents/{row.Id}";
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
Title = row.Name,
|
||||
InfoUrl = infoUrl,
|
||||
DownloadUrl = $"{_settings.BaseUrl}torrent/download/{row.Id}.{jsonResponse.Resource.Rsskey}",
|
||||
Guid = infoUrl,
|
||||
PosterUrl = row.PosterImage,
|
||||
PublishDate = row.CreatedAt,
|
||||
Categories = _categories.MapTrackerCatToNewznab(row.CategoryId),
|
||||
Size = row.Size,
|
||||
Seeders = row.Seeders,
|
||||
Peers = row.Leechers + row.Seeders,
|
||||
Grabs = row.TimesCompleted,
|
||||
DownloadVolumeFactor = row.Free ? 0 : 1,
|
||||
UploadVolumeFactor = row.Doubleup ? 2 : 1
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
// order by date
|
||||
return torrentInfos.OrderByDescending(o => o.PublishDate).ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class DanishBytesSettingsValidator : AbstractValidator<DanishBytesSettings>
|
||||
{
|
||||
public DanishBytesSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.ApiKey).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class DanishBytesSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly DanishBytesSettingsValidator Validator = new DanishBytesSettingsValidator();
|
||||
|
||||
public DanishBytesSettings()
|
||||
{
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "API Key", HelpText = "API Key from Site", Privacy = PrivacyLevel.ApiKey)]
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
[FieldDefinition(3)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
|
||||
public class DanishBytesTorrent
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "info_hash")]
|
||||
public string InfoHash { get; set; }
|
||||
public long Size { get; set; }
|
||||
public int Leechers { get; set; }
|
||||
public int Seeders { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "times_completed")]
|
||||
public int TimesCompleted { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "category_id")]
|
||||
public string CategoryId { get; set; }
|
||||
public string Tmdb { get; set; }
|
||||
public string Igdb { get; set; }
|
||||
public string Mal { get; set; }
|
||||
public string Tvdb { get; set; }
|
||||
public string Imdb { get; set; }
|
||||
public int Stream { get; set; }
|
||||
public bool Free { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "on_fire")]
|
||||
public bool OnFire { get; set; }
|
||||
public bool Doubleup { get; set; }
|
||||
public bool Highspeed { get; set; }
|
||||
public bool Featured { get; set; }
|
||||
public bool Webstream { get; set; }
|
||||
public bool Anon { get; set; }
|
||||
public bool Sticky { get; set; }
|
||||
public bool Sd { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "created_at")]
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "resolution_id")]
|
||||
public int ResolutionId { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "poster_image")]
|
||||
public string PosterImage { get; set; }
|
||||
public string Video { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "thanks_count")]
|
||||
public int ThanksCount { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "comments_count")]
|
||||
public int CommentsCount { get; set; }
|
||||
public string GetSize { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "created_at_human")]
|
||||
public string CreatedAtHuman { get; set; }
|
||||
public bool Bookmarked { get; set; }
|
||||
public bool Liked { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "show_last_torrents")]
|
||||
public bool ShowLastTorrents { get; set; }
|
||||
}
|
||||
|
||||
public class DanishBytesPageLinks
|
||||
{
|
||||
public int To { get; set; }
|
||||
public string Qty { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "current_page")]
|
||||
public int CurrentPage { get; set; }
|
||||
}
|
||||
|
||||
public class DanishBytesResponse
|
||||
{
|
||||
public DanishBytesTorrent[] Torrents { get; set; }
|
||||
public int ResultsCount { get; set; }
|
||||
public DanishBytesPageLinks Links { get; set; }
|
||||
public string CurrentCount { get; set; }
|
||||
public int TorrentCountTotal { get; set; }
|
||||
public string Rsskey { get; set; }
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class DesiTorrents : Unit3dBase
|
||||
{
|
||||
public override string Name => "DesiTorrents";
|
||||
public override string Language => "en-US";
|
||||
public override string[] IndexerUrls => new[] { "https://desitorrents.tv/", "https://desitorrents.rocks/" };
|
||||
public override string Description => "Desitorrents is a Private Torrent Tracker for BOLLYWOOD / TOLLYWOOD / GENERAL";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public DesiTorrents(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new DesiTorrentsParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.BooksEBook, "ebooks");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVSport, "Sports");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PCGames, "Games");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class DesiTorrentsParser : Unit3dParser
|
||||
{
|
||||
public DesiTorrentsParser(Unit3dSettings settings, IndexerCapabilitiesCategories categories)
|
||||
: base(settings, categories)
|
||||
{
|
||||
}
|
||||
|
||||
public override IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var releases = base.ParseResponse(indexerResponse);
|
||||
|
||||
foreach (TorrentInfo release in releases)
|
||||
{
|
||||
release.MinimumRatio = 0.6;
|
||||
release.MinimumSeedTime = 259200;
|
||||
}
|
||||
|
||||
return releases;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,348 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class DigitalCore : TorrentIndexerBase<DigitalCoreSettings>
|
||||
{
|
||||
public override string Name => "DigitalCore";
|
||||
public override string[] IndexerUrls => new string[] { "https://digitalcore.club/" };
|
||||
public override string Description => "DigitalCore is a Private Torrent Tracker for MOVIES / TV / GENERAL";
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public DigitalCore(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new DigitalCoreRequestGenerator() { Settings = Settings, PageSize = PageSize, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new DigitalCoreParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
protected override IDictionary<string, string> GetCookies()
|
||||
{
|
||||
var cookies = new Dictionary<string, string>();
|
||||
|
||||
cookies.Add("uid", Settings.UId);
|
||||
cookies.Add("pass", Settings.Passphrase);
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesDVD, "Movies/DVDR");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesSD, "Movies/SD");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesBluRay, "Movies/BluRay");
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesUHD, "Movies/4K");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.MoviesHD, "Movies/720p");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesHD, "Movies/1080p");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesHD, "Movies/PACKS");
|
||||
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVHD, "TV/720p");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVHD, "TV/1080p");
|
||||
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.TVSD, "TV/SD");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.TVSD, "TV/DVDR");
|
||||
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.TVHD, "TV/PACKS");
|
||||
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.TVUHD, "TV/4K");
|
||||
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.TVHD, "TV/BluRay");
|
||||
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.Other, "Unknown");
|
||||
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.PC0day, "Apps/0day");
|
||||
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.PCISO, "Apps/PC");
|
||||
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.PCMac, "Apps/Mac");
|
||||
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.PC, "Apps/Tutorials");
|
||||
|
||||
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.AudioMP3, "Music/MP3");
|
||||
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.AudioLossless, "Music/FLAC");
|
||||
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.Audio, "Music/MTV");
|
||||
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.Audio, "Music/PACKS");
|
||||
|
||||
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCGames, "Games/PC");
|
||||
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.Console, "Games/NSW");
|
||||
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.PCMac, "Games/Mac");
|
||||
|
||||
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.Books, "Ebooks");
|
||||
|
||||
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.XXXSD, "XXX/SD");
|
||||
caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.XXX, "XXX/HD");
|
||||
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.XXXUHD, "XXX/4K");
|
||||
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.XXXSD, "XXX/Movies/SD");
|
||||
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.XXX, "XXX/Movies/HD");
|
||||
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.XXXUHD, "XXX/Movies/4K");
|
||||
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.XXXImageSet, "XXX/Imagesets");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class DigitalCoreRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public DigitalCoreSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public int MaxPages { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
|
||||
public DigitalCoreRequestGenerator()
|
||||
{
|
||||
MaxPages = 30;
|
||||
PageSize = 100;
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
|
||||
{
|
||||
var searchUrl = string.Format("{0}/api/v1/torrents", Settings.BaseUrl.TrimEnd('/'));
|
||||
|
||||
var parameters = new NameValueCollection();
|
||||
|
||||
parameters.Add("extendedSearch", "false");
|
||||
parameters.Add("freeleech", "false");
|
||||
parameters.Add("index", "0");
|
||||
parameters.Add("limit", "100");
|
||||
parameters.Add("order", "desc");
|
||||
parameters.Add("page", "search");
|
||||
|
||||
if (imdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
parameters.Add("searchText", imdbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.Add("searchText", term);
|
||||
}
|
||||
|
||||
parameters.Add("sort", "d");
|
||||
parameters.Add("section", "all");
|
||||
parameters.Add("stereoscopic", "false");
|
||||
parameters.Add("watchview", "false");
|
||||
|
||||
searchUrl += "?" + parameters.GetQueryString();
|
||||
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories))
|
||||
{
|
||||
searchUrl += "&categories[]=" + cat;
|
||||
}
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class DigitalCoreParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly DigitalCoreSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public DigitalCoreParser(DigitalCoreSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
throw new IndexerException(indexerResponse,
|
||||
"Unexpected response status {0} code from API request",
|
||||
indexerResponse.HttpResponse.StatusCode);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//var json = JArray.Parse(results.Content);
|
||||
var json = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content);
|
||||
|
||||
foreach (var row in json ?? Enumerable.Empty<dynamic>())
|
||||
{
|
||||
var release = new TorrentInfo();
|
||||
var descriptions = new List<string>();
|
||||
var tags = new List<string>();
|
||||
|
||||
release.MinimumRatio = 1.1;
|
||||
release.MinimumSeedTime = 432000; // 120 hours
|
||||
release.Title = row.name;
|
||||
release.Categories = _categories.MapTrackerCatToNewznab(row.category.ToString());
|
||||
release.Size = row.size;
|
||||
release.Seeders = row.seeders;
|
||||
release.Peers = row.leechers + release.Seeders;
|
||||
release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture);
|
||||
release.Files = row.numfiles;
|
||||
release.Grabs = row.times_completed;
|
||||
|
||||
var infoUrl = _settings.BaseUrl + "torrent/" + row.id.ToString() + "/";
|
||||
|
||||
release.Guid = infoUrl;
|
||||
release.DownloadUrl = _settings.BaseUrl + "api/v1/torrents/download/" + row.id.ToString();
|
||||
release.InfoUrl = infoUrl;
|
||||
|
||||
if (row.frileech == 1)
|
||||
{
|
||||
release.DownloadVolumeFactor = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
release.DownloadVolumeFactor = 1;
|
||||
}
|
||||
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
if (row.imdbid2 != null && row.imdbid2.ToString().StartsWith("tt"))
|
||||
{
|
||||
if (int.TryParse((string)row.imdbid2, out int imdbNumber))
|
||||
{
|
||||
release.ImdbId = imdbNumber;
|
||||
}
|
||||
}
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new IndexerException(indexerResponse,
|
||||
"Unable to parse response from DigitalCore: {0}",
|
||||
ex.Message);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class DigitalCoreSettingsValidator : AbstractValidator<DigitalCoreSettings>
|
||||
{
|
||||
public DigitalCoreSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.UId).NotEmpty();
|
||||
RuleFor(c => c.Passphrase).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class DigitalCoreSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly DigitalCoreSettingsValidator Validator = new DigitalCoreSettingsValidator();
|
||||
|
||||
public DigitalCoreSettings()
|
||||
{
|
||||
UId = "";
|
||||
Passphrase = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "UID", HelpText = "UID from login cookie", Privacy = PrivacyLevel.UserName)]
|
||||
public string UId { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Passphrase", HelpText = "Passphrase from login cookie", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||
public string Passphrase { get; set; }
|
||||
|
||||
[FieldDefinition(4)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,330 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class InternetArchive : TorrentIndexerBase<InternetArchiveSettings>
|
||||
{
|
||||
public override string Name => "Internet Archive";
|
||||
|
||||
public override string[] IndexerUrls => new string[] { "https://archive.org/" };
|
||||
|
||||
public override string Description => "Internet Archive is a non-profit library of millions of free books, movies, software, music, websites, and more.";
|
||||
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
|
||||
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public override bool FollowRedirect => true;
|
||||
|
||||
public InternetArchive(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new InternetArchiveParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new InternetArchiveRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
// c.f. https://archive.org/services/docs/api/metadata-schema/index.html?highlight=mediatype#mediatype
|
||||
// "Movies" is a catch all category for videos
|
||||
caps.Categories.AddCategoryMapping("texts", NewznabStandardCategory.Books);
|
||||
caps.Categories.AddCategoryMapping("etree", NewznabStandardCategory.Audio);
|
||||
caps.Categories.AddCategoryMapping("audio", NewznabStandardCategory.Audio);
|
||||
caps.Categories.AddCategoryMapping("movies", NewznabStandardCategory.Movies);
|
||||
caps.Categories.AddCategoryMapping("movies", NewznabStandardCategory.TV);
|
||||
caps.Categories.AddCategoryMapping("software", NewznabStandardCategory.PC);
|
||||
caps.Categories.AddCategoryMapping("image", NewznabStandardCategory.OtherMisc);
|
||||
caps.Categories.AddCategoryMapping("data", NewznabStandardCategory.Other);
|
||||
caps.Categories.AddCategoryMapping("web", NewznabStandardCategory.Other);
|
||||
caps.Categories.AddCategoryMapping("collection", NewznabStandardCategory.Other);
|
||||
caps.Categories.AddCategoryMapping("account", NewznabStandardCategory.Other);
|
||||
|
||||
caps.Categories.AddCategoryMapping("other", NewznabStandardCategory.Other);
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class InternetArchiveRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public InternetArchiveSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public InternetArchiveRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string searchTerm, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var query = "format:(\"Archive BitTorrent\")";
|
||||
|
||||
if (searchTerm.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
if (Settings.TitleOnly)
|
||||
{
|
||||
query = string.Format("title:({0}) AND {1}", searchTerm, query);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = string.Format("{0} AND {1}", searchTerm, query);
|
||||
}
|
||||
}
|
||||
|
||||
var categories = Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories);
|
||||
if (categories.Count > 0)
|
||||
{
|
||||
query = string.Format("{0} AND mediatype:({1})", query, string.Join(" OR ", categories));
|
||||
}
|
||||
|
||||
string sortBy = (InternetArchiveSort)Settings.SortBy switch
|
||||
{
|
||||
InternetArchiveSort.PublicDate => "publicdate",
|
||||
InternetArchiveSort.Downloads => "downloads",
|
||||
InternetArchiveSort.Size => "item_size",
|
||||
_ => "publicdate",
|
||||
};
|
||||
|
||||
string sortOrder = (InternetArchiveSortOrder)Settings.SortOrder switch
|
||||
{
|
||||
InternetArchiveSortOrder.Descending => "desc",
|
||||
InternetArchiveSortOrder.Ascending => "asc",
|
||||
_ => "desc",
|
||||
};
|
||||
|
||||
var parameters = new NameValueCollection
|
||||
{
|
||||
{ "q", query },
|
||||
{ "fields", "btih,downloads,identifier,item_size,mediatype,publicdate,title" },
|
||||
{ "count", searchCriteria.Limit.GetValueOrDefault(100).ToString() }, // API default is 5000, don't think thats viable at all.
|
||||
{ "sorts", string.Format("{0} {1}", sortBy, sortOrder) }
|
||||
};
|
||||
|
||||
var searchUrl = string.Format("{0}/services/search/v1/scrape?{1}", Settings.BaseUrl.TrimEnd('/'), parameters.GetQueryString());
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria));
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class InternetArchiveParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly InternetArchiveSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
|
||||
public InternetArchiveParser(InternetArchiveSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<TorrentInfo>();
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
|
||||
}
|
||||
|
||||
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||||
{
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
||||
}
|
||||
|
||||
var jsonResponse = new HttpResponse<InternetArchiveResponse>(indexerResponse.HttpResponse);
|
||||
|
||||
foreach (var searchResult in jsonResponse.Resource.SearchResults)
|
||||
{
|
||||
var title = searchResult.Title ?? searchResult.Identifier;
|
||||
|
||||
var downloadUrl = string.Format("{0}/download/{1}/{1}_archive.torrent", _settings.BaseUrl.TrimEnd('/'), searchResult.Identifier);
|
||||
var detailsUrl = string.Format("{0}/details/{1}", _settings.BaseUrl.TrimEnd('/'), searchResult.Identifier);
|
||||
|
||||
var category = _categories.MapTrackerCatToNewznab(searchResult.MediaType ?? "other");
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
Categories = category,
|
||||
CommentUrl = detailsUrl,
|
||||
DownloadUrl = downloadUrl,
|
||||
DownloadVolumeFactor = 0,
|
||||
Guid = detailsUrl,
|
||||
Grabs = searchResult.Downloads,
|
||||
InfoHash = searchResult.InfoHash,
|
||||
InfoUrl = detailsUrl,
|
||||
Peers = 2,
|
||||
PublishDate = searchResult.PublicDate,
|
||||
Seeders = 1,
|
||||
Size = searchResult.Size,
|
||||
Title = title,
|
||||
UploadVolumeFactor = 1
|
||||
};
|
||||
|
||||
if (!_settings.TorrentFileOnly && searchResult.InfoHash != null)
|
||||
{
|
||||
release.MagnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(searchResult.InfoHash, title);
|
||||
}
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class InternetArchiveResponse
|
||||
{
|
||||
[JsonProperty(PropertyName = "items")]
|
||||
public List<InternetArchiveTorrent> SearchResults { get; set; }
|
||||
|
||||
public string Cursor { get; set; }
|
||||
public int Count { get; set; }
|
||||
public int Total { get; set; }
|
||||
}
|
||||
|
||||
public class InternetArchiveTorrent
|
||||
{
|
||||
public int Downloads { get; set; }
|
||||
public string Identifier { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "btih")]
|
||||
public string InfoHash { get; set; }
|
||||
public string MediaType { get; set; }
|
||||
public DateTime PublicDate { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "item_size")]
|
||||
public long Size { get; set; }
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
public class InternetArchiveSettings : IIndexerSettings
|
||||
{
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Sort By", Type = FieldType.Select, Advanced = true, SelectOptions = typeof(InternetArchiveSort), HelpText = "Field used to sort the search results.")]
|
||||
public int SortBy { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Sort Order", Type = FieldType.Select, Advanced = true, SelectOptions = typeof(InternetArchiveSortOrder), HelpText = "Order to use when sorting results.")]
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
[FieldDefinition(4, Label = "Title Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Whether to search in title only.")]
|
||||
public bool TitleOnly { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "Torrent File Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Only use torrent files, not magnet links.")]
|
||||
public bool TorrentFileOnly { get; set; }
|
||||
|
||||
[FieldDefinition(6)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public InternetArchiveSettings()
|
||||
{
|
||||
SortBy = (int)InternetArchiveSort.PublicDate;
|
||||
SortOrder = (int)InternetArchiveSortOrder.Descending;
|
||||
TitleOnly = false;
|
||||
TorrentFileOnly = false;
|
||||
}
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult();
|
||||
}
|
||||
}
|
||||
|
||||
public enum InternetArchiveSort
|
||||
{
|
||||
PublicDate,
|
||||
Downloads,
|
||||
Size
|
||||
}
|
||||
|
||||
public enum InternetArchiveSortOrder
|
||||
{
|
||||
Descending,
|
||||
Ascending
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
public class LatTeam : Unit3dBase
|
||||
{
|
||||
public override string Name => "Lat-Team";
|
||||
public override string Language => "es";
|
||||
public override string[] IndexerUrls => new[] { "https://lat-team.com/" };
|
||||
public override string Description => "Lat-Team is a Private Torrent Tracker for HD MOVIES / TV";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public LatTeam(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Peliculas");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesOther, "Retro Pelicula");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.TVAnime, "Anime");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV Series");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TVOther, "Retro Serie TV");
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TVForeign, "Telenovelas y Teleseries");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Musica");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,40 +1,21 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Indexers.Settings;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Rarbg
|
||||
{
|
||||
public class RarbgSettingsValidator : AbstractValidator<RarbgSettings>
|
||||
public class RarbgSettings : NoAuthTorrentBaseSettings
|
||||
{
|
||||
public RarbgSettingsValidator()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class RarbgSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly RarbgSettingsValidator Validator = new RarbgSettingsValidator();
|
||||
|
||||
public RarbgSettings()
|
||||
{
|
||||
RankedOnly = false;
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Ranked Only", HelpText = "Only include ranked results.")]
|
||||
public bool RankedOnly { get; set; }
|
||||
|
||||
[FieldDefinition(3, Type = FieldType.Captcha, Label = "CAPTCHA Token", HelpText = "CAPTCHA Clearance token used to handle CloudFlare Anti-DDOS measures on shared-ip VPNs.")]
|
||||
public string CaptchaToken { get; set; }
|
||||
|
||||
[FieldDefinition(4)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Definitions.UNIT3D;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class ShareIsland : Unit3dBase
|
||||
{
|
||||
public override string Name => "ShareIsland";
|
||||
public override string[] IndexerUrls => new string[] { "https://shareisland.org/" };
|
||||
public override string Description => "A general italian tracker.";
|
||||
public override string Language => "it-IT";
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
|
||||
public ShareIsland(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep, TvSearchParam.ImdbId, TvSearchParam.TvdbId
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId, MovieSearchParam.TmdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movie");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "Serie TV");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.BooksEBook, "Ebook");
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.BooksMags, "Riviste e Giornali");
|
||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.XXX, "XXX");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.PCGames, "Games");
|
||||
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PC, "Software");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,354 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class SuperBits : TorrentIndexerBase<SuperBitsSettings>
|
||||
{
|
||||
public override string Name => "SuperBits";
|
||||
|
||||
public override string[] IndexerUrls => new string[] { "https://superbits.org/" };
|
||||
public override string Description => "Superbits is a SWEDISH Private Torrent Tracker for MOVIES / TV / GENERAL";
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public SuperBits(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new SuperBitsRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new SuperBitsParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
protected override IDictionary<string, string> GetCookies()
|
||||
{
|
||||
return CookieUtil.CookieHeaderToDictionary(Settings.Cookie);
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesDVD, "DVD-R Swesub");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "DVD-R TV");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.BooksEBook, "eBok");
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Film 1080");
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Movies3D, "Film 3D");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesHD, "Film 720");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.MoviesBluRay, "Film Bluray");
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.TV, "Svensk TV");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.AudioAudiobook, "Ljudböcker");
|
||||
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.AudioVideo, "Musikvideos");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.BooksMags, "E-tidningar");
|
||||
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.Audio, "Musik");
|
||||
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.Other, "Omslag");
|
||||
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.Other, "Övrigt");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.PCGames, "PC-Spel");
|
||||
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.PC0day, "Program");
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.ConsolePS3, "PS3");
|
||||
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.TV, "TV");
|
||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.ConsoleWii, "Wii");
|
||||
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.ConsoleXBox, "Xbox");
|
||||
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.MoviesOther, "Xvid");
|
||||
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.XXX, "XXX");
|
||||
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.MoviesUHD, "Film 4K");
|
||||
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TV, "TV DK");
|
||||
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TV, "TV NO");
|
||||
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.TV, "TV FI");
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class SuperBitsRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public SuperBitsSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public SuperBitsRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
|
||||
{
|
||||
var searchUrl = Settings.BaseUrl + "api/v1/torrents";
|
||||
|
||||
// And this was option one from
|
||||
// https://github.com/Jackett/Jackett/pull/7166#discussion_r376817517
|
||||
var queryCollection = new NameValueCollection();
|
||||
var searchString = term;
|
||||
|
||||
queryCollection.Add("extendedSearch", "false");
|
||||
queryCollection.Add("freeleech", "false");
|
||||
queryCollection.Add("index", "0");
|
||||
queryCollection.Add("limit", "100");
|
||||
queryCollection.Add("order", "desc");
|
||||
queryCollection.Add("page", "search");
|
||||
|
||||
if (imdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
queryCollection.Add("searchText", imdbId);
|
||||
}
|
||||
else
|
||||
{
|
||||
queryCollection.Add("searchText", searchString);
|
||||
}
|
||||
|
||||
queryCollection.Add("sort", "d");
|
||||
queryCollection.Add("section", "all");
|
||||
queryCollection.Add("stereoscopic", "false");
|
||||
queryCollection.Add("sweaudio", "false");
|
||||
queryCollection.Add("swesub", "false");
|
||||
queryCollection.Add("watchview", "false");
|
||||
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories))
|
||||
{
|
||||
searchUrl += "&categories[]=" + cat;
|
||||
}
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
|
||||
|
||||
request.HttpRequest.Headers.Add("Referer", Settings.BaseUrl);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class SuperBitsParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly SuperBitsSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public SuperBitsParser(SuperBitsSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<TorrentInfo>();
|
||||
|
||||
var json = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content);
|
||||
foreach (var row in json ?? Enumerable.Empty<dynamic>())
|
||||
{
|
||||
var release = new TorrentInfo();
|
||||
var descriptions = new List<string>();
|
||||
var tags = new List<string>();
|
||||
|
||||
release.MinimumRatio = 1.1;
|
||||
release.MinimumSeedTime = 172800; // 48 hours
|
||||
release.Title = row.name;
|
||||
release.Categories = _categories.MapTrackerCatToNewznab(row.category.ToString());
|
||||
release.Size = row.size;
|
||||
release.Seeders = row.seeders;
|
||||
release.Peers = row.leechers + release.Seeders;
|
||||
release.PublishDate = DateTime.ParseExact(row.added.ToString() + " +01:00", "yyyy-MM-dd HH:mm:ss zzz", CultureInfo.InvariantCulture);
|
||||
release.Files = row.numfiles;
|
||||
release.Grabs = row.times_completed;
|
||||
|
||||
release.InfoUrl = _settings.BaseUrl + "torrent/" + row.id.ToString() + "/";
|
||||
release.Guid = release.InfoUrl;
|
||||
release.DownloadUrl = _settings.BaseUrl + "api/v1/torrents/download/" + row.id.ToString();
|
||||
|
||||
if (row.frileech == 1)
|
||||
{
|
||||
release.DownloadVolumeFactor = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
release.DownloadVolumeFactor = 1;
|
||||
}
|
||||
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(row.customcover.ToString()))
|
||||
{
|
||||
release.PosterUrl = _settings.BaseUrl + row.customcover;
|
||||
}
|
||||
|
||||
if (row.imdbid2 != null && row.imdbid2.ToString().StartsWith("tt"))
|
||||
{
|
||||
release.ImdbId = ParseUtil.CoerceInt(row.imdbid2.ToString().Substring(2));
|
||||
descriptions.Add("Title: " + row.title);
|
||||
descriptions.Add("Year: " + row.year);
|
||||
descriptions.Add("Genres: " + row.genres);
|
||||
descriptions.Add("Tagline: " + row.tagline);
|
||||
descriptions.Add("Cast: " + row.cast);
|
||||
descriptions.Add("Rating: " + row.rating);
|
||||
descriptions.Add("Plot: " + row.plot);
|
||||
|
||||
release.PosterUrl = _settings.BaseUrl + "img/imdb/" + row.imdbid2 + ".jpg";
|
||||
}
|
||||
|
||||
if ((int)row.p2p == 1)
|
||||
{
|
||||
tags.Add("P2P");
|
||||
}
|
||||
|
||||
if ((int)row.pack == 1)
|
||||
{
|
||||
tags.Add("Pack");
|
||||
}
|
||||
|
||||
if ((int)row.reqid != 0)
|
||||
{
|
||||
tags.Add("Request");
|
||||
}
|
||||
|
||||
if ((int)row.sweaudio != 0)
|
||||
{
|
||||
tags.Add("Swedish audio");
|
||||
}
|
||||
|
||||
if ((int)row.swesub != 0)
|
||||
{
|
||||
tags.Add("Swedish subtitles");
|
||||
}
|
||||
|
||||
if (tags.Count > 0)
|
||||
{
|
||||
descriptions.Add("Tags: " + string.Join(", ", tags));
|
||||
}
|
||||
|
||||
var preDate = row.preDate.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(preDate) && preDate != "1970-01-01 01:00:00")
|
||||
{
|
||||
descriptions.Add("PRE: " + preDate);
|
||||
}
|
||||
|
||||
descriptions.Add("Section: " + row.section);
|
||||
|
||||
//release.Description = string.Join("<br>\n", descriptions);
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class SuperBitsSettingsValidator : AbstractValidator<SuperBitsSettings>
|
||||
{
|
||||
public SuperBitsSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Cookie).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class SuperBitsSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly SuperBitsSettingsValidator Validator = new SuperBitsSettingsValidator();
|
||||
|
||||
public SuperBitsSettings()
|
||||
{
|
||||
Cookie = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie")]
|
||||
public string Cookie { get; set; }
|
||||
|
||||
[FieldDefinition(3)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,380 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class TorrentLeech : TorrentIndexerBase<TorrentLeechSettings>
|
||||
{
|
||||
public override string Name => "TorrentLeech";
|
||||
|
||||
public override string[] IndexerUrls => new string[] { "https://www.torrentleech.org/" };
|
||||
public override string Description => "This is what happens when you seed";
|
||||
private string LoginUrl => Settings.BaseUrl + "user/account/login/";
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public TorrentLeech(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new TorrentLeechRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new TorrentLeechParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
protected override async Task DoLogin()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
requestBuilder.Method = HttpMethod.Post;
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
|
||||
var cookies = Cookies;
|
||||
|
||||
Cookies = null;
|
||||
var authLoginRequest = requestBuilder
|
||||
.AddFormParameter("username", Settings.Username)
|
||||
.AddFormParameter("password", Settings.Password)
|
||||
.SetHeader("Content-Type", "multipart/form-data")
|
||||
.Build();
|
||||
|
||||
var response = await ExecuteAuth(authLoginRequest);
|
||||
|
||||
cookies = response.GetCookies();
|
||||
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));
|
||||
|
||||
_logger.Debug("TorrentLeech authentication succeeded.");
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
if (httpResponse.Content.Contains("/user/account/login"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
// Torrentleech does technically support ImdbId Search but only with no other params
|
||||
// ImdbId + S/E search returns unrelated results
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q, MovieSearchParam.ImdbId
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies");
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.MoviesSD, "Movies Cam");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.MoviesSD, "Movies TS/TC");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.MoviesSD, "Movies DVDRip/DVDScreener");
|
||||
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.MoviesDVD, "Movies DVD-R");
|
||||
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.MoviesBluRay, "Movies Bluray");
|
||||
caps.Categories.AddCategoryMapping(14, NewznabStandardCategory.MoviesHD, "Movies BlurayRip");
|
||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.Movies, "Movies Boxsets");
|
||||
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.TVDocumentary, "Documentaries");
|
||||
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.MoviesUHD, "Movies 4K");
|
||||
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.MoviesForeign, "Movies Foreign");
|
||||
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.MoviesWEBDL, "Movies WEBRip");
|
||||
caps.Categories.AddCategoryMapping(43, NewznabStandardCategory.MoviesHD, "Movies HDRip");
|
||||
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.TV, "TV");
|
||||
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TVSD, "TV Episodes");
|
||||
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TV, "TV Boxsets");
|
||||
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.TVHD, "TV Episodes HD");
|
||||
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.TVForeign, "TV Foreign");
|
||||
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.PCGames, "Games");
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.PCGames, "Games PC");
|
||||
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.ConsoleXBox, "Games XBOX");
|
||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.ConsoleXBox360, "Games XBOX360");
|
||||
caps.Categories.AddCategoryMapping(40, NewznabStandardCategory.ConsoleXBoxOne, "Games XBOXONE");
|
||||
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.ConsolePS3, "Games PS2");
|
||||
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.ConsolePS3, "Games Mac");
|
||||
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.ConsolePSP, "Games PSP");
|
||||
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.ConsoleWii, "Games Wii");
|
||||
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.ConsoleNDS, "Games Nintendo DS");
|
||||
caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.ConsolePS4, "Games PS4");
|
||||
caps.Categories.AddCategoryMapping(42, NewznabStandardCategory.PCMac, "Games Mac");
|
||||
caps.Categories.AddCategoryMapping(48, NewznabStandardCategory.ConsoleOther, "Games Nintendo Switch");
|
||||
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.Audio, "Music");
|
||||
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.AudioVideo, "Music videos");
|
||||
caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.Audio, "Audio");
|
||||
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.TV, "Animation");
|
||||
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.TVAnime, "TV Anime");
|
||||
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.TV, "TV Cartoons");
|
||||
|
||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.Books, "Books");
|
||||
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.BooksEBook, "Books EBooks");
|
||||
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.BooksComics, "Books Comics");
|
||||
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.PC, "Apps");
|
||||
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.PCISO, "PC ISO");
|
||||
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.PCMac, "PC Mac");
|
||||
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.PCMobileOther, "PC Mobile");
|
||||
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.PC0day, "PC 0-day");
|
||||
caps.Categories.AddCategoryMapping(38, NewznabStandardCategory.Other, "Education");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class TorrentLeechRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public TorrentLeechSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public TorrentLeechRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
|
||||
{
|
||||
var searchString = Regex.Replace(term, @"(^|\s)-", " ");
|
||||
|
||||
var searchUrl = Settings.BaseUrl + "torrents/browse/list/";
|
||||
|
||||
if (Settings.FreeLeechOnly)
|
||||
{
|
||||
searchUrl += "facets/tags%3AFREELEECH/";
|
||||
}
|
||||
|
||||
if (imdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
searchUrl += "imdbID/" + imdbId + "/";
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
searchUrl += "exact/1/query/" + WebUtility.UrlEncode(searchString) + "/";
|
||||
}
|
||||
|
||||
var cats = Capabilities.Categories.MapTorznabCapsToTrackers(categories);
|
||||
if (cats.Count > 0)
|
||||
{
|
||||
searchUrl += "categories/" + string.Join(",", cats);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchUrl += "newfilter/2"; // include 0day and music
|
||||
}
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Rss);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentLeechParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly TorrentLeechSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public TorrentLeechParser(TorrentLeechSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<TorrentInfo>();
|
||||
|
||||
var rows = JsonConvert.DeserializeObject<dynamic>(indexerResponse.Content).torrentList;
|
||||
foreach (var row in rows ?? Enumerable.Empty<dynamic>())
|
||||
{
|
||||
var title = row.name.ToString();
|
||||
|
||||
var torrentId = row.fid.ToString();
|
||||
var details = new Uri(_settings.BaseUrl + "torrent/" + torrentId);
|
||||
var link = new Uri(_settings.BaseUrl + "download/" + torrentId + "/" + row.filename);
|
||||
var publishDate = DateTime.ParseExact(row.addedTimestamp.ToString(), "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
|
||||
var seeders = (int)row.seeders;
|
||||
var leechers = (int)row.leechers;
|
||||
var grabs = (int)row.completed;
|
||||
var size = (long)row.size;
|
||||
var cats = _categories.MapTrackerCatToNewznab(((int)row.categoryID).ToString());
|
||||
var imdb = (string)row.imdbID;
|
||||
var imdbId = 0;
|
||||
if (imdb.Length > 2)
|
||||
{
|
||||
imdbId = int.Parse(imdb.Substring(2));
|
||||
}
|
||||
|
||||
// freeleech #6579 #6624 #7367
|
||||
string dlMultiplier = row.download_multiplier.ToString();
|
||||
var dlVolumeFactor = dlMultiplier.IsNullOrWhiteSpace() ? 1 : ParseUtil.CoerceInt(dlMultiplier);
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
Title = title,
|
||||
InfoUrl = details.AbsoluteUri,
|
||||
Guid = details.AbsoluteUri,
|
||||
DownloadUrl = link.AbsoluteUri,
|
||||
PublishDate = publishDate,
|
||||
Categories = cats,
|
||||
Size = size,
|
||||
Grabs = grabs,
|
||||
Seeders = seeders,
|
||||
Peers = seeders + leechers,
|
||||
ImdbId = imdbId,
|
||||
UploadVolumeFactor = 1,
|
||||
DownloadVolumeFactor = dlVolumeFactor,
|
||||
MinimumRatio = 1,
|
||||
MinimumSeedTime = 864000 // 10 days for registered users, less for upgraded users
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentLeechSettingsValidator : AbstractValidator<TorrentLeechSettings>
|
||||
{
|
||||
public TorrentLeechSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
|
||||
RuleFor(c => c.VipExpiration).Must(c => c.IsValidDate())
|
||||
.When(c => c.VipExpiration.IsNotNullOrWhiteSpace())
|
||||
.WithMessage("Correctly formatted date is required");
|
||||
|
||||
RuleFor(c => c.VipExpiration).Must(c => c.IsFutureDate())
|
||||
.When(c => c.VipExpiration.IsNotNullOrWhiteSpace())
|
||||
.WithMessage("Must be a future date");
|
||||
}
|
||||
}
|
||||
|
||||
public class TorrentLeechSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly TorrentLeechSettingsValidator Validator = new TorrentLeechSettingsValidator();
|
||||
|
||||
public TorrentLeechSettings()
|
||||
{
|
||||
Username = "";
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(4, Label = "FreeLeech Only", Type = FieldType.Checkbox, Advanced = true, HelpText = "Search Freeleech torrents only")]
|
||||
public bool FreeLeechOnly { get; set; }
|
||||
|
||||
[FieldDefinition(5, Label = "VIP Expiration", HelpText = "Enter date (yyyy-mm-dd) for VIP Expiration or blank, Prowlarr will notify 1 week from expiration of VIP")]
|
||||
public string VipExpiration { get; set; }
|
||||
|
||||
[FieldDefinition(6)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class TorrentParadiseMl : TorrentIndexerBase<TorrentParadiseMlSettings>
|
||||
{
|
||||
public override string Name => "TorrentParadiseMl";
|
||||
public override string[] IndexerUrls => new[] { "https://torrent-paradise.ml/" };
|
||||
public override string Language => "en-US";
|
||||
public override string Description => "The most innovative torrent site";
|
||||
public override Encoding Encoding => Encoding.UTF8;
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public TorrentParadiseMl(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new TorrentParadiseMlRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new TorrentParadiseMlParser(Settings);
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(8000, NewznabStandardCategory.Other);
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class TorrentParadiseMlRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public TorrentParadiseMlSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public TorrentParadiseMlRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term)
|
||||
{
|
||||
var searchTerm = term;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
searchTerm = DateTime.Now.Year.ToString();
|
||||
}
|
||||
|
||||
var qc = new NameValueCollection
|
||||
{
|
||||
{ "q", searchTerm }
|
||||
};
|
||||
|
||||
var searchUrl = string.Format("{0}/api/search?{1}", Settings.BaseUrl.TrimEnd('/'), qc.GetQueryString());
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Json);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm)));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentParadiseMlParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly TorrentParadiseMlSettings _settings;
|
||||
|
||||
public TorrentParadiseMlParser(TorrentParadiseMlSettings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
// Remove cookie cache
|
||||
CookiesUpdater(null, null);
|
||||
|
||||
throw new IndexerException(indexerResponse, $"Unexpected response status {indexerResponse.HttpResponse.StatusCode} code from API request");
|
||||
}
|
||||
|
||||
var results = JsonConvert.DeserializeObject<List<TorrentParadiseResult>>(indexerResponse.Content);
|
||||
|
||||
if (results == null)
|
||||
{
|
||||
return torrentInfos;
|
||||
}
|
||||
|
||||
foreach (var result in results)
|
||||
{
|
||||
var magnetUrl = MagnetLinkBuilder.BuildPublicMagnetLink(result.Id, result.Text);
|
||||
|
||||
var release = new TorrentInfo
|
||||
{
|
||||
Title = result.Text,
|
||||
Size = result.Size,
|
||||
Seeders = result.Seeders,
|
||||
Peers = result.Seeders + result.Leechers,
|
||||
InfoHash = result.Id,
|
||||
Guid = magnetUrl,
|
||||
MagnetUrl = magnetUrl,
|
||||
PublishDate = DateTime.UtcNow,
|
||||
InfoUrl = _settings.BaseUrl,
|
||||
DownloadVolumeFactor = 0,
|
||||
UploadVolumeFactor = 1,
|
||||
Categories = new List<IndexerCategory> { NewznabStandardCategory.Other }
|
||||
};
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
private class TorrentParadiseResult
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Text { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "len")]
|
||||
public long? Size { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "s")]
|
||||
public int? Seeders { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "l")]
|
||||
public int? Leechers { get; set; }
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentParadiseMlSettingsValidator : AbstractValidator<TorrentParadiseMlSettings>
|
||||
{
|
||||
}
|
||||
|
||||
public class TorrentParadiseMlSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly TorrentParadiseMlSettingsValidator Validator = new TorrentParadiseMlSettingsValidator();
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +1,20 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Indexers.Settings;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.TorrentPotato
|
||||
{
|
||||
public class TorrentPotatoSettingsValidator : AbstractValidator<TorrentPotatoSettings>
|
||||
public class TorrentPotatoSettings : NoAuthTorrentBaseSettings
|
||||
{
|
||||
public TorrentPotatoSettingsValidator()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class TorrentPotatoSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly TorrentPotatoSettingsValidator Validator = new TorrentPotatoSettingsValidator();
|
||||
|
||||
public TorrentPotatoSettings()
|
||||
{
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Username", HelpText = "Indexer Username", Privacy = PrivacyLevel.UserName)]
|
||||
public string User { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Passkey", HelpText = "Indexer Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||
public string Passkey { get; set; }
|
||||
|
||||
[FieldDefinition(4)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,378 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Html.Parser;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Indexers.Exceptions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class TorrentSeeds : TorrentIndexerBase<TorrentSeedsSettings>
|
||||
{
|
||||
public override string Name => "TorrentSeeds";
|
||||
|
||||
public override string[] IndexerUrls => new string[] { "https://torrentseeds.org/" };
|
||||
public override string Description => "TorrentSeeds is a Private site for MOVIES / TV / GENERAL";
|
||||
private string LoginUrl => Settings.BaseUrl + "takelogin.php";
|
||||
private string CaptchaUrl => Settings.BaseUrl + "simpleCaptcha.php?numImages=1";
|
||||
private string TokenUrl => Settings.BaseUrl + "login.php";
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public TorrentSeeds(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new TorrentSeedsRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new TorrentSeedsParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
protected override async Task DoLogin()
|
||||
{
|
||||
var requestBuilder = new HttpRequestBuilder(LoginUrl)
|
||||
{
|
||||
LogResponseContent = true
|
||||
};
|
||||
|
||||
Cookies = null;
|
||||
|
||||
var loginPage = await ExecuteAuth(new HttpRequest(CaptchaUrl));
|
||||
var json1 = JObject.Parse(loginPage.Content);
|
||||
var captchaSelection = json1["images"][0]["hash"];
|
||||
|
||||
requestBuilder.Method = HttpMethod.Post;
|
||||
requestBuilder.PostProcess += r => r.RequestTimeout = TimeSpan.FromSeconds(15);
|
||||
requestBuilder.SetCookies(loginPage.GetCookies());
|
||||
|
||||
var authLoginRequest = requestBuilder
|
||||
.AddFormParameter("username", Settings.Username)
|
||||
.AddFormParameter("password", Settings.Password)
|
||||
.AddFormParameter("submitme", "X")
|
||||
.AddFormParameter("captchaSelection", (string)captchaSelection)
|
||||
.SetHeader("Content-Type", "multipart/form-data")
|
||||
.Build();
|
||||
|
||||
var response = await ExecuteAuth(authLoginRequest);
|
||||
|
||||
if (CheckIfLoginNeeded(response))
|
||||
{
|
||||
throw new IndexerAuthException("TorrentSeeds Login Failed");
|
||||
}
|
||||
|
||||
var cookies = response.GetCookies();
|
||||
UpdateCookies(cookies, DateTime.Now + TimeSpan.FromDays(30));
|
||||
|
||||
_logger.Debug("TorrentSeeds authentication succeeded.");
|
||||
}
|
||||
|
||||
protected override bool CheckIfLoginNeeded(HttpResponse httpResponse)
|
||||
{
|
||||
if ((httpResponse.HasHttpRedirect && httpResponse.Headers.GetSingleValue("Location").Contains("/login.php?")) ||
|
||||
(!httpResponse.HasHttpRedirect && !httpResponse.Content.Contains("/logout.php?")))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
TvSearchParam.Q, TvSearchParam.Season, TvSearchParam.Ep
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam>
|
||||
{
|
||||
MovieSearchParam.Q
|
||||
},
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
MusicSearchParam.Q
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
BookSearchParam.Q
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(37, NewznabStandardCategory.TVAnime, "Anime/HD");
|
||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.TVAnime, "Anime/SD");
|
||||
caps.Categories.AddCategoryMapping(72, NewznabStandardCategory.TVAnime, "Anime/UHD");
|
||||
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.PC0day, "Apps/0DAY");
|
||||
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.Books, "Apps/Bookware");
|
||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.PCISO, "Apps/ISO");
|
||||
caps.Categories.AddCategoryMapping(73, NewznabStandardCategory.AudioAudiobook, "Music/Audiobooks");
|
||||
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.ConsoleOther, "Console/NSW");
|
||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.ConsolePS3, "Console/PS3");
|
||||
caps.Categories.AddCategoryMapping(30, NewznabStandardCategory.ConsolePS4, "Console/PS4");
|
||||
caps.Categories.AddCategoryMapping(71, NewznabStandardCategory.ConsolePS4, "Console/PS5");
|
||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.ConsolePSP, "Console/PSP");
|
||||
caps.Categories.AddCategoryMapping(70, NewznabStandardCategory.ConsolePSVita, "Console/PSV");
|
||||
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.ConsoleWii, "Console/WII");
|
||||
caps.Categories.AddCategoryMapping(29, NewznabStandardCategory.ConsoleWiiU, "Console/WIIU");
|
||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.ConsoleXBox360, "Console/XBOX360");
|
||||
caps.Categories.AddCategoryMapping(32, NewznabStandardCategory.BooksEBook, "E-books");
|
||||
caps.Categories.AddCategoryMapping(63, NewznabStandardCategory.ConsoleOther, "Games/DOX");
|
||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.PCGames, "Games/ISO");
|
||||
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.PCGames, "Games/PC Rips");
|
||||
caps.Categories.AddCategoryMapping(31, NewznabStandardCategory.MoviesBluRay, "Movies/Bluray");
|
||||
caps.Categories.AddCategoryMapping(50, NewznabStandardCategory.MoviesBluRay, "Movies/Bluray-UHD");
|
||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesDVD, "Movies/DVDR");
|
||||
caps.Categories.AddCategoryMapping(69, NewznabStandardCategory.MoviesForeign, "Movies/DVDR-Foreign");
|
||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesHD, "Movies/HD");
|
||||
caps.Categories.AddCategoryMapping(39, NewznabStandardCategory.MoviesForeign, "Movies/HD-Foreign");
|
||||
caps.Categories.AddCategoryMapping(74, NewznabStandardCategory.MoviesHD, "Movies/Remuxes");
|
||||
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.MoviesSD, "Movies/SD");
|
||||
caps.Categories.AddCategoryMapping(62, NewznabStandardCategory.MoviesForeign, "Movies/SD-Foreign");
|
||||
caps.Categories.AddCategoryMapping(49, NewznabStandardCategory.MoviesUHD, "Movies/UHD");
|
||||
caps.Categories.AddCategoryMapping(76, NewznabStandardCategory.MoviesForeign, "Movies/UHD-Foreign");
|
||||
caps.Categories.AddCategoryMapping(33, NewznabStandardCategory.AudioLossless, "Music/FLAC");
|
||||
caps.Categories.AddCategoryMapping(28, NewznabStandardCategory.AudioOther, "Music/MBluRay-Rips");
|
||||
caps.Categories.AddCategoryMapping(34, NewznabStandardCategory.AudioOther, "Music/MDVDR");
|
||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.AudioMP3, "Music/MP3");
|
||||
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.AudioVideo, "Music/MVID");
|
||||
caps.Categories.AddCategoryMapping(77, NewznabStandardCategory.TVAnime, "Anime/Packs");
|
||||
caps.Categories.AddCategoryMapping(78, NewznabStandardCategory.BooksEBook, "Books/Packs");
|
||||
caps.Categories.AddCategoryMapping(80, NewznabStandardCategory.MoviesHD, "Movies/HD-Packs");
|
||||
caps.Categories.AddCategoryMapping(81, NewznabStandardCategory.MoviesHD, "Movies/Remux-Packs");
|
||||
caps.Categories.AddCategoryMapping(79, NewznabStandardCategory.MoviesSD, "Movies/SD-Packs");
|
||||
caps.Categories.AddCategoryMapping(68, NewznabStandardCategory.Audio, "Music/Packs");
|
||||
caps.Categories.AddCategoryMapping(67, NewznabStandardCategory.TVHD, "TV/HD-Packs");
|
||||
caps.Categories.AddCategoryMapping(82, NewznabStandardCategory.TVHD, "TV/Remux-Packs");
|
||||
caps.Categories.AddCategoryMapping(65, NewznabStandardCategory.TVSD, "TV/SD-Packs");
|
||||
caps.Categories.AddCategoryMapping(84, NewznabStandardCategory.TVUHD, "TV/UHD-Packs");
|
||||
caps.Categories.AddCategoryMapping(85, NewznabStandardCategory.XXX, "XXX/Packs");
|
||||
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVSD, "TV/DVDR");
|
||||
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.TVHD, "TV/HD");
|
||||
caps.Categories.AddCategoryMapping(64, NewznabStandardCategory.TVForeign, "TV/HD-Foreign");
|
||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.TVHD, "TV/HD-Retail");
|
||||
caps.Categories.AddCategoryMapping(36, NewznabStandardCategory.TVSport, "TV/HD-Sport");
|
||||
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.TVSD, "TV/SD");
|
||||
caps.Categories.AddCategoryMapping(86, NewznabStandardCategory.TVForeign, "TV/SD-Foreign");
|
||||
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVSD, "TV/SD-Retail");
|
||||
caps.Categories.AddCategoryMapping(35, NewznabStandardCategory.TVSport, "TV/SD-Sport");
|
||||
caps.Categories.AddCategoryMapping(61, NewznabStandardCategory.TVUHD, "TV/UHD");
|
||||
caps.Categories.AddCategoryMapping(87, NewznabStandardCategory.TVForeign, "TV/UHD-Foreign");
|
||||
caps.Categories.AddCategoryMapping(53, NewznabStandardCategory.XXX, "XXX/HD");
|
||||
caps.Categories.AddCategoryMapping(88, NewznabStandardCategory.XXXImageSet, "XXX/Image-Sets");
|
||||
caps.Categories.AddCategoryMapping(57, NewznabStandardCategory.XXX, "XXX/Paysite");
|
||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.XXX, "XXX/SD");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class TorrentSeedsRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public TorrentSeedsSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public TorrentSeedsRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories)
|
||||
{
|
||||
// remove operator characters
|
||||
var cleanSearchString = Regex.Replace(term.Trim(), "[ _.+-]+", " ", RegexOptions.Compiled);
|
||||
|
||||
var searchUrl = Settings.BaseUrl + "browse_elastic.php";
|
||||
var queryCollection = new NameValueCollection
|
||||
{
|
||||
{ "search_in", "name" },
|
||||
{ "search_mode", "all" },
|
||||
{ "order_by", "added" },
|
||||
{ "order_way", "desc" }
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(cleanSearchString))
|
||||
{
|
||||
queryCollection.Add("query", cleanSearchString);
|
||||
}
|
||||
|
||||
foreach (var cat in Capabilities.Categories.MapTorznabCapsToTrackers(categories))
|
||||
{
|
||||
queryCollection.Add($"cat[{cat}]", "1");
|
||||
}
|
||||
|
||||
searchUrl += "?" + queryCollection.GetQueryString();
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedTvSearchString), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentSeedsParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly TorrentSeedsSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public TorrentSeedsParser(TorrentSeedsSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<TorrentInfo>();
|
||||
|
||||
var parser = new HtmlParser();
|
||||
var dom = parser.ParseDocument(indexerResponse.Content);
|
||||
var rows = dom.QuerySelectorAll("table.table-bordered > tbody > tr[class*=\"torrent_row_\"]");
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var release = new TorrentInfo();
|
||||
release.MinimumRatio = 1;
|
||||
release.MinimumSeedTime = 72 * 60 * 60;
|
||||
var qCatLink = row.QuerySelector("a[href^=\"/browse_elastic.php?cat=\"]");
|
||||
var catStr = qCatLink.GetAttribute("href").Split('=')[1];
|
||||
release.Categories = _categories.MapTrackerCatToNewznab(catStr);
|
||||
var qDetailsLink = row.QuerySelector("a[href^=\"/details.php?id=\"]");
|
||||
var qDetailsTitle = row.QuerySelector("td:has(a[href^=\"/details.php?id=\"]) b");
|
||||
release.Title = qDetailsTitle.TextContent.Trim();
|
||||
var qDlLink = row.QuerySelector("a[href^=\"/download.php?torrent=\"]");
|
||||
|
||||
release.DownloadUrl = _settings.BaseUrl + qDlLink.GetAttribute("href").TrimStart('/');
|
||||
release.InfoUrl = _settings.BaseUrl + qDetailsLink.GetAttribute("href").TrimStart('/');
|
||||
release.Guid = release.InfoUrl;
|
||||
|
||||
var qColumns = row.QuerySelectorAll("td");
|
||||
release.Files = ParseUtil.CoerceInt(qColumns[3].TextContent);
|
||||
release.PublishDate = DateTimeUtil.FromUnknown(qColumns[5].TextContent);
|
||||
release.Size = ParseUtil.GetBytes(qColumns[6].TextContent);
|
||||
release.Grabs = ParseUtil.CoerceInt(qColumns[7].TextContent.Replace("Times", ""));
|
||||
release.Seeders = ParseUtil.CoerceInt(qColumns[8].TextContent);
|
||||
release.Peers = ParseUtil.CoerceInt(qColumns[9].TextContent) + release.Seeders;
|
||||
|
||||
var qImdb = row.QuerySelector("a[href*=\"www.imdb.com\"]");
|
||||
if (qImdb != null)
|
||||
{
|
||||
var deRefUrl = qImdb.GetAttribute("href");
|
||||
release.ImdbId = ParseUtil.GetImdbID(WebUtility.UrlDecode(deRefUrl).Split('/').Last()) ?? 0;
|
||||
}
|
||||
|
||||
release.DownloadVolumeFactor = row.QuerySelector("span.freeleech") != null ? 0 : 1;
|
||||
release.UploadVolumeFactor = 1;
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class TorrentSeedsSettingsValidator : AbstractValidator<TorrentSeedsSettings>
|
||||
{
|
||||
public TorrentSeedsSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public class TorrentSeedsSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly TorrentSeedsSettingsValidator Validator = new TorrentSeedsSettingsValidator();
|
||||
|
||||
public TorrentSeedsSettings()
|
||||
{
|
||||
Username = "";
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(4)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using FluentValidation;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Definitions
|
||||
{
|
||||
[Obsolete("Moved to YML for Cardigann v3")]
|
||||
public class YTS : TorrentIndexerBase<YTSSettings>
|
||||
{
|
||||
public override string Name => "YTS";
|
||||
public override string[] IndexerUrls => new string[] { "https://yts.mx/" };
|
||||
public override string Language => "en-US";
|
||||
public override string Description => "YTS is a Public torrent site specialising in HD movies of small size";
|
||||
public override Encoding Encoding => Encoding.GetEncoding("windows-1252");
|
||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Public;
|
||||
|
||||
public override TimeSpan RateLimit => TimeSpan.FromSeconds(2.5);
|
||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||
|
||||
public YTS(IIndexerHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||
{
|
||||
}
|
||||
|
||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new YTSRequestGenerator() { Settings = Settings, Capabilities = Capabilities };
|
||||
}
|
||||
|
||||
public override IParseIndexerResponse GetParser()
|
||||
{
|
||||
return new YTSParser(Settings, Capabilities.Categories);
|
||||
}
|
||||
|
||||
private IndexerCapabilities SetCapabilities()
|
||||
{
|
||||
var caps = new IndexerCapabilities
|
||||
{
|
||||
TvSearchParams = new List<TvSearchParam>
|
||||
{
|
||||
},
|
||||
MovieSearchParams = new List<MovieSearchParam> { MovieSearchParam.Q, MovieSearchParam.ImdbId },
|
||||
MusicSearchParams = new List<MusicSearchParam>
|
||||
{
|
||||
},
|
||||
BookSearchParams = new List<BookSearchParam>
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
caps.Categories.AddCategoryMapping(45, NewznabStandardCategory.MoviesHD, "Movies/x264/720p");
|
||||
caps.Categories.AddCategoryMapping(44, NewznabStandardCategory.MoviesHD, "Movies/x264/1080p");
|
||||
caps.Categories.AddCategoryMapping(46, NewznabStandardCategory.MoviesUHD, "Movies/x264/2160p");
|
||||
caps.Categories.AddCategoryMapping(47, NewznabStandardCategory.Movies3D, "Movies/x264/3D");
|
||||
|
||||
return caps;
|
||||
}
|
||||
}
|
||||
|
||||
public class YTSRequestGenerator : IIndexerRequestGenerator
|
||||
{
|
||||
public YTSSettings Settings { get; set; }
|
||||
public IndexerCapabilities Capabilities { get; set; }
|
||||
|
||||
public YTSRequestGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
private IEnumerable<IndexerRequest> GetPagedRequests(string term, int[] categories, string imdbId = null)
|
||||
{
|
||||
var searchUrl = string.Format("{0}/api/v2/list_movies.json", Settings.BaseUrl.TrimEnd('/'));
|
||||
|
||||
var searchString = term;
|
||||
|
||||
var queryCollection = new NameValueCollection
|
||||
{
|
||||
// without this the API sometimes returns nothing
|
||||
{ "sort", "date_added" },
|
||||
{ "limit", "50" }
|
||||
};
|
||||
|
||||
if (imdbId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
queryCollection.Add("query_term", imdbId);
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(searchString))
|
||||
{
|
||||
searchString = searchString.Replace("'", ""); // ignore ' (e.g. search for america's Next Top Model)
|
||||
queryCollection.Add("query_term", searchString);
|
||||
}
|
||||
|
||||
searchUrl = searchUrl + "?" + queryCollection.GetQueryString();
|
||||
|
||||
var request = new IndexerRequest(searchUrl, HttpAccept.Html);
|
||||
|
||||
yield return request;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories, searchCriteria.FullImdbId));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||
{
|
||||
var pageableRequests = new IndexerPageableRequestChain();
|
||||
|
||||
pageableRequests.Add(GetPagedRequests(string.Format("{0}", searchCriteria.SanitizedSearchTerm), searchCriteria.Categories));
|
||||
|
||||
return pageableRequests;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class YTSParser : IParseIndexerResponse
|
||||
{
|
||||
private readonly YTSSettings _settings;
|
||||
private readonly IndexerCapabilitiesCategories _categories;
|
||||
|
||||
public YTSParser(YTSSettings settings, IndexerCapabilitiesCategories categories)
|
||||
{
|
||||
_settings = settings;
|
||||
_categories = categories;
|
||||
}
|
||||
|
||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||
{
|
||||
var torrentInfos = new List<ReleaseInfo>();
|
||||
|
||||
var contentString = indexerResponse.Content;
|
||||
|
||||
// returned content might start with an html error message, remove it first
|
||||
var jsonStart = contentString.IndexOf('{');
|
||||
var jsonContentStr = contentString.Remove(0, jsonStart);
|
||||
|
||||
var jsonContent = JObject.Parse(jsonContentStr);
|
||||
|
||||
var result = jsonContent.Value<string>("status");
|
||||
|
||||
// query was not successful
|
||||
if (result != "ok")
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
var dataItems = jsonContent.Value<JToken>("data");
|
||||
var movieCount = dataItems.Value<int>("movie_count");
|
||||
|
||||
// no results found in query
|
||||
if (movieCount < 1)
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
var movies = dataItems.Value<JToken>("movies");
|
||||
if (movies == null)
|
||||
{
|
||||
return new List<ReleaseInfo>();
|
||||
}
|
||||
|
||||
foreach (var movie in movies)
|
||||
{
|
||||
var torrents = movie.Value<JArray>("torrents");
|
||||
if (torrents == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var torrent in torrents)
|
||||
{
|
||||
var release = new TorrentInfo();
|
||||
|
||||
// append type: BRRip or WEBRip, resolves #3558 via #4577
|
||||
var type = torrent.Value<string>("type");
|
||||
switch (type)
|
||||
{
|
||||
case "web":
|
||||
type = "WEBRip";
|
||||
break;
|
||||
default:
|
||||
type = "BRRip";
|
||||
break;
|
||||
}
|
||||
|
||||
var quality = torrent.Value<string>("quality");
|
||||
var title = movie.Value<string>("title").Replace(":", "").Replace(' ', '.');
|
||||
var year = movie.Value<int>("year");
|
||||
release.Title = $"{title}.{year}.{quality}.{type}-YTS";
|
||||
|
||||
var imdb = movie.Value<string>("imdb_code");
|
||||
release.ImdbId = ParseUtil.GetImdbID(imdb).Value;
|
||||
|
||||
release.InfoHash = torrent.Value<string>("hash"); // magnet link is auto generated from infohash
|
||||
|
||||
// ex: 2015-08-16 21:25:08 +0000
|
||||
var dateStr = torrent.Value<string>("date_uploaded");
|
||||
var dateTime = DateTime.ParseExact(dateStr, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
release.PublishDate = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc).ToLocalTime();
|
||||
|
||||
release.DownloadUrl = torrent.Value<string>("url");
|
||||
release.Seeders = torrent.Value<int>("seeds");
|
||||
release.Peers = torrent.Value<int>("peers") + release.Seeders;
|
||||
release.Size = torrent.Value<long>("size_bytes");
|
||||
release.DownloadVolumeFactor = 0;
|
||||
release.UploadVolumeFactor = 1;
|
||||
|
||||
release.InfoUrl = movie.Value<string>("url");
|
||||
|
||||
release.PosterUrl = new Uri(movie.Value<string>("large_cover_image")).AbsoluteUri;
|
||||
release.Guid = release.DownloadUrl;
|
||||
|
||||
// map the quality to a newznab category for torznab compatibility (for Radarr, etc)
|
||||
switch (quality)
|
||||
{
|
||||
case "720p":
|
||||
release.Categories = _categories.MapTrackerCatToNewznab("45");
|
||||
break;
|
||||
case "1080p":
|
||||
release.Categories = _categories.MapTrackerCatToNewznab("44");
|
||||
break;
|
||||
case "2160p":
|
||||
release.Categories = _categories.MapTrackerCatToNewznab("46");
|
||||
break;
|
||||
case "3D":
|
||||
release.Categories = _categories.MapTrackerCatToNewznab("47");
|
||||
break;
|
||||
default:
|
||||
release.Categories = _categories.MapTrackerCatToNewznab("45");
|
||||
break;
|
||||
}
|
||||
|
||||
if (release == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
torrentInfos.Add(release);
|
||||
}
|
||||
}
|
||||
|
||||
return torrentInfos.ToArray();
|
||||
}
|
||||
|
||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||
}
|
||||
|
||||
public class YTSSettingsValidator : AbstractValidator<YTSSettings>
|
||||
{
|
||||
}
|
||||
|
||||
public class YTSSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly YTSSettingsValidator Validator = new YTSSettingsValidator();
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Settings
|
||||
{
|
||||
public class CookieTorrentBaseSettings : IIndexerSettings
|
||||
{
|
||||
public class CookieBaseSettingsValidator : AbstractValidator<CookieTorrentBaseSettings>
|
||||
{
|
||||
public CookieBaseSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Cookie).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly CookieBaseSettingsValidator Validator = new CookieBaseSettingsValidator();
|
||||
|
||||
public CookieTorrentBaseSettings()
|
||||
{
|
||||
Cookie = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Cookie", HelpText = "Site Cookie", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||
public string Cookie { get; set; }
|
||||
|
||||
[FieldDefinition(3)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Settings
|
||||
{
|
||||
public class NoAuthSettingsValidator : AbstractValidator<NoAuthTorrentBaseSettings>
|
||||
{
|
||||
}
|
||||
|
||||
public class NoAuthTorrentBaseSettings : IIndexerSettings
|
||||
{
|
||||
private static readonly NoAuthSettingsValidator Validator = new NoAuthSettingsValidator();
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls", HelpText = "Select which baseurl Prowlarr will use for requests to the site")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public virtual NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.Validation;
|
||||
|
||||
namespace NzbDrone.Core.Indexers.Settings
|
||||
{
|
||||
public class UserPassTorrentBaseSettings : IIndexerSettings
|
||||
{
|
||||
public class UserPassBaseSettingsValidator : AbstractValidator<UserPassTorrentBaseSettings>
|
||||
{
|
||||
public UserPassBaseSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.Username).NotEmpty();
|
||||
RuleFor(c => c.Password).NotEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly UserPassBaseSettingsValidator Validator = new UserPassBaseSettingsValidator();
|
||||
|
||||
public UserPassTorrentBaseSettings()
|
||||
{
|
||||
Username = "";
|
||||
Password = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(1, Label = "Base Url", HelpText = "Select which baseurl Prowlarr will use for requests to the site", Type = FieldType.Select, SelectOptionsProviderAction = "getUrls")]
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)]
|
||||
public string Username { get; set; }
|
||||
|
||||
[FieldDefinition(3, Label = "Password", HelpText = "Site Password", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||
public string Password { get; set; }
|
||||
|
||||
[FieldDefinition(4)]
|
||||
public IndexerBaseSettings BaseSettings { get; set; } = new IndexerBaseSettings();
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue