mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 09:18:54 +00:00
206 lines
7.4 KiB
PHP
206 lines
7.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\AdditionalProcessing;
|
|
|
|
use App\Services\AdditionalProcessing\Config\ProcessingConfiguration;
|
|
use App\Services\AdditionalProcessing\DTO\AdditionalWorkPlan;
|
|
use App\Services\AdditionalProcessing\DTO\ArchiveCandidate;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
final readonly class AdditionalWorkPlanner
|
|
{
|
|
private const string ARCHIVE_PATTERN = '/(\.(part\d+|[rz]\d+|rar|0+|0*10?|zipr\d{2,3}|zipx?)("|\s*\.rar)*($|[ ")]|-])|"[a-f0-9]{32}\.[1-9]\d{1,2}".*\(\d+\/\d{2,}\)$)/i';
|
|
|
|
public function __construct(private ProcessingConfiguration $config) {}
|
|
|
|
/**
|
|
* @param array<int|string, mixed> $nzbContents
|
|
*/
|
|
public function plan(array $nzbContents, string $groupName): AdditionalWorkPlan
|
|
{
|
|
$sampleMessageIds = [];
|
|
$jpgMessageIds = [];
|
|
$mediaInfoMessageId = '';
|
|
$audioInfoMessageId = '';
|
|
$audioInfoExtension = '';
|
|
$archiveCandidates = [];
|
|
$bookFileCount = 0;
|
|
$duplicateMessageIdCount = 0;
|
|
$seenMessageIds = [];
|
|
|
|
foreach (array_values($nzbContents) as $sourceIndex => $file) {
|
|
if (! is_array($file)) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$title = (string) ($file['title'] ?? '');
|
|
$segments = is_array($file['segments'] ?? null) ? $file['segments'] : [];
|
|
|
|
if (preg_match($this->config->ignoreBookRegex, $title) === 1) {
|
|
$bookFileCount++;
|
|
}
|
|
|
|
if (preg_match(self::ARCHIVE_PATTERN, $title) === 1) {
|
|
$archiveMessageIds = $this->extractSegments(
|
|
$segments,
|
|
$this->config->maximumRarSegments,
|
|
$seenMessageIds,
|
|
$duplicateMessageIdCount,
|
|
);
|
|
if ($archiveMessageIds !== []) {
|
|
$archiveCandidates[] = new ArchiveCandidate(
|
|
title: $title,
|
|
messageIds: $archiveMessageIds,
|
|
likelyFirstVolume: $this->isLikelyFirstVolume($title),
|
|
sourceIndex: $sourceIndex,
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($this->isSupportFile($title)) {
|
|
continue;
|
|
}
|
|
|
|
if ($this->config->processThumbnails && $sampleMessageIds === [] && $segments !== []
|
|
&& stripos($title, 'sample') !== false
|
|
&& preg_match('/\.(?:jpe?g|png|webp)$/i', $title) !== 1
|
|
) {
|
|
$sampleMessageIds = $this->extractSegments(
|
|
$segments,
|
|
$this->config->segmentsToDownload,
|
|
$seenMessageIds,
|
|
$duplicateMessageIdCount,
|
|
);
|
|
}
|
|
|
|
if ($this->config->processJPGSample && $jpgMessageIds === [] && $segments !== []
|
|
&& preg_match('/flac|lossless|mp3|music|inner-sanctum|sound/i', $groupName) !== 1
|
|
&& preg_match('/\.(?:jpe?g|png|webp)[. ")\]]/i', $title) === 1
|
|
) {
|
|
$jpgMessageIds = $this->extractSegments(
|
|
$segments,
|
|
$this->config->segmentsToDownload,
|
|
$seenMessageIds,
|
|
$duplicateMessageIdCount,
|
|
);
|
|
}
|
|
|
|
if ($this->config->processMediaInfo && $mediaInfoMessageId === '' && isset($segments[0])
|
|
&& stripos($title, 'sample') !== false
|
|
&& preg_match('/'.$this->config->videoFileRegex.'[. ")\]]/i', $title) === 1
|
|
) {
|
|
$mediaInfoMessageId = (string) $segments[0];
|
|
$this->recordMessageId($mediaInfoMessageId, $seenMessageIds, $duplicateMessageIdCount);
|
|
}
|
|
|
|
if ($this->config->processAudioInfo && $audioInfoMessageId === '' && isset($segments[0])
|
|
&& preg_match('/'.$this->config->audioFileRegex.'[. ")\]]/i', $title, $type) === 1
|
|
) {
|
|
$audioInfoExtension = (string) ($type[1] ?? '');
|
|
$audioInfoMessageId = (string) $segments[0];
|
|
$this->recordMessageId($audioInfoMessageId, $seenMessageIds, $duplicateMessageIdCount);
|
|
}
|
|
} catch (\ErrorException $e) {
|
|
Log::debug($e->getTraceAsString());
|
|
}
|
|
}
|
|
|
|
$bookFlood = $bookFileCount > 80 && ($bookFileCount * 2) >= count($nzbContents);
|
|
$unsupportedReasons = [];
|
|
if ($bookFlood) {
|
|
$unsupportedReasons[] = 'book-flood';
|
|
}
|
|
if ($archiveCandidates === []
|
|
&& $sampleMessageIds === []
|
|
&& $jpgMessageIds === []
|
|
&& $mediaInfoMessageId === ''
|
|
&& $audioInfoMessageId === ''
|
|
) {
|
|
$unsupportedReasons[] = 'no-supported-candidates';
|
|
}
|
|
|
|
return new AdditionalWorkPlan(
|
|
sampleMessageIds: $sampleMessageIds,
|
|
jpgMessageIds: $jpgMessageIds,
|
|
mediaInfoMessageId: $mediaInfoMessageId,
|
|
audioInfoMessageId: $audioInfoMessageId,
|
|
audioInfoExtension: $audioInfoExtension,
|
|
archiveCandidates: $archiveCandidates,
|
|
bookFileCount: $bookFileCount,
|
|
bookFlood: $bookFlood,
|
|
duplicateMessageIdCount: $duplicateMessageIdCount,
|
|
unsupportedReasons: $unsupportedReasons,
|
|
);
|
|
}
|
|
|
|
private function isSupportFile(string $title): bool
|
|
{
|
|
return preg_match(
|
|
'/(?:'.$this->config->supportFileRegex.'|nfo\b|inf\b|ofn\b)($|[ ")]|-])(?!.{20,})/i',
|
|
$title,
|
|
) === 1;
|
|
}
|
|
|
|
private function isLikelyFirstVolume(string $title): bool
|
|
{
|
|
if (preg_match('/\.part0*(\d+)/i', $title, $part) === 1) {
|
|
return (int) $part[1] === 1;
|
|
}
|
|
|
|
if (preg_match('/"[a-f0-9]{32}\.[1-9]\d{1,2}".*\((\d+)\/\d{2,}\)$/i', $title, $position) === 1) {
|
|
return (int) $position[1] === 1;
|
|
}
|
|
|
|
return preg_match('/\.(rar|zip)($|[ ")]|-])/i', $title) === 1;
|
|
}
|
|
|
|
/**
|
|
* @param array<int|string, mixed> $segments
|
|
* @param array<string, true> $seenMessageIds
|
|
* @return list<string>
|
|
*/
|
|
private function extractSegments(
|
|
array $segments,
|
|
int $limit,
|
|
array &$seenMessageIds,
|
|
int &$duplicateMessageIdCount,
|
|
): array {
|
|
$messageIds = [];
|
|
$requestMessageIds = [];
|
|
|
|
foreach (array_slice($segments, 0, max($limit, 0)) as $segment) {
|
|
$messageId = (string) $segment;
|
|
if ($messageId === '' || isset($requestMessageIds[$messageId])) {
|
|
if ($messageId !== '') {
|
|
$duplicateMessageIdCount++;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
$requestMessageIds[$messageId] = true;
|
|
$messageIds[] = $messageId;
|
|
$this->recordMessageId($messageId, $seenMessageIds, $duplicateMessageIdCount);
|
|
}
|
|
|
|
return $messageIds;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, true> $seenMessageIds
|
|
*/
|
|
private function recordMessageId(string $messageId, array &$seenMessageIds, int &$duplicateMessageIdCount): void
|
|
{
|
|
if (isset($seenMessageIds[$messageId])) {
|
|
$duplicateMessageIdCount++;
|
|
|
|
return;
|
|
}
|
|
|
|
$seenMessageIds[$messageId] = true;
|
|
}
|
|
}
|