Move ProcessReleases and PostProcess into services

This commit is contained in:
DariusIII
2025-12-20 12:18:39 +01:00
parent d420fd5278
commit d441fad32f
12 changed files with 1061 additions and 1188 deletions
+18 -19
View File
@@ -1,16 +1,17 @@
<?php
declare(strict_types=1);
namespace Blacklight;
use App\Models\Release;
use App\Models\Settings;
use Blacklight\processing\PostProcess;
use App\Services\PostProcessService;
use Blacklight\utility\Utility;
/**
* Gets information contained within the NZB.
*
*
* Class NZBContents
*/
class NZBContents
@@ -19,29 +20,25 @@ class NZBContents
protected Nfo $nfo;
protected PostProcess $pp;
protected PostProcessService $postProcessService;
protected NZB $nzb;
protected bool $lookuppar2;
/**
* @var bool
*/
protected mixed $echooutput;
protected bool $echooutput;
protected bool $alternateNNTP;
public function __construct()
{
$this->echooutput = config('nntmux.echocli');
$this->nntp = new NNTP;
$this->nfo = new Nfo;
$this->pp = new PostProcess;
$this->nzb = new NZB;
$this->echooutput = (bool) config('nntmux.echocli');
$this->nntp = new NNTP();
$this->nfo = new Nfo();
$this->postProcessService = app(PostProcessService::class);
$this->nzb = new NZB();
$this->lookuppar2 = (int) Settings::settingValue('lookuppar2') === 1;
$this->alternateNNTP = config('nntmux_nntp.use_alternate_nntp_server');
$this->alternateNNTP = (bool) config('nntmux_nntp.use_alternate_nntp_server');
}
/**
@@ -237,9 +234,8 @@ class NZBContents
// Look specifically for the .par2 index file (often small, but not always 1/1)
if ($this->lookuppar2 && ! $foundPAR2 && isset($firstSegmentId) && preg_match('/\.par2$/i', $subject)) {
// Attempt to parse the PAR2 file using its first segment ID
// Ensure $this->pp is initialized and parsePAR2 exists and accepts these parameters
if (method_exists($this->pp, 'parsePAR2') && $this->pp->parsePAR2($firstSegmentId, $relID, $groupID, $this->nntp, 1) === true) {
Release::query()->where('id', $relID)->update(['proc_par2' => 1]); // Use constant if available
if ($this->postProcessService->parsePAR2($firstSegmentId, $relID, $groupID, $this->nntp, 1) === true) {
Release::query()->where('id', $relID)->update(['proc_par2' => 1]);
$foundPAR2 = true;
}
}
@@ -329,7 +325,6 @@ class NZBContents
/**
* Attempts to get the release name from a par2 file.
*
*
* @throws \Exception
*/
public function checkPAR2(string $guid, int $relID, int $groupID, int $nameStatus, int $show): bool
@@ -337,13 +332,17 @@ class NZBContents
$nzbFile = $this->loadNzb($guid);
if ($nzbFile !== false) {
foreach ($nzbFile->file as $nzbContents) {
if ($nameStatus === 1 && $this->pp->parsePAR2((string) $nzbContents->segments->segment, $relID, $groupID, $this->nntp, $show) && preg_match('/\.(par[2" ]|\d{2,3}").+\(1\/1\)/i', (string) $nzbContents->attributes()->subject)) {
if ($nameStatus === 1
&& $this->postProcessService->parsePAR2((string) $nzbContents->segments->segment, $relID, $groupID, $this->nntp, $show)
&& preg_match('/\.(par[2" ]|\d{2,3}").+\(1\/1\)/i', (string) $nzbContents->attributes()->subject)
) {
Release::query()->where('id', $relID)->update(['proc_par2' => 1]);
return true;
}
}
}
if ($nameStatus === 1) {
Release::query()->where('id', $relID)->update(['proc_par2' => 1]);
}
+12 -9
View File
@@ -1,12 +1,14 @@
<?php
declare(strict_types=1);
namespace Blacklight;
use App\Models\Release;
use App\Models\ReleaseNfo;
use App\Models\Settings;
use App\Models\UsenetGroup;
use Blacklight\processing\PostProcess;
use App\Services\PostProcessService;
use Blacklight\utility\Utility;
use dariusiii\rarinfo\Par2Info;
use dariusiii\rarinfo\SfvInfo;
@@ -147,31 +149,32 @@ class Nfo
*/
public function __construct()
{
$this->echo = config('nntmux.echocli');
$this->colorCli = new ColorCLI;
$this->echo = (bool) config('nntmux.echocli');
$this->colorCli = new ColorCLI();
// Cache settings to reduce database queries
$this->nzbs = Cache::remember('nfo_maxnfoprocessed', self::SETTINGS_CACHE_TTL, function () {
// Note: Cast after Cache::remember as cached values may be stored as strings
$this->nzbs = (int) Cache::remember('nfo_maxnfoprocessed', self::SETTINGS_CACHE_TTL, function () {
$value = Settings::settingValue('maxnfoprocessed');
return $value !== '' ? (int) $value : 100;
});
$maxRetries = Cache::remember('nfo_maxnforetries', self::SETTINGS_CACHE_TTL, function () {
$maxRetries = (int) Cache::remember('nfo_maxnforetries', self::SETTINGS_CACHE_TTL, function () {
return (int) Settings::settingValue('maxnforetries');
});
$this->maxRetries = $maxRetries >= 0 ? -($maxRetries + 1) : self::NFO_UNPROC;
$this->maxRetries = max($this->maxRetries, -8);
$this->maxSize = Cache::remember('nfo_maxsizetoprocessnfo', self::SETTINGS_CACHE_TTL, function () {
$this->maxSize = (int) Cache::remember('nfo_maxsizetoprocessnfo', self::SETTINGS_CACHE_TTL, function () {
return (int) Settings::settingValue('maxsizetoprocessnfo');
});
$this->minSize = Cache::remember('nfo_minsizetoprocessnfo', self::SETTINGS_CACHE_TTL, function () {
$this->minSize = (int) Cache::remember('nfo_minsizetoprocessnfo', self::SETTINGS_CACHE_TTL, function () {
return (int) Settings::settingValue('minsizetoprocessnfo');
});
$this->tmpPath = rtrim(config('nntmux.tmp_unrar_path'), '/\\').'/';
$this->tmpPath = rtrim((string) config('nntmux.tmp_unrar_path'), '/\\') . '/';
}
/**
@@ -481,7 +484,7 @@ class Nfo
'NNTP' => $nntp,
'Nfo' => $this,
'Settings' => null,
'PostProcess' => new PostProcess(['Echo' => $this->echo, 'Nfo' => $this]),
'PostProcess' => app(PostProcessService::class),
]
);
$nzbContents->parseNZB($release->guid, $release->id, $release->guid);
-260
View File
@@ -1,260 +0,0 @@
<?php
namespace Blacklight\processing;
use App\Services\AnimeProcessor;
use App\Services\BooksProcessor;
use App\Services\ConsolesProcessor;
use App\Services\GamesProcessor;
use App\Services\MoviesProcessor;
use App\Services\MusicProcessor;
use App\Services\NameFixing\NameFixingService;
use App\Services\NfoProcessor;
use App\Services\Par2Processor;
use App\Services\TvProcessor;
use App\Services\XXXProcessor;
use App\Services\AdditionalProcessing\AdditionalProcessingOrchestrator;
use Blacklight\Nfo;
use Blacklight\NNTP;
use dariusiii\rarinfo\Par2Info;
class PostProcess
{
protected NameFixingService $nameFixingService;
protected Par2Info $_par2Info;
/**
* Use alternate NNTP provider when download fails?
*/
private bool $alternateNNTP;
/**
* Add par2 info to rar list?
*/
private bool $addpar2;
/**
* Should we echo to CLI?
*/
private bool $echooutput;
private Nfo $Nfo;
private Par2Processor $par2Processor;
private TvProcessor $tvProcessor;
private NfoProcessor $nfoProcessor;
private MoviesProcessor $moviesProcessor;
private MusicProcessor $musicProcessor;
private BooksProcessor $booksProcessor;
private ConsolesProcessor $consolesProcessor;
private GamesProcessor $gamesProcessor;
private AnimeProcessor $animeProcessor;
private XXXProcessor $xxxProcessor;
public function __construct()
{
// Various.
$this->echooutput = config('nntmux.echocli');
// Class instances.
$this->_par2Info = new Par2Info;
$this->nameFixingService = new NameFixingService;
$this->Nfo = new Nfo;
// Site settings.
$this->addpar2 = config('nntmux_settings.add_par2');
$this->alternateNNTP = config('nntmux_nntp.use_alternate_nntp_server');
// Services.
$this->par2Processor = new Par2Processor($this->nameFixingService, $this->_par2Info, $this->addpar2, $this->alternateNNTP);
$this->tvProcessor = new TvProcessor($this->echooutput);
$this->nfoProcessor = new NfoProcessor($this->Nfo, $this->echooutput);
$this->moviesProcessor = new MoviesProcessor($this->echooutput);
$this->musicProcessor = new MusicProcessor($this->echooutput);
$this->booksProcessor = new BooksProcessor($this->echooutput);
$this->consolesProcessor = new ConsolesProcessor($this->echooutput);
$this->gamesProcessor = new GamesProcessor($this->echooutput);
$this->animeProcessor = new AnimeProcessor($this->echooutput);
$this->xxxProcessor = new XXXProcessor($this->echooutput);
}
/**
* Go through every type of post proc.
*
*
* @throws \Exception
*/
public function processAll($nntp): void
{
$this->processAdditional();
$this->processNfos($nntp);
$this->processMovies();
$this->processMusic();
$this->processConsoles();
$this->processGames();
$this->processAnime();
$this->processTv();
$this->processXXX();
$this->processBooks();
}
/**
* Lookup anidb if enabled.
*
* @param string $groupID (Optional) ID of a group to work on.
* @param string $guidChar (Optional) First letter of a release GUID to use to get work.
*
* @throws \Exception
*/
public function processAnime(string $groupID = '', string $guidChar = ''): void
{
$this->animeProcessor->process($groupID, $guidChar);
}
/**
* Process books using amazon.com.
*
* @param string $groupID (Optional) ID of a group to work on.
* @param string $guidChar (Optional) First letter of a release GUID to use to get work.
*
* @throws \Exception
*/
public function processBooks(string $groupID = '', string $guidChar = ''): void
{
$this->booksProcessor->process($groupID, $guidChar);
}
/**
* @throws \Exception
*/
public function processConsoles(): void
{
$this->consolesProcessor->process();
}
/**
* @throws \Exception
*/
public function processGames(): void
{
$this->gamesProcessor->process();
}
/**
* Lookup imdb if enabled.
*
* @param string $groupID (Optional) ID of a group to work on.
* @param string $guidChar (Optional) First letter of a release GUID to use to get work.
* @param int|string|null $processMovies (Optional) 0 Don't process, 1 process all releases,
* 2 process renamed releases only, '' check site setting
*
* @throws \Exception
*/
public function processMovies(string $groupID = '', string $guidChar = '', int|string|null $processMovies = ''): void
{
$this->moviesProcessor->process($groupID, $guidChar, $processMovies);
}
/**
* @throws \Exception
*/
public function processMusic(): void
{
$this->musicProcessor->process();
}
/**
* Process nfo files.
*
* @param string $groupID (Optional) ID of a group to work on.
* @param string $guidChar (Optional) First letter of a release GUID to use to get work.
*
* @throws \Exception
*/
public function processNfos(NNTP $nntp, string $groupID = '', string $guidChar = ''): void
{
$this->nfoProcessor->process($nntp, $groupID, $guidChar);
}
/**
* Process all TV related releases which will assign their series/episode/rage data.
*
* @param string $groupID (Optional) ID of a group to work on.
* @param string $guidChar (Optional) First letter of a release GUID to use to get work.
* @param int|string|null $processTV (Optional) 0 Don't process, 1 process all releases,
* 2 process renamed releases only, '' check site setting
* @param string $mode (Optional) Processing mode: 'pipeline' (default) or 'parallel'
*
* @throws \Exception
*/
public function processTv(string $groupID = '', string $guidChar = '', int|string|null $processTV = '', string $mode = 'pipeline'): void
{
// If no GUID character specified, use parallel-pipeline processing via ForkingService
if ($guidChar === '') {
$forkingService = new \App\Services\ForkingService;
// Convert processTV setting to renamed-only flag
$processTV = (is_numeric($processTV) ? $processTV : \App\Models\Settings::settingValue('lookuptv'));
$renamedOnly = ($processTV == 2);
$forkingService->processTv($renamedOnly);
} else {
// Process single GUID bucket with pipeline
$this->tvProcessor->process($groupID, $guidChar, $processTV, $mode);
}
}
/**
* Lookup xxx if enabled.
*
* @throws \Exception
*/
public function processXXX(): void
{
$this->xxxProcessor->process();
}
/**
* Check for passworded releases, RAR/ZIP contents and Sample/Media info.
*
* @note Called externally by tmux/bin/update_per_group and update/postprocess.php
*
* @param int|string $groupID (Optional) ID of a group to work on.
* @param string $guidChar (Optional) First char of release GUID, can be used to select work.
*
* @throws \Exception
*/
public function processAdditional(int|string $groupID = '', string $guidChar = ''): void
{
app(AdditionalProcessingOrchestrator::class)->start($groupID, $guidChar);
}
/**
* Attempt to get a better name from a par2 file and categorize the release.
*
* @note Called from NZBContents.php
*
* @param string $messageID MessageID from NZB file.
* @param int $relID ID of the release.
* @param int $groupID Group ID of the release.
* @param NNTP $nntp Class NNTP
* @param int $show Only show result or apply iy.
*
* @throws \Exception
*/
public function parsePAR2(string $messageID, int $relID, int $groupID, NNTP $nntp, int $show): bool
{
return $this->par2Processor->parseFromMessage($messageID, $relID, $groupID, $nntp, $show);
}
}
+47 -42
View File
@@ -1,12 +1,14 @@
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Models\Settings;
use App\Services\AdditionalProcessing\AdditionalProcessingOrchestrator;
use App\Services\PostProcessService;
use Blacklight\Nfo;
use Blacklight\NNTP;
use Blacklight\processing\PostProcess;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
@@ -29,6 +31,13 @@ class PostProcessGuid extends Command
*/
protected $description = 'Post process releases by GUID character';
public function __construct(
private readonly PostProcessService $postProcessService,
private readonly AdditionalProcessingOrchestrator $additionalProcessor
) {
parent::__construct();
}
/**
* Execute the console command.
*/
@@ -38,51 +47,24 @@ class PostProcessGuid extends Command
$guid = $this->argument('guid');
$renamed = $this->argument('renamed') ?? '';
if (! $this->isValidChar($guid)) {
if (!$this->isValidChar($guid)) {
$this->error('GUID character must be a-f or 0-9.');
return self::FAILURE;
}
try {
switch ($type) {
case 'additional':
$nntp = $this->getNntp();
app(AdditionalProcessingOrchestrator::class)->start('', $guid);
break;
case 'nfo':
$nntp = $this->getNntp();
(new Nfo)->processNfoFiles(
$nntp,
'',
$guid,
(int) Settings::settingValue('lookupimdb'),
(int) Settings::settingValue('lookuptv')
);
break;
case 'movie':
(new PostProcess)->processMovies('', $guid, $renamed);
break;
case 'tv':
(new PostProcess)->processTv('', $guid, $renamed);
break;
case 'anime':
(new PostProcess)->processAnime('', $guid);
break;
case 'books':
(new PostProcess)->processBooks('', $guid);
break;
default:
$this->error('Invalid type. Must be: additional, nfo, movie, tv, anime, or books.');
return self::FAILURE;
}
match ($type) {
'additional' => $this->processAdditional($guid),
'nfo' => $this->processNfo($guid),
'movie' => $this->postProcessService->processMovies('', $guid, $renamed),
'tv' => $this->postProcessService->processTv('', $guid, $renamed),
'anime' => $this->postProcessService->processAnime('', $guid),
'books' => $this->postProcessService->processBooks('', $guid),
default => throw new \InvalidArgumentException(
'Invalid type. Must be: additional, nfo, movie, tv, anime, or books.'
),
};
return self::SUCCESS;
} catch (\Throwable $e) {
@@ -93,6 +75,29 @@ class PostProcessGuid extends Command
}
}
/**
* Process additional data for releases.
*/
private function processAdditional(string $guid): void
{
$this->additionalProcessor->start('', $guid);
}
/**
* Process NFO files for releases.
*/
private function processNfo(string $guid): void
{
$nntp = $this->getNntp();
(new Nfo())->processNfoFiles(
$nntp,
'',
$guid,
(bool) Settings::settingValue('lookupimdb'),
(bool) Settings::settingValue('lookuptv')
);
}
/**
* Check if the character contains a-f or 0-9.
*/
@@ -110,12 +115,12 @@ class PostProcessGuid extends Command
*/
private function getNntp(): NNTP
{
$nntp = new NNTP;
$nntp = new NNTP();
if ((config('nntmux_nntp.use_alternate_nntp_server') === true
? $nntp->doConnect(false, true)
: $nntp->doConnect()) !== true) {
throw new \Exception('Unable to connect to usenet.');
throw new \RuntimeException('Unable to connect to usenet.');
}
return $nntp;
+22 -21
View File
@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace App\Console\Commands;
use Blacklight\processing\ProcessReleases;
use App\Services\ReleaseProcessingService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
@@ -24,6 +24,12 @@ class ProcessReleasesCommand extends Command
*/
protected $description = 'Process releases for a specific group or all groups';
public function __construct(
private readonly ReleaseProcessingService $releaseProcessingService
) {
parent::__construct();
}
/**
* Execute the console command.
*/
@@ -32,13 +38,11 @@ class ProcessReleasesCommand extends Command
$groupId = $this->argument('groupId');
try {
$releases = new ProcessReleases();
if (is_numeric($groupId)) {
$this->processReleasesForGroup($releases, (string) $groupId);
$this->processReleasesForGroup((string) $groupId);
} else {
$this->processReleasesForGroup($releases, '');
$this->runPostProcessingTasks($releases);
$this->processReleasesForGroup('');
$this->runPostProcessingTasks();
}
return self::SUCCESS;
@@ -52,35 +56,32 @@ class ProcessReleasesCommand extends Command
/**
* Create / process releases for a groupID.
*
* Uses the ProcessReleases DTO-based workflow for cleaner code.
*/
private function processReleasesForGroup(ProcessReleases $releases, string $groupID): void
private function processReleasesForGroup(string $groupID): void
{
$limit = $releases->getReleaseCreationLimit();
$limit = $this->releaseProcessingService->getReleaseCreationLimit();
$releases->processIncompleteCollections($groupID);
$releases->processCollectionSizes($groupID);
$releases->deleteUnwantedCollections($groupID);
$this->releaseProcessingService->processIncompleteCollections($groupID);
$this->releaseProcessingService->processCollectionSizes($groupID);
$this->releaseProcessingService->deleteUnwantedCollections($groupID);
do {
$result = $releases->createReleases($groupID);
$nzbFilesAdded = $releases->createNZBs($groupID);
$result = $this->releaseProcessingService->createReleases($groupID);
$nzbFilesAdded = $this->releaseProcessingService->createNZBs($groupID);
// Continue if we processed up to the limit (more work may be available)
$shouldContinue = $result->total() >= $limit || $nzbFilesAdded >= $limit;
} while ($shouldContinue);
$releases->deleteCollections($groupID);
$this->releaseProcessingService->deleteCollections($groupID);
}
/**
* Run post-processing tasks after all group releases are processed.
*/
private function runPostProcessingTasks(ProcessReleases $releases): void
private function runPostProcessingTasks(): void
{
$releases->deletedReleasesByGroup();
$releases->deleteReleases();
$releases->categorizeReleases(2);
$this->releaseProcessingService->deletedReleasesByGroup();
$this->releaseProcessingService->deleteReleases();
$this->releaseProcessingService->categorizeReleases(2);
}
}
@@ -1,15 +1,17 @@
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Models\Category;
use App\Models\Predb;
use App\Models\Release;
use App\Services\NameFixing\NameFixingService;
use App\Services\PostProcessService;
use Blacklight\Nfo;
use Blacklight\NNTP;
use Blacklight\NZBContents;
use Blacklight\processing\PostProcess;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
@@ -209,7 +211,7 @@ class ReleasesFixNamesGroup extends Command
if ((int) $release->proc_par2 === NameFixingService::PROC_PAR2_NONE) {
// Initialize NZB contents if needed
if (! isset($nzbcontents)) {
$nntp = new NNTP;
$nntp = new NNTP();
$compressedHeaders = config('nntmux_nntp.compressed_headers');
if ((config('nntmux_nntp.use_alternate_nntp_server') === true
@@ -217,12 +219,12 @@ class ReleasesFixNamesGroup extends Command
: $nntp->doConnect()) !== true) {
$this->warn('Unable to connect to usenet for PAR2 processing');
} else {
$Nfo = new Nfo;
$Nfo = new Nfo();
$nzbcontents = new NZBContents([
'Echo' => false,
'NNTP' => $nntp,
'Nfo' => $Nfo,
'PostProcess' => new PostProcess(),
'PostProcess' => app(PostProcessService::class),
]);
}
}
+18 -15
View File
@@ -9,9 +9,9 @@ use App\Models\UsenetGroup;
use App\Services\AdditionalProcessing\AdditionalProcessingOrchestrator;
use App\Services\Backfill\BackfillService;
use App\Services\Binaries\BinariesService;
use App\Services\ReleaseProcessingService;
use Blacklight\Nfo;
use Blacklight\NNTP;
use Blacklight\processing\ProcessReleases;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
@@ -31,6 +31,12 @@ class UpdatePerGroup extends Command
*/
protected $description = 'Do a single group (update_binaries/backFill/update_releases/postprocess)';
public function __construct(
private readonly ReleaseProcessingService $releaseProcessingService
) {
parent::__construct();
}
/**
* Execute the console command.
*/
@@ -67,7 +73,7 @@ class UpdatePerGroup extends Command
// Create releases
$this->info("Processing releases for group: {$groupMySQL['name']}");
$this->processReleases(new ProcessReleases(), (string) $groupId);
$this->processReleases((string) $groupId);
// Post process the releases
$this->info("Post-processing additional for group: {$groupMySQL['name']}");
@@ -78,8 +84,8 @@ class UpdatePerGroup extends Command
$nntp,
$groupId,
'',
(bool)Settings::settingValue('lookupimdb'),
(bool)Settings::settingValue('lookuptv')
(bool) Settings::settingValue('lookupimdb'),
(bool) Settings::settingValue('lookuptv')
);
$this->info("Completed all processing for group: {$groupMySQL['name']}");
@@ -95,26 +101,23 @@ class UpdatePerGroup extends Command
/**
* Create / process releases for a groupID.
*
* Uses the ProcessReleases DTO-based workflow for cleaner code.
*/
private function processReleases(ProcessReleases $releases, string $groupID): void
private function processReleases(string $groupID): void
{
$limit = $releases->getReleaseCreationLimit();
$limit = $this->releaseProcessingService->getReleaseCreationLimit();
$releases->processIncompleteCollections($groupID);
$releases->processCollectionSizes($groupID);
$releases->deleteUnwantedCollections($groupID);
$this->releaseProcessingService->processIncompleteCollections($groupID);
$this->releaseProcessingService->processCollectionSizes($groupID);
$this->releaseProcessingService->deleteUnwantedCollections($groupID);
do {
$result = $releases->createReleases($groupID);
$nzbFilesAdded = $releases->createNZBs($groupID);
$result = $this->releaseProcessingService->createReleases($groupID);
$nzbFilesAdded = $this->releaseProcessingService->createNZBs($groupID);
// Continue if we processed up to the limit (more work may be available)
$shouldContinue = $result->total() >= $limit || $nzbFilesAdded >= $limit;
} while ($shouldContinue);
$releases->deleteCollections($groupID);
$this->releaseProcessingService->deleteCollections($groupID);
}
/**
+35 -28
View File
@@ -1,9 +1,11 @@
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Services\PostProcessService;
use Blacklight\NNTP;
use Blacklight\processing\PostProcess;
use Illuminate\Console\Command;
class UpdatePostProcess extends Command
@@ -26,11 +28,13 @@ class UpdatePostProcess extends Command
/**
* Valid types and whether they require NNTP.
*
* @var array<string, bool>
*/
private array $validTypes = [
private const array VALID_TYPES = [
'additional' => false,
'all' => true,
'amazon' => false, // Alias for book, music, console, games, xxx
'amazon' => false,
'anime' => false,
'book' => false,
'console' => false,
@@ -42,16 +46,20 @@ class UpdatePostProcess extends Command
'xxx' => false,
];
public function __construct(
private readonly PostProcessService $postProcessService
) {
parent::__construct();
}
/**
* Execute the console command.
*/
public function handle(): int
{
$type = $this->argument('type');
$echoArg = $this->argument('echo');
$echo = ($echoArg === null || $echoArg === 'true');
if (! array_key_exists($type, $this->validTypes)) {
if (!array_key_exists($type, self::VALID_TYPES)) {
$this->error("Invalid type: {$type}");
$this->showHelp();
@@ -59,22 +67,21 @@ class UpdatePostProcess extends Command
}
try {
$nntp = $this->validTypes[$type] ? $this->getNntp() : null;
$postProcess = new PostProcess;
$nntp = self::VALID_TYPES[$type] ? $this->getNntp() : null;
match ($type) {
'all' => $postProcess->processAll($nntp),
'amazon' => $this->processAmazon($postProcess),
'nfo' => $postProcess->processNfos($nntp),
'movies' => $postProcess->processMovies(),
'music' => $postProcess->processMusic(),
'console' => $postProcess->processConsoles(),
'games' => $postProcess->processGames(),
'book' => $postProcess->processBooks(),
'anime' => $postProcess->processAnime(),
'tv' => $postProcess->processTv(),
'xxx' => $postProcess->processXXX(),
'additional' => $postProcess->processAdditional(),
'all' => $this->postProcessService->processAll($nntp),
'amazon' => $this->processAmazon(),
'nfo' => $this->postProcessService->processNfos($nntp),
'movies' => $this->postProcessService->processMovies(),
'music' => $this->postProcessService->processMusic(),
'console' => $this->postProcessService->processConsoles(),
'games' => $this->postProcessService->processGames(),
'book' => $this->postProcessService->processBooks(),
'anime' => $this->postProcessService->processAnime(),
'tv' => $this->postProcessService->processTv(),
'xxx' => $this->postProcessService->processXXX(),
'additional' => $this->postProcessService->processAdditional(),
default => throw new \Exception("Unhandled type: {$type}"),
};
@@ -110,13 +117,13 @@ class UpdatePostProcess extends Command
/**
* Process amazon types (books, music, console, games, xxx).
*/
private function processAmazon(PostProcess $postProcess): void
private function processAmazon(): void
{
$postProcess->processBooks();
$postProcess->processMusic();
$postProcess->processConsoles();
$postProcess->processGames();
$postProcess->processXXX();
$this->postProcessService->processBooks();
$this->postProcessService->processMusic();
$this->postProcessService->processConsoles();
$this->postProcessService->processGames();
$this->postProcessService->processXXX();
}
/**
@@ -124,12 +131,12 @@ class UpdatePostProcess extends Command
*/
private function getNntp(): NNTP
{
$nntp = new NNTP;
$nntp = new NNTP();
if ((config('nntmux_nntp.use_alternate_nntp_server') === true
? $nntp->doConnect(false, true)
: $nntp->doConnect()) !== true) {
throw new \Exception('Unable to connect to usenet.');
throw new \RuntimeException('Unable to connect to usenet.');
}
return $nntp;
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace App\Providers;
use App\Services\PostProcessService;
use App\Services\ReleaseProcessingService;
use Illuminate\Support\ServiceProvider;
class ProcessingServiceProvider extends ServiceProvider
{
/**
* Register services.
*/
public function register(): void
{
$this->app->singleton(PostProcessService::class, function ($app) {
return new PostProcessService();
});
$this->app->singleton(ReleaseProcessingService::class, function ($app) {
return new ReleaseProcessingService();
});
}
/**
* Bootstrap services.
*/
public function boot(): void
{
//
}
}
+266
View File
@@ -0,0 +1,266 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Services\AdditionalProcessing\AdditionalProcessingOrchestrator;
use App\Services\NameFixing\NameFixingService;
use Blacklight\Nfo;
use Blacklight\NNTP;
use dariusiii\rarinfo\Par2Info;
use Illuminate\Contracts\Foundation\Application;
/**
* Orchestrates post-processing of releases.
*
* This service coordinates various post-processing operations including:
* - NFO processing
* - Movie/TV/Anime lookups
* - Music/Books/Games/Console processing
* - XXX content processing
* - Additional processing (RAR/ZIP contents, samples, etc.)
*/
final class PostProcessService
{
private readonly bool $echoOutput;
private readonly bool $alternateNNTP;
private readonly bool $addPar2;
private readonly NameFixingService $nameFixingService;
private readonly Par2Info $par2Info;
private readonly Nfo $nfo;
private readonly Par2Processor $par2Processor;
private readonly TvProcessor $tvProcessor;
private readonly NfoProcessor $nfoProcessor;
private readonly MoviesProcessor $moviesProcessor;
private readonly MusicProcessor $musicProcessor;
private readonly BooksProcessor $booksProcessor;
private readonly ConsolesProcessor $consolesProcessor;
private readonly GamesProcessor $gamesProcessor;
private readonly AnimeProcessor $animeProcessor;
private readonly XXXProcessor $xxxProcessor;
public function __construct(
?NameFixingService $nameFixingService = null,
?Par2Info $par2Info = null,
?Nfo $nfo = null,
?Par2Processor $par2Processor = null,
?TvProcessor $tvProcessor = null,
?NfoProcessor $nfoProcessor = null,
?MoviesProcessor $moviesProcessor = null,
?MusicProcessor $musicProcessor = null,
?BooksProcessor $booksProcessor = null,
?ConsolesProcessor $consolesProcessor = null,
?GamesProcessor $gamesProcessor = null,
?AnimeProcessor $animeProcessor = null,
?XXXProcessor $xxxProcessor = null,
) {
$this->echoOutput = (bool) config('nntmux.echocli');
$this->addPar2 = (bool) config('nntmux_settings.add_par2');
$this->alternateNNTP = (bool) config('nntmux_nntp.use_alternate_nntp_server');
// Core dependencies
$this->nameFixingService = $nameFixingService ?? new NameFixingService();
$this->par2Info = $par2Info ?? new Par2Info();
$this->nfo = $nfo ?? new Nfo();
// Processors
$this->par2Processor = $par2Processor ?? new Par2Processor(
$this->nameFixingService,
$this->par2Info,
$this->addPar2,
$this->alternateNNTP
);
$this->tvProcessor = $tvProcessor ?? new TvProcessor($this->echoOutput);
$this->nfoProcessor = $nfoProcessor ?? new NfoProcessor($this->nfo, $this->echoOutput);
$this->moviesProcessor = $moviesProcessor ?? new MoviesProcessor($this->echoOutput);
$this->musicProcessor = $musicProcessor ?? new MusicProcessor($this->echoOutput);
$this->booksProcessor = $booksProcessor ?? new BooksProcessor($this->echoOutput);
$this->consolesProcessor = $consolesProcessor ?? new ConsolesProcessor($this->echoOutput);
$this->gamesProcessor = $gamesProcessor ?? new GamesProcessor($this->echoOutput);
$this->animeProcessor = $animeProcessor ?? new AnimeProcessor($this->echoOutput);
$this->xxxProcessor = $xxxProcessor ?? new XXXProcessor($this->echoOutput);
}
/**
* Run all post-processing types.
*
* @throws \Exception
*/
public function processAll(NNTP $nntp): void
{
$this->processAdditional();
$this->processNfos($nntp);
$this->processMovies();
$this->processMusic();
$this->processConsoles();
$this->processGames();
$this->processAnime();
$this->processTv();
$this->processXXX();
$this->processBooks();
}
/**
* Process anime releases using AniDB.
*
* @param string $groupID Optional group ID filter
* @param string $guidChar Optional GUID character filter
*
* @throws \Exception
*/
public function processAnime(string $groupID = '', string $guidChar = ''): void
{
$this->animeProcessor->process($groupID, $guidChar);
}
/**
* Process book releases using Amazon.
*
* @param string $groupID Optional group ID filter
* @param string $guidChar Optional GUID character filter
*
* @throws \Exception
*/
public function processBooks(string $groupID = '', string $guidChar = ''): void
{
$this->booksProcessor->process($groupID, $guidChar);
}
/**
* Process console game releases.
*
* @throws \Exception
*/
public function processConsoles(): void
{
$this->consolesProcessor->process();
}
/**
* Process PC game releases.
*
* @throws \Exception
*/
public function processGames(): void
{
$this->gamesProcessor->process();
}
/**
* Process movie releases using IMDB/TMDB.
*
* @param string $groupID Optional group ID filter
* @param string $guidChar Optional GUID character filter
* @param int|string|null $processMovies Processing mode (0=skip, 1=all, 2=renamed only, ''=check setting)
*
* @throws \Exception
*/
public function processMovies(
string $groupID = '',
string $guidChar = '',
int|string|null $processMovies = ''
): void {
$this->moviesProcessor->process($groupID, $guidChar, $processMovies);
}
/**
* Process music releases.
*
* @throws \Exception
*/
public function processMusic(): void
{
$this->musicProcessor->process();
}
/**
* Process NFO files for releases.
*
* @param NNTP $nntp NNTP connection for downloading NFOs
* @param string $groupID Optional group ID filter
* @param string $guidChar Optional GUID character filter
*
* @throws \Exception
*/
public function processNfos(NNTP $nntp, string $groupID = '', string $guidChar = ''): void
{
$this->nfoProcessor->process($nntp, $groupID, $guidChar);
}
/**
* Process TV releases.
*
* @param string $groupID Optional group ID filter
* @param string $guidChar Optional GUID character filter
* @param int|string|null $processTV Processing mode (0=skip, 1=all, 2=renamed only, ''=check setting)
* @param string $mode Processing mode ('pipeline' or 'parallel')
*
* @throws \Exception
*/
public function processTv(
string $groupID = '',
string $guidChar = '',
int|string|null $processTV = '',
string $mode = 'pipeline'
): void {
if ($guidChar === '') {
$forkingService = new ForkingService();
$processTV = is_numeric($processTV)
? $processTV
: \App\Models\Settings::settingValue('lookuptv');
$renamedOnly = ((int) $processTV === 2);
$forkingService->processTv($renamedOnly);
} else {
$this->tvProcessor->process($groupID, $guidChar, $processTV, $mode);
}
}
/**
* Process XXX releases.
*
* @throws \Exception
*/
public function processXXX(): void
{
$this->xxxProcessor->process();
}
/**
* Process additional release data (RAR/ZIP contents, samples, media info).
*
* @param int|string $groupID Optional group ID filter
* @param string $guidChar Optional GUID character filter
*
* @throws \Exception
*/
public function processAdditional(int|string $groupID = '', string $guidChar = ''): void
{
app(AdditionalProcessingOrchestrator::class)->start($groupID, $guidChar);
}
/**
* Attempt to get a better name from a PAR2 file and re-categorize.
*
* @param string $messageID Message ID from NZB
* @param int $relID Release ID
* @param int $groupID Group ID
* @param NNTP $nntp NNTP connection
* @param int $show Display mode (0=apply, 1=show only)
*
* @throws \Exception
*/
public function parsePAR2(
string $messageID,
int $relID,
int $groupID,
NNTP $nntp,
int $show
): bool {
return $this->par2Processor->parseFromMessage($messageID, $relID, $groupID, $nntp, $show);
}
}
File diff suppressed because it is too large Load Diff
+1
View File
@@ -7,6 +7,7 @@ return [
App\Providers\CategorizationServiceProvider::class,
App\Providers\ForumServiceProvider::class,
App\Providers\HorizonServiceProvider::class,
App\Providers\ProcessingServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,
App\Providers\TvProcessingServiceProvider::class,