Passed
Push — master ( 5bacce...8b334f )
by Darko
10:34
created

LocalDbPipe   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 126
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
eloc 66
c 1
b 0
f 0
dl 0
loc 126
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getStatusCode() 0 3 1
A getLocalDb() 0 6 2
A getName() 0 3 1
A hasEpisodeNumbers() 0 6 4
D process() 0 85 18
1
<?php
2
3
namespace App\Services\TvProcessing\Pipes;
4
5
use App\Services\TvProcessing\TvProcessingPassable;
6
use App\Services\TvProcessing\TvProcessingResult;
7
use App\Services\TvProcessing\Providers\LocalDbProvider;
8
9
/**
10
 * Pipe for local database lookups.
11
 * Attempts to match releases against existing video data before hitting external APIs.
12
 */
13
class LocalDbPipe extends AbstractTvProviderPipe
14
{
15
    // Video type constants (matching Videos class protected constants)
16
    private const TYPE_TV = 0;
17
18
    protected int $priority = 10;
19
    private ?LocalDbProvider $localDb = null;
20
21
    public function getName(): string
22
    {
23
        return 'Local DB';
24
    }
25
26
    public function getStatusCode(): int
27
    {
28
        return 0; // PROCESS_TVDB - Local DB processes unmatched releases first
29
    }
30
31
    /**
32
     * Get or create the LocalDB instance.
33
     */
34
    private function getLocalDb(): LocalDbProvider
35
    {
36
        if ($this->localDb === null) {
37
            $this->localDb = new LocalDbProvider();
38
        }
39
        return $this->localDb;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->localDb could return the type null which is incompatible with the type-hinted return App\Services\TvProcessin...oviders\LocalDbProvider. Consider adding an additional type-check to rule them out.
Loading history...
40
    }
41
42
    protected function process(TvProcessingPassable $passable): TvProcessingResult
43
    {
44
        $parsedInfo = $passable->getParsedInfo();
45
        $context = $passable->context;
46
47
        if ($parsedInfo === null || empty($parsedInfo['cleanname'])) {
48
            return TvProcessingResult::notFound($this->getName());
49
        }
50
51
        $cleanName = $parsedInfo['cleanname'];
52
        $localDb = $this->getLocalDb();
53
54
        // Try to find the show in our local database by title
55
        $videoId = $localDb->getByTitle($cleanName, self::TYPE_TV, 0);
56
57
        // If not found and cleanName contains a year in parentheses, try without the year
58
        if (($videoId === 0 || $videoId === false) && preg_match('/^(.+?)\s*\(\d{4}\)$/', $cleanName, $yearMatch)) {
59
            $nameWithoutYear = trim($yearMatch[1]);
60
            $videoId = $localDb->getByTitle($nameWithoutYear, self::TYPE_TV, 0);
61
        }
62
63
        if ($videoId === 0 || $videoId === false) {
64
            $this->outputNotFound($cleanName);
65
            return TvProcessingResult::notFound($this->getName(), ['title' => $cleanName]);
66
        }
67
68
        // Found a matching show in local DB
69
        $episodeId = false;
70
        $hasEpisodeNumbers = $this->hasEpisodeNumbers($parsedInfo);
71
        $hasAirdate = ! empty($parsedInfo['airdate']);
72
73
        if ($hasEpisodeNumbers || $hasAirdate) {
74
            // Try to find the specific episode
75
            $episodeId = $localDb->getBySeasonEp(
76
                $videoId,
77
                (int) ($parsedInfo['season'] ?? 0),
78
                (int) ($parsedInfo['episode'] ?? 0),
79
                $parsedInfo['airdate'] ?? ''
80
            );
81
        }
82
83
        if ($episodeId !== false && $episodeId > 0) {
84
            // Complete match - both show and episode found
85
            $localDb->setVideoIdFound($videoId, $context->releaseId, $episodeId);
0 ignored issues
show
Bug introduced by
It seems like $episodeId can also be of type true; however, parameter $episodeId of App\Services\TvProcessin...ider::setVideoIdFound() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

85
            $localDb->setVideoIdFound($videoId, $context->releaseId, /** @scrutinizer ignore-type */ $episodeId);
Loading history...
86
87
            $this->outputMatch(
88
                $cleanName,
89
                $hasEpisodeNumbers ? (int) $parsedInfo['season'] : null,
90
                $hasEpisodeNumbers ? (int) $parsedInfo['episode'] : null,
91
                $hasAirdate ? $parsedInfo['airdate'] : null
92
            );
93
94
            return TvProcessingResult::matched($videoId, $episodeId, $this->getName());
0 ignored issues
show
Bug introduced by
It seems like $episodeId can also be of type true; however, parameter $episodeId of App\Services\TvProcessin...essingResult::matched() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

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

94
            return TvProcessingResult::matched($videoId, /** @scrutinizer ignore-type */ $episodeId, $this->getName());
Loading history...
95
        }
96
97
        // Series matched but no specific episode located
98
        // Set video ID but mark episode as 0 (needs further lookup)
99
        $localDb->setVideoIdFound($videoId, $context->releaseId, 0);
100
101
        if ($this->echoOutput) {
102
            $this->colorCli->primaryOver('    → ');
103
            $this->colorCli->headerOver($this->truncateTitle($cleanName));
104
            if ($hasAirdate) {
105
                $this->colorCli->primaryOver(' | ');
106
                $this->colorCli->warningOver($parsedInfo['airdate']);
107
                $this->colorCli->headerOver(' → ');
108
                $this->colorCli->notice('Series matched, airdate not in local DB');
109
            } elseif ($hasEpisodeNumbers) {
110
                $this->colorCli->primaryOver(' S');
111
                $this->colorCli->warningOver(sprintf('%02d', (int) $parsedInfo['season']));
112
                $this->colorCli->primaryOver('E');
113
                $this->colorCli->warningOver(sprintf('%02d', (int) $parsedInfo['episode']));
114
                $this->colorCli->headerOver(' → ');
115
                $this->colorCli->notice('Series matched, episode not in local DB');
116
            } else {
117
                $this->colorCli->primaryOver(' → ');
118
                $this->colorCli->notice('Series matched (no episode info)');
119
            }
120
        }
121
122
        // Return not found so external APIs can try to get the episode
123
        return TvProcessingResult::notFound($this->getName(), [
124
            'video_id' => $videoId,
125
            'series_matched' => true,
126
            'episode_missing' => true,
127
        ]);
128
    }
129
130
    /**
131
     * Check if parsed info has valid episode numbers.
132
     */
133
    private function hasEpisodeNumbers(array $parsedInfo): bool
134
    {
135
        return isset($parsedInfo['season'], $parsedInfo['episode'])
136
            && $parsedInfo['episode'] !== 'all'
137
            && (int) $parsedInfo['season'] > 0
138
            && (int) $parsedInfo['episode'] > 0;
139
    }
140
}
141