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.
Prowlarr/src/NzbDrone.Core/Indexers/Definitions/Gazelle/GazelleParser.cs

198 lines
7.5 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Indexers.Definitions.Gazelle;
public class GazelleParser : IParseIndexerResponse
{
protected GazelleSettings Settings { get; }
protected IndexerCapabilities Capabilities { get; }
public GazelleParser(GazelleSettings settings, IndexerCapabilities capabilities)
{
Settings = settings;
Capabilities = capabilities;
}
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
public virtual 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 indexer 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 indexer 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)
{
var posterUrl = GetPosterUrl(result.Cover);
if (result.Torrents != null)
{
foreach (var torrent in result.Torrents)
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (Settings.UseFreeleechToken && !torrent.CanUseToken)
{
continue;
}
var id = torrent.TorrentId;
var title = $"{result.Artist} - {result.GroupName} ({result.GroupYear}) [{torrent.Format} {torrent.Encoding}] [{torrent.Media}]";
if (torrent.HasCue)
{
title += " [Cue]";
}
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new TorrentInfo
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, !torrent.IsFreeLeech && !torrent.IsNeutralLeech && !torrent.IsPersonalFreeLeech),
Title = WebUtility.HtmlDecode(title),
Container = torrent.Encoding,
Files = torrent.FileCount,
Grabs = torrent.Snatches,
Codec = torrent.Format,
Size = long.Parse(torrent.Size),
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime(),
Scene = torrent.Scene,
PosterUrl = posterUrl,
DownloadVolumeFactor = torrent.IsFreeLeech || torrent.IsNeutralLeech || torrent.IsPersonalFreeLeech ? 0 : 1,
UploadVolumeFactor = torrent.IsNeutralLeech ? 0 : 1
};
var category = torrent.Category;
if (category == null || category.Contains("Select Category"))
{
release.Categories = Capabilities.Categories.MapTrackerCatToNewznab("1");
}
else
{
release.Categories = Capabilities.Categories.MapTrackerCatDescToNewznab(category);
}
torrentInfos.Add(release);
}
}
else
{
// skip releases that cannot be used with freeleech tokens when the option is enabled
if (Settings.UseFreeleechToken && !result.CanUseToken)
{
continue;
}
var id = result.TorrentId;
var groupName = WebUtility.HtmlDecode(result.GroupName);
var infoUrl = GetInfoUrl(result.GroupId, id);
var release = new TorrentInfo
{
Guid = infoUrl,
InfoUrl = infoUrl,
DownloadUrl = GetDownloadUrl(id, !result.IsFreeLeech && !result.IsNeutralLeech && !result.IsPersonalFreeLeech),
Title = groupName,
Size = long.Parse(result.Size),
Seeders = int.Parse(result.Seeders),
Peers = int.Parse(result.Leechers) + int.Parse(result.Seeders),
Files = result.FileCount,
Grabs = result.Snatches,
PublishDate = long.TryParse(result.GroupTime, out var num) ? DateTimeOffset.FromUnixTimeSeconds(num).UtcDateTime : DateTimeUtil.FromFuzzyTime((string)result.GroupTime),
PosterUrl = posterUrl,
DownloadVolumeFactor = result.IsFreeLeech || result.IsNeutralLeech || result.IsPersonalFreeLeech ? 0 : 1,
UploadVolumeFactor = result.IsNeutralLeech ? 0 : 1
};
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();
}
protected virtual string GetDownloadUrl(int torrentId, bool canUseToken)
{
var url = new HttpUri(Settings.BaseUrl)
.CombinePath("/torrents.php")
.AddQueryParam("action", "download")
.AddQueryParam("id", torrentId);
if (Settings.UseFreeleechToken)
{
url = url.AddQueryParam("usetoken", "1");
}
return url.FullUri;
}
protected virtual string GetPosterUrl(string cover)
{
if (!string.IsNullOrEmpty(cover))
{
return cover.StartsWith("http") ?
new HttpUri(cover).FullUri :
new HttpUri(Settings.BaseUrl).CombinePath(cover).FullUri;
}
return null;
}
protected virtual string GetInfoUrl(string groupId, int torrentId)
{
var url = new HttpUri(Settings.BaseUrl)
.CombinePath("/torrents.php")
.AddQueryParam("id", groupId)
.AddQueryParam("torrentid", torrentId);
return url.FullUri;
}
}