> */ public array $nzbContents = []; public ?AdditionalWorkPlan $workPlan = null; /** * @var list */ public array $downloadedArchives = []; private int $retainedArchiveBytes = 0; // Message IDs for downloading /** * @var list */ public array $sampleMessageIDs = []; /** * @var list */ public array $jpgMessageIDs = []; /** * @var list|string */ public string|array $mediaInfoMessageIDs = []; /** * @var list|string */ public string|array $audioInfoMessageIDs = []; /** * @var list */ public array $rarFileMessageIDs = []; public string $audioInfoExtension = ''; // File info counters public int $addedFileInfo = 0; public int $totalFileInfo = 0; public int $compressedFilesChecked = 0; /** * @var array> */ public array $pendingReleaseFiles = []; /** * @var array> */ public array $pendingParHashes = []; /** * @var array|null */ public ?array $existingReleaseFileNames = null; public bool $releaseFilesChanged = false; // Temp path for this release public string $tmpPath = ''; // Timeout tracking public float $startTime = 0; public function __construct(Release $release) { $this->release = $release; $this->startTime = hrtime(true); } /** * Initialize processing state based on configuration flags. * Sets "found" flags to true if processing is disabled (to skip those steps). */ public function initializeFromConfig( bool $processVideo, bool $processMediaInfo, bool $processAudioInfo, bool $processAudioSample, bool $processJPGSample, bool $processThumbnails ): void { $this->foundVideo = ! $processVideo; $this->foundMediaInfo = ! $processMediaInfo; $this->foundAudioInfo = ! $processAudioInfo; $this->foundAudioSample = ! $processAudioSample; $this->foundJPGSample = ! $processJPGSample; $this->foundSample = ! $processThumbnails; $this->foundPAR2Info = false; } /** * Reset message ID arrays for a fresh processing run. */ public function resetMessageIDs(): void { $this->sampleMessageIDs = []; $this->jpgMessageIDs = []; $this->mediaInfoMessageIDs = []; $this->audioInfoMessageIDs = []; $this->rarFileMessageIDs = []; $this->audioInfoExtension = ''; } /** * Reset file counters. */ public function resetCounters(): void { $this->addedFileInfo = 0; $this->totalFileInfo = 0; $this->compressedFilesChecked = 0; $this->pendingReleaseFiles = []; $this->pendingParHashes = []; $this->existingReleaseFileNames = null; $this->releaseFilesChanged = false; } /** * Full reset for processing a new release. */ public function reset(): void { $this->passwordStatus = 0; $this->releaseHasPassword = false; $this->nzbHasCompressedFile = false; $this->groupUnavailable = false; $this->workPlan = null; $this->releaseDownloadedArchives(); $this->resetMessageIDs(); $this->resetCounters(); } /** * Retain only small, immediately reusable archive payloads for this release. * * @param array> $files */ public function rememberDownloadedArchive(string $title, string $data, array $files): bool { $byteSize = strlen($data); if ($byteSize === 0 || count($this->downloadedArchives) >= self::MAX_RETAINED_ARCHIVES || ($this->retainedArchiveBytes + $byteSize) > self::MAX_RETAINED_ARCHIVE_BYTES ) { return false; } $archive = new DownloadedArchive($title, $data, $files); $this->downloadedArchives[] = $archive; $this->retainedArchiveBytes += $archive->byteSize(); return true; } public function releaseDownloadedArchives(): void { $this->downloadedArchives = []; $this->retainedArchiveBytes = 0; } public function duplicateMessageIdCount(): int { return $this->workPlan === null ? 0 : $this->workPlan->duplicateMessageIdCount; } /** * @return list */ public function unsupportedReasons(): array { return $this->workPlan === null ? [] : $this->workPlan->unsupportedReasons; } /** * Mark a processing artifact as found. */ public function markFound(string $type): void { match ($type) { 'video' => $this->foundVideo = true, 'mediaInfo' => $this->foundMediaInfo = true, 'audioInfo' => $this->foundAudioInfo = true, 'audioSample' => $this->foundAudioSample = true, 'jpgSample' => $this->foundJPGSample = true, 'sample' => $this->foundSample = true, 'par2Info' => $this->foundPAR2Info = true, default => null, }; } /** * Check if more media processing is needed. */ public function needsMediaProcessing(): bool { return ! $this->foundVideo || ! $this->foundMediaInfo || ! $this->foundAudioInfo || ! $this->foundAudioSample; } /** * Check if any sample is still needed. */ public function needsSample(): bool { return ! $this->foundSample || ! $this->foundJPGSample; } /** * Check if the release has exceeded the processing timeout. */ public function isTimedOut(int $timeoutSeconds): bool { if ($timeoutSeconds <= 0) { return false; } return (hrtime(true) - $this->startTime) / 1e9 > $timeoutSeconds; } /** * Get elapsed processing time in seconds. */ public function getElapsedSeconds(): int { return (int) ((hrtime(true) - $this->startTime) / 1e9); } }