You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
10 KiB
238 lines
10 KiB
3 years ago
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using System.Net;
|
||
|
using System.Text;
|
||
|
using System.Text.RegularExpressions;
|
||
|
using System.Threading.Tasks;
|
||
|
using FluentValidation;
|
||
|
using FluentValidation.Results;
|
||
|
using NLog;
|
||
|
using NzbDrone.Common.Extensions;
|
||
|
using NzbDrone.Common.Http;
|
||
|
using NzbDrone.Common.Serializer;
|
||
|
using NzbDrone.Core.Annotations;
|
||
|
using NzbDrone.Core.Configuration;
|
||
|
using NzbDrone.Core.Indexers.Exceptions;
|
||
|
using NzbDrone.Core.Indexers.Gazelle;
|
||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||
|
using NzbDrone.Core.Messaging.Events;
|
||
|
using NzbDrone.Core.Parser.Model;
|
||
|
using NzbDrone.Core.Validation;
|
||
|
|
||
|
namespace NzbDrone.Core.Indexers.Definitions
|
||
|
{
|
||
|
public class SecretCinema : Gazelle.Gazelle
|
||
|
{
|
||
|
public override string Name => "Secret Cinema";
|
||
|
public override string[] IndexerUrls => new string[] { "https://secret-cinema.pw/" };
|
||
|
public override string Description => "A tracker for rare movies.";
|
||
|
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
|
||
|
public override IndexerPrivacy Privacy => IndexerPrivacy.Private;
|
||
|
public override IndexerCapabilities Capabilities => SetCapabilities();
|
||
|
|
||
|
public SecretCinema(IHttpClient httpClient, IEventAggregator eventAggregator, IIndexerStatusService indexerStatusService, IConfigService configService, Logger logger)
|
||
|
: base(httpClient, eventAggregator, indexerStatusService, configService, logger)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
public override IParseIndexerResponse GetParser()
|
||
|
{
|
||
|
return new SecretCinemaParser(Settings, Capabilities);
|
||
|
}
|
||
|
|
||
|
protected override IndexerCapabilities SetCapabilities()
|
||
|
{
|
||
|
var caps = new IndexerCapabilities
|
||
|
{
|
||
|
MovieSearchParams = new List<MovieSearchParam>
|
||
|
{
|
||
|
MovieSearchParam.Q
|
||
|
},
|
||
|
MusicSearchParams = new List<MusicSearchParam>
|
||
|
{
|
||
|
MusicSearchParam.Q, MusicSearchParam.Album, MusicSearchParam.Artist, MusicSearchParam.Label, MusicSearchParam.Year
|
||
|
}
|
||
|
};
|
||
|
|
||
|
caps.Categories.AddCategoryMapping(1, NewznabStandardCategory.Movies, "Movies");
|
||
|
caps.Categories.AddCategoryMapping(2, NewznabStandardCategory.Audio, "Music");
|
||
|
|
||
|
return caps;
|
||
|
}
|
||
|
|
||
|
public class SecretCinemaParser : IParseIndexerResponse
|
||
|
{
|
||
|
protected readonly GazelleSettings _settings;
|
||
|
protected readonly IndexerCapabilities _capabilities;
|
||
|
|
||
|
public SecretCinemaParser(GazelleSettings settings, IndexerCapabilities capabilities)
|
||
|
{
|
||
|
_settings = settings;
|
||
|
_capabilities = capabilities;
|
||
|
}
|
||
|
|
||
|
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
||
|
|
||
|
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");
|
||
|
}
|
||
|
|
||
|
if (!indexerResponse.HttpResponse.Headers.ContentType.Contains(HttpAccept.Json.Value))
|
||
|
{
|
||
|
// Remove cookie cache
|
||
|
CookiesUpdater(null, null);
|
||
|
|
||
|
throw new IndexerException(indexerResponse, $"Unexpected response header {indexerResponse.HttpResponse.Headers.ContentType} from API request, expected {HttpAccept.Json.Value}");
|
||
|
}
|
||
|
|
||
|
var jsonResponse = new HttpResponse<GazelleResponse>(indexerResponse.HttpResponse);
|
||
|
if (jsonResponse.Resource.Status != "success" ||
|
||
|
jsonResponse.Resource.Status.IsNullOrWhiteSpace() ||
|
||
|
jsonResponse.Resource.Response == null)
|
||
|
{
|
||
|
return torrentInfos;
|
||
|
}
|
||
|
|
||
|
foreach (var result in jsonResponse.Resource.Response.Results)
|
||
|
{
|
||
|
if (result.Torrents != null)
|
||
|
{
|
||
|
foreach (var torrent in result.Torrents)
|
||
|
{
|
||
|
var id = torrent.TorrentId;
|
||
|
|
||
|
// in SC movies, artist=director and GroupName=title
|
||
|
var artist = WebUtility.HtmlDecode(result.Artist);
|
||
|
var album = WebUtility.HtmlDecode(result.GroupName);
|
||
|
var title = WebUtility.HtmlDecode(result.GroupName);
|
||
|
|
||
|
var release = new GazelleInfo()
|
||
|
{
|
||
|
Guid = string.Format("SecretCinema-{0}", id),
|
||
|
Title = WebUtility.HtmlDecode(title),
|
||
|
Container = torrent.Encoding,
|
||
|
Files = torrent.FileCount,
|
||
|
Grabs = torrent.Snatches,
|
||
|
Codec = torrent.Format,
|
||
|
Size = long.Parse(torrent.Size),
|
||
|
DownloadUrl = GetDownloadUrl(id),
|
||
|
InfoUrl = GetInfoUrl(result.GroupId, id),
|
||
|
Seeders = int.Parse(torrent.Seeders),
|
||
|
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
|
||
|
PublishDate = torrent.Time.ToUniversalTime(),
|
||
|
Scene = torrent.Scene,
|
||
|
};
|
||
|
|
||
|
var category = torrent.Category;
|
||
|
if (category == null || category.Contains("Select Category"))
|
||
|
{
|
||
|
release.Categories = _capabilities.Categories.MapTrackerCatToNewznab("1");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
release.Categories = _capabilities.Categories.MapTrackerCatDescToNewznab(category);
|
||
|
}
|
||
|
|
||
|
if (IsAnyMovieCategory(release.Categories))
|
||
|
{
|
||
|
// Remove director from title
|
||
|
// SC API returns no more useful information than this
|
||
|
release.Title = $"{result.GroupName} ({result.GroupYear}) {torrent.Media}";
|
||
|
|
||
|
// Replace media formats with standards
|
||
|
release.Title = Regex.Replace(release.Title, "BDMV", "COMPLETE BLURAY", RegexOptions.IgnoreCase);
|
||
|
release.Title = Regex.Replace(release.Title, "SD", "DVDRip", RegexOptions.IgnoreCase);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// SC API currently doesn't return anything but title.
|
||
|
release.Title = $"{result.Artist} - {result.GroupName} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
|
||
|
}
|
||
|
|
||
|
if (torrent.HasCue)
|
||
|
{
|
||
|
release.Title += " [Cue]";
|
||
|
}
|
||
|
|
||
|
torrentInfos.Add(release);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var id = result.TorrentId;
|
||
|
var groupName = WebUtility.HtmlDecode(result.GroupName);
|
||
|
|
||
|
var release = new GazelleInfo()
|
||
|
{
|
||
|
Guid = string.Format("SecretCinema-{0}", id),
|
||
|
Title = groupName,
|
||
|
Size = long.Parse(result.Size),
|
||
|
DownloadUrl = GetDownloadUrl(id),
|
||
|
InfoUrl = GetInfoUrl(result.GroupId, id),
|
||
|
Seeders = int.Parse(result.Seeders),
|
||
|
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
|
||
|
Files = result.FileCount,
|
||
|
Grabs = result.Snatches,
|
||
|
PublishDate = DateTimeOffset.FromUnixTimeSeconds(result.GroupTime).UtcDateTime,
|
||
|
};
|
||
|
|
||
|
var category = result.Category;
|
||
|
if (category == null || category.Contains("Select Category"))
|
||
|
{
|
||
|
release.Categories = _capabilities.Categories.MapTrackerCatToNewznab("1");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
release.Categories = _capabilities.Categories.MapTrackerCatDescToNewznab(category);
|
||
|
}
|
||
|
|
||
|
torrentInfos.Add(release);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// order by date
|
||
|
return
|
||
|
torrentInfos
|
||
|
.OrderByDescending(o => o.PublishDate)
|
||
|
.ToArray();
|
||
|
}
|
||
|
|
||
|
private bool IsAnyMovieCategory(ICollection<IndexerCategory> category)
|
||
|
{
|
||
|
return category.Contains(NewznabStandardCategory.Movies)
|
||
|
|| NewznabStandardCategory.Movies.SubCategories.Any(subCat => category.Contains(subCat));
|
||
|
}
|
||
|
|
||
|
protected virtual string GetDownloadUrl(int torrentId)
|
||
|
{
|
||
|
var url = new HttpUri(_settings.BaseUrl)
|
||
|
.CombinePath("/torrents.php")
|
||
|
.AddQueryParam("action", "download")
|
||
|
.AddQueryParam("useToken", _settings.UseFreeleechToken ? "1" : "0")
|
||
|
.AddQueryParam("id", torrentId);
|
||
|
|
||
|
return url.FullUri;
|
||
|
}
|
||
|
|
||
|
private string GetInfoUrl(string groupId, int torrentId)
|
||
|
{
|
||
|
var url = new HttpUri(_settings.BaseUrl)
|
||
|
.CombinePath("/torrents.php")
|
||
|
.AddQueryParam("id", groupId)
|
||
|
.AddQueryParam("torrentid", torrentId);
|
||
|
|
||
|
return url.FullUri;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|