Total Complexity | 244 |
Total Lines | 1258 |
Duplicated Lines | 0 % |
Changes | 12 | ||
Bugs | 6 | Features | 0 |
Complex classes like Movie often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Movie, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
37 | class Movie |
||
38 | { |
||
39 | /** |
||
40 | * @var int |
||
41 | */ |
||
42 | protected const MATCH_PERCENT = 75; |
||
43 | |||
44 | /** |
||
45 | * @var int |
||
46 | */ |
||
47 | protected const YEAR_MATCH_PERCENT = 80; |
||
48 | |||
49 | /** |
||
50 | * Current title being passed through various sites/api's. |
||
51 | */ |
||
52 | protected string $currentTitle = ''; |
||
53 | |||
54 | /** |
||
55 | * Current year of parsed search name. |
||
56 | */ |
||
57 | protected string $currentYear = ''; |
||
58 | |||
59 | /** |
||
60 | * Current release id of parsed search name. |
||
61 | */ |
||
62 | protected string $currentRelID = ''; |
||
63 | |||
64 | protected string $showPasswords; |
||
65 | |||
66 | protected ReleaseImage $releaseImage; |
||
67 | |||
68 | protected Client $client; |
||
69 | |||
70 | /** |
||
71 | * Language to fetch from IMDB. |
||
72 | */ |
||
73 | protected string $lookuplanguage; |
||
74 | |||
75 | public FanartTV $fanart; |
||
76 | |||
77 | /** |
||
78 | * @var null|string |
||
79 | */ |
||
80 | public mixed $fanartapikey; |
||
81 | |||
82 | /** |
||
83 | * @var null|string |
||
84 | */ |
||
85 | public mixed $omdbapikey; |
||
86 | |||
87 | /** |
||
88 | * @var bool |
||
89 | */ |
||
90 | public $imdburl; |
||
91 | |||
92 | public int $movieqty; |
||
93 | |||
94 | public bool $echooutput; |
||
95 | |||
96 | public string $imgSavePath; |
||
97 | |||
98 | public string $service; |
||
99 | |||
100 | public TraktTv $traktTv; |
||
101 | |||
102 | public ?OMDbAPI $omdbApi; |
||
103 | |||
104 | private Config $config; |
||
105 | |||
106 | /** |
||
107 | * @var null|string |
||
108 | */ |
||
109 | protected mixed $traktcheck; |
||
110 | |||
111 | protected ColorCLI $colorCli; |
||
112 | |||
113 | /** |
||
114 | * @throws \Exception |
||
115 | */ |
||
116 | public function __construct() |
||
152 | } |
||
153 | |||
154 | /** |
||
155 | * @return Builder|Model|null|object |
||
156 | */ |
||
157 | public function getMovieInfo($imdbId) |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * Get movie releases with covers for movie browse page. |
||
164 | * |
||
165 | * |
||
166 | * @return array|mixed |
||
167 | */ |
||
168 | public function getMovieRange($page, $cat, $start, $num, $orderBy, int $maxAge = -1, array $excludedCats = []): mixed |
||
169 | { |
||
170 | $categorySearch = $this->buildCategorySearch($cat); |
||
171 | |||
172 | $order = $this->getMovieOrder($orderBy); |
||
173 | $cacheKey = md5(json_encode([$cat, $start, $num, $orderBy, $maxAge, $excludedCats, $page])); |
||
174 | $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium')); |
||
175 | |||
176 | // Try to get from cache |
||
177 | $cachedMovies = Cache::get($cacheKey); |
||
178 | if ($cachedMovies) { |
||
179 | return $cachedMovies; |
||
180 | } |
||
181 | |||
182 | $moviesQuery = MovieInfo::query() |
||
183 | ->selectRaw('movieinfo.imdbid, GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_id') |
||
184 | ->join('releases as r', 'movieinfo.imdbid', '=', 'r.imdbid') |
||
185 | ->where('r.nzbstatus', 1) |
||
186 | ->where('movieinfo.title', '!=', '') |
||
187 | ->where('movieinfo.imdbid', '!=', '0000000') |
||
188 | ->when($maxAge > 0, fn ($query) => $query->whereRaw('r.postdate > NOW() - INTERVAL ? DAY', [$maxAge])) |
||
189 | ->when(! empty($excludedCats), fn ($query) => $query->whereNotIn('r.categories_id', $excludedCats)) |
||
190 | ->when(! empty($categorySearch), fn ($query) => $query->whereRaw( |
||
191 | // Check if $categorySearch starts with AND or OR and clean it up |
||
192 | preg_match('/^\s*(AND|OR)\s+/i', $categorySearch) ? preg_replace('/^\s*(AND|OR)\s+/i', '', $categorySearch) : $categorySearch |
||
193 | )) |
||
194 | ->groupBy('movieinfo.imdbid') |
||
195 | ->orderBy($order[0], $order[1]) |
||
196 | ->offset($start) |
||
197 | ->limit($num); |
||
198 | |||
199 | $movies = $moviesQuery->get(); |
||
200 | $total = DB::select('SELECT FOUND_ROWS() AS total'); |
||
201 | |||
202 | $movieIDs = $movies->pluck('imdbid')->toArray(); |
||
203 | $releaseIDs = $movies->pluck('grp_release_id')->toArray(); |
||
204 | |||
205 | if (! empty($movieIDs)) { |
||
206 | $moviesDetailQuery = Release::query() |
||
207 | ->selectRaw(' |
||
208 | GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_id, |
||
209 | GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ",") AS grp_rarinnerfilecount, |
||
210 | GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ",") AS grp_haspreview, |
||
211 | GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_password, |
||
212 | GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_guid, |
||
213 | GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_nfoid, |
||
214 | GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_grpname, |
||
215 | GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR "#") AS grp_release_name, |
||
216 | GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_postdate, |
||
217 | GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_size, |
||
218 | GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_totalparts, |
||
219 | GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_comments, |
||
220 | GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_grabs, |
||
221 | GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_failed, |
||
222 | GROUP_CONCAT(CONCAT(cp.title, " > ", c.title) ORDER BY r.postdate DESC SEPARATOR ",") AS grp_release_catname, |
||
223 | m.*, |
||
224 | g.name AS group_name, |
||
225 | rn.releases_id AS nfoid |
||
226 | ') |
||
227 | ->leftJoin('usenet_groups as g', 'g.id', '=', 'r.groups_id') |
||
228 | ->leftJoin('release_nfos as rn', 'rn.releases_id', '=', 'r.id') |
||
229 | ->leftJoin('dnzb_failures as df', 'df.release_id', '=', 'r.id') |
||
230 | ->leftJoin('categories as c', 'c.id', '=', 'r.categories_id') |
||
231 | ->leftJoin('root_categories as cp', 'cp.id', '=', 'c.root_categories_id') |
||
232 | ->join('movieinfo as m', 'm.imdbid', '=', 'r.imdbid') |
||
233 | ->whereIn('m.imdbid', $movieIDs) |
||
234 | ->whereIn('r.id', $releaseIDs) |
||
235 | ->when(! empty($categorySearch), fn ($query) => $query->whereRaw($categorySearch)) |
||
236 | ->groupBy('m.imdbid') |
||
237 | ->orderBy($order[0], $order[1]) |
||
238 | ->get(); |
||
239 | |||
240 | // Add total count to the first record if available |
||
241 | if ($moviesDetailQuery->count() > 0) { |
||
242 | $moviesDetailQuery[0]->_totalcount = $total[0]->total ?? 0; |
||
243 | } |
||
244 | |||
245 | // Cache the result |
||
246 | //Cache::put($cacheKey, $moviesDetailQuery, $expiresAt); |
||
247 | |||
248 | return $moviesDetailQuery; |
||
249 | } |
||
250 | |||
251 | return collect(); |
||
252 | } |
||
253 | |||
254 | protected function buildCategorySearch($cat): string |
||
255 | { |
||
256 | if (\count($cat) > 0 && $cat[0] !== -1) { |
||
257 | return Category::getCategorySearch($cat); |
||
258 | } |
||
259 | |||
260 | return ''; |
||
261 | } |
||
262 | |||
263 | /** |
||
264 | * Get the order type the user requested on the movies page. |
||
265 | */ |
||
266 | protected function getMovieOrder($orderBy): array |
||
267 | { |
||
268 | $orderArr = explode('_', (($orderBy === '') ? 'MAX(r.postdate)' : $orderBy)); |
||
269 | $orderField = match ($orderArr[0]) { |
||
270 | 'title' => 'm.title', |
||
271 | 'year' => 'm.year', |
||
272 | 'rating' => 'm.rating', |
||
273 | default => DB::raw('MAX(r.postdate)'), |
||
274 | }; |
||
275 | |||
276 | return [$orderField, isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1]) ? $orderArr[1] : 'desc']; |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * Order types for movies page. |
||
281 | */ |
||
282 | public function getMovieOrdering(): array |
||
283 | { |
||
284 | return ['title_asc', 'title_desc', 'year_asc', 'year_desc', 'rating_asc', 'rating_desc']; |
||
285 | } |
||
286 | |||
287 | protected function getBrowseBy(): string |
||
288 | { |
||
289 | $browseBy = ' '; |
||
290 | $browseByArr = ['title', 'director', 'actors', 'genre', 'rating', 'year', 'imdb']; |
||
291 | foreach ($browseByArr as $bb) { |
||
292 | if (request()->has($bb) && ! empty(request()->input($bb))) { |
||
293 | $bbv = stripslashes(request()->input($bb)); |
||
294 | if ($bb === 'rating') { |
||
295 | $bbv .= '.'; |
||
296 | } |
||
297 | if ($bb === 'imdb') { |
||
298 | $browseBy .= sprintf(' AND m.imdbid = %d', $bbv); |
||
299 | } else { |
||
300 | $browseBy .= ' AND m.'.$bb.' '.'LIKE '.escapeString('%'.$bbv.'%'); |
||
301 | } |
||
302 | } |
||
303 | } |
||
304 | |||
305 | return $browseBy; |
||
306 | } |
||
307 | |||
308 | /** |
||
309 | * Get trailer using IMDB Id. |
||
310 | * |
||
311 | * @return bool|string |
||
312 | * |
||
313 | * @throws \Exception |
||
314 | * @throws GuzzleException |
||
315 | */ |
||
316 | public function getTrailer(int $imdbId) |
||
317 | { |
||
318 | $trailer = MovieInfo::query()->where('imdbid', $imdbId)->where('trailer', '<>', '')->first(['trailer']); |
||
319 | if ($trailer !== null) { |
||
320 | return $trailer['trailer']; |
||
321 | } |
||
322 | |||
323 | if ($this->traktcheck !== null) { |
||
324 | $data = $this->traktTv->client->movieSummary('tt'.$imdbId, 'full'); |
||
325 | if (($data !== false) && ! empty($data['trailer'])) { |
||
326 | return $data['trailer']; |
||
327 | } |
||
328 | } |
||
329 | |||
330 | $trailer = Utility::imdb_trailers($imdbId); |
||
331 | if ($trailer) { |
||
332 | MovieInfo::query()->where('imdbid', $imdbId)->update(['trailer' => $trailer]); |
||
333 | |||
334 | return $trailer; |
||
335 | } |
||
336 | |||
337 | return false; |
||
338 | } |
||
339 | |||
340 | /** |
||
341 | * Parse trakt info, insert into DB. |
||
342 | * |
||
343 | * @return mixed |
||
344 | */ |
||
345 | public function parseTraktTv(array &$data) |
||
346 | { |
||
347 | if (empty($data['ids']['imdb'])) { |
||
348 | return false; |
||
349 | } |
||
350 | |||
351 | if (! empty($data['trailer'])) { |
||
352 | $data['trailer'] = str_ireplace( |
||
353 | ['watch?v=', 'http://'], |
||
354 | ['embed/', 'https://'], |
||
355 | $data['trailer'] |
||
356 | ); |
||
357 | } |
||
358 | $imdbId = (str_starts_with($data['ids']['imdb'], 'tt')) ? substr($data['ids']['imdb'], 2) : $data['ids']['imdb']; |
||
359 | $cover = 0; |
||
360 | if (File::isFile($this->imgSavePath.$imdbId).'-cover.jpg') { |
||
361 | $cover = 1; |
||
362 | } |
||
363 | |||
364 | return $this->update([ |
||
365 | 'genre' => implode(', ', $data['genres']), |
||
366 | 'imdbid' => $this->checkTraktValue($imdbId), |
||
367 | 'language' => $this->checkTraktValue($data['language']), |
||
368 | 'plot' => $this->checkTraktValue($data['overview']), |
||
369 | 'rating' => $this->checkTraktValue($data['rating']), |
||
370 | 'tagline' => $this->checkTraktValue($data['tagline']), |
||
371 | 'title' => $this->checkTraktValue($data['title']), |
||
372 | 'tmdbid' => $this->checkTraktValue($data['ids']['tmdb']), |
||
373 | 'traktid' => $this->checkTraktValue($data['ids']['trakt']), |
||
374 | 'trailer' => $this->checkTraktValue($data['trailer']), |
||
375 | 'cover' => $cover, |
||
376 | 'year' => $this->checkTraktValue($data['year']), |
||
377 | ]); |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * @return mixed|string |
||
382 | */ |
||
383 | private function checkTraktValue($value) |
||
384 | { |
||
385 | if (\is_array($value) && ! empty($value)) { |
||
386 | $temp = ''; |
||
387 | foreach ($value as $val) { |
||
388 | if (! \is_array($val) && ! \is_object($val)) { |
||
389 | $temp .= $val; |
||
390 | } |
||
391 | } |
||
392 | $value = $temp; |
||
393 | } |
||
394 | |||
395 | return ! empty($value) ? $value : ''; |
||
396 | } |
||
397 | |||
398 | /** |
||
399 | * Get array of column keys, for inserting / updating. |
||
400 | */ |
||
401 | public function getColumnKeys(): array |
||
402 | { |
||
403 | return [ |
||
404 | 'actors', 'backdrop', 'cover', 'director', 'genre', 'imdbid', 'language', |
||
405 | 'plot', 'rating', 'rtrating', 'tagline', 'title', 'tmdbid', 'traktid', 'trailer', 'type', 'year', |
||
406 | ]; |
||
407 | } |
||
408 | |||
409 | /** |
||
410 | * Update movie on movie-edit page. |
||
411 | * |
||
412 | * @param array $values Array of keys/values to update. See $validKeys |
||
413 | */ |
||
414 | public function update(array $values): bool |
||
415 | { |
||
416 | if (! \count($values)) { |
||
417 | return false; |
||
418 | } |
||
419 | |||
420 | $query = []; |
||
421 | $onDuplicateKey = ['created_at' => now()]; |
||
422 | $found = 0; |
||
423 | foreach ($values as $key => $value) { |
||
424 | if (! empty($value)) { |
||
425 | $found++; |
||
426 | if (\in_array($key, ['genre', 'language'], false)) { |
||
427 | $value = substr($value, 0, 64); |
||
428 | } |
||
429 | $query += [$key => $value]; |
||
430 | $onDuplicateKey += [$key => $value]; |
||
431 | } |
||
432 | } |
||
433 | if (! $found) { |
||
434 | return false; |
||
435 | } |
||
436 | foreach ($query as $key => $value) { |
||
437 | $query[$key] = rtrim($value, ', '); |
||
438 | } |
||
439 | |||
440 | MovieInfo::upsert($query, ['imdbid'], $onDuplicateKey); |
||
441 | |||
442 | return true; |
||
443 | } |
||
444 | |||
445 | /** |
||
446 | * @return array|string |
||
447 | */ |
||
448 | protected function setVariables(string|array $variable1, string|array $variable2, string|array $variable3, string|array $variable4, string|array $variable5) |
||
449 | { |
||
450 | if (! empty($variable1)) { |
||
451 | return $variable1; |
||
452 | } |
||
453 | if (! empty($variable2)) { |
||
454 | return $variable2; |
||
455 | } |
||
456 | if (! empty($variable3)) { |
||
457 | return $variable3; |
||
458 | } |
||
459 | if (! empty($variable4)) { |
||
460 | return $variable4; |
||
461 | } |
||
462 | if (! empty($variable5)) { |
||
463 | return $variable5; |
||
464 | } |
||
465 | |||
466 | return ''; |
||
467 | } |
||
468 | |||
469 | /** |
||
470 | * Fetch IMDB/TMDB/TRAKT/OMDB/iTunes info for the movie. |
||
471 | * |
||
472 | * |
||
473 | * @throws \Exception |
||
474 | */ |
||
475 | public function updateMovieInfo($imdbId): bool |
||
476 | { |
||
477 | if ($this->echooutput && $this->service !== '') { |
||
478 | $this->colorCli->primary('Fetching IMDB info from TMDB/IMDB/Trakt/OMDB/iTunes using IMDB id: '.$imdbId); |
||
479 | } |
||
480 | |||
481 | // Check TMDB for IMDB info. |
||
482 | $tmdb = $this->fetchTMDBProperties($imdbId); |
||
483 | |||
484 | // Check IMDB for movie info. |
||
485 | $imdb = $this->fetchIMDBProperties($imdbId); |
||
486 | |||
487 | // Check TRAKT for movie info |
||
488 | $trakt = $this->fetchTraktTVProperties($imdbId); |
||
489 | |||
490 | // Check OMDb for movie info |
||
491 | $omdb = $this->fetchOmdbAPIProperties($imdbId); |
||
492 | |||
493 | // Check iTunes for movie info as last resort (iTunes do not provide all the info we need) |
||
494 | |||
495 | $iTunes = $this->fetchItunesMovieProperties($this->currentTitle); |
||
496 | |||
497 | if (! $imdb && ! $tmdb && ! $trakt && ! $omdb && empty($iTunes)) { |
||
498 | return false; |
||
499 | } |
||
500 | |||
501 | // Check FanArt.tv for cover and background images. |
||
502 | $fanart = $this->fetchFanartTVProperties($imdbId); |
||
503 | |||
504 | $mov = []; |
||
505 | |||
506 | $mov['cover'] = $mov['backdrop'] = $mov['banner'] = 0; |
||
507 | $mov['type'] = $mov['director'] = $mov['actors'] = $mov['language'] = ''; |
||
508 | |||
509 | $mov['imdbid'] = $imdbId; |
||
510 | $mov['tmdbid'] = (! isset($tmdb['tmdbid']) || $tmdb['tmdbid'] === '') ? 0 : $tmdb['tmdbid']; |
||
511 | $mov['traktid'] = (! isset($trakt['id']) || $trakt['id'] === '') ? 0 : $trakt['id']; |
||
512 | |||
513 | // Prefer Fanart.tv cover over TMDB,TMDB over IMDB,IMDB over OMDB and OMDB over iTunes. |
||
514 | if (! empty($fanart['cover'])) { |
||
515 | $mov['cover'] = $this->releaseImage->saveImage($imdbId.'-cover', $fanart['cover'], $this->imgSavePath); |
||
516 | } elseif (! empty($tmdb['cover'])) { |
||
517 | $mov['cover'] = $this->releaseImage->saveImage($imdbId.'-cover', $tmdb['cover'], $this->imgSavePath); |
||
518 | } elseif (! empty($imdb['cover'])) { |
||
519 | $mov['cover'] = $this->releaseImage->saveImage($imdbId.'-cover', $imdb['cover'], $this->imgSavePath); |
||
520 | } elseif (! empty($omdb['cover'])) { |
||
521 | $mov['cover'] = $this->releaseImage->saveImage($imdbId.'-cover', $omdb['cover'], $this->imgSavePath); |
||
522 | } elseif (! empty($iTunes['cover'])) { |
||
523 | $mov['cover'] = $this->releaseImage->saveImage($imdbId.'-cover', $iTunes['cover'], $this->imgSavePath); |
||
524 | } |
||
525 | |||
526 | // Backdrops. |
||
527 | if (! empty($fanart['backdrop'])) { |
||
528 | $mov['backdrop'] = $this->releaseImage->saveImage($imdbId.'-backdrop', $fanart['backdrop'], $this->imgSavePath, 1920, 1024); |
||
529 | } elseif (! empty($tmdb['backdrop'])) { |
||
530 | $mov['backdrop'] = $this->releaseImage->saveImage($imdbId.'-backdrop', $tmdb['backdrop'], $this->imgSavePath, 1920, 1024); |
||
531 | } |
||
532 | |||
533 | // Banner |
||
534 | if (! empty($fanart['banner'])) { |
||
535 | $mov['banner'] = $this->releaseImage->saveImage($imdbId.'-banner', $fanart['banner'], $this->imgSavePath); |
||
536 | } |
||
537 | |||
538 | // RottenTomatoes rating from OmdbAPI |
||
539 | if ($omdb !== false && ! empty($omdb['rtRating'])) { |
||
540 | $mov['rtrating'] = $omdb['rtRating']; |
||
541 | } |
||
542 | |||
543 | $mov['title'] = $this->setVariables($imdb['title'] ?? '', $tmdb['title'] ?? '', $trakt['title'] ?? '', $omdb['title'] ?? '', $iTunes['title'] ?? ''); |
||
544 | $mov['rating'] = $this->setVariables($imdb['rating'] ?? '', $tmdb['rating'] ?? '', $trakt['rating'] ?? '', $omdb['rating'] ?? '', $iTunes['rating'] ?? ''); |
||
545 | $mov['plot'] = $this->setVariables($imdb['plot'] ?? '', $tmdb['plot'] ?? '', $trakt['overview'] ?? '', $omdb['plot'] ?? '', $iTunes['plot'] ?? ''); |
||
546 | $mov['tagline'] = $this->setVariables($imdb['tagline'] ?? '', $tmdb['tagline'] ?? '', $trakt['tagline'] ?? '', $omdb['tagline'] ?? '', $iTunes['tagline'] ?? ''); |
||
547 | $mov['year'] = $this->setVariables($imdb['year'] ?? '', $tmdb['year'] ?? '', $trakt['year'] ?? '', $omdb['year'] ?? '', $iTunes['year'] ?? ''); |
||
548 | $mov['genre'] = $this->setVariables($imdb['genre'] ?? '', $tmdb['genre'] ?? '', $trakt['genres'] ?? '', $omdb['genre'] ?? '', $iTunes['genre'] ?? ''); |
||
549 | |||
550 | if (! empty($imdb['type'])) { |
||
551 | $mov['type'] = $imdb['type']; |
||
552 | } |
||
553 | |||
554 | if (! empty($imdb['director'])) { |
||
555 | $mov['director'] = \is_array($imdb['director']) ? implode(', ', array_unique($imdb['director'])) : $imdb['director']; |
||
556 | } elseif (! empty($omdb['director'])) { |
||
557 | $mov['director'] = \is_array($omdb['director']) ? implode(', ', array_unique($omdb['director'])) : $omdb['director']; |
||
558 | } elseif (! empty($tmdb['director'])) { |
||
559 | $mov['director'] = \is_array($tmdb['director']) ? implode(', ', array_unique($tmdb['director'])) : $tmdb['director']; |
||
560 | } |
||
561 | |||
562 | if (! empty($imdb['actors'])) { |
||
563 | $mov['actors'] = \is_array($imdb['actors']) ? implode(', ', array_unique($imdb['actors'])) : $imdb['actors']; |
||
564 | } elseif (! empty($omdb['actors'])) { |
||
565 | $mov['actors'] = \is_array($omdb['actors']) ? implode(', ', array_unique($omdb['actors'])) : $omdb['actors']; |
||
566 | } elseif (! empty($tmdb['actors'])) { |
||
567 | $mov['actors'] = \is_array($tmdb['actors']) ? implode(', ', array_unique($tmdb['actors'])) : $tmdb['actors']; |
||
568 | } |
||
569 | |||
570 | if (! empty($imdb['language'])) { |
||
571 | $mov['language'] = \is_array($imdb['language']) ? implode(', ', array_unique($imdb['language'])) : $imdb['language']; |
||
572 | } elseif (! empty($omdb['language']) && ! is_bool($omdb['language'])) { |
||
573 | $mov['language'] = \is_array($omdb['language']) ? implode(', ', array_unique($omdb['language'])) : $omdb['language']; |
||
574 | } |
||
575 | |||
576 | if (\is_array($mov['genre'])) { |
||
577 | $mov['genre'] = implode(', ', array_unique($mov['genre'])); |
||
578 | } |
||
579 | |||
580 | if (\is_array($mov['type'])) { |
||
581 | $mov['type'] = implode(', ', array_unique($mov['type'])); |
||
582 | } |
||
583 | |||
584 | $mov['title'] = html_entity_decode($mov['title'], ENT_QUOTES, 'UTF-8'); |
||
585 | |||
586 | $mov['title'] = str_replace(['/', '\\'], '', $mov['title']); |
||
587 | $movieID = $this->update([ |
||
588 | 'actors' => html_entity_decode($mov['actors'], ENT_QUOTES, 'UTF-8'), |
||
589 | 'backdrop' => $mov['backdrop'], |
||
590 | 'cover' => $mov['cover'], |
||
591 | 'director' => html_entity_decode($mov['director'], ENT_QUOTES, 'UTF-8'), |
||
592 | 'genre' => html_entity_decode($mov['genre'], ENT_QUOTES, 'UTF-8'), |
||
593 | 'imdbid' => $mov['imdbid'], |
||
594 | 'language' => html_entity_decode($mov['language'], ENT_QUOTES, 'UTF-8'), |
||
595 | 'plot' => html_entity_decode(preg_replace('/\s+See full summary »/u', ' ', $mov['plot']), ENT_QUOTES, 'UTF-8'), |
||
596 | 'rating' => round((int) $mov['rating'], 1), |
||
597 | 'rtrating' => $mov['rtrating'] ?? 'N/A', |
||
598 | 'tagline' => html_entity_decode($mov['tagline'], ENT_QUOTES, 'UTF-8'), |
||
599 | 'title' => $mov['title'], |
||
600 | 'tmdbid' => $mov['tmdbid'], |
||
601 | 'traktid' => $mov['traktid'], |
||
602 | 'type' => html_entity_decode(ucwords(preg_replace('/[\.\_]/', ' ', $mov['type'])), ENT_QUOTES, 'UTF-8'), |
||
603 | 'year' => $mov['year'], |
||
604 | ]); |
||
605 | |||
606 | if ($this->echooutput && $this->service !== '') { |
||
607 | PHP_EOL.$this->colorCli->headerOver('Added/updated movie: '). |
||
608 | $this->colorCli->primary( |
||
609 | $mov['title']. |
||
610 | ' ('. |
||
611 | $mov['year']. |
||
612 | ') - '. |
||
613 | $mov['imdbid'] |
||
614 | ); |
||
615 | } |
||
616 | |||
617 | return $movieID; |
||
618 | } |
||
619 | |||
620 | /** |
||
621 | * Fetch FanArt.tv backdrop / cover / title. |
||
622 | * |
||
623 | * @return array|false |
||
624 | */ |
||
625 | protected function fetchFanartTVProperties($imdbId) |
||
626 | { |
||
627 | if ($this->fanartapikey !== null) { |
||
628 | $art = $this->fanart->getMovieFanArt('tt'.$imdbId); |
||
629 | |||
630 | if (! empty($art)) { |
||
631 | if (isset($art['status']) && $art['status'] === 'error') { |
||
632 | return false; |
||
633 | } |
||
634 | $ret = []; |
||
635 | if (! empty($art['moviebackground'][0]['url'])) { |
||
636 | $ret['backdrop'] = $art['moviebackground'][0]['url']; |
||
637 | } elseif (! empty($art['moviethumb'][0]['url'])) { |
||
638 | $ret['backdrop'] = $art['moviethumb'][0]['url']; |
||
639 | } |
||
640 | if (! empty($art['movieposter'][0]['url'])) { |
||
641 | $ret['cover'] = $art['movieposter'][0]['url']; |
||
642 | } |
||
643 | if (! empty($art['moviebanner'][0]['url'])) { |
||
644 | $ret['banner'] = $art['moviebanner'][0]['url']; |
||
645 | } |
||
646 | |||
647 | if (isset($ret['backdrop'], $ret['cover'])) { |
||
648 | $ret['title'] = $imdbId; |
||
649 | if (isset($art['name'])) { |
||
650 | $ret['title'] = $art['name']; |
||
651 | } |
||
652 | if ($this->echooutput) { |
||
653 | $this->colorCli->climate()->info('Fanart found '.$ret['title']); |
||
654 | } |
||
655 | |||
656 | return $ret; |
||
657 | } |
||
658 | } |
||
659 | } |
||
660 | |||
661 | return false; |
||
662 | } |
||
663 | |||
664 | /** |
||
665 | * Fetch info for IMDB id from TMDB. |
||
666 | * |
||
667 | * |
||
668 | * @return array|false |
||
669 | */ |
||
670 | public function fetchTMDBProperties($imdbId, bool $text = false) |
||
671 | { |
||
672 | $lookupId = $text === false && (\strlen($imdbId) === 7 || strlen($imdbId) === 8) ? 'tt'.$imdbId : $imdbId; |
||
673 | |||
674 | try { |
||
675 | $tmdbLookup = Tmdb::getMoviesApi()->getMovie($lookupId, ['append_to_response' => 'credits']); |
||
676 | } catch (TmdbApiException|\ErrorException $error) { |
||
677 | return false; |
||
678 | } |
||
679 | |||
680 | if (! empty($tmdbLookup)) { |
||
681 | if ($this->currentTitle !== '') { |
||
682 | // Check the similarity. |
||
683 | similar_text($this->currentTitle, $tmdbLookup['title'], $percent); |
||
684 | if ($percent < self::MATCH_PERCENT) { |
||
685 | return false; |
||
686 | } |
||
687 | } |
||
688 | |||
689 | if ($this->currentYear !== '') { |
||
690 | // Check the similarity. |
||
691 | similar_text($this->currentYear, Carbon::parse($tmdbLookup['release_date'])->year, $percent); |
||
692 | if ($percent < self::YEAR_MATCH_PERCENT) { |
||
693 | return false; |
||
694 | } |
||
695 | } |
||
696 | |||
697 | $ret = []; |
||
698 | $ret['title'] = $tmdbLookup['title']; |
||
699 | |||
700 | $ret['tmdbid'] = $tmdbLookup['id']; |
||
701 | $ret['imdbid'] = str_replace('tt', '', $tmdbLookup['imdb_id']); |
||
702 | $vote = $tmdbLookup['vote_average']; |
||
703 | if ($vote !== null) { |
||
704 | $ret['rating'] = (int) $vote === 0 ? '' : $vote; |
||
705 | } else { |
||
706 | $ret['rating'] = ''; |
||
707 | } |
||
708 | $actors = Arr::pluck($tmdbLookup['credits']['cast'], 'name'); |
||
709 | if (! empty($actors)) { |
||
710 | $ret['actors'] = $actors; |
||
711 | } else { |
||
712 | $ret['actors'] = ''; |
||
713 | } |
||
714 | foreach ($tmdbLookup['credits']['crew'] as $crew) { |
||
715 | if ($crew['department'] === 'Directing' && $crew['job'] === 'Director') { |
||
716 | $ret['director'] = $crew['name']; |
||
717 | } |
||
718 | } |
||
719 | $overview = $tmdbLookup['overview']; |
||
720 | if (! empty($overview)) { |
||
721 | $ret['plot'] = $overview; |
||
722 | } else { |
||
723 | $ret['plot'] = ''; |
||
724 | } |
||
725 | $tagline = $tmdbLookup['tagline']; |
||
726 | |||
727 | $ret['tagline'] = $tagline ?? ''; |
||
728 | |||
729 | $released = $tmdbLookup['release_date']; |
||
730 | if (! empty($released)) { |
||
731 | $ret['year'] = Carbon::parse($released)->year; |
||
732 | } else { |
||
733 | $ret['year'] = ''; |
||
734 | } |
||
735 | $genresa = $tmdbLookup['genres']; |
||
736 | if (! empty($genresa) && \count($genresa) > 0) { |
||
737 | $genres = []; |
||
738 | foreach ($genresa as $genre) { |
||
739 | $genres[] = $genre['name']; |
||
740 | } |
||
741 | $ret['genre'] = $genres; |
||
742 | } else { |
||
743 | $ret['genre'] = ''; |
||
744 | } |
||
745 | $posterp = $tmdbLookup['poster_path']; |
||
746 | if (! empty($posterp)) { |
||
747 | $ret['cover'] = 'https://image.tmdb.org/t/p/original'.$posterp; |
||
748 | } else { |
||
749 | $ret['cover'] = ''; |
||
750 | } |
||
751 | $backdrop = $tmdbLookup['backdrop_path']; |
||
752 | if (! empty($backdrop)) { |
||
753 | $ret['backdrop'] = 'https://image.tmdb.org/t/p/original'.$backdrop; |
||
754 | } else { |
||
755 | $ret['backdrop'] = ''; |
||
756 | } |
||
757 | if ($this->echooutput) { |
||
758 | $this->colorCli->climate()->info('TMDb found '.$ret['title']); |
||
759 | } |
||
760 | |||
761 | return $ret; |
||
762 | } |
||
763 | |||
764 | return false; |
||
765 | } |
||
766 | |||
767 | /** |
||
768 | * @return array|false |
||
769 | */ |
||
770 | public function fetchIMDBProperties($imdbId) |
||
771 | { |
||
772 | $realId = (new Title($imdbId, $this->config))->real_id(); |
||
773 | $result = new Title($realId, $this->config); |
||
774 | $title = ! empty($result->orig_title()) ? $result->orig_title() : $result->title(); |
||
775 | if (! empty($title)) { |
||
776 | if (! empty($this->currentTitle)) { |
||
777 | similar_text($this->currentTitle, $title, $percent); |
||
778 | if ($percent >= self::MATCH_PERCENT) { |
||
779 | similar_text($this->currentYear, $result->year(), $percent); |
||
780 | if ($percent >= self::YEAR_MATCH_PERCENT) { |
||
781 | $ret = [ |
||
782 | 'title' => $title, |
||
783 | 'tagline' => $result->tagline() ?? '', |
||
784 | 'plot' => Arr::get($result->plot_split(), '0.plot'), |
||
785 | 'rating' => ! empty($result->rating()) ? $result->rating() : '', |
||
786 | 'year' => $result->year() ?? '', |
||
787 | 'cover' => $result->photo() ?? '', |
||
788 | 'genre' => $result->genre() ?? '', |
||
789 | 'language' => $result->language() ?? '', |
||
790 | 'type' => $result->movietype() ?? '', |
||
791 | ]; |
||
792 | |||
793 | if ($this->echooutput) { |
||
794 | $this->colorCli->climate()->info('IMDb found '.$title); |
||
795 | } |
||
796 | |||
797 | return $ret; |
||
798 | } |
||
799 | |||
800 | return false; |
||
801 | } |
||
802 | |||
803 | return false; |
||
804 | } |
||
805 | |||
806 | return [ |
||
807 | 'title' => $title, |
||
808 | 'tagline' => $result->tagline() ?? '', |
||
809 | 'plot' => Arr::get($result->plot_split(), '0.plot'), |
||
810 | 'rating' => ! empty($result->rating()) ? $result->rating() : '', |
||
811 | 'year' => $result->year() ?? '', |
||
812 | 'cover' => $result->photo() ?? '', |
||
813 | 'genre' => $result->genre() ?? '', |
||
814 | 'language' => $result->language() ?? '', |
||
815 | 'type' => $result->movietype() ?? '', |
||
816 | ]; |
||
817 | } |
||
818 | |||
819 | return false; |
||
820 | } |
||
821 | |||
822 | /** |
||
823 | * Fetch TraktTV backdrop / cover / title. |
||
824 | * |
||
825 | * @return array|false |
||
826 | * |
||
827 | * @throws \Exception |
||
828 | * @throws GuzzleException |
||
829 | */ |
||
830 | public function fetchTraktTVProperties($imdbId) |
||
831 | { |
||
832 | if ($this->traktcheck !== null) { |
||
833 | $resp = $this->traktTv->client->movieSummary('tt'.$imdbId, 'full'); |
||
834 | if ($resp !== false) { |
||
835 | similar_text($this->currentTitle, $resp['title'], $percent); |
||
836 | if ($percent >= self::MATCH_PERCENT) { |
||
837 | similar_text($this->currentYear, $resp['year'], $percent); |
||
838 | if ($percent >= self::YEAR_MATCH_PERCENT) { |
||
839 | $ret = []; |
||
840 | if (isset($resp['ids']['trakt'])) { |
||
841 | $ret['id'] = $resp['ids']['trakt']; |
||
842 | } |
||
843 | |||
844 | $ret['overview'] = $resp['overview'] ?? ''; |
||
845 | $ret['tagline'] = $resp['tagline'] ?? ''; |
||
846 | $ret['year'] = $resp['year'] ?? ''; |
||
847 | $ret['genres'] = $resp['genres'] ?? ''; |
||
848 | |||
849 | if (isset($resp['title'])) { |
||
850 | $ret['title'] = $resp['title']; |
||
851 | } else { |
||
852 | return false; |
||
853 | } |
||
854 | |||
855 | if ($this->echooutput) { |
||
856 | $this->colorCli->climate()->info('Trakt found '.$ret['title']); |
||
857 | } |
||
858 | |||
859 | return $ret; |
||
860 | } |
||
861 | |||
862 | return false; |
||
863 | } |
||
864 | |||
865 | return false; |
||
866 | } |
||
867 | |||
868 | return false; |
||
869 | } |
||
870 | |||
871 | return false; |
||
872 | } |
||
873 | |||
874 | /** |
||
875 | * Fetch OMDb backdrop / cover / title. |
||
876 | * |
||
877 | * @return array|false |
||
878 | */ |
||
879 | public function fetchOmdbAPIProperties($imdbId) |
||
880 | { |
||
881 | if ($this->omdbapikey !== null) { |
||
882 | $resp = $this->omdbApi->fetch('i', 'tt'.$imdbId); |
||
883 | |||
884 | if (\is_object($resp) && $resp->message === 'OK' && ! Str::contains($resp->data->Response, 'Error:') && $resp->data->Response !== 'False') { |
||
885 | similar_text($this->currentTitle, $resp->data->Title, $percent); |
||
886 | if ($percent >= self::MATCH_PERCENT) { |
||
887 | similar_text($this->currentYear, $resp->data->Year, $percent); |
||
888 | if ($percent >= self::YEAR_MATCH_PERCENT) { |
||
889 | $ret = [ |
||
890 | 'title' => $resp->data->Title ?? '', |
||
891 | 'cover' => $resp->data->Poster ?? '', |
||
892 | 'genre' => $resp->data->Genre ?? '', |
||
893 | 'year' => $resp->data->Year ?? '', |
||
894 | 'plot' => $resp->data->Plot ?? '', |
||
895 | 'rating' => $resp->data->imdbRating ?? '', |
||
896 | 'rtRating' => $resp->data->Ratings[1]->Value ?? '', |
||
897 | 'tagline' => $resp->data->Tagline ?? '', |
||
898 | 'director' => $resp->data->Director ?? '', |
||
899 | 'actors' => $resp->data->Actors ?? '', |
||
900 | 'language' => $resp->data->Language ?? '', |
||
901 | 'boxOffice' => $resp->data->BoxOffice ?? '', |
||
902 | ]; |
||
903 | |||
904 | if ($this->echooutput) { |
||
905 | $this->colorCli->climate()->info('OMDbAPI Found '.$ret['title']); |
||
906 | } |
||
907 | |||
908 | return $ret; |
||
909 | } |
||
910 | |||
911 | return false; |
||
912 | } |
||
913 | |||
914 | return false; |
||
915 | } |
||
916 | |||
917 | return false; |
||
918 | } |
||
919 | |||
920 | return false; |
||
921 | } |
||
922 | |||
923 | /** |
||
924 | * @return array|bool |
||
925 | * |
||
926 | * @throws InvalidProviderException |
||
927 | * @throws \Exception |
||
928 | */ |
||
929 | public function fetchItunesMovieProperties(string $title) |
||
930 | { |
||
931 | $movie = true; |
||
932 | try { |
||
933 | $iTunesMovie = iTunes::load('movie')->fetchOneByName($title); |
||
934 | } catch (MovieNotFoundException $e) { |
||
935 | $movie = false; |
||
936 | } catch (SearchNoResultsException $e) { |
||
937 | $movie = false; |
||
938 | } |
||
939 | |||
940 | if ($movie !== false) { |
||
941 | similar_text($this->currentTitle, $iTunesMovie->getName(), $percent); |
||
942 | if ($percent >= self::MATCH_PERCENT) { |
||
943 | $movie = [ |
||
944 | 'title' => $iTunesMovie->getName(), |
||
945 | 'director' => $iTunesMovie->getDirector() ?? '', |
||
946 | 'tagline' => $iTunesMovie->getTagLine() ?? '', |
||
947 | 'cover' => str_replace('100x100', '800x800', $iTunesMovie->getCover()), |
||
948 | 'genre' => $iTunesMovie->getGenre() ?? '', |
||
949 | 'plot' => $iTunesMovie->getDescription() ?? '', |
||
950 | 'year' => $iTunesMovie->getReleaseDate() ? $iTunesMovie->getReleaseDate()->format('Y') : '', |
||
951 | ]; |
||
952 | } else { |
||
953 | $movie = false; |
||
954 | } |
||
955 | } |
||
956 | |||
957 | return $movie; |
||
958 | } |
||
959 | |||
960 | /** |
||
961 | * Update a release with a IMDB id. |
||
962 | * |
||
963 | * @param string $buffer Data to parse a IMDB id/Trakt Id from. |
||
964 | * @param string $service Method that called this method. |
||
965 | * @param int $id id of the release. |
||
966 | * @param int $processImdb To get IMDB info on this IMDB id or not. |
||
967 | * |
||
968 | * @throws \Exception |
||
969 | */ |
||
970 | public function doMovieUpdate(string $buffer, string $service, int $id, int $processImdb = 1): string |
||
971 | { |
||
972 | $imdbId = false; |
||
973 | if (preg_match('/(?:imdb.*?)?(?:tt|Title\?)(?P<imdbid>\d{5,8})/i', $buffer, $hits)) { |
||
974 | $imdbId = $hits['imdbid']; |
||
975 | } |
||
976 | |||
977 | if ($imdbId !== false) { |
||
978 | $this->service = $service; |
||
979 | if ($this->echooutput && $this->service !== '') { |
||
980 | $this->colorCli->climate()->info($this->service.' found IMDBid: tt'.$imdbId); |
||
981 | } |
||
982 | |||
983 | $movieInfoId = MovieInfo::query()->where('imdbid', $imdbId)->first(['id']); |
||
984 | |||
985 | Release::query()->where('id', $id)->update(['imdbid' => $imdbId, 'movieinfo_id' => $movieInfoId !== null ? $movieInfoId['id'] : null]); |
||
986 | |||
987 | // If set, scan for imdb info. |
||
988 | if ($processImdb === 1) { |
||
989 | $movCheck = $this->getMovieInfo($imdbId); |
||
990 | if ($movCheck === null || (isset($movCheck['updated_at']) && (time() - strtotime($movCheck['updated_at'])) > 2592000)) { |
||
991 | $info = $this->updateMovieInfo($imdbId); |
||
992 | if ($info === false) { |
||
993 | Release::query()->where('id', $id)->update(['imdbid' => 0000000]); |
||
994 | } elseif ($info === true) { |
||
995 | $movieInfoId = MovieInfo::query()->where('imdbid', $imdbId)->first(['id']); |
||
996 | |||
997 | Release::query()->where('id', $id)->update(['imdbid' => $imdbId, 'movieinfo_id' => $movieInfoId !== null ? $movieInfoId['id'] : null]); |
||
998 | } |
||
999 | } |
||
1000 | } |
||
1001 | } |
||
1002 | |||
1003 | return $imdbId; |
||
1004 | } |
||
1005 | |||
1006 | /** |
||
1007 | * Process releases with no IMDB id's. |
||
1008 | * |
||
1009 | * |
||
1010 | * |
||
1011 | * @throws \Exception |
||
1012 | * @throws GuzzleException |
||
1013 | */ |
||
1014 | public function processMovieReleases(string $groupID = '', string $guidChar = '', int $lookupIMDB = 1): void |
||
1173 | } |
||
1174 | } |
||
1175 | } |
||
1176 | } |
||
1177 | |||
1178 | /** |
||
1179 | * @return false|mixed |
||
1180 | */ |
||
1181 | protected function localIMDBSearch() |
||
1182 | { |
||
1183 | //If we found a year, try looking in a 4 year range. |
||
1184 | $check = MovieInfo::query() |
||
1185 | ->where('title', 'like', '%'.$this->currentTitle.'%'); |
||
1186 | |||
1187 | if ($this->currentYear !== '') { |
||
1188 | $start = Carbon::createFromFormat('Y', $this->currentYear)->subYears(2)->year; |
||
1189 | $end = Carbon::createFromFormat('Y', $this->currentYear)->addYears(2)->year; |
||
1190 | $check->whereBetween('year', [$start, $end]); |
||
1191 | } |
||
1192 | $IMDBCheck = $check->get(['imdbid']); |
||
1193 | foreach ($IMDBCheck as $check) { |
||
1194 | // match the title and year of the movie as close as possible. |
||
1195 | if ($this->currentYear !== '') { |
||
1196 | $IMDBCheck = MovieInfo::query() |
||
1197 | ->where('imdbid', $check['imdbid']) |
||
1198 | ->where('title', 'like', '%'.$this->currentTitle.'%') |
||
1199 | ->whereBetween('year', [$start, $end]) |
||
1200 | ->first(['imdbid', 'title']); |
||
1201 | } else { |
||
1202 | $IMDBCheck = MovieInfo::query() |
||
1203 | ->where('imdbid', $check['imdbid']) |
||
1204 | ->where('title', 'like', '%'.$this->currentTitle.'%') |
||
1205 | ->first(['imdbid', 'title']); |
||
1206 | } |
||
1207 | // If we found a match, check if percentage is high enough. If so, return the IMDB id. |
||
1208 | if ($IMDBCheck !== null) { |
||
1209 | similar_text($this->currentTitle, $IMDBCheck['title'], $percent); |
||
1210 | if ($percent >= self::MATCH_PERCENT) { |
||
1211 | return $IMDBCheck['imdbid']; |
||
1212 | } |
||
1213 | } |
||
1214 | } |
||
1215 | |||
1216 | return false; |
||
1217 | } |
||
1218 | |||
1219 | /** |
||
1220 | * Parse a movie name from a release search name. |
||
1221 | */ |
||
1222 | protected function parseMovieSearchName(string $releaseName): bool |
||
1261 | } |
||
1262 | |||
1263 | /** |
||
1264 | * Get IMDB genres. |
||
1265 | */ |
||
1266 | public function getGenres(): array |
||
1295 | ]; |
||
1296 | } |
||
1297 | } |
||
1298 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.