Passed
Push — master ( 179943...1193c4 )
by Darko
09:13
created

TvdbPipe::process()   F

Complexity

Conditions 30
Paths 10970

Size

Total Lines 131
Code Lines 74

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 74
c 1
b 0
f 0
dl 0
loc 131
rs 0
cc 30
nc 10970
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Services\TvProcessing\Pipes;
4
5
use App\Services\TvProcessing\TvProcessingPassable;
6
use App\Services\TvProcessing\TvProcessingResult;
7
use Blacklight\libraries\FanartTV;
8
use Blacklight\processing\tv\TVDB;
9
10
/**
11
 * Pipe for TVDB API lookups.
12
 */
13
class TvdbPipe extends AbstractTvProviderPipe
14
{
15
    protected int $priority = 20;
16
    private ?TVDB $tvdb = null;
17
    private ?FanartTV $fanart = null;
18
19
    public function getName(): string
20
    {
21
        return 'TVDB';
22
    }
23
24
    public function getStatusCode(): int
25
    {
26
        return 0; // PROCESS_TVDB
27
    }
28
29
    /**
30
     * Get or create the TVDB instance.
31
     */
32
    private function getTvdb(): TVDB
33
    {
34
        if ($this->tvdb === null) {
35
            $this->tvdb = new TVDB();
36
        }
37
        return $this->tvdb;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->tvdb could return the type null which is incompatible with the type-hinted return Blacklight\processing\tv\TVDB. Consider adding an additional type-check to rule them out.
Loading history...
38
    }
39
40
    protected function process(TvProcessingPassable $passable): TvProcessingResult
41
    {
42
        $parsedInfo = $passable->getParsedInfo();
43
        $context = $passable->context;
44
45
        if ($parsedInfo === null || empty($parsedInfo['cleanname'])) {
46
            return TvProcessingResult::notFound($this->getName());
47
        }
48
49
        $cleanName = $parsedInfo['cleanname'];
50
51
        // Check if we've already failed this title
52
        if ($this->isInTitleCache($cleanName)) {
53
            $this->outputSkipped($cleanName);
54
            return TvProcessingResult::skipped('previously failed', $this->getName());
55
        }
56
57
        $tvdb = $this->getTvdb();
58
        $siteId = false;
59
        $posterUrl = '';
60
61
        // Find the Video ID if it already exists by checking the title
62
        $videoId = $tvdb->getByTitle($cleanName, TVDB::TYPE_TV);
63
64
        if ($videoId !== 0) {
65
            $siteId = $tvdb->getSiteByID('tvdb', $videoId);
66
        }
67
68
        // Check if we have a valid country
69
        $country = (
70
            isset($parsedInfo['country']) && strlen($parsedInfo['country']) === 2
71
                ? (string) $parsedInfo['country']
72
                : ''
73
        );
74
75
        if ($siteId === false) {
76
            // Not in local DB, search TVDB
77
            $this->outputSearching($cleanName);
78
79
            $tvdbShow = $tvdb->getShowInfo((string) $cleanName);
80
81
            if (is_array($tvdbShow)) {
0 ignored issues
show
introduced by
The condition is_array($tvdbShow) is always true.
Loading history...
82
                $tvdbShow['country'] = $country;
83
                $videoId = $tvdb->add($tvdbShow);
84
                $siteId = (int) $tvdbShow['tvdb'];
85
                $posterUrl = $tvdbShow['poster'] ?? '';
86
            }
87
        } else {
88
            $this->outputFoundInDb($cleanName);
89
        }
90
91
        if ((int) $videoId === 0 || (int) $siteId === 0) {
92
            // Show not found
93
            $this->addToTitleCache($cleanName);
94
            $this->outputNotFound($cleanName);
95
            return TvProcessingResult::notFound($this->getName(), ['title' => $cleanName]);
96
        }
97
98
        // Fetch poster if available
99
        if (! empty($posterUrl)) {
100
            $tvdb->getPoster($videoId);
101
        } else {
102
            $this->fetchFanartPoster($videoId, $siteId);
103
        }
104
105
        // Process episode
106
        $seriesNo = ! empty($parsedInfo['season']) ? preg_replace('/^S0*/i', '', (string) $parsedInfo['season']) : '';
107
        $episodeNo = ! empty($parsedInfo['episode']) ? preg_replace('/^E0*/i', '', (string) $parsedInfo['episode']) : '';
108
        $hasAirdate = ! empty($parsedInfo['airdate']);
109
110
        if ($episodeNo === 'all') {
111
            // Full season release
112
            $tvdb->setVideoIdFound($videoId, $context->releaseId, 0);
113
            $this->outputFullSeason($cleanName);
114
            return TvProcessingResult::matched($videoId, 0, $this->getName(), ['full_season' => true]);
115
        }
116
117
        // Download all episodes if new show to reduce API/bandwidth usage
118
        if (! $tvdb->countEpsByVideoID($videoId)) {
119
            $tvdb->getEpisodeInfo($siteId, -1, -1, $videoId);
120
        }
121
122
        // Check if we have the episode for this video ID
123
        $episode = $tvdb->getBySeasonEp($videoId, $seriesNo, $episodeNo, $parsedInfo['airdate'] ?? '');
124
125
        if ($episode === false) {
126
            if ($seriesNo !== '' && $episodeNo !== '') {
127
                // Try to get episode from TVDB
128
                $tvdbEpisode = $tvdb->getEpisodeInfo($siteId, (int) $seriesNo, (int) $episodeNo, $videoId);
129
130
                if ($tvdbEpisode) {
0 ignored issues
show
introduced by
$tvdbEpisode is a non-empty array, thus is always true.
Loading history...
Bug Best Practice introduced by
The expression $tvdbEpisode of type array<string,integer|mixed|string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
131
                    $episode = $tvdb->addEpisode($videoId, $tvdbEpisode);
132
                }
133
            }
134
135
            if ($episode === false && $hasAirdate) {
136
                // Refresh episode cache and attempt airdate match
137
                $tvdb->getEpisodeInfo($siteId, -1, -1, $videoId);
138
                $episode = $tvdb->getBySeasonEp($videoId, 0, 0, $parsedInfo['airdate']);
139
            }
140
        }
141
142
        if ($episode !== false && is_numeric($episode) && $episode > 0) {
143
            // Success!
144
            $tvdb->setVideoIdFound($videoId, $context->releaseId, $episode);
145
            $this->outputMatch(
146
                $cleanName,
147
                $seriesNo !== '' ? (int) $seriesNo : null,
148
                $episodeNo !== '' ? (int) $episodeNo : null,
149
                $hasAirdate ? $parsedInfo['airdate'] : null
150
            );
151
            return TvProcessingResult::matched($videoId, (int) $episode, $this->getName());
152
        }
153
154
        // Episode not found
155
        $tvdb->setVideoIdFound($videoId, $context->releaseId, 0);
156
157
        if ($this->echoOutput) {
158
            $this->colorCli->primaryOver('    → ');
159
            $this->colorCli->alternateOver($this->truncateTitle($cleanName));
160
            if ($hasAirdate) {
161
                $this->colorCli->primaryOver(' | ');
162
                $this->colorCli->warningOver($parsedInfo['airdate']);
163
            }
164
            $this->colorCli->primaryOver(' → ');
165
            $this->colorCli->warning('Episode not found');
166
        }
167
168
        return TvProcessingResult::notFound($this->getName(), [
169
            'video_id' => $videoId,
170
            'episode_not_found' => true,
171
        ]);
172
    }
173
174
    /**
175
     * Fetch poster from Fanart.tv.
176
     */
177
    private function fetchFanartPoster(int $videoId, int $siteId): void
178
    {
179
        $fanartApiKey = config('nntmux_api.fanarttv_api_key');
180
        if ($fanartApiKey === null) {
181
            return;
182
        }
183
184
        if ($this->fanart === null) {
185
            $this->fanart = new FanartTV($fanartApiKey);
186
        }
187
188
        $poster = $this->fanart->getTVFanArt($siteId);
0 ignored issues
show
Bug introduced by
The method getTVFanArt() does not exist on null. ( Ignorable by Annotation )

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

188
        /** @scrutinizer ignore-call */ 
189
        $poster = $this->fanart->getTVFanArt($siteId);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
189
        if (is_array($poster) && ! empty($poster['tvposter'])) {
0 ignored issues
show
introduced by
The condition is_array($poster) is always false.
Loading history...
190
            $best = collect($poster['tvposter'])->sortByDesc('likes')->first();
191
            if (! empty($best['url'])) {
192
                $this->getTvdb()->posterUrl = $best['url'];
193
                $this->getTvdb()->getPoster($videoId);
194
            }
195
        }
196
    }
197
198
    /**
199
     * Output full season match message.
200
     */
201
    private function outputFullSeason(string $title): void
202
    {
203
        if (! $this->echoOutput) {
204
            return;
205
        }
206
207
        $this->colorCli->primaryOver('    → ');
208
        $this->colorCli->headerOver($this->truncateTitle($title));
209
        $this->colorCli->primaryOver(' → ');
210
        $this->colorCli->primary('Full Season matched');
211
    }
212
}
213
214