mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
Fixed: (FileList) Add alternative URL and return only FL results when fl-only is set
This commit is contained in:
@@ -8,7 +8,7 @@ using Moq;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Indexers.FileList;
|
using NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
@@ -3,7 +3,7 @@ using System.Linq;
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Indexers.FileList;
|
using NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
@@ -3,95 +3,98 @@ using NLog;
|
|||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.FileList
|
namespace NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
|
|
||||||
|
public class FileList : TorrentIndexerBase<FileListSettings>
|
||||||
{
|
{
|
||||||
public class FileList : TorrentIndexerBase<FileListSettings>
|
public override string Name => "FileList.io";
|
||||||
|
public override string[] IndexerUrls => new[]
|
||||||
{
|
{
|
||||||
public override string Name => "FileList.io";
|
"https://filelist.io/",
|
||||||
public override string[] IndexerUrls => new[] { "https://filelist.io/" };
|
"https://flro.org/"
|
||||||
public override string[] LegacyUrls => new[] { "https://filelist.io" };
|
};
|
||||||
public override string Description => "FileList (FL) is a ROMANIAN Private Torrent Tracker for 0DAY / GENERAL";
|
public override string[] LegacyUrls => new[] { "https://filelist.io" };
|
||||||
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
public override string Description => "FileList (FL) is a ROMANIAN Private Torrent Tracker for 0DAY / GENERAL";
|
||||||
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||||||
public override bool SupportsRss => true;
|
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||||||
public override bool SupportsSearch => true;
|
public override bool SupportsRss => true;
|
||||||
public override bool SupportsRedirect => true;
|
public override bool SupportsSearch => true;
|
||||||
public override IndexerCapabilities Capabilities => SetCapabilities();
|
public override bool SupportsRedirect => true;
|
||||||
|
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||||||
|
|
||||||
public FileList(IIndexerHttpClient httpClient,
|
public FileList(IIndexerHttpClient httpClient,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
IIndexerStatusService indexerStatusService,
|
IIndexerStatusService indexerStatusService,
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IIndexerRequestGenerator GetRequestGenerator()
|
public override IIndexerRequestGenerator GetRequestGenerator()
|
||||||
{
|
{
|
||||||
return new FileListRequestGenerator { Settings = Settings, Capabilities = Capabilities };
|
return new FileListRequestGenerator { Settings = Settings, Capabilities = Capabilities };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IParseIndexerResponse GetParser()
|
public override IParseIndexerResponse GetParser()
|
||||||
{
|
{
|
||||||
return new FileListParser(Settings, Capabilities.Categories);
|
return new FileListParser(Settings, Capabilities.Categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndexerCapabilities SetCapabilities()
|
private IndexerCapabilities SetCapabilities()
|
||||||
|
{
|
||||||
|
var caps = new IndexerCapabilities
|
||||||
{
|
{
|
||||||
var caps = new IndexerCapabilities
|
TvSearchParams = new List<TvSearchParam>
|
||||||
{
|
{
|
||||||
TvSearchParams = new List<TvSearchParam>
|
TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep
|
||||||
{
|
},
|
||||||
TvSearchParam.Q, TvSearchParam.ImdbId, TvSearchParam.Season, TvSearchParam.Ep
|
MovieSearchParams = new List<MovieSearchParam>
|
||||||
},
|
{
|
||||||
MovieSearchParams = new List<MovieSearchParam>
|
MovieSearchParam.Q, MovieSearchParam.ImdbId
|
||||||
{
|
},
|
||||||
MovieSearchParam.Q, MovieSearchParam.ImdbId
|
MusicSearchParams = new List<MusicSearchParam>
|
||||||
},
|
{
|
||||||
MusicSearchParams = new List<MusicSearchParam>
|
MusicSearchParam.Q
|
||||||
{
|
},
|
||||||
MusicSearchParam.Q
|
BookSearchParams = new List<BookSearchParam>
|
||||||
},
|
{
|
||||||
BookSearchParams = new List<BookSearchParam>
|
BookSearchParam.Q
|
||||||
{
|
},
|
||||||
BookSearchParam.Q
|
Flags = new List<IndexerFlag>
|
||||||
},
|
{
|
||||||
Flags = new List<IndexerFlag>
|
IndexerFlag.Internal,
|
||||||
{
|
IndexerFlag.FreeLeech
|
||||||
IndexerFlag.Internal,
|
}
|
||||||
IndexerFlag.FreeLeech
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD");
|
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.MoviesSD, "Filme SD");
|
||||||
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesDVD, "Filme DVD");
|
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.MoviesDVD, "Filme DVD");
|
||||||
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesForeign, "Filme DVD-RO");
|
caps.Categories.AddCategoryMapping(3, NewznabStandardCategory.MoviesForeign, "Filme DVD-RO");
|
||||||
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Filme HD");
|
caps.Categories.AddCategoryMapping(4, NewznabStandardCategory.MoviesHD, "Filme HD");
|
||||||
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.AudioLossless, "FLAC");
|
caps.Categories.AddCategoryMapping(5, NewznabStandardCategory.AudioLossless, "FLAC");
|
||||||
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesUHD, "Filme 4K");
|
caps.Categories.AddCategoryMapping(6, NewznabStandardCategory.MoviesUHD, "Filme 4K");
|
||||||
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXX, "XXX");
|
caps.Categories.AddCategoryMapping(7, NewznabStandardCategory.XXX, "XXX");
|
||||||
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.PC, "Programe");
|
caps.Categories.AddCategoryMapping(8, NewznabStandardCategory.PC, "Programe");
|
||||||
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.PCGames, "Jocuri PC");
|
caps.Categories.AddCategoryMapping(9, NewznabStandardCategory.PCGames, "Jocuri PC");
|
||||||
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.Console, "Jocuri Console");
|
caps.Categories.AddCategoryMapping(10, NewznabStandardCategory.Console, "Jocuri Console");
|
||||||
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Audio, "Audio");
|
caps.Categories.AddCategoryMapping(11, NewznabStandardCategory.Audio, "Audio");
|
||||||
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.AudioVideo, "Videoclip");
|
caps.Categories.AddCategoryMapping(12, NewznabStandardCategory.AudioVideo, "Videoclip");
|
||||||
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.TVSport, "Sport");
|
caps.Categories.AddCategoryMapping(13, NewznabStandardCategory.TVSport, "Sport");
|
||||||
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.TV, "Desene");
|
caps.Categories.AddCategoryMapping(15, NewznabStandardCategory.TV, "Desene");
|
||||||
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.Books, "Docs");
|
caps.Categories.AddCategoryMapping(16, NewznabStandardCategory.Books, "Docs");
|
||||||
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.PC, "Linux");
|
caps.Categories.AddCategoryMapping(17, NewznabStandardCategory.PC, "Linux");
|
||||||
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.Other, "Diverse");
|
caps.Categories.AddCategoryMapping(18, NewznabStandardCategory.Other, "Diverse");
|
||||||
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesForeign, "Filme HD-RO");
|
caps.Categories.AddCategoryMapping(19, NewznabStandardCategory.MoviesForeign, "Filme HD-RO");
|
||||||
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.MoviesBluRay, "Filme Blu-Ray");
|
caps.Categories.AddCategoryMapping(20, NewznabStandardCategory.MoviesBluRay, "Filme Blu-Ray");
|
||||||
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.TVHD, "Seriale HD");
|
caps.Categories.AddCategoryMapping(21, NewznabStandardCategory.TVHD, "Seriale HD");
|
||||||
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.PCMobileOther, "Mobile");
|
caps.Categories.AddCategoryMapping(22, NewznabStandardCategory.PCMobileOther, "Mobile");
|
||||||
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVSD, "Seriale SD");
|
caps.Categories.AddCategoryMapping(23, NewznabStandardCategory.TVSD, "Seriale SD");
|
||||||
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVAnime, "Anime");
|
caps.Categories.AddCategoryMapping(24, NewznabStandardCategory.TVAnime, "Anime");
|
||||||
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.Movies3D, "Filme 3D");
|
caps.Categories.AddCategoryMapping(25, NewznabStandardCategory.Movies3D, "Filme 3D");
|
||||||
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.MoviesBluRay, "Filme 4K Blu-Ray");
|
caps.Categories.AddCategoryMapping(26, NewznabStandardCategory.MoviesBluRay, "Filme 4K Blu-Ray");
|
||||||
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TVUHD, "Seriale 4K");
|
caps.Categories.AddCategoryMapping(27, NewznabStandardCategory.TVUHD, "Seriale 4K");
|
||||||
|
|
||||||
return caps;
|
return caps;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,29 +1,28 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.FileList
|
namespace NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
|
|
||||||
|
public class FileListTorrent
|
||||||
{
|
{
|
||||||
public class FileListTorrent
|
public string Id { get; set; }
|
||||||
{
|
public string Name { get; set; }
|
||||||
public string Id { get; set; }
|
public long Size { get; set; }
|
||||||
public string Name { get; set; }
|
public int Leechers { get; set; }
|
||||||
public long Size { get; set; }
|
public int Seeders { get; set; }
|
||||||
public int Leechers { get; set; }
|
[JsonProperty(PropertyName = "times_completed")]
|
||||||
public int Seeders { get; set; }
|
public uint TimesCompleted { get; set; }
|
||||||
[JsonProperty(PropertyName = "times_completed")]
|
public uint Comments { get; set; }
|
||||||
public uint TimesCompleted { get; set; }
|
public uint Files { get; set; }
|
||||||
public uint Comments { get; set; }
|
[JsonProperty(PropertyName = "imdb")]
|
||||||
public uint Files { get; set; }
|
public string ImdbId { get; set; }
|
||||||
[JsonProperty(PropertyName = "imdb")]
|
public bool Internal { get; set; }
|
||||||
public string ImdbId { get; set; }
|
[JsonProperty(PropertyName = "freeleech")]
|
||||||
public bool Internal { get; set; }
|
public bool FreeLeech { get; set; }
|
||||||
[JsonProperty(PropertyName = "freeleech")]
|
[JsonProperty(PropertyName = "doubleup")]
|
||||||
public bool FreeLeech { get; set; }
|
public bool DoubleUp { get; set; }
|
||||||
[JsonProperty(PropertyName = "doubleup")]
|
[JsonProperty(PropertyName = "upload_date")]
|
||||||
public bool DoubleUp { get; set; }
|
public string UploadDate { get; set; }
|
||||||
[JsonProperty(PropertyName = "upload_date")]
|
public string Category { get; set; }
|
||||||
public string UploadDate { get; set; }
|
[JsonProperty(PropertyName = "small_description")]
|
||||||
public string Category { get; set; }
|
public string SmallDescription { get; set; }
|
||||||
[JsonProperty(PropertyName = "small_description")]
|
|
||||||
public string SmallDescription { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -8,101 +8,105 @@ using NzbDrone.Common.Http;
|
|||||||
using NzbDrone.Core.Indexers.Exceptions;
|
using NzbDrone.Core.Indexers.Exceptions;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.FileList
|
namespace NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
|
|
||||||
|
public class FileListParser : IParseIndexerResponse
|
||||||
{
|
{
|
||||||
public class FileListParser : IParseIndexerResponse
|
private readonly FileListSettings _settings;
|
||||||
|
private readonly IndexerCapabilitiesCategories _categories;
|
||||||
|
|
||||||
|
public FileListParser(FileListSettings settings, IndexerCapabilitiesCategories categories)
|
||||||
{
|
{
|
||||||
private readonly FileListSettings _settings;
|
_settings = settings;
|
||||||
private readonly IndexerCapabilitiesCategories _categories;
|
_categories = categories;
|
||||||
|
}
|
||||||
|
|
||||||
public FileListParser(FileListSettings settings, IndexerCapabilitiesCategories categories)
|
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
||||||
|
{
|
||||||
|
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
_settings = settings;
|
throw new IndexerException(indexerResponse, "Unexpected response status {0} code from API request", indexerResponse.HttpResponse.StatusCode);
|
||||||
_categories = categories;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||||||
{
|
{
|
||||||
var torrentInfos = new List<ReleaseInfo>();
|
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
||||||
|
}
|
||||||
|
|
||||||
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
|
var releaseInfos = new List<ReleaseInfo>();
|
||||||
|
|
||||||
|
var results = JsonConvert.DeserializeObject<List<FileListTorrent>>(indexerResponse.Content);
|
||||||
|
|
||||||
|
foreach (var row in results)
|
||||||
|
{
|
||||||
|
// skip non-freeleech results when freeleech only is set
|
||||||
|
if (_settings.FreeleechOnly && !row.FreeLeech)
|
||||||
{
|
{
|
||||||
throw new IndexerException(indexerResponse, "Unexpected response status {0} code from API request", indexerResponse.HttpResponse.StatusCode);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
var id = row.Id;
|
||||||
|
|
||||||
|
var flags = new HashSet<IndexerFlag>();
|
||||||
|
if (row.Internal)
|
||||||
{
|
{
|
||||||
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
flags.Add(IndexerFlag.Internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryResults = JsonConvert.DeserializeObject<List<FileListTorrent>>(indexerResponse.Content);
|
var imdbId = 0;
|
||||||
|
if (row.ImdbId != null && row.ImdbId.Length > 2)
|
||||||
foreach (var result in queryResults)
|
|
||||||
{
|
{
|
||||||
var id = result.Id;
|
imdbId = int.Parse(row.ImdbId.Substring(2));
|
||||||
|
|
||||||
var flags = new HashSet<IndexerFlag>();
|
|
||||||
|
|
||||||
if (result.Internal)
|
|
||||||
{
|
|
||||||
flags.Add(IndexerFlag.Internal);
|
|
||||||
}
|
|
||||||
|
|
||||||
var imdbId = 0;
|
|
||||||
if (result.ImdbId != null && result.ImdbId.Length > 2)
|
|
||||||
{
|
|
||||||
imdbId = int.Parse(result.ImdbId.Substring(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
var downloadVolumeFactor = result.FreeLeech ? 0 : 1;
|
|
||||||
var uploadVolumeFactor = result.DoubleUp ? 2 : 1;
|
|
||||||
|
|
||||||
torrentInfos.Add(new TorrentInfo
|
|
||||||
{
|
|
||||||
Guid = string.Format("FileList-{0}", id),
|
|
||||||
Title = result.Name,
|
|
||||||
Size = result.Size,
|
|
||||||
Categories = _categories.MapTrackerCatDescToNewznab(result.Category),
|
|
||||||
DownloadUrl = GetDownloadUrl(id),
|
|
||||||
InfoUrl = GetInfoUrl(id),
|
|
||||||
Seeders = result.Seeders,
|
|
||||||
Peers = result.Leechers + result.Seeders,
|
|
||||||
PublishDate = DateTime.Parse(result.UploadDate + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
|
|
||||||
Description = result.SmallDescription,
|
|
||||||
Genres = result.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
|
|
||||||
ImdbId = imdbId,
|
|
||||||
IndexerFlags = flags,
|
|
||||||
Files = (int)result.Files,
|
|
||||||
Grabs = (int)result.TimesCompleted,
|
|
||||||
DownloadVolumeFactor = downloadVolumeFactor,
|
|
||||||
UploadVolumeFactor = uploadVolumeFactor,
|
|
||||||
MinimumRatio = 1,
|
|
||||||
MinimumSeedTime = 172800, // 48 hours
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return torrentInfos.ToArray();
|
var downloadVolumeFactor = row.FreeLeech ? 0 : 1;
|
||||||
|
var uploadVolumeFactor = row.DoubleUp ? 2 : 1;
|
||||||
|
|
||||||
|
releaseInfos.Add(new TorrentInfo
|
||||||
|
{
|
||||||
|
Guid = string.Format("FileList-{0}", id),
|
||||||
|
Title = row.Name,
|
||||||
|
Size = row.Size,
|
||||||
|
Categories = _categories.MapTrackerCatDescToNewznab(row.Category),
|
||||||
|
DownloadUrl = GetDownloadUrl(id),
|
||||||
|
InfoUrl = GetInfoUrl(id),
|
||||||
|
Seeders = row.Seeders,
|
||||||
|
Peers = row.Leechers + row.Seeders,
|
||||||
|
PublishDate = DateTime.Parse(row.UploadDate + " +0200", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal),
|
||||||
|
Description = row.SmallDescription,
|
||||||
|
Genres = row.SmallDescription.Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries).ToList(),
|
||||||
|
ImdbId = imdbId,
|
||||||
|
IndexerFlags = flags,
|
||||||
|
Files = (int)row.Files,
|
||||||
|
Grabs = (int)row.TimesCompleted,
|
||||||
|
DownloadVolumeFactor = downloadVolumeFactor,
|
||||||
|
UploadVolumeFactor = uploadVolumeFactor,
|
||||||
|
MinimumRatio = 1,
|
||||||
|
MinimumSeedTime = 172800, // 48 hours
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
return releaseInfos.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
private string GetDownloadUrl(string torrentId)
|
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||||
{
|
|
||||||
var url = new HttpUri(_settings.BaseUrl)
|
|
||||||
.CombinePath("/download.php")
|
|
||||||
.AddQueryParam("id", torrentId)
|
|
||||||
.AddQueryParam("passkey", _settings.Passkey);
|
|
||||||
|
|
||||||
return url.FullUri;
|
private string GetDownloadUrl(string torrentId)
|
||||||
}
|
{
|
||||||
|
var url = new HttpUri(_settings.BaseUrl)
|
||||||
|
.CombinePath("/download.php")
|
||||||
|
.AddQueryParam("id", torrentId)
|
||||||
|
.AddQueryParam("passkey", _settings.Passkey);
|
||||||
|
|
||||||
private string GetInfoUrl(string torrentId)
|
return url.FullUri;
|
||||||
{
|
}
|
||||||
var url = new HttpUri(_settings.BaseUrl)
|
|
||||||
.CombinePath("/details.php")
|
|
||||||
.AddQueryParam("id", torrentId);
|
|
||||||
|
|
||||||
return url.FullUri;
|
private string GetInfoUrl(string torrentId)
|
||||||
}
|
{
|
||||||
|
var url = new HttpUri(_settings.BaseUrl)
|
||||||
|
.CombinePath("/details.php")
|
||||||
|
.AddQueryParam("id", torrentId);
|
||||||
|
|
||||||
|
return url.FullUri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,149 +6,148 @@ using NzbDrone.Common.Http;
|
|||||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.FileList
|
namespace NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
|
|
||||||
|
public class FileListRequestGenerator : IIndexerRequestGenerator
|
||||||
{
|
{
|
||||||
public class FileListRequestGenerator : IIndexerRequestGenerator
|
public FileListSettings Settings { get; set; }
|
||||||
|
public IndexerCapabilities Capabilities { get; set; }
|
||||||
|
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
||||||
|
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
||||||
{
|
{
|
||||||
public FileListSettings Settings { get; set; }
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
public IndexerCapabilities Capabilities { get; set; }
|
var parameters = GetDefaultParameters();
|
||||||
public Func<IDictionary<string, string>> GetCookies { get; set; }
|
|
||||||
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
|
||||||
|
|
||||||
public IndexerPageableRequestChain GetSearchRequests(TvSearchCriteria searchCriteria)
|
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() || searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
var pageableRequests = new IndexerPageableRequestChain();
|
parameters.Add("action", "search-torrents");
|
||||||
var parameters = GetDefaultParameters();
|
|
||||||
|
|
||||||
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace() || searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
parameters.Add("action", "search-torrents");
|
|
||||||
|
|
||||||
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
parameters.Add("type", "imdb");
|
|
||||||
parameters.Add("query", searchCriteria.FullImdbId);
|
|
||||||
}
|
|
||||||
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
parameters.Add("type", "name");
|
|
||||||
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchCriteria.Season.HasValue)
|
|
||||||
{
|
|
||||||
parameters.Add("season", searchCriteria.Season.ToString());
|
|
||||||
parameters.Add("episode", searchCriteria.Episode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
|
||||||
|
|
||||||
return pageableRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
|
||||||
{
|
|
||||||
var pageableRequests = new IndexerPageableRequestChain();
|
|
||||||
var parameters = GetDefaultParameters();
|
|
||||||
|
|
||||||
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
|
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
parameters.Add("action", "search-torrents");
|
|
||||||
parameters.Add("type", "imdb");
|
parameters.Add("type", "imdb");
|
||||||
parameters.Add("query", searchCriteria.FullImdbId);
|
parameters.Add("query", searchCriteria.FullImdbId);
|
||||||
}
|
}
|
||||||
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
parameters.Add("action", "search-torrents");
|
|
||||||
parameters.Add("type", "name");
|
parameters.Add("type", "name");
|
||||||
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
if (searchCriteria.Season.HasValue)
|
||||||
|
|
||||||
return pageableRequests;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
|
||||||
{
|
|
||||||
var pageableRequests = new IndexerPageableRequestChain();
|
|
||||||
var parameters = GetDefaultParameters();
|
|
||||||
|
|
||||||
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
{
|
||||||
parameters.Add("action", "search-torrents");
|
parameters.Add("season", searchCriteria.Season.ToString());
|
||||||
parameters.Add("type", "name");
|
parameters.Add("episode", searchCriteria.Episode);
|
||||||
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
|
||||||
|
|
||||||
return pageableRequests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
var parameters = GetDefaultParameters();
|
||||||
|
|
||||||
|
if (searchCriteria.ImdbId.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
var pageableRequests = new IndexerPageableRequestChain();
|
parameters.Add("action", "search-torrents");
|
||||||
var parameters = GetDefaultParameters();
|
parameters.Add("type", "imdb");
|
||||||
|
parameters.Add("query", searchCriteria.FullImdbId);
|
||||||
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
parameters.Add("action", "search-torrents");
|
|
||||||
parameters.Add("type", "name");
|
|
||||||
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
|
||||||
|
|
||||||
return pageableRequests;
|
|
||||||
}
|
}
|
||||||
|
else if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||||
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
|
||||||
{
|
{
|
||||||
var pageableRequests = new IndexerPageableRequestChain();
|
parameters.Add("action", "search-torrents");
|
||||||
var parameters = GetDefaultParameters();
|
parameters.Add("type", "name");
|
||||||
|
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
||||||
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
parameters.Add("action", "search-torrents");
|
|
||||||
parameters.Add("type", "name");
|
|
||||||
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
|
||||||
|
|
||||||
return pageableRequests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<IndexerRequest> GetRequest(SearchCriteriaBase searchCriteria, NameValueCollection parameters)
|
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(MusicSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
var parameters = GetDefaultParameters();
|
||||||
|
|
||||||
|
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
if (parameters.Get("action") is null)
|
parameters.Add("action", "search-torrents");
|
||||||
{
|
parameters.Add("type", "name");
|
||||||
parameters.Add("action", "latest-torrents");
|
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
||||||
}
|
|
||||||
|
|
||||||
parameters.Add("category", string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories)));
|
|
||||||
|
|
||||||
var searchUrl = $"{Settings.BaseUrl.TrimEnd('/')}/api.php?{parameters.GetQueryString()}";
|
|
||||||
|
|
||||||
yield return new IndexerRequest(searchUrl, HttpAccept.Json);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private NameValueCollection GetDefaultParameters()
|
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(BookSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
var parameters = GetDefaultParameters();
|
||||||
|
|
||||||
|
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||||
{
|
{
|
||||||
var parameters = new NameValueCollection
|
parameters.Add("action", "search-torrents");
|
||||||
{
|
parameters.Add("type", "name");
|
||||||
{ "username", Settings.Username.Trim() },
|
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
||||||
{ "passkey", Settings.Passkey.Trim() }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Settings.FreeleechOnly)
|
|
||||||
{
|
|
||||||
parameters.Add("freeleech", "1");
|
|
||||||
}
|
|
||||||
|
|
||||||
return parameters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IndexerPageableRequestChain GetSearchRequests(BasicSearchCriteria searchCriteria)
|
||||||
|
{
|
||||||
|
var pageableRequests = new IndexerPageableRequestChain();
|
||||||
|
var parameters = GetDefaultParameters();
|
||||||
|
|
||||||
|
if (searchCriteria.SearchTerm.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
parameters.Add("action", "search-torrents");
|
||||||
|
parameters.Add("type", "name");
|
||||||
|
parameters.Add("query", searchCriteria.SanitizedSearchTerm.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
pageableRequests.Add(GetRequest(searchCriteria, parameters));
|
||||||
|
|
||||||
|
return pageableRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IndexerRequest> GetRequest(SearchCriteriaBase searchCriteria, NameValueCollection parameters)
|
||||||
|
{
|
||||||
|
if (parameters.Get("action") is null)
|
||||||
|
{
|
||||||
|
parameters.Add("action", "latest-torrents");
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.Add("category", string.Join(",", Capabilities.Categories.MapTorznabCapsToTrackers(searchCriteria.Categories)));
|
||||||
|
|
||||||
|
var searchUrl = $"{Settings.BaseUrl.TrimEnd('/')}/api.php?{parameters.GetQueryString()}";
|
||||||
|
|
||||||
|
yield return new IndexerRequest(searchUrl, HttpAccept.Json);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NameValueCollection GetDefaultParameters()
|
||||||
|
{
|
||||||
|
var parameters = new NameValueCollection
|
||||||
|
{
|
||||||
|
{ "username", Settings.Username.Trim() },
|
||||||
|
{ "passkey", Settings.Passkey.Trim() }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Settings.FreeleechOnly)
|
||||||
|
{
|
||||||
|
parameters.Add("freeleech", "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,33 +3,32 @@ using NzbDrone.Core.Annotations;
|
|||||||
using NzbDrone.Core.Indexers.Settings;
|
using NzbDrone.Core.Indexers.Settings;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Indexers.FileList
|
namespace NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
|
|
||||||
|
public class FileListSettingsValidator : NoAuthSettingsValidator<FileListSettings>
|
||||||
{
|
{
|
||||||
public class FileListSettingsValidator : NoAuthSettingsValidator<FileListSettings>
|
public FileListSettingsValidator()
|
||||||
{
|
{
|
||||||
public FileListSettingsValidator()
|
RuleFor(c => c.Username).NotEmpty();
|
||||||
{
|
RuleFor(c => c.Passkey).NotEmpty();
|
||||||
RuleFor(c => c.Username).NotEmpty();
|
}
|
||||||
RuleFor(c => c.Passkey).NotEmpty();
|
}
|
||||||
}
|
|
||||||
}
|
public class FileListSettings : NoAuthTorrentBaseSettings
|
||||||
|
{
|
||||||
public class FileListSettings : NoAuthTorrentBaseSettings
|
private static readonly FileListSettingsValidator Validator = new ();
|
||||||
{
|
|
||||||
private static readonly FileListSettingsValidator Validator = new ();
|
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)]
|
||||||
|
public string Username { get; set; }
|
||||||
[FieldDefinition(2, Label = "Username", HelpText = "Site Username", Privacy = PrivacyLevel.UserName)]
|
|
||||||
public string Username { get; set; }
|
[FieldDefinition(3, Label = "Passkey", HelpText = "Site Passkey (This is the alphanumeric string in the tracker url shown in your download client)", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
||||||
|
public string Passkey { get; set; }
|
||||||
[FieldDefinition(3, Label = "Passkey", HelpText = "Site Passkey (This is the alphanumeric string in the tracker url shown in your download client)", Privacy = PrivacyLevel.Password, Type = FieldType.Password)]
|
|
||||||
public string Passkey { get; set; }
|
[FieldDefinition(4, Label = "Freeleech Only", HelpText = "Search Freeleech torrents only", Type = FieldType.Checkbox)]
|
||||||
|
public bool FreeleechOnly { get; set; }
|
||||||
[FieldDefinition(4, Label = "Freeleech Only", HelpText = "Search Freeleech torrents only", Type = FieldType.Checkbox)]
|
|
||||||
public bool FreeleechOnly { get; set; }
|
public override NzbDroneValidationResult Validate()
|
||||||
|
{
|
||||||
public override NzbDroneValidationResult Validate()
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
{
|
|
||||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using Npgsql;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
using NzbDrone.Core.Indexers.FileList;
|
using NzbDrone.Core.Indexers.Definitions.FileList;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
using NzbDrone.Test.Common.Datastore;
|
using NzbDrone.Test.Common.Datastore;
|
||||||
using Prowlarr.Http.ClientSchema;
|
using Prowlarr.Http.ClientSchema;
|
||||||
|
Reference in New Issue
Block a user