TmuxTaskRunner::buildSleepCommand()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 10
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace App\Services\Tmux;
4
5
use App\Models\Settings;
6
7
/**
8
 * Service for running tasks in tmux panes
9
 */
10
class TmuxTaskRunner
11
{
12
    protected TmuxPaneManager $paneManager;
13
14
    protected string $sessionName;
15
16
    public function __construct(string $sessionName)
17
    {
18
        $this->sessionName = $sessionName;
19
        $this->paneManager = new TmuxPaneManager($sessionName);
20
    }
21
22
    /**
23
     * Get niceness value from settings or config with sensible default
24
     */
25
    protected function getNiceness(): int
26
    {
27
        // Try to get from settings first
28
        $niceness = Settings::settingValue('niceness');
29
30
        // If empty string or null, try config
31
        if (empty($niceness) && $niceness !== 0 && $niceness !== '0') {
32
            $niceness = config('nntmux.niceness');
33
        }
34
35
        // If still empty, use system default
36
        if (empty($niceness) && $niceness !== 0 && $niceness !== '0') {
37
            $niceness = 10; // Standard nice default
38
        }
39
40
        return (int) $niceness;
41
    }
42
43
    /**
44
     * Run a task in a specific pane
45
     */
46
    public function runTask(string $taskName, array $config): bool
47
    {
48
        $pane = $config['pane'] ?? null;
49
        $command = $config['command'] ?? null;
50
        $enabled = $config['enabled'] ?? true;
51
        $workAvailable = $config['work_available'] ?? true;
52
53
        if (! $pane || ! $command) {
54
            return false;
55
        }
56
57
        // Check if task is enabled and has work
58
        if (! $enabled) {
59
            return $this->disablePane($pane, $taskName, 'disabled in settings');
60
        }
61
62
        if (! $workAvailable) {
63
            return $this->disablePane($pane, $taskName, 'no work available');
64
        }
65
66
        // Respawn the pane with the command
67
        return $this->paneManager->respawnPane($pane, $command);
68
    }
69
70
    /**
71
     * Disable a pane with a message
72
     */
73
    protected function disablePane(string $pane, string $taskName, string $reason): bool
74
    {
75
        $color = $this->getRandomColor();
76
        $message = "echo -e \"\033[38;5;{$color}m\n{$taskName} has been disabled: {$reason}\"";
77
78
        return $this->paneManager->respawnPane($pane, $message, kill: true);
79
    }
80
81
    /**
82
     * Build a command with logging
83
     */
84
    public function buildCommand(string $baseCommand, array $options = []): string
85
    {
86
        $parts = [$baseCommand];
87
88
        // Add sleep timer at the end if specified
89
        if (isset($options['sleep'])) {
90
            $sleepCommand = $this->buildSleepCommand($options['sleep']);
91
            $parts[] = 'date +"%Y-%m-%d %T"';
92
            $parts[] = $sleepCommand;
93
        }
94
95
        // Add logging if enabled
96
        if (isset($options['log_pane'])) {
97
            $logFile = $this->getLogFile($options['log_pane']);
98
            $command = implode('; ', $parts);
99
100
            return "{$command} 2>&1 | tee -a {$logFile}";
101
        }
102
103
        return implode('; ', $parts);
104
    }
105
106
    /**
107
     * Build sleep command
108
     */
109
    protected function buildSleepCommand(int $seconds): string
110
    {
111
        $niceness = $this->getNiceness();
112
        $sleepScript = base_path('app/Services/Tmux/Scripts/showsleep.php');
113
114
        if (file_exists($sleepScript)) {
115
            return "nice -n{$niceness} php {$sleepScript} {$seconds}";
116
        }
117
118
        return "sleep {$seconds}";
119
    }
120
121
    /**
122
     * Get log file path for a pane
123
     */
124
    protected function getLogFile(string $paneName): string
125
    {
126
        $logsEnabled = (int) Settings::settingValue('write_logs') === 1;
127
128
        if (! $logsEnabled) {
129
            return '/dev/null';
130
        }
131
132
        $logDir = config('tmux.paths.logs', storage_path('logs/tmux'));
133
134
        if (! is_dir($logDir)) {
135
            mkdir($logDir, 0755, true);
136
        }
137
138
        $date = now()->format('Y_m_d');
139
140
        return "{$logDir}/{$paneName}-{$date}.log";
141
    }
142
143
    /**
144
     * Get a random color for terminal output
145
     */
146
    protected function getRandomColor(): int
147
    {
148
        $start = (int) Settings::settingValue('colors_start') ?? 0;
149
        $end = (int) Settings::settingValue('colors_end') ?? 255;
150
        $exclude = Settings::settingValue('colors_exc') ?? '';
151
152
        if (empty($exclude)) {
153
            return random_int($start, $end);
154
        }
155
156
        $exceptions = array_map('intval', explode(',', $exclude));
157
        sort($exceptions);
158
159
        $number = random_int($start, $end - count($exceptions));
160
161
        foreach ($exceptions as $exception) {
162
            if ($number >= $exception) {
163
                $number++;
164
            } else {
165
                break;
166
            }
167
        }
168
169
        return $number;
170
    }
171
172
    /**
173
     * Run the IRC scraper
174
     */
175
    public function runIRCScraper(array $config): bool
176
    {
177
        $runScraper = (int) ($config['constants']['run_ircscraper'] ?? 0);
178
        $pane = '3.0';
179
180
        if ($runScraper !== 1) {
181
            return $this->disablePane($pane, 'IRC Scraper', 'disabled in settings');
182
        }
183
184
        $niceness = $this->getNiceness();
185
        $artisan = base_path('artisan');
186
        $command = "nice -n{$niceness} php {$artisan} irc:scrape";
187
        $command = $this->buildCommand($command, ['log_pane' => 'scraper']);
188
189
        return $this->paneManager->respawnPane($pane, $command);
190
    }
191
192
    /**
193
     * Run binaries update
194
     */
195
    public function runBinariesUpdate(array $config): bool
196
    {
197
        $enabled = (int) ($config['settings']['binaries_run'] ?? 0);
198
        $killswitch = $config['killswitch']['pp'] ?? false;
199
        $pane = '0.1';
200
201
        if (! $enabled) {
202
            return $this->disablePane($pane, 'Update Binaries', 'disabled in settings');
203
        }
204
205
        if ($killswitch) {
206
            return $this->disablePane($pane, 'Update Binaries', 'postprocess kill limit exceeded');
207
        }
208
209
        $artisanCommand = match ((int) $enabled) {
210
            1 => 'multiprocessing:safe binaries',
211
            default => null,
212
        };
213
214
        if (! $artisanCommand) {
215
            return false;
216
        }
217
218
        $niceness = $this->getNiceness();
219
        $command = "nice -n{$niceness} ".PHP_BINARY." artisan {$artisanCommand}";
220
        $sleep = (int) ($config['settings']['bins_timer'] ?? 60);
221
        $command = $this->buildCommand($command, ['log_pane' => 'binaries', 'sleep' => $sleep]);
222
223
        return $this->paneManager->respawnPane($pane, $command);
224
    }
225
226
    /**
227
     * Run backfill
228
     */
229
    public function runBackfill(array $config): bool
230
    {
231
        $enabled = (int) ($config['settings']['backfill'] ?? 0);
232
        $collKillswitch = $config['killswitch']['coll'] ?? false;
233
        $ppKillswitch = $config['killswitch']['pp'] ?? false;
234
        $pane = '0.2';
235
236
        if (! $enabled) {
237
            return $this->disablePane($pane, 'Backfill', 'disabled in settings');
238
        }
239
240
        if ($collKillswitch || $ppKillswitch) {
241
            return $this->disablePane($pane, 'Backfill', 'kill limit exceeded');
242
        }
243
244
        $artisanCommand = match ((int) $enabled) {
245
            1 => 'multiprocessing:backfill',
246
            4 => 'multiprocessing:safe backfill',
247
            default => null,
248
        };
249
250
        if (! $artisanCommand) {
251
            return false;
252
        }
253
254
        // Calculate sleep time (progressive if enabled)
255
        $baseSleep = (int) ($config['settings']['back_timer'] ?? 600);
256
        $collections = (int) ($config['counts']['now']['collections_table'] ?? 0);
257
        $progressive = (int) ($config['settings']['progressive'] ?? 0);
258
259
        $sleep = ($progressive === 1 && floor($collections / 500) > $baseSleep)
260
            ? floor($collections / 500)
261
            : $baseSleep;
262
263
        $niceness = $this->getNiceness();
264
        $command = "nice -n{$niceness} ".PHP_BINARY." artisan {$artisanCommand}";
265
        $command = $this->buildCommand($command, ['log_pane' => 'backfill', 'sleep' => $sleep]);
266
267
        return $this->paneManager->respawnPane($pane, $command);
268
    }
269
270
    /**
271
     * Run releases update
272
     */
273
    public function runReleasesUpdate(array $config): bool
274
    {
275
        $enabled = (int) ($config['settings']['releases_run'] ?? 0);
276
        $pane = $config['pane'] ?? '0.3';
277
278
        if (! $enabled) {
279
            return $this->disablePane($pane, 'Update Releases', 'disabled in settings');
280
        }
281
282
        $niceness = $this->getNiceness();
283
        $command = "nice -n{$niceness} ".PHP_BINARY.' artisan multiprocessing:releases';
284
        $sleep = (int) ($config['settings']['rel_timer'] ?? 60);
285
        $command = $this->buildCommand($command, ['log_pane' => 'releases', 'sleep' => $sleep]);
286
287
        return $this->paneManager->respawnPane($pane, $command);
288
    }
289
290
    /**
291
     * Run a specific pane task based on task name
292
     *
293
     * @param  string  $taskName  The name of the task to run
294
     * @param  array  $config  Configuration for the task (target pane, etc.)
295
     * @param  array  $runVar  Runtime variables and settings
296
     * @return bool Success status
297
     */
298
    public function runPaneTask(string $taskName, array $config, array $runVar): bool
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

298
    public function runPaneTask(string $taskName, /** @scrutinizer ignore-unused */ array $config, array $runVar): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
299
    {
300
        $sequential = (int) ($runVar['constants']['sequential'] ?? 0);
301
302
        return match ($taskName) {
303
            'main' => $this->runMainTask($sequential, $runVar),
304
            'fixnames' => $this->runFixNamesTask($runVar),
305
            'removecrap' => $this->runRemoveCrapTask($runVar),
306
            'ppadditional' => $this->runPostProcessAdditional($runVar),
307
            'tv' => $this->runTvTask($runVar),
308
            'movies' => $this->runMoviesTask($runVar),
309
            'amazon' => $this->runAmazonTask($runVar),
310
            'xxx' => $this->runXXXTask($runVar),
311
            'scraper' => $this->runIRCScraper($runVar),
312
            // Legacy mapping for backward compatibility
313
            'nonamazon' => $this->runTvTask($runVar),
314
            default => false,
315
        };
316
    }
317
318
    /**
319
     * Run main task (varies by sequential mode)
320
     */
321
    protected function runMainTask(int $sequential, array $runVar): bool
322
    {
323
        return match ($sequential) {
324
            0 => $this->runMainNonSequential($runVar),
325
            1 => $this->runMainBasic($runVar),
326
            2 => $this->runMainSequential($runVar),
327
            default => false,
328
        };
329
    }
330
331
    /**
332
     * Run main non-sequential task (binaries, backfill, releases)
333
     */
334
    protected function runMainNonSequential(array $runVar): bool
335
    {
336
        // This runs in pane 0.1, 0.2, 0.3
337
        // For now, delegate to existing methods
338
        $this->runBinariesUpdate($runVar);
339
        $this->runBackfill($runVar);
340
        $this->runReleasesUpdate(array_merge($runVar, ['pane' => '0.3']));
341
342
        return true;
343
    }
344
345
    /**
346
     * Run main basic sequential task (just releases)
347
     */
348
    protected function runMainBasic(array $runVar): bool
349
    {
350
        return $this->runReleasesUpdate(array_merge($runVar, ['pane' => '0.1']));
351
    }
352
353
    /**
354
     * Run main full sequential task
355
     */
356
    protected function runMainSequential(array $runVar): bool
0 ignored issues
show
Unused Code introduced by
The parameter $runVar is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

356
    protected function runMainSequential(/** @scrutinizer ignore-unused */ array $runVar): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
357
    {
358
        // Full sequential mode - runs group:update-all for each group
359
        $pane = '0.1';
360
361
        $niceness = $this->getNiceness();
362
        $artisan = base_path('artisan');
363
        $command = "nice -n{$niceness} php {$artisan} group:update-all";
364
        $command = $this->buildCommand($command, ['log_pane' => 'sequential']);
365
366
        return $this->paneManager->respawnPane($pane, $command);
367
    }
368
369
    /**
370
     * Run fix release names task
371
     */
372
    protected function runFixNamesTask(array $runVar): bool
373
    {
374
        $enabled = (int) ($runVar['settings']['fix_names'] ?? 0);
375
        $work = (int) ($runVar['counts']['now']['processrenames'] ?? 0);
376
        $pane = '1.0';
377
378
        if ($enabled !== 1) {
379
            return $this->disablePane($pane, 'Fix Release Names', 'disabled in settings');
380
        }
381
382
        if ($work === 0) {
383
            return $this->disablePane($pane, 'Fix Release Names', 'no releases to process');
384
        }
385
386
        $artisan = base_path('artisan');
387
        $log = $this->getLogFile('fixnames');
388
389
        // Run multiple fix-names passes
390
        $commands = [];
391
        foreach ([3, 5, 7, 9, 11, 13, 15, 17, 19] as $level) {
392
            $commands[] = "php {$artisan} releases:fix-names {$level} --update --category=other --set-status --show 2>&1 | tee -a {$log}";
393
        }
394
395
        $sleep = (int) ($runVar['settings']['fix_timer'] ?? 300);
396
        $allCommands = implode('; ', $commands);
397
        $sleepCommand = $this->buildSleepCommand($sleep);
398
        $fullCommand = "{$allCommands}; date +'%Y-%m-%d %T'; {$sleepCommand}";
399
400
        return $this->paneManager->respawnPane($pane, $fullCommand);
401
    }
402
403
    /**
404
     * Run remove crap releases task
405
     */
406
    protected function runRemoveCrapTask(array $runVar): bool
407
    {
408
        $option = $runVar['settings']['fix_crap_opt'] ?? 'Disabled';
409
        $pane = '1.1';
410
411
        // Handle disabled state
412
        if ($option === 'Disabled' || $option === 0 || $option === '0') {
413
            return $this->disablePane($pane, 'Remove Crap', 'disabled in settings');
414
        }
415
416
        $niceness = $this->getNiceness();
417
        $artisan = base_path('artisan');
418
        $sleep = (int) ($runVar['settings']['crap_timer'] ?? 300);
419
420
        // Handle 'All' mode - run all types with 2 hour time limit
421
        if ($option === 'All') {
422
            $command = "nice -n{$niceness} php {$artisan} releases:remove-crap --time=2 --delete";
423
            $command = $this->buildCommand($command, ['log_pane' => 'removecrap', 'sleep' => $sleep]);
424
425
            return $this->paneManager->respawnPane($pane, $command);
426
        }
427
428
        // Handle 'Custom' mode - run all selected types sequentially
429
        if ($option === 'Custom') {
430
            $selectedTypes = $runVar['settings']['fix_crap'] ?? '';
431
432
            // Convert numeric 0 or empty values to empty string
433
            if (empty($selectedTypes) || $selectedTypes === 0 || $selectedTypes === '0') {
434
                return $this->disablePane($pane, 'Remove Crap', 'no crap types selected');
435
            }
436
437
            $types = is_array($selectedTypes) ? $selectedTypes : explode(',', $selectedTypes);
438
439
            // Trim whitespace and filter out empty values and '0'
440
            $types = array_map('trim', $types);
441
            $types = array_filter($types, fn ($type) => ! empty($type) && $type !== '0');
442
443
            // Re-index array to ensure sequential keys
444
            $types = array_values($types);
445
446
            if (empty($types)) {
447
                return $this->disablePane($pane, 'Remove Crap', 'no crap types selected');
448
            }
449
450
            // Get state to determine if this is first run
451
            $stateFile = storage_path('tmux/removecrap_state.json');
452
            $state = $this->loadCrapState($stateFile);
453
            $isFirstRun = $state['first_run'] ?? true;
454
455
            // Determine time limit: full on first run, 4 hours otherwise
456
            $time = $isFirstRun ? 'full' : '4';
0 ignored issues
show
introduced by
The condition $isFirstRun is always true.
Loading history...
457
458
            // Build commands for all enabled types to run sequentially
459
            $log = $this->getLogFile('removecrap');
460
            $commands = [];
461
            foreach ($types as $type) {
462
                $commands[] = "echo \"\nRunning removeCrapReleases for {$type}\"; nice -n{$niceness} php {$artisan} releases:remove-crap --type={$type} --time={$time} --delete 2>&1 | tee -a {$log}";
463
            }
464
465
            // Join all commands with semicolons and add final timestamp and sleep
466
            $allCommands = implode('; ', $commands);
467
            $sleepCommand = $this->buildSleepCommand($sleep);
468
            $fullCommand = "{$allCommands}; date +'%Y-%m-%d %T'; {$sleepCommand}";
469
470
            // Mark that we're not on the first run anymore for next cycle
471
            $this->saveCrapState($stateFile, [
472
                'first_run' => false,
473
                'types' => $types,
474
            ]);
475
476
            return $this->paneManager->respawnPane($pane, $fullCommand);
477
        }
478
479
        // Default fallback - disabled
480
        return $this->disablePane($pane, 'Remove Crap', 'invalid configuration');
481
    }
482
483
    /**
484
     * Load crap removal state
485
     */
486
    protected function loadCrapState(string $file): array
487
    {
488
        if (! file_exists($file)) {
489
            return ['first_run' => true];
490
        }
491
492
        $content = file_get_contents($file);
493
        $state = json_decode($content, true);
494
495
        return $state ?: ['first_run' => true];
496
    }
497
498
    /**
499
     * Save crap removal state
500
     */
501
    protected function saveCrapState(string $file, array $state): void
502
    {
503
        $dir = dirname($file);
504
        if (! is_dir($dir)) {
505
            mkdir($dir, 0755, true);
506
        }
507
508
        file_put_contents($file, json_encode($state, JSON_PRETTY_PRINT));
509
    }
510
511
    /**
512
     * Run post-process additional task
513
     */
514
    protected function runPostProcessAdditional(array $runVar): bool
515
    {
516
        $postSetting = (int) ($runVar['settings']['post'] ?? 0);
517
        $pane = '2.0';
518
519
        // Check if post processing is enabled (1 = additional, 2 = nfo, 3 = both)
520
        if ($postSetting === 0) {
521
            return $this->disablePane($pane, 'Post-process Additional', 'disabled in settings');
522
        }
523
524
        $hasWork = (int) ($runVar['counts']['now']['work'] ?? 0) > 0;
525
        $hasNfo = (int) ($runVar['counts']['now']['processnfo'] ?? 0) > 0;
526
527
        $niceness = Settings::settingValue('niceness') ?? 2;
528
        $log = $this->getLogFile('post_additional');
529
        $sleep = (int) ($runVar['settings']['post_timer'] ?? 300);
530
531
        $commands = [];
532
533
        // Build commands based on post setting value
534
        if ($postSetting === 1) {
535
            // Post = 1: Additional processing only
536
            if ($hasWork) {
537
                $commands[] = "nice -n{$niceness} ".PHP_BINARY." artisan update:postprocess additional true 2>&1 | tee -a {$log}";
538
            }
539
        } elseif ($postSetting === 2) {
540
            // Post = 2: NFO processing only
541
            if ($hasNfo) {
542
                $commands[] = "nice -n{$niceness} ".PHP_BINARY." artisan update:postprocess nfo true 2>&1 | tee -a {$log}";
543
            }
544
        } elseif ($postSetting === 3) {
545
            // Post = 3: Both additional and NFO
546
            if ($hasWork) {
547
                $commands[] = "nice -n{$niceness} ".PHP_BINARY." artisan update:postprocess additional true 2>&1 | tee -a {$log}";
548
            }
549
            if ($hasNfo) {
550
                $commands[] = "nice -n{$niceness} ".PHP_BINARY." artisan update:postprocess nfo true 2>&1 | tee -a {$log}";
551
            }
552
        }
553
554
        // If no work available, disable the pane
555
        if (empty($commands)) {
556
            $reason = match ($postSetting) {
557
                1 => 'no additional work to process',
558
                2 => 'no NFOs to process',
559
                3 => 'no additional work or NFOs to process',
560
                default => 'invalid post setting value',
561
            };
562
563
            return $this->disablePane($pane, 'Post-process Additional', $reason);
564
        }
565
566
        // Build the full command with all parts
567
        $allCommands = implode('; ', $commands);
568
        $sleepCommand = $this->buildSleepCommand($sleep);
569
        $fullCommand = "{$allCommands}; date +'%Y-%m-%d %T'; {$sleepCommand}";
570
571
        return $this->paneManager->respawnPane($pane, $fullCommand);
572
    }
573
574
    /**
575
     * Run TV/Anime post-processing
576
     */
577
    protected function runTvTask(array $runVar): bool
578
    {
579
        $enabled = (int) ($runVar['settings']['post_non'] ?? 0);
580
        $pane = '2.1';
581
582
        if ($enabled !== 1) {
583
            return $this->disablePane($pane, 'Post-process TV/Anime', 'disabled in settings');
584
        }
585
586
        $niceness = $this->getNiceness();
587
        $log = $this->getLogFile('post_tv');
588
        $artisan = PHP_BINARY.' artisan';
589
        $commands = [];
590
591
        // TV processing - Check work count before adding to queue
592
        $processTv = (int) ($runVar['settings']['processtvrage'] ?? 0);
593
        $hasTvWork = (int) ($runVar['counts']['now']['processtv'] ?? 0) > 0;
594
        if ($processTv > 0 && $hasTvWork) {
595
            $commands[] = "nice -n{$niceness} {$artisan} update:postprocess tv 2>&1 | tee -a {$log}";
596
        }
597
598
        // Anime processing
599
        $processAnime = (int) ($runVar['settings']['processanime'] ?? 0);
600
        $hasAnimeWork = (int) ($runVar['counts']['now']['processanime'] ?? 0) > 0;
601
        if ($processAnime > 0 && $hasAnimeWork) {
602
            $commands[] = "nice -n{$niceness} {$artisan} update:postprocess anime true 2>&1 | tee -a {$log}";
603
        }
604
605
        // If no work available for any enabled type, disable the pane
606
        if (empty($commands)) {
607
            $enabledTypes = [];
608
            if ($processTv > 0) {
609
                $enabledTypes[] = 'TV';
610
            }
611
            if ($processAnime > 0) {
612
                $enabledTypes[] = 'Anime';
613
            }
614
615
            if (empty($enabledTypes)) {
616
                return $this->disablePane($pane, 'Post-process TV/Anime', 'no types enabled (TV/Anime)');
617
            }
618
619
            $typesList = implode(', ', $enabledTypes);
620
621
            return $this->disablePane($pane, 'Post-process TV/Anime', "no work for enabled types ({$typesList})");
622
        }
623
624
        $sleep = (int) ($runVar['settings']['post_timer_non'] ?? 300);
625
        $allCommands = implode('; ', $commands);
626
        $sleepCommand = $this->buildSleepCommand($sleep);
627
        $fullCommand = "{$allCommands}; date +'%Y-%m-%d %T'; {$sleepCommand}";
628
629
        return $this->paneManager->respawnPane($pane, $fullCommand);
630
    }
631
632
    /**
633
     * Run Movies post-processing
634
     */
635
    protected function runMoviesTask(array $runVar): bool
636
    {
637
        $enabled = (int) ($runVar['settings']['post_non'] ?? 0);
638
        $pane = '2.3';
639
640
        if ($enabled !== 1) {
641
            return $this->disablePane($pane, 'Post-process Movies', 'disabled in settings');
642
        }
643
644
        $niceness = $this->getNiceness();
645
        $log = $this->getLogFile('post_movies');
646
        $artisan = PHP_BINARY.' artisan';
647
648
        // Movies processing - Uses single-process command
649
        $processMovies = (int) ($runVar['settings']['processmovies'] ?? 0);
650
        $hasMoviesWork = (int) ($runVar['counts']['now']['processmovies'] ?? 0) > 0;
651
652
        if ($processMovies === 0) {
653
            return $this->disablePane($pane, 'Post-process Movies', 'disabled in settings');
654
        }
655
656
        if (! $hasMoviesWork) {
657
            return $this->disablePane($pane, 'Post-process Movies', 'no work available');
658
        }
659
660
        $sleep = (int) ($runVar['settings']['post_timer_non'] ?? 300);
661
        $command = "nice -n{$niceness} {$artisan} update:postprocess movies true 2>&1 | tee -a {$log}";
662
        $sleepCommand = $this->buildSleepCommand($sleep);
663
        $fullCommand = "{$command}; date +'%Y-%m-%d %T'; {$sleepCommand}";
664
665
        return $this->paneManager->respawnPane($pane, $fullCommand);
666
    }
667
668
    /**
669
     * Legacy method for backward compatibility - now just calls runTvTask
670
     * @deprecated Use runTvTask() instead
671
     */
672
    protected function runNonAmazonTask(array $runVar): bool
673
    {
674
        return $this->runTvTask($runVar);
675
    }
676
677
    /**
678
     * Run Amazon post-processing (Books, Music, Games, Console)
679
     */
680
    protected function runAmazonTask(array $runVar): bool
681
    {
682
        $enabled = (int) ($runVar['settings']['post_amazon'] ?? 0);
683
        $pane = '2.2';
684
685
        if ($enabled !== 1) {
686
            return $this->disablePane($pane, 'Post-process Amazon', 'disabled in settings');
687
        }
688
689
        $hasWork = (int) ($runVar['counts']['now']['processmusic'] ?? 0) > 0
690
            || (int) ($runVar['counts']['now']['processbooks'] ?? 0) > 0
691
            || (int) ($runVar['counts']['now']['processconsole'] ?? 0) > 0
692
            || (int) ($runVar['counts']['now']['processgames'] ?? 0) > 0;
693
694
        if (! $hasWork) {
695
            return $this->disablePane($pane, 'Post-process Amazon', 'no music/books/games to process');
696
        }
697
698
        $niceness = Settings::settingValue('niceness') ?? 2;
699
        $log = $this->getLogFile('post_amazon');
700
        $artisan = PHP_BINARY.' artisan';
701
        $commands = [];
702
703
        // Books processing
704
        $processBooks = (int) ($runVar['settings']['processbooks'] ?? 0);
705
        $hasBooksWork = (int) ($runVar['counts']['now']['processbooks'] ?? 0) > 0;
706
        if ($processBooks > 0 && $hasBooksWork) {
707
            $commands[] = "nice -n{$niceness} {$artisan} update:postprocess book 2>&1 | tee -a {$log}";
708
        }
709
710
        // Music processing
711
        $processMusic = (int) ($runVar['settings']['processmusic'] ?? 0);
712
        $hasMusicWork = (int) ($runVar['counts']['now']['processmusic'] ?? 0) > 0;
713
        if ($processMusic > 0 && $hasMusicWork) {
714
            $commands[] = "nice -n{$niceness} {$artisan} update:postprocess music 2>&1 | tee -a {$log}";
715
        }
716
717
        // Console processing (uses same lookupgames setting as games)
718
        $processConsole = (int) ($runVar['settings']['processgames'] ?? 0);
719
        $hasConsoleWork = (int) ($runVar['counts']['now']['processconsole'] ?? 0) > 0;
720
        if ($processConsole > 0 && $hasConsoleWork) {
721
            $commands[] = "nice -n{$niceness} {$artisan} update:postprocess console 2>&1 | tee -a {$log}";
722
        }
723
724
        // Games processing
725
        $processGames = (int) ($runVar['settings']['processgames'] ?? 0);
726
        $hasGamesWork = (int) ($runVar['counts']['now']['processgames'] ?? 0) > 0;
727
        if ($processGames > 0 && $hasGamesWork) {
728
            $commands[] = "nice -n{$niceness} {$artisan} update:postprocess games 2>&1 | tee -a {$log}";
729
        }
730
731
        // If no commands were added (no work available), disable the pane
732
        if (empty($commands)) {
733
            return $this->disablePane($pane, 'Post-process Amazon', 'no work available for any enabled type');
734
        }
735
736
        $sleep = (int) ($runVar['settings']['post_timer_amazon'] ?? 300);
737
        $allCommands = implode('; ', $commands);
738
        $sleepCommand = $this->buildSleepCommand($sleep);
739
        $fullCommand = "{$allCommands}; date +'%Y-%m-%d %T'; {$sleepCommand}";
740
741
        return $this->paneManager->respawnPane($pane, $fullCommand);
742
    }
743
744
    /**
745
     * Run XXX post-processing
746
     */
747
    protected function runXXXTask(array $runVar): bool
748
    {
749
        $enabled = (int) ($runVar['settings']['processxxx'] ?? 0);
750
        $pane = '2.4';
751
752
        if ($enabled !== 1) {
753
            return $this->disablePane($pane, 'Post-process XXX', 'disabled in settings');
754
        }
755
756
        $hasWork = (int) ($runVar['counts']['now']['processxxx'] ?? 0) > 0;
757
758
        if (! $hasWork) {
759
            return $this->disablePane($pane, 'Post-process XXX', 'no XXX releases to process');
760
        }
761
762
        $niceness = Settings::settingValue('niceness') ?? 2;
763
        $command = "nice -n{$niceness} ".PHP_BINARY.' artisan update:postprocess xxx true';
764
        $sleep = (int) ($runVar['settings']['post_timer_amazon'] ?? 300);
765
        $command = $this->buildCommand($command, ['log_pane' => 'post_xxx', 'sleep' => $sleep]);
766
767
        return $this->paneManager->respawnPane($pane, $command);
768
    }
769
}
770