mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-04-18 21:55:12 -04:00
153 lines
6.3 KiB
C#
153 lines
6.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Text.RegularExpressions;
|
|
using NzbDrone.Common.Extensions;
|
|
using NzbDrone.Common.Http;
|
|
using NzbDrone.Core.Indexers.Exceptions;
|
|
using NzbDrone.Core.Parser.Model;
|
|
|
|
namespace NzbDrone.Core.Indexers.BroadcastheNet
|
|
{
|
|
public class BroadcastheNetParser : IParseIndexerResponse
|
|
{
|
|
private static readonly Regex RegexProtocol = new ("^https?:", RegexOptions.Compiled);
|
|
|
|
public Action<IDictionary<string, string>, DateTime?> CookiesUpdater { get; set; }
|
|
|
|
private readonly IndexerCapabilitiesCategories _categories;
|
|
|
|
public BroadcastheNetParser(IndexerCapabilitiesCategories categories)
|
|
{
|
|
_categories = categories;
|
|
}
|
|
|
|
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
|
|
{
|
|
var releaseInfos = new List<ReleaseInfo>();
|
|
var indexerHttpResponse = indexerResponse.HttpResponse;
|
|
|
|
switch (indexerHttpResponse.StatusCode)
|
|
{
|
|
case HttpStatusCode.Unauthorized:
|
|
throw new IndexerAuthException("API Key invalid or not authorized");
|
|
case HttpStatusCode.NotFound:
|
|
throw new IndexerException(indexerResponse, "Indexer API call returned NotFound, the Indexer API may have changed.");
|
|
case HttpStatusCode.ServiceUnavailable:
|
|
throw new RequestLimitReachedException(indexerResponse, "Cannot do more than 150 API requests per hour.");
|
|
default:
|
|
if (indexerHttpResponse.StatusCode != HttpStatusCode.OK)
|
|
{
|
|
throw new IndexerException(indexerResponse, "Indexer API call returned an unexpected StatusCode [{0}]", indexerHttpResponse.StatusCode);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (indexerHttpResponse.Headers.ContentType != null && indexerHttpResponse.Headers.ContentType.Contains("text/html"))
|
|
{
|
|
throw new IndexerException(indexerResponse, "Indexer responded with html content. Site is likely blocked or unavailable.");
|
|
}
|
|
|
|
if (indexerResponse.Content.ContainsIgnoreCase("Call Limit Exceeded"))
|
|
{
|
|
throw new RequestLimitReachedException(indexerResponse, "Cannot do more than 150 API requests per hour.");
|
|
}
|
|
|
|
if (indexerResponse.Content == "Query execution was interrupted")
|
|
{
|
|
throw new IndexerException(indexerResponse, "Indexer API returned an internal server error");
|
|
}
|
|
|
|
var jsonResponse = new HttpResponse<JsonRpcResponse<BroadcastheNetTorrents>>(indexerHttpResponse).Resource;
|
|
|
|
if (jsonResponse.Error != null || jsonResponse.Result == null)
|
|
{
|
|
throw new IndexerException(indexerResponse, "Indexer API call returned an error [{0}]", jsonResponse.Error);
|
|
}
|
|
|
|
if (jsonResponse.Result.Results == 0 || jsonResponse.Result?.Torrents?.Values == null)
|
|
{
|
|
return releaseInfos;
|
|
}
|
|
|
|
var protocol = indexerResponse.HttpRequest.Url.Scheme + ":";
|
|
|
|
foreach (var torrent in jsonResponse.Result.Torrents.Values)
|
|
{
|
|
var flags = new HashSet<IndexerFlag>();
|
|
|
|
if (torrent.Origin.ToUpperInvariant() == "INTERNAL")
|
|
{
|
|
flags.Add(IndexerFlag.Internal);
|
|
}
|
|
|
|
var releaseInfo = new TorrentInfo
|
|
{
|
|
Guid = $"BTN-{torrent.TorrentID}",
|
|
InfoUrl = $"{protocol}//broadcasthe.net/torrents.php?id={torrent.GroupID}&torrentid={torrent.TorrentID}",
|
|
DownloadUrl = RegexProtocol.Replace(torrent.DownloadURL, protocol),
|
|
Title = GetTitle(torrent),
|
|
Categories = _categories.MapTrackerCatToNewznab(torrent.Resolution),
|
|
InfoHash = torrent.InfoHash,
|
|
Size = torrent.Size,
|
|
Grabs = torrent.Snatched,
|
|
Seeders = torrent.Seeders,
|
|
Peers = torrent.Leechers + torrent.Seeders,
|
|
PublishDate = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().AddSeconds(torrent.Time),
|
|
Origin = torrent.Origin,
|
|
Source = torrent.Source,
|
|
Container = torrent.Container,
|
|
Codec = torrent.Codec,
|
|
Resolution = torrent.Resolution,
|
|
Scene = torrent.Origin.ToUpperInvariant() == "SCENE",
|
|
IndexerFlags = flags,
|
|
DownloadVolumeFactor = 0,
|
|
UploadVolumeFactor = 1,
|
|
MinimumRatio = 1,
|
|
MinimumSeedTime = torrent.Category.ToUpperInvariant() == "SEASON" ? 432000 : 86400, // 120 hours for seasons and 24 hours for episodes
|
|
};
|
|
|
|
if (torrent.TvdbID is > 0)
|
|
{
|
|
releaseInfo.TvdbId = torrent.TvdbID.Value;
|
|
}
|
|
|
|
if (torrent.TvrageID is > 0)
|
|
{
|
|
releaseInfo.TvRageId = torrent.TvrageID.Value;
|
|
}
|
|
|
|
if (torrent.ImdbID.IsNotNullOrWhiteSpace() && int.TryParse(torrent.ImdbID, out var imdbId))
|
|
{
|
|
releaseInfo.ImdbId = imdbId;
|
|
}
|
|
|
|
// Default to TV if category could not be mapped
|
|
if (releaseInfo.Categories == null || !releaseInfo.Categories.Any())
|
|
{
|
|
releaseInfo.Categories = new List<IndexerCategory> { NewznabStandardCategory.TV };
|
|
}
|
|
|
|
releaseInfos.Add(releaseInfo);
|
|
}
|
|
|
|
return releaseInfos;
|
|
}
|
|
|
|
private static string GetTitle(BroadcastheNetTorrent torrent)
|
|
{
|
|
var releaseName = torrent.ReleaseName.Replace("\\", "");
|
|
|
|
if (torrent.Container.ToUpperInvariant() is "M2TS" or "ISO")
|
|
{
|
|
releaseName = Regex.Replace(releaseName, @"\b(H\.?265)\b", "HEVC", RegexOptions.Compiled);
|
|
releaseName = Regex.Replace(releaseName, @"\b(H\.?264)\b", "AVC", RegexOptions.Compiled);
|
|
}
|
|
|
|
return releaseName;
|
|
}
|
|
}
|
|
}
|