Completed
Push — dev ( 7a3759...5ffddd )
by Darko
05:53
created

Releases::moviesSearch()   C

Complexity

Conditions 16
Paths 6

Size

Total Lines 59
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 272

Importance

Changes 0
Metric Value
eloc 45
c 0
b 0
f 0
dl 0
loc 59
ccs 0
cts 33
cp 0
rs 5.5666
cc 16
nc 6
nop 11
crap 272

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace Blacklight;
4
5
use App\Models\Release;
6
use App\Models\Category;
7
use App\Models\Settings;
8
use App\Models\UsenetGroup;
9
use Illuminate\Support\Arr;
10
use Illuminate\Support\Facades\DB;
11
use Illuminate\Support\Facades\File;
12
use Illuminate\Support\Facades\Cache;
13
use Illuminate\Database\Eloquent\Collection;
14
15
/**
16
 * Class Releases.
17
 */
18
class Releases extends Release
19
{
20
    // RAR/ZIP Passworded indicator.
21
    public const PASSWD_NONE = 0; // No password.
22
    public const PASSWD_RAR = 1; // Definitely passworded.
23
24
    /**
25
     * @var \Blacklight\SphinxSearch
26
     */
27
    public $sphinxSearch;
28
29
    /**
30
     * @var int
31
     */
32
    public $passwordStatus;
33
34
    /**
35
     * @var array Class instances.
36
     * @throws \Exception
37
     */
38
    public function __construct()
39
    {
40
        parent::__construct();
41
        $this->sphinxSearch = new SphinxSearch();
42
    }
43
44
    /**
45
     * Used for Browse results.
46
     *
47
     *
48
     * @param       $page
49
     * @param       $cat
50
     * @param       $start
51
     * @param       $num
52
     * @param       $orderBy
53
     * @param int   $maxAge
54
     * @param array $excludedCats
55
     * @param array $tags
56
     * @param int   $groupName
57
     * @param int   $minSize
58
     *
59
     * @return Collection|mixed
60
     */
61
    public function getBrowseRange($page, $cat, $start, $num, $orderBy, $maxAge = -1, array $excludedCats = [], $groupName = -1, $minSize = 0, array $tags = [])
62
    {
63
        $orderBy = $this->getBrowseOrder($orderBy);
64
65
        $qry = sprintf(
66
            "SELECT r.id, r.searchname, r.groups_id, r.guid, r.postdate, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus, cp.title AS parent_category, c.title AS sub_category, r.group_name,
67
				CONCAT(cp.title, ' > ', c.title) AS category_name,
68
				CONCAT(cp.id, ',', c.id) AS category_ids,
69
				df.failed AS failed,
70
				rn.releases_id AS nfoid,
71
				re.releases_id AS reid,
72
				v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
73
				tve.title, tve.firstaired
74
			FROM
75
			(
76
				SELECT r.id, r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus, g.name AS group_name
77
				FROM releases r
78
				LEFT JOIN usenet_groups g ON g.id = r.groups_id
79
				%s
80
				WHERE r.nzbstatus = %d
81
				AND r.passwordstatus %s
82
				%s %s %s %s %s %s
83
				ORDER BY %s %s %s
84
			) r
85
			LEFT JOIN categories c ON c.id = r.categories_id
86
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
87
			LEFT OUTER JOIN videos v ON r.videos_id = v.id
88
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
89
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
90
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
91
			LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
92
			GROUP BY r.id
93
			ORDER BY %10\$s %11\$s",
94
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
95
            NZB::NZB_ADDED,
96
            $this->showPasswords(),
97
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
98
            Category::getCategorySearch($cat),
99
            ($maxAge > 0 ? (' AND postdate > NOW() - INTERVAL '.$maxAge.' DAY ') : ''),
100
            (\count($excludedCats) ? (' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')') : ''),
101
            ((int) $groupName !== -1 ? sprintf(' AND g.name = %s ', escapeString($groupName)) : ''),
102
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : ''),
103
            $orderBy[0],
104
            $orderBy[1],
105
            ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start)
106
        );
107
108
        $releases = Cache::get(md5($qry.$page));
109
        if ($releases !== null) {
110
            return $releases;
111
        }
112
        $sql = self::fromQuery($qry);
113
        if (\count($sql) > 0) {
114
            $possibleRows = $this->getBrowseCount($cat, $maxAge, $excludedCats, $groupName, $tags);
115
            $sql[0]->_totalcount = $sql[0]->_totalrows = $possibleRows;
116
        }
117
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
118
        Cache::put(md5($qry.$page), $sql, $expiresAt);
119
120
        return $sql;
121
    }
122
123
    /**
124
     * Used for pager on browse page.
125
     *
126
     * @param array      $cat
127
     * @param int        $maxAge
128
     * @param array      $excludedCats
129
     * @param string|int $groupName
130
     *
131
     * @param array      $tags
132
     *
133
     * @return int
134
     */
135
    public function getBrowseCount($cat, $maxAge = -1, array $excludedCats = [], $groupName = '', array $tags = []): int
136
    {
137
        $sql = sprintf(
138
            'SELECT COUNT(r.id) AS count
139
				FROM releases r
140
				%s %s
141
				WHERE r.nzbstatus = %d
142
				AND r.passwordstatus %s
143
				%s
144
				%s %s %s %s ',
145
            ($groupName !== -1 ? 'LEFT JOIN usenet_groups g ON g.id = r.groups_id' : ''),
146
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
147
            NZB::NZB_ADDED,
148
            $this->showPasswords(),
149
            ($groupName !== -1 ? sprintf(' AND g.name = %s', escapeString($groupName)) : ''),
150
            ! empty($tags) ? ' AND tt.tag_name IN ('.escapeString(implode(',', $tags)).')' : '',
151
            Category::getCategorySearch($cat),
152
            ($maxAge > 0 ? (' AND r.postdate > NOW() - INTERVAL '.$maxAge.' DAY ') : ''),
153
            (\count($excludedCats) ? (' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')') : '')
154
        );
155
        $count = Cache::get(md5($sql));
156
        if ($count !== null) {
157
            return $count;
158
        }
159
        $count = self::fromQuery($sql);
160
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_short'));
161
        Cache::put(md5($sql), $count[0]->count, $expiresAt);
162
163
        return $count[0]->count ?? 0;
164
    }
165
166
    /**
167
     * @return string
168
     */
169
    public function showPasswords(): ?string
170
    {
171
        $show = (int) Settings::settingValue('..showpasswordedrelease');
172
        $setting = $show ?? 1;
173
        switch ($setting) {
174
            case 0: // Hide releases with a password or a potential password (Hide unprocessed releases).
175
176
                    return '= '.self::PASSWD_NONE;
177
178
            case 1: // Shows everything.
179
            default:
180
                    return '<= '.self::PASSWD_RAR;
181
        }
182
    }
183
184
    /**
185
     * Use to order releases on site.
186
     *
187
     * @param string|array $orderBy
188
     *
189
     * @return array
190
     */
191
    public function getBrowseOrder($orderBy): array
192
    {
193
        $orderArr = explode('_', ($orderBy === '' ? 'posted_desc' : $orderBy));
0 ignored issues
show
Bug introduced by
It seems like $orderBy === '' ? 'posted_desc' : $orderBy can also be of type array; however, parameter $string of explode() does only seem to accept string, 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

193
        $orderArr = explode('_', /** @scrutinizer ignore-type */ ($orderBy === '' ? 'posted_desc' : $orderBy));
Loading history...
194
        switch ($orderArr[0]) {
195
            case 'cat':
196
                $orderField = 'categories_id';
197
                break;
198
            case 'name':
199
                $orderField = 'searchname';
200
                break;
201
            case 'size':
202
                $orderField = 'size';
203
                break;
204
            case 'files':
205
                $orderField = 'totalpart';
206
                break;
207
            case 'stats':
208
                $orderField = 'grabs';
209
                break;
210
            case 'posted':
211
            default:
212
                $orderField = 'postdate';
213
                break;
214
        }
215
216
        return [$orderField, isset($orderArr[1]) && preg_match('/^(asc|desc)$/i', $orderArr[1]) ? $orderArr[1] : 'desc'];
217
    }
218
219
    /**
220
     * Return ordering types usable on site.
221
     *
222
     * @return string[]
223
     */
224
    public function getBrowseOrdering(): array
225
    {
226
        return [
227
            'name_asc',
228
            'name_desc',
229
            'cat_asc',
230
            'cat_desc',
231
            'posted_asc',
232
            'posted_desc',
233
            'size_asc',
234
            'size_desc',
235
            'files_asc',
236
            'files_desc',
237
            'stats_asc',
238
            'stats_desc',
239
        ];
240
    }
241
242
    /**
243
     * Get list of releases available for export.
244
     *
245
     *
246
     * @param string $postFrom
247
     * @param string $postTo
248
     * @param string $groupID
249
     *
250
     * @return Collection|\Illuminate\Support\Collection|static[]
251
     */
252
    public function getForExport($postFrom = '', $postTo = '', $groupID = '')
253
    {
254
        $query = self::query()
255
            ->where('r.nzbstatus', NZB::NZB_ADDED)
256
            ->select(['r.searchname', 'r.guid', 'g.name as gname', DB::raw("CONCAT(cp.title,'_',c.title) AS catName")])
257
            ->from('releases as r')
258
            ->leftJoin('categories as c', 'c.id', '=', 'r.categories_id')
259
            ->leftJoin('root_categories as cp', 'cp.id', '=', 'c.root_categories_id')
260
            ->leftJoin('usenet_groups as g', 'g.id', '=', 'r.groups_id');
261
262
        if ($groupID !== '') {
263
            $query->where('r.groups_id', $groupID);
264
        }
265
266
        if ($postFrom !== '') {
267
            $dateParts = explode('/', $postFrom);
268
            if (\count($dateParts) === 3) {
269
                $query->where('r.postdate', '>', $dateParts[2].'-'.$dateParts[1].'-'.$dateParts[0].'00:00:00');
270
            }
271
        }
272
273
        if ($postTo !== '') {
274
            $dateParts = explode('/', $postTo);
275
            if (\count($dateParts) === 3) {
276
                $query->where('r.postdate', '<', $dateParts[2].'-'.$dateParts[1].'-'.$dateParts[0].'23:59:59');
277
            }
278
        }
279
280
        return $query->get();
281
    }
282
283
    /**
284
     * Get date in this format : 01/01/2014 of the oldest release.
285
     *
286
     * @note Used for exporting NZBs.
287
     * @return mixed
288
     */
289
    public function getEarliestUsenetPostDate()
290
    {
291
        $row = self::query()->selectRaw("DATE_FORMAT(min(postdate), '%d/%m/%Y') AS postdate")->first();
292
293
        return $row === null ? '01/01/2014' : $row['postdate'];
294
    }
295
296
    /**
297
     * Get date in this format : 01/01/2014 of the newest release.
298
     *
299
     * @note Used for exporting NZBs.
300
     * @return mixed
301
     */
302
    public function getLatestUsenetPostDate()
303
    {
304
        $row = self::query()->selectRaw("DATE_FORMAT(max(postdate), '%d/%m/%Y') AS postdate")->first();
305
306
        return $row === null ? '01/01/2014' : $row['postdate'];
307
    }
308
309
    /**
310
     * Gets all groups for drop down selection on NZB-Export web page.
311
     *
312
     * @param bool $blnIncludeAll
313
     *
314
     * @note Used for exporting NZBs.
315
     * @return array
316
     */
317
    public function getReleasedGroupsForSelect($blnIncludeAll = true): array
318
    {
319
        $groups = self::query()
320
            ->selectRaw('DISTINCT g.id, g.name')
321
            ->leftJoin('usenet_groups as g', 'g.id', '=', 'releases.groups_id')
322
            ->get();
323
        $temp_array = [];
324
325
        if ($blnIncludeAll) {
326
            $temp_array[-1] = '--All Groups--';
327
        }
328
329
        foreach ($groups as $group) {
330
            $temp_array[$group['id']] = $group['name'];
331
        }
332
333
        return $temp_array;
334
    }
335
336
    /**
337
     * Get TV for My Shows page.
338
     *
339
     *
340
     * @param $userShows
341
     * @param $offset
342
     * @param $limit
343
     * @param $orderBy
344
     * @param int $maxAge
345
     * @param array $excludedCats
346
     * @return Collection|mixed
347
     */
348
    public function getShowsRange($userShows, $offset, $limit, $orderBy, $maxAge = -1, array $excludedCats = [])
349
    {
350
        $orderBy = $this->getBrowseOrder($orderBy);
351
        $sql = sprintf(
352
            "SELECT r.id, r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus,  cp.title AS parent_category, c.title AS sub_category,
353
					CONCAT(cp.title, '-', c.title) AS category_name,
354
					g.name AS group_name,
355
					rn.releases_id AS nfoid, re.releases_id AS reid,
356
					tve.firstaired,
357
					df.failed AS failed
358
				FROM releases r
359
				LEFT OUTER JOIN video_data re ON re.releases_id = r.id
360
				LEFT JOIN usenet_groups g ON g.id = r.groups_id
361
				LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
362
				LEFT OUTER JOIN tv_episodes tve ON tve.videos_id = r.videos_id
363
				LEFT JOIN categories c ON c.id = r.categories_id
364
				LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
365
				LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
366
				WHERE %s %s
367
				AND r.nzbstatus = %d
368
				AND r.categories_id BETWEEN %d AND %d
369
				AND r.passwordstatus %s
370
				%s
371
				GROUP BY r.id
372
				ORDER BY %s %s %s",
373
            $this->uSQL($userShows, 'videos_id'),
374
            (\count($excludedCats) ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
375
            NZB::NZB_ADDED,
376
            Category::TV_ROOT,
377
            Category::TV_OTHER,
378
            $this->showPasswords(),
379
            ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : ''),
380
            $orderBy[0],
381
            $orderBy[1],
382
            ($offset === false ? '' : (' LIMIT '.$limit.' OFFSET '.$offset))
383
        );
384
385
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
386
        $result = Cache::get(md5($sql));
387
        if ($result !== null) {
388
            return $result;
389
        }
390
391
        $result = self::fromQuery($sql);
392
        Cache::put(md5($sql), $result, $expiresAt);
393
394
        return $result;
395
    }
396
397
    /**
398
     * Get count for my shows page pagination.
399
     *
400
     * @param       $userShows
401
     * @param int   $maxAge
402
     * @param array $excludedCats
403
     *
404
     * @return int
405
     */
406
    public function getShowsCount($userShows, $maxAge = -1, array $excludedCats = []): int
407
    {
408
        return $this->getPagerCount(
409
            sprintf(
410
                'SELECT r.id
411
				FROM releases r
412
				WHERE %s %s
413
				AND r.nzbstatus = %d
414
				AND r.categories_id BETWEEN %d AND %d
415
				AND r.passwordstatus %s
416
				%s',
417
                $this->uSQL($userShows, 'videos_id'),
418
                (\count($excludedCats) ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
419
                NZB::NZB_ADDED,
420
                Category::TV_ROOT,
421
                Category::TV_OTHER,
422
                $this->showPasswords(),
423
                ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '')
424
            )
425
        );
426
    }
427
428
    /**
429
     * Delete multiple releases, or a single by ID.
430
     *
431
     * @param array|int|string $list   Array of GUID or ID of releases to delete.
432
     * @throws \Exception
433
     */
434
    public function deleteMultiple($list): void
435
    {
436
        $list = (array) $list;
437
438
        $nzb = new NZB();
439
        $releaseImage = new ReleaseImage();
440
441
        foreach ($list as $identifier) {
442
            $this->deleteSingle(['g' => $identifier, 'i' => false], $nzb, $releaseImage);
443
        }
444
    }
445
446
    /**
447
     * Deletes a single release by GUID, and all the corresponding files.
448
     *
449
     * @param array                    $identifiers ['g' => Release GUID(mandatory), 'id => ReleaseID(optional, pass
450
     *                                              false)]
451
     * @param \Blacklight\NZB          $nzb
452
     * @param \Blacklight\ReleaseImage $releaseImage
453
     *
454
     * @throws \Exception
455
     */
456
    public function deleteSingle($identifiers, NZB $nzb, ReleaseImage $releaseImage): void
457
    {
458
        // Delete NZB from disk.
459
        $nzbPath = $nzb->NZBPath($identifiers['g']);
460
        if (! empty($nzbPath)) {
461
            File::delete($nzbPath);
462
        }
463
464
        // Delete images.
465
        $releaseImage->delete($identifiers['g']);
466
467
        // Delete from sphinx.
468
        $this->sphinxSearch->deleteRelease($identifiers);
469
470
        // Delete from DB.
471
        self::whereGuid($identifiers['g'])->delete();
472
    }
473
474
    /**
475
     * @param $guids
476
     * @param $category
477
     * @param $grabs
478
     * @param $videoId
479
     * @param $episodeId
480
     * @param $anidbId
481
     * @param $imdbId
482
     * @return bool|int
483
     */
484
    public function updateMulti($guids, $category, $grabs, $videoId, $episodeId, $anidbId, $imdbId)
485
    {
486
        if (! \is_array($guids) || \count($guids) < 1) {
487
            return false;
488
        }
489
490
        $update = [
491
            'categories_id'     => $category === -1 ? 'categories_id' : $category,
492
            'grabs'          => $grabs,
493
            'videos_id'      => $videoId,
494
            'tv_episodes_id' => $episodeId,
495
            'anidbid'        => $anidbId,
496
            'imdbid'         => $imdbId,
497
        ];
498
499
        return self::query()->whereIn('guid', $guids)->update($update);
500
    }
501
502
    /**
503
     * Creates part of a query for some functions.
504
     *
505
     * @param array|Collection  $userQuery
506
     * @param string $type
507
     *
508
     * @return string
509
     */
510
    public function uSQL($userQuery, $type): string
511
    {
512
        $sql = '(1=2 ';
513
        foreach ($userQuery as $query) {
514
            $sql .= sprintf('OR (r.%s = %d', $type, $query->$type);
515
            if (! empty($query->categories)) {
516
                $catsArr = explode('|', $query->categories);
517
                if (\count($catsArr) > 1) {
518
                    $sql .= sprintf(' AND r.categories_id IN (%s)', implode(',', $catsArr));
519
                } else {
520
                    $sql .= sprintf(' AND r.categories_id = %d', $catsArr[0]);
521
                }
522
            }
523
            $sql .= ') ';
524
        }
525
        $sql .= ') ';
526
527
        return $sql;
528
    }
529
530
    /**
531
     * Function for searching on the site (by subject, searchname or advanced).
532
     *
533
     *
534
     * @param  array       $searchArr
535
     * @param              $groupName
536
     * @param              $sizeFrom
537
     * @param              $sizeTo
538
     * @param              $daysNew
539
     * @param              $daysOld
540
     * @param int          $offset
541
     * @param int          $limit
542
     * @param string|array $orderBy
543
     * @param int          $maxAge
544
     * @param array        $excludedCats
545
     * @param string       $type
546
     * @param array        $cat
547
     * @param int          $minSize
548
     * @param array        $tags
549
     *
550
     * @return array|Collection|mixed
551
     */
552
    public function search($searchArr, $groupName, $sizeFrom, $sizeTo, $daysNew, $daysOld, $offset = 0, $limit = 1000, $orderBy = '', $maxAge = -1, array $excludedCats = [], $type = 'basic', array $cat = [-1], $minSize = 0, array $tags = [])
553
    {
554
        $sizeRange = [
555
            1 => 1,
556
            2 => 2.5,
557
            3 => 5,
558
            4 => 10,
559
            5 => 20,
560
            6 => 30,
561
            7 => 40,
562
            8 => 80,
563
            9 => 160,
564
            10 => 320,
565
            11 => 640,
566
        ];
567
        if ($orderBy === '') {
568
            $orderBy = [];
569
            $orderBy[0] = 'postdate ';
570
            $orderBy[1] = 'desc ';
571
        } else {
572
            $orderBy = $this->getBrowseOrder($orderBy);
573
        }
574
575
        $searchFields = Arr::where($searchArr, function ($value) {
576
            return $value !== -1;
577
        });
578
579
        $results = $this->sphinxSearch->searchIndexes('releases_rt', '', [], $searchFields);
580
581
        $searchResult = Arr::pluck($results, 'id');
582
583
        $catQuery = '';
584
        if ($type === 'basic') {
585
            $catQuery = Category::getCategorySearch($cat);
586
        } elseif ($type === 'advanced' && (int) $cat[0] !== -1) {
587
            $catQuery = sprintf('AND r.categories_id = %d', $cat[0]);
588
        }
589
        $whereSql = sprintf(
590
            'WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s %s %s %s %s',
591
            $this->showPasswords(),
592
            NZB::NZB_ADDED,
593
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
594
            ($maxAge > 0 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $maxAge) : ''),
595
            ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', UsenetGroup::getIDByName($groupName)) : ''),
0 ignored issues
show
Bug introduced by
It seems like App\Models\UsenetGroup::getIDByName($groupName) can also be of type false; however, parameter $args of sprintf() does only seem to accept string, 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

595
            ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', /** @scrutinizer ignore-type */ UsenetGroup::getIDByName($groupName)) : ''),
Loading history...
596
            (array_key_exists($sizeFrom, $sizeRange) ? ' AND r.size > '.(104857600 * (int) $sizeRange[$sizeFrom]).' ' : ''),
597
            (array_key_exists($sizeTo, $sizeRange) ? ' AND r.size < '.(104857600 * (int) $sizeRange[$sizeTo]).' ' : ''),
598
            $catQuery,
599
            ((int) $daysNew !== -1 ? sprintf(' AND r.postdate < (NOW() - INTERVAL %d DAY) ', $daysNew) : ''),
600
            ((int) $daysOld !== -1 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $daysOld) : ''),
601
            (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
602
            (! empty($searchResult) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
603
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : '')
604
        );
605
        $baseSql = sprintf(
606
            "SELECT r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus,  cp.title AS parent_category, c.title AS sub_category,
607
				CONCAT(cp.title, ' > ', c.title) AS category_name,
608
				df.failed AS failed,
609
				g.name AS group_name,
610
				rn.releases_id AS nfoid,
611
				re.releases_id AS reid,
612
				cp.id AS categoryparentid,
613
				v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
614
				tve.firstaired
615
			FROM releases r
616
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
617
			LEFT OUTER JOIN videos v ON r.videos_id = v.id
618
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
619
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
620
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
621
			LEFT JOIN categories c ON c.id = r.categories_id
622
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
623
			LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
624
			%s %s",
625
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
626
            $whereSql
627
        );
628
        $sql = sprintf(
629
            'SELECT * FROM (
630
				%s
631
			) r
632
			ORDER BY r.%s %s
633
			LIMIT %d OFFSET %d',
634
            $baseSql,
635
            $orderBy[0],
636
            $orderBy[1],
637
            $limit,
638
            $offset
639
        );
640
        $releases = Cache::get(md5($sql));
641
        if ($releases !== null) {
642
            return $releases;
643
        }
644
        $releases = ! empty($searchResult) ? self::fromQuery($sql) : collect();
645
        if ($releases->isNotEmpty()) {
646
            $releases[0]->_totalrows = $this->getPagerCount($baseSql);
647
        }
648
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
649
        Cache::put(md5($sql), $releases, $expiresAt);
650
651
        return $releases;
652
    }
653
654
    /**
655
     * Search function for API.
656
     *
657
     *
658
     * @param       $searchName
659
     * @param       $groupName
660
     * @param int   $offset
661
     * @param int   $limit
662
     * @param int   $maxAge
663
     * @param array $excludedCats
664
     * @param array $cat
665
     * @param int   $minSize
666
     * @param array $tags
667
     *
668
     * @return Collection|mixed
669
     */
670
    public function apiSearch($searchName, $groupName, $offset = 0, $limit = 1000, $maxAge = -1, array $excludedCats = [], array $cat = [-1], $minSize = 0, array $tags = [])
671
    {
672
        if ($searchName !== -1) {
673
            $searchResult = Arr::pluck($this->sphinxSearch->searchIndexes('releases_rt', $searchName, ['searchname']), 'id');
674
        }
675
676
        $catQuery = Category::getCategorySearch($cat);
677
678
        $whereSql = sprintf(
679
            'WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s',
680
            $this->showPasswords(),
681
            NZB::NZB_ADDED,
682
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
683
            ($maxAge > 0 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $maxAge) : ''),
684
            ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', UsenetGroup::getIDByName($groupName)) : ''),
0 ignored issues
show
Bug introduced by
It seems like App\Models\UsenetGroup::getIDByName($groupName) can also be of type false; however, parameter $args of sprintf() does only seem to accept string, 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

684
            ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', /** @scrutinizer ignore-type */ UsenetGroup::getIDByName($groupName)) : ''),
Loading history...
685
            $catQuery,
686
            (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
687
            (! empty($searchResult) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
688
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : '')
689
        );
690
        $baseSql = sprintf(
691
            "SELECT r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus, m.imdbid, m.tmdbid, m.traktid, cp.title AS parent_category, c.title AS sub_category,
692
				CONCAT(cp.title, ' > ', c.title) AS category_name,
693
				g.name AS group_name,
694
				cp.id AS categoryparentid,
695
				v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
696
				tve.firstaired, tve.title, tve.series, tve.episode
697
			FROM releases r
698
			LEFT OUTER JOIN videos v ON r.videos_id = v.id
699
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
700
			LEFT JOIN movieinfo m ON m.id = r.movieinfo_id
701
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
702
			LEFT JOIN categories c ON c.id = r.categories_id
703
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
704
			%s %s",
705
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
706
            $whereSql
707
        );
708
        $sql = sprintf(
709
            'SELECT * FROM (
710
				%s
711
			) r
712
			ORDER BY r.postdate DESC
713
			LIMIT %d OFFSET %d',
714
            $baseSql,
715
            $limit,
716
            $offset
717
        );
718
        $releases = Cache::get(md5($sql));
719
        if ($releases !== null) {
720
            return $releases;
721
        }
722
        if ($searchName !== -1 && ! empty($searchResult)) {
723
            $releases = self::fromQuery($sql);
724
        } elseif ($searchName !== -1 && empty($searchResult)) {
725
            $releases = collect();
726
        } else {
727
            $releases = self::fromQuery($sql);
728
        }
729
        if ($releases->isNotEmpty()) {
730
            $releases[0]->_totalrows = $this->getPagerCount($baseSql);
731
        }
732
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
733
        Cache::put(md5($sql), $releases, $expiresAt);
734
735
        return $releases;
736
    }
737
738
    /**
739
     * Search TV Shows via API.
740
     *
741
     *
742
     * @param array $siteIdArr
743
     * @param string $series
744
     * @param string $episode
745
     * @param string $airdate
746
     * @param int $offset
747
     * @param int $limit
748
     * @param string $name
749
     * @param array $cat
750
     * @param int $maxAge
751
     * @param int $minSize
752
     * @param array $excludedCategories
753
     * @param array $tags
754
     * @return Collection|mixed
755
     */
756
    public function tvSearch(array $siteIdArr = [], $series = '', $episode = '', $airdate = '', $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = [], array $tags = [])
757
    {
758
        $siteSQL = [];
759
        $showSql = '';
760
761
        foreach ($siteIdArr as $column => $Id) {
762
            if ($Id > 0) {
763
                $siteSQL[] = sprintf('v.%s = %d', $column, $Id);
764
            }
765
        }
766
767
        if (\count($siteSQL) > 0) {
768
            // If we have show info, find the Episode ID/Video ID first to avoid table scans
769
            $showQry = sprintf(
770
                "
771
				SELECT
772
					v.id AS video,
773
					GROUP_CONCAT(tve.id SEPARATOR ',') AS episodes
774
				FROM videos v
775
				LEFT JOIN tv_episodes tve ON v.id = tve.videos_id
776
				WHERE (%s) %s %s %s
777
				GROUP BY v.id
778
				LIMIT 1",
779
                implode(' OR ', $siteSQL),
780
                ($series !== '' ? sprintf('AND tve.series = %d', (int) preg_replace('/^s0*/i', '', $series)) : ''),
781
                ($episode !== '' ? sprintf('AND tve.episode = %d', (int) preg_replace('/^e0*/i', '', $episode)) : ''),
782
                ($airdate !== '' ? sprintf('AND DATE(tve.firstaired) = %s', escapeString($airdate)) : '')
783
            );
784
            $show = self::fromQuery($showQry);
785
786
            if (! empty($show[0])) {
787
                if ((! empty($series) || ! empty($episode) || ! empty($airdate)) && $show[0]->episodes !== '') {
788
                    $showSql = sprintf('AND r.tv_episodes_id IN (%s)', $show[0]->episodes);
789
                } elseif ((int) $show[0]->video > 0) {
790
                    $showSql = 'AND r.videos_id = '.$show[0]->video;
791
                    // If $series is set but episode is not, return Season Packs only
792
                    if (! empty($series) && empty($episode)) {
793
                        $showSql .= ' AND r.tv_episodes_id = 0';
794
                    }
795
                } else {
796
                    // If we were passed Episode Info and no match was found, do not run the query
797
                    return [];
798
                }
799
            } else {
800
                // If we were passed Site ID Info and no match was found, do not run the query
801
                return [];
802
            }
803
        }
804
        // If $name is set it is a fallback search, add available SxxExx/airdate info to the query
805
        if (! empty($name) && $showSql === '') {
806
            if (! empty($series) && (int) $series < 1900) {
807
                $name .= sprintf(' S%s', str_pad($series, 2, '0', STR_PAD_LEFT));
808
                if (! empty($episode) && strpos($episode, '/') === false) {
809
                    $name .= sprintf('E%s', str_pad($episode, 2, '0', STR_PAD_LEFT));
810
                }
811
            } elseif (! empty($airdate)) {
812
                $name .= sprintf(' %s', str_replace(['/', '-', '.', '_'], ' ', $airdate));
813
            }
814
        }
815
816
        if (! empty($name)) {
817
            $searchResult = Arr::pluck($this->sphinxSearch->searchIndexes('releases_rt', $name, ['searchname']), 'id');
818
        }
819
820
        $whereSql = sprintf(
821
            'WHERE r.nzbstatus = %d
822
			AND r.passwordstatus %s
823
			%s %s %s %s %s %s %s',
824
            NZB::NZB_ADDED,
825
            $this->showPasswords(),
826
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
827
            $showSql,
828
            ((! empty($name) && ! empty($searchResult)) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
829
            Category::getCategorySearch($cat),
830
            ($maxAge > 0 ? sprintf('AND r.postdate > NOW() - INTERVAL %d DAY', $maxAge) : ''),
831
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : ''),
832
            ! empty($excludedCategories) ? sprintf('AND r.categories_id NOT IN('.implode(',', $excludedCategories).')') : ''
833
        );
834
        $baseSql = sprintf(
835
            "SELECT r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus,
836
				v.title, v.countries_id, v.started, v.tvdb, v.trakt,
837
					v.imdb, v.tmdb, v.tvmaze, v.tvrage, v.source,
838
				tvi.summary, tvi.publisher, tvi.image,
839
				tve.series, tve.episode, tve.se_complete, tve.title, tve.firstaired, tve.summary, cp.title AS parent_category, c.title AS sub_category,
840
				CONCAT(cp.title, ' > ', c.title) AS category_name,
841
				g.name AS group_name,
842
				rn.releases_id AS nfoid,
843
				re.releases_id AS reid
844
			FROM releases r
845
			LEFT OUTER JOIN videos v ON r.videos_id = v.id AND v.type = 0
846
			LEFT OUTER JOIN tv_info tvi ON v.id = tvi.videos_id
847
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
848
			LEFT JOIN categories c ON c.id = r.categories_id
849
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
850
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
851
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
852
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
853
			%s %s",
854
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
855
            $whereSql
856
        );
857
        $sql = sprintf(
858
            '%s
859
			ORDER BY postdate DESC
860
			LIMIT %d OFFSET %d',
861
            $baseSql,
862
            $limit,
863
            $offset
864
        );
865
        $releases = Cache::get(md5($sql));
866
        if ($releases !== null) {
867
            return $releases;
868
        }
869
        ((! empty($name) && ! empty($searchResult)) || empty($name)) ? $releases = self::fromQuery($sql) : [];
870
        if (! empty($releases) && $releases->isNotEmpty()) {
871
            $releases[0]->_totalrows = $this->getPagerCount(
872
                preg_replace('#LEFT(\s+OUTER)?\s+JOIN\s+(?!tv_episodes)\s+.*ON.*=.*\n#i', ' ', $baseSql)
873
            );
874
        }
875
876
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
877
        Cache::put(md5($sql), $releases, $expiresAt);
878
879
        return $releases;
880
    }
881
882
    /**
883
     * Search TV Shows via APIv2.
884
     *
885
     *
886
     * @param array $siteIdArr
887
     * @param string $series
888
     * @param string $episode
889
     * @param string $airdate
890
     * @param int $offset
891
     * @param int $limit
892
     * @param string $name
893
     * @param array $cat
894
     * @param int $maxAge
895
     * @param int $minSize
896
     * @param array $excludedCategories
897
     * @param array $tags
898
     * @return Collection|mixed
899
     */
900
    public function apiTvSearch(array $siteIdArr = [], $series = '', $episode = '', $airdate = '', $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = [], array $tags = [])
901
    {
902
        $siteSQL = [];
903
        $showSql = '';
904
        foreach ($siteIdArr as $column => $Id) {
905
            if ($Id > 0) {
906
                $siteSQL[] = sprintf('v.%s = %d', $column, $Id);
907
            }
908
        }
909
910
        if (\count($siteSQL) > 0) {
911
            // If we have show info, find the Episode ID/Video ID first to avoid table scans
912
            $showQry = sprintf(
913
                "
914
				SELECT
915
					v.id AS video,
916
					GROUP_CONCAT(tve.id SEPARATOR ',') AS episodes
917
				FROM videos v
918
				LEFT JOIN tv_episodes tve ON v.id = tve.videos_id
919
				WHERE (%s) %s %s %s
920
				GROUP BY v.id
921
				LIMIT 1",
922
                implode(' OR ', $siteSQL),
923
                ($series !== '' ? sprintf('AND tve.series = %d', (int) preg_replace('/^s0*/i', '', $series)) : ''),
924
                ($episode !== '' ? sprintf('AND tve.episode = %d', (int) preg_replace('/^e0*/i', '', $episode)) : ''),
925
                ($airdate !== '' ? sprintf('AND DATE(tve.firstaired) = %s', escapeString($airdate)) : '')
926
            );
927
            $show = self::fromQuery($showQry);
928
929
            if ($show->isNotEmpty()) {
930
                if ((! empty($series) || ! empty($episode) || ! empty($airdate)) && $show[0]->episodes != '') {
931
                    $showSql = sprintf('AND r.tv_episodes_id IN (%s)', $show[0]->episodes);
932
                } elseif ((int) $show[0]->video > 0) {
933
                    $showSql = 'AND r.videos_id = '.$show[0]->video;
934
                    // If $series is set but episode is not, return Season Packs only
935
                    if (! empty($series) && empty($episode)) {
936
                        $showSql .= ' AND r.tv_episodes_id = 0';
937
                    }
938
                } else {
939
                    // If we were passed Episode Info and no match was found, do not run the query
940
                    return [];
941
                }
942
            } else {
943
                // If we were passed Site ID Info and no match was found, do not run the query
944
                return [];
945
            }
946
        }
947
        // If $name is set it is a fallback search, add available SxxExx/airdate info to the query
948
        if (! empty($name) && $showSql === '') {
949
            if (! empty($series) && (int) $series < 1900) {
950
                $name .= sprintf(' S%s', str_pad($series, 2, '0', STR_PAD_LEFT));
951
                if (! empty($episode) && strpos($episode, '/') === false) {
952
                    $name .= sprintf('E%s', str_pad($episode, 2, '0', STR_PAD_LEFT));
953
                }
954
            } elseif (! empty($airdate)) {
955
                $name .= sprintf(' %s', str_replace(['/', '-', '.', '_'], ' ', $airdate));
956
            }
957
        }
958
959
        if (! empty($name)) {
960
            $searchResult = Arr::pluck($this->sphinxSearch->searchIndexes('releases_rt', $name, ['searchname']), 'id');
961
        }
962
963
        $whereSql = sprintf(
964
            'WHERE r.nzbstatus = %d
965
			AND r.passwordstatus %s
966
			%s %s %s %s %s %s %s',
967
            NZB::NZB_ADDED,
968
            $this->showPasswords(),
969
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
970
            $showSql,
971
            (! empty($searchResult) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
972
            Category::getCategorySearch($cat),
973
            ($maxAge > 0 ? sprintf('AND r.postdate > NOW() - INTERVAL %d DAY', $maxAge) : ''),
974
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : ''),
975
            ! empty($excludedCategories) ? sprintf('AND r.categories_id NOT IN('.implode(',', $excludedCategories).')') : ''
976
        );
977
        $baseSql = sprintf(
978
            "SELECT r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.tv_episodes_id, r.haspreview, r.jpgstatus,
979
				v.title, v.type, v.tvdb, v.trakt,v.imdb, v.tmdb, v.tvmaze, v.tvrage,
980
				tve.series, tve.episode, tve.se_complete, tve.title, tve.firstaired, cp.title AS parent_category, c.title AS sub_category,
981
				CONCAT(cp.title, ' > ', c.title) AS category_name,
982
				g.name AS group_name
983
			FROM releases r
984
			LEFT OUTER JOIN videos v ON r.videos_id = v.id AND v.type = 0
985
			LEFT OUTER JOIN tv_info tvi ON v.id = tvi.videos_id
986
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
987
			LEFT JOIN categories c ON c.id = r.categories_id
988
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
989
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
990
			%s %s",
991
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
992
            $whereSql
993
        );
994
        $sql = sprintf(
995
            '%s
996
			ORDER BY postdate DESC
997
			LIMIT %d OFFSET %d',
998
            $baseSql,
999
            $limit,
1000
            $offset
1001
        );
1002
        $releases = Cache::get(md5($sql));
1003
        if ($releases !== null) {
1004
            return $releases;
1005
        }
1006
        $releases = self::fromQuery($sql);
1007
        if ($releases->isNotEmpty()) {
1008
            $releases[0]->_totalrows = $this->getPagerCount(
1009
                preg_replace('#LEFT(\s+OUTER)?\s+JOIN\s+(?!tv_episodes)\s+.*ON.*=.*\n#i', ' ', $baseSql)
1010
            );
1011
        }
1012
1013
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
1014
        Cache::put(md5($sql), $releases, $expiresAt);
1015
1016
        return $releases;
1017
    }
1018
1019
    /**
1020
     * Search anime releases.
1021
     *
1022
     *
1023
     * @param $aniDbID
1024
     * @param int $offset
1025
     * @param int $limit
1026
     * @param string $name
1027
     * @param array $cat
1028
     * @param int $maxAge
1029
     * @param array $excludedCategories
1030
     * @return Collection|mixed
1031
     */
1032
    public function animeSearch($aniDbID, $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, array $excludedCategories = [])
1033
    {
1034
        if (! empty($name)) {
1035
            $searchResult = Arr::pluck($this->sphinxSearch->searchIndexes('releases_rt', $name, ['searchname']), 'id');
1036
        }
1037
1038
        $whereSql = sprintf(
1039
            'WHERE r.passwordstatus %s
1040
			AND r.nzbstatus = %d
1041
			%s %s %s %s %s',
1042
            $this->showPasswords(),
1043
            NZB::NZB_ADDED,
1044
            ($aniDbID > -1 ? sprintf(' AND r.anidbid = %d ', $aniDbID) : ''),
1045
            (! empty($searchResult) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
1046
            ! empty($excludedCategories) ? sprintf('AND r.categories_id NOT IN('.implode(',', $excludedCategories).')') : '',
1047
            Category::getCategorySearch($cat),
1048
            ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '')
1049
        );
1050
        $baseSql = sprintf(
1051
            "SELECT r.id, r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.haspreview, r.jpgstatus,  cp.title AS parent_category, c.title AS sub_category,
1052
				CONCAT(cp.title, ' > ', c.title) AS category_name,
1053
				g.name AS group_name,
1054
				rn.releases_id AS nfoid,
1055
				re.releases_id AS reid
1056
			FROM releases r
1057
			LEFT JOIN categories c ON c.id = r.categories_id
1058
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
1059
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
1060
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
1061
			LEFT OUTER JOIN releaseextrafull re ON re.releases_id = r.id
1062
			%s",
1063
            $whereSql
1064
        );
1065
        $sql = sprintf(
1066
            '%s
1067
			ORDER BY postdate DESC
1068
			LIMIT %d OFFSET %d',
1069
            $baseSql,
1070
            $limit,
1071
            $offset
1072
        );
1073
        $releases = Cache::get(md5($sql));
1074
        if ($releases !== null) {
1075
            return $releases;
1076
        }
1077
        $releases = self::fromQuery($sql);
1078
        if ($releases->isNotEmpty()) {
1079
            $releases[0]->_totalrows = $this->getPagerCount($baseSql);
1080
        }
1081
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
1082
        Cache::put(md5($sql), $releases, $expiresAt);
1083
1084
        return $releases;
1085
    }
1086
1087
    /**
1088
     * Movies search through API and site.
1089
     *
1090
     *
1091
     * @param int $imDbId
1092
     * @param int $tmDbId
1093
     * @param int $traktId
1094
     * @param int $offset
1095
     * @param int $limit
1096
     * @param string $name
1097
     * @param array $cat
1098
     * @param int $maxAge
1099
     * @param int $minSize
1100
     * @param array $excludedCategories
1101
     * @param array $tags
1102
     * @return Collection|mixed
1103
     */
1104
    public function moviesSearch($imDbId = -1, $tmDbId = -1, $traktId = -1, $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0, array $excludedCategories = [], array $tags = [])
1105
    {
1106
        if (! empty($name)) {
1107
            $searchResult = Arr::pluck($this->sphinxSearch->searchIndexes('releases_rt', $name, ['searchname']), 'id');
1108
        }
1109
1110
        $whereSql = sprintf(
1111
            'WHERE r.categories_id BETWEEN '.Category::MOVIE_ROOT.' AND '.Category::MOVIE_OTHER.'
1112
			AND r.nzbstatus = %d
1113
			AND r.passwordstatus %s
1114
			%s %s %s %s %s %s %s %s',
1115
            NZB::NZB_ADDED,
1116
            $this->showPasswords(),
1117
            (! empty($searchResult) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
1118
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
1119
            ($imDbId !== -1 && is_numeric($imDbId)) ? sprintf(' AND m.imdbid = %d ', $imDbId) : '',
1120
            ($tmDbId !== -1 && is_numeric($tmDbId)) ? sprintf(' AND m.tmdbid = %d ', $tmDbId) : '',
1121
            ($traktId !== -1 && is_numeric($traktId)) ? sprintf(' AND m.traktid = %d ', $traktId) : '',
1122
            ! empty($excludedCategories) ? sprintf('AND r.categories_id NOT IN('.implode(',', $excludedCategories).')') : '',
1123
            Category::getCategorySearch($cat),
1124
            $maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '',
1125
            $minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : ''
1126
        );
1127
        $baseSql = sprintf(
1128
            "SELECT r.id, r.searchname, r.guid, r.postdate, r.groups_id, r.categories_id, r.size, r.totalpart, r.fromname, r.passwordstatus, r.grabs, r.comments, r.adddate, r.imdbid, r.videos_id, r.tv_episodes_id, r.haspreview, r.jpgstatus, m.imdbid, m.tmdbid, m.traktid, cp.title AS parent_category, c.title AS sub_category,
1129
				concat(cp.title, ' > ', c.title) AS category_name,
1130
				g.name AS group_name,
1131
				rn.releases_id AS nfoid
1132
			FROM releases r
1133
			LEFT JOIN movieinfo m ON m.id = r.movieinfo_id
1134
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
1135
			LEFT JOIN categories c ON c.id = r.categories_id
1136
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
1137
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
1138
			%s %s",
1139
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
1140
            $whereSql
1141
        );
1142
        $sql = sprintf(
1143
            '%s
1144
			ORDER BY postdate DESC
1145
			LIMIT %d OFFSET %d',
1146
            $baseSql,
1147
            $limit,
1148
            $offset
1149
        );
1150
1151
        $releases = Cache::get(md5($sql));
1152
        if ($releases !== null) {
1153
            return $releases;
1154
        }
1155
        $releases = self::fromQuery($sql);
1156
        if ($releases->isNotEmpty()) {
1157
            $releases[0]->_totalrows = $this->getPagerCount($baseSql);
1158
        }
1159
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
1160
        Cache::put(md5($sql), $releases, $expiresAt);
1161
1162
        return $releases;
1163
    }
1164
1165
    /**
1166
     * @param $currentID
1167
     * @param $name
1168
     * @param array $excludedCats
1169
     * @return array|Collection
1170
     */
1171
    public function searchSimilar($currentID, $name, array $excludedCats = [])
1172
    {
1173
        // Get the category for the parent of this release.
1174
        $ret = false;
1175
        $currRow = self::getCatByRelId($currentID);
1176
        if ($currRow !== null) {
1177
            $catRow = Category::find($currRow['categories_id']);
1178
            $parentCat = $catRow['root_categories_id'];
1179
1180
            $results = $this->search(['searchname' => getSimilarName($name)], -1, '', '', -1, -1, 0, config('nntmux.items_per_page'), '', -1, $excludedCats, [$parentCat]);
1181
            if (! $results) {
1182
                return $results;
1183
            }
1184
1185
            $ret = [];
1186
            foreach ($results as $res) {
1187
                if ($res['id'] !== $currentID && $res['categoryparentid'] === $parentCat) {
1188
                    $ret[] = $res;
1189
                }
1190
            }
1191
        }
1192
1193
        return $ret;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $ret could also return false which is incompatible with the documented return type Illuminate\Database\Eloquent\Collection|array. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
1194
    }
1195
1196
    /**
1197
     * Get count of releases for pager.
1198
     *
1199
     *
1200
     * @param string $query The query to get the count from.
1201
     *
1202
     * @return int
1203
     */
1204
    private function getPagerCount($query): int
1205
    {
1206
        $sql = sprintf(
1207
            'SELECT COUNT(z.id) AS count FROM (%s LIMIT %s) z',
1208
            preg_replace('/SELECT.+?FROM\s+releases/is', 'SELECT r.id FROM releases', $query),
1209
            config('nntmux.max_pager_results')
1210
        );
1211
        $count = Cache::get(md5($sql));
1212
        if ($count !== null) {
1213
            return $count;
1214
        }
1215
        $count = self::fromQuery($sql);
1216
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_short'));
1217
        Cache::put(md5($sql), $count[0]->count, $expiresAt);
1218
1219
        return $count[0]->count ?? 0;
1220
    }
1221
}
1222