Passed
Push — dev ( 535ca7...b7c17d )
by Darko
07:22
created

Releases::moviesSearch()   D

Complexity

Conditions 18
Paths 11

Size

Total Lines 67
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 12
Bugs 3 Features 0
Metric Value
eloc 50
c 12
b 3
f 0
dl 0
loc 67
rs 4.8666
ccs 0
cts 5
cp 0
cc 18
nc 11
nop 11
crap 342

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\Category;
6
use App\Models\Release;
7
use App\Models\Settings;
8
use App\Models\UsenetGroup;
9
use Illuminate\Database\Eloquent\Collection;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Facades\Cache;
12
use Illuminate\Support\Facades\DB;
13
use Illuminate\Support\Facades\File;
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 === 0 ? ' LIMIT '.$num : ' 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
        return $this->getPagerCount(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
    }
156
157
    /**
158
     * @return string
159
     */
160
    public function showPasswords()
161
    {
162
        $show = (int) Settings::settingValue('..showpasswordedrelease');
163
        $setting = $show ?? 0;
164
        switch ($setting) {
165
            case 1: // Shows everything.
166
                    return '<= '.self::PASSWD_RAR;
167
            case 0:
168
            default:// Hide releases with a password.
169
                return '= '.self::PASSWD_NONE;
170
        }
171
    }
172
173
    /**
174
     * Use to order releases on site.
175
     *
176
     * @param string|array $orderBy
177
     *
178
     * @return array
179
     */
180
    public function getBrowseOrder($orderBy): array
181
    {
182
        $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

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

606
            ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', /** @scrutinizer ignore-type */ UsenetGroup::getIDByName($groupName)) : ''),
Loading history...
607
            (array_key_exists($sizeFrom, $sizeRange) ? ' AND r.size > '.(104857600 * (int) $sizeRange[$sizeFrom]).' ' : ''),
608
            (array_key_exists($sizeTo, $sizeRange) ? ' AND r.size < '.(104857600 * (int) $sizeRange[$sizeTo]).' ' : ''),
609
            $catQuery,
610
            ((int) $daysNew !== -1 ? sprintf(' AND r.postdate < (NOW() - INTERVAL %d DAY) ', $daysNew) : ''),
611
            ((int) $daysOld !== -1 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $daysOld) : ''),
612
            (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
613
            (! empty($searchResult) ? 'AND r.id IN ('.implode(',', $searchResult).')' : ''),
614
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : '')
615
        );
616
        $baseSql = sprintf(
617
            "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,
618
				CONCAT(cp.title, ' > ', c.title) AS category_name,
619
				df.failed AS failed,
620
				g.name AS group_name,
621
				rn.releases_id AS nfoid,
622
				re.releases_id AS reid,
623
				cp.id AS categoryparentid,
624
				v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
625
				tve.firstaired
626
			FROM releases r
627
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
628
			LEFT OUTER JOIN videos v ON r.videos_id = v.id
629
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
630
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
631
			LEFT JOIN usenet_groups g ON g.id = r.groups_id
632
			LEFT JOIN categories c ON c.id = r.categories_id
633
			LEFT JOIN root_categories cp ON cp.id = c.root_categories_id
634
			LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
635
			%s %s",
636
            ! empty($tags) ? ' LEFT JOIN tagging_tagged tt ON tt.taggable_id = r.id' : '',
637
            $whereSql
638
        );
639
        $sql = sprintf(
640
            'SELECT * FROM (
641
				%s
642
			) r
643
			ORDER BY r.%s %s
644
			LIMIT %d OFFSET %d',
645
            $baseSql,
646
            $orderBy[0],
647
            $orderBy[1],
648
            $limit,
649
            $offset
650
        );
651
        $releases = Cache::get(md5($sql));
652
        if ($releases !== null) {
653
            return $releases;
654
        }
655
        $releases = ! empty($searchResult) ? self::fromQuery($sql) : collect();
656
        if ($releases->isNotEmpty()) {
657
            $releases[0]->_totalrows = $this->getPagerCount($baseSql);
658
        }
659
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
660
        Cache::put(md5($sql), $releases, $expiresAt);
661
662
        return $releases;
663
    }
664
665
    /**
666
     * Search function for API.
667
     *
668
     *
669
     * @param       $searchName
670
     * @param       $groupName
671
     * @param int $offset
672
     * @param int $limit
673
     * @param int $maxAge
674
     * @param array $excludedCats
675
     * @param array $cat
676
     * @param int $minSize
677
     * @param array $tags
678
     *
679
     * @return Collection|mixed
680
     * @throws \Foolz\SphinxQL\Exception\ConnectionException
681
     * @throws \Foolz\SphinxQL\Exception\DatabaseException
682
     * @throws \Foolz\SphinxQL\Exception\SphinxQLException
683
     */
684
    public function apiSearch($searchName, $groupName, $offset = 0, $limit = 1000, $maxAge = -1, array $excludedCats = [], array $cat = [-1], $minSize = 0, array $tags = [])
685
    {
686
        if ($searchName !== -1) {
687
            if (config('nntmux.elasticsearch_enabled') === true) {
688
                $searchResult = (new ElasticSearchSiteSearch())->indexSearchApi($searchName, $limit);
689
            } else {
690
                $searchResult = Arr::pluck($this->sphinxSearch->searchIndexes('releases_rt', $searchName, ['searchname']), 'id');
691
            }
692
        }
693
694
        $catQuery = Category::getCategorySearch($cat);
695
696
        $whereSql = sprintf(
697
            'WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s',
698
            $this->showPasswords(),
699
            NZB::NZB_ADDED,
700
            ! empty($tags) ? " AND tt.tag_name IN ('".implode("','", $tags)."')" : '',
701
            ($maxAge > 0 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $maxAge) : ''),
702
            ((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

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