Completed
Branch dev (4bcb34)
by Darko
13:52
created

Releases::deleteSingle()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 3
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Blacklight;
4
5
use App\Models\Group;
6
use Blacklight\db\DB;
7
use App\Models\Release;
8
use App\Models\Category;
9
use App\Models\Settings;
10
use Illuminate\Support\Carbon;
11
use Blacklight\utility\Utility;
12
use Illuminate\Support\Facades\Cache;
13
14
/**
15
 * Class Releases.
16
 */
17
class Releases
18
{
19
    // RAR/ZIP Passworded indicator.
20
    public const PASSWD_NONE = 0; // No password.
21
    public const PASSWD_POTENTIAL = 1; // Might have a password.
22
    public const BAD_FILE = 2; // Possibly broken RAR/ZIP.
23
    public const PASSWD_RAR = 10; // Definitely passworded.
24
25
    /**
26
     * @var \Blacklight\db\DB
27
     */
28
    public $pdo;
29
30
    /**
31
     * @var \Blacklight\ReleaseSearch
32
     */
33
    public $releaseSearch;
34
35
    /**
36
     * @var \Blacklight\SphinxSearch
37
     */
38
    public $sphinxSearch;
39
40
    /**
41
     * @var string
42
     */
43
    public $showPasswords;
44
45
    /**
46
     * @var int
47
     */
48
    public $passwordStatus;
49
50
    /**
51
     * @var array Class instances.
52
     * @throws \Exception
53
     */
54
    public function __construct(array $options = [])
55
    {
56
        $defaults = [
57
            'Settings' => null,
58
            'Groups'   => null,
59
        ];
60
        $options += $defaults;
61
62
        $this->pdo = ($options['Settings'] instanceof DB ? $options['Settings'] : new DB());
63
        $this->sphinxSearch = new SphinxSearch();
64
        $this->releaseSearch = new ReleaseSearch($this->pdo);
65
        $this->showPasswords = self::showPasswords();
66
    }
67
68
    /**
69
     * Used for pager on browse page.
70
     *
71
     * @param array  $cat
72
     * @param int    $maxAge
73
     * @param array  $excludedCats
74
     * @param string|int $groupName
75
     *
76
     * @return int
77
     */
78
    public function getBrowseCount($cat, $maxAge = -1, array $excludedCats = [], $groupName = ''): int
79
    {
80
        $sql = sprintf(
81
                'SELECT COUNT(r.id) AS count
82
				FROM releases r
83
				%s
84
				WHERE r.nzbstatus = %d
85
				AND r.passwordstatus %s
86
				%s %s %s %s',
87
                ($groupName !== -1 ? 'LEFT JOIN groups g ON g.id = r.groups_id' : ''),
88
                NZB::NZB_ADDED,
89
                $this->showPasswords,
90
                ($groupName !== -1 ? sprintf(' AND g.name = %s', $this->pdo->escapeString($groupName)) : ''),
91
                Category::getCategorySearch($cat),
92
                ($maxAge > 0 ? (' AND r.postdate > NOW() - INTERVAL '.$maxAge.' DAY ') : ''),
93
                (\count($excludedCats) ? (' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')') : '')
94
        );
95
        $count = Cache::get(md5($sql));
96
        if ($count !== null) {
97
            return $count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $count returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return integer.
Loading history...
98
        }
99
        $count = $this->pdo->query($sql);
100
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_short'));
101
        Cache::put(md5($sql), $count[0]['count'], $expiresAt);
102
103
        return $count[0]['count'] ?? 0;
104
    }
105
106
    /**
107
     * Used for browse results.
108
     *
109
     * @param array  $cat
110
     * @param        $start
111
     * @param        $num
112
     * @param string|array $orderBy
113
     * @param int    $maxAge
114
     * @param array  $excludedCats
115
     * @param string|int $groupName
116
     * @param int    $minSize
117
     *
118
     * @return array
119
     */
120
    public function getBrowseRange($cat, $start, $num, $orderBy, $maxAge = -1, array $excludedCats = [], $groupName = -1, $minSize = 0): array
121
    {
122
        $orderBy = $this->getBrowseOrder($orderBy);
123
124
        $qry = sprintf(
125
            "SELECT r.*,
126
				CONCAT(cp.title, ' > ', c.title) AS category_name,
127
				CONCAT(cp.id, ',', c.id) AS category_ids,
128
				df.failed AS failed,
129
				rn.releases_id AS nfoid,
130
				re.releases_id AS reid,
131
				v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
132
				tve.title, tve.firstaired
133
			FROM
134
			(
135
				SELECT r.*, g.name AS group_name
136
				FROM releases r
137
				LEFT JOIN groups g ON g.id = r.groups_id
138
				WHERE r.nzbstatus = %d
139
				AND r.passwordstatus %s
140
				%s %s %s %s %s
141
				ORDER BY %s %s %s
142
			) r
143
			LEFT JOIN categories c ON c.id = r.categories_id
144
			LEFT JOIN categories cp ON cp.id = c.parentid
145
			LEFT OUTER JOIN videos v ON r.videos_id = v.id
146
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
147
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
148
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
149
			LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
150
			GROUP BY r.id
151
			ORDER BY %8\$s %9\$s",
152
            NZB::NZB_ADDED,
153
            $this->showPasswords,
154
            Category::getCategorySearch($cat),
155
            ($maxAge > 0 ? (' AND postdate > NOW() - INTERVAL '.$maxAge.' DAY ') : ''),
156
            (\count($excludedCats) ? (' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')') : ''),
157
            ((int) $groupName !== -1 ? sprintf(' AND g.name = %s ', $this->pdo->escapeString($groupName)) : ''),
158
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : ''),
159
            $orderBy[0],
160
            $orderBy[1],
161
            ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start)
162
        );
163
164
        $releases = Cache::get(md5($qry));
165
        if ($releases !== null) {
166
            return $releases;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $releases returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return array.
Loading history...
167
        }
168
        $sql = $this->pdo->query($qry);
169
        if (\count($sql) > 0) {
170
            $possibleRows = $this->getBrowseCount($cat, $maxAge, $excludedCats, $groupName);
171
            $sql[0]['_totalcount'] = $sql[0]['_totalrows'] = $possibleRows;
172
        }
173
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
174
        Cache::put(md5($qry), $sql, $expiresAt);
175
176
        return $sql;
177
    }
178
179
    /**
180
     * Return site setting for hiding/showing passworded releases.
181
     *
182
     * @return string
183
     * @throws \Exception
184
     */
185
    public static function showPasswords(): ?string
186
    {
187
        $setting = Settings::settingValue('..showpasswordedrelease', true);
0 ignored issues
show
Bug introduced by
'..showpasswordedrelease' of type string is incompatible with the type boolean|array expected by parameter $setting of App\Models\Settings::settingValue(). ( Ignorable by Annotation )

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

187
        $setting = Settings::settingValue(/** @scrutinizer ignore-type */ '..showpasswordedrelease', true);
Loading history...
188
        $setting = ($setting !== null && is_numeric($setting)) ? $setting : 10;
189
190
        switch ($setting) {
191
            case 0: // Hide releases with a password or a potential password (Hide unprocessed releases).
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
192
                return '='.self::PASSWD_NONE;
193
            case 1: // Show releases with no password or a potential password (Show unprocessed releases).
194
                return '<= '.self::PASSWD_POTENTIAL;
195
            case 2: // Hide releases with a password or a potential password (Show unprocessed releases).
196
                return '<= '.self::PASSWD_NONE;
197
            case 10: // Shows everything.
198
            default:
199
                return '<= '.self::PASSWD_RAR;
200
        }
201
    }
202
203
    /**
204
     * Use to order releases on site.
205
     *
206
     * @param string|array $orderBy
207
     *
208
     * @return array
209
     */
210
    public function getBrowseOrder($orderBy): array
211
    {
212
        $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

212
        $orderArr = explode('_', /** @scrutinizer ignore-type */ ($orderBy === '' ? 'posted_desc' : $orderBy));
Loading history...
213
        switch ($orderArr[0]) {
214
            case 'cat':
215
                $orderField = 'categories_id';
216
                break;
217
            case 'name':
218
                $orderField = 'searchname';
219
                break;
220
            case 'size':
221
                $orderField = 'size';
222
                break;
223
            case 'files':
224
                $orderField = 'totalpart';
225
                break;
226
            case 'stats':
227
                $orderField = 'grabs';
228
                break;
229
            case 'posted':
230
            default:
231
                $orderField = 'postdate';
232
                break;
233
        }
234
235
        return [$orderField, isset($orderArr[1]) && preg_match('/^(asc|desc)$/i', $orderArr[1]) ? $orderArr[1] : 'desc'];
236
    }
237
238
    /**
239
     * Return ordering types usable on site.
240
     *
241
     * @return string[]
242
     */
243
    public function getBrowseOrdering(): array
244
    {
245
        return [
246
            'name_asc',
247
            'name_desc',
248
            'cat_asc',
249
            'cat_desc',
250
            'posted_asc',
251
            'posted_desc',
252
            'size_asc',
253
            'size_desc',
254
            'files_asc',
255
            'files_desc',
256
            'stats_asc',
257
            'stats_desc',
258
        ];
259
    }
260
261
    /**
262
     * Get list of releases available for export.
263
     *
264
     * @param string $postFrom (optional) Date in this format : 01/01/2014
265
     * @param string $postTo   (optional) Date in this format : 01/01/2014
266
     * @param string|int $groupID  (optional) Group ID.
267
     *
268
     * @return array
269
     */
270
    public function getForExport($postFrom = '', $postTo = '', $groupID = ''): array
271
    {
272
        return $this->pdo->query(
273
            sprintf(
274
                "SELECT searchname, guid, groups.name AS gname, CONCAT(cp.title,'_',categories.title) AS catName
275
				FROM releases r
276
				LEFT JOIN categories c ON r.categories_id = c.id
277
				LEFT JOIN groups g ON r.groups_id = g.id
278
				LEFT JOIN categories cp ON cp.id = c.parentid
279
				WHERE r.nzbstatus = %d
280
				%s %s %s",
281
                NZB::NZB_ADDED,
282
                $this->exportDateString($postFrom),
283
                $this->exportDateString($postTo, false),
284
                $groupID !== '' && $groupID !== -1 ? sprintf(' AND r.groups_id = %d ', $groupID) : ''
285
            )
286
        );
287
    }
288
289
    /**
290
     * Create a date query string for exporting.
291
     *
292
     * @param string $date
293
     * @param bool   $from
294
     *
295
     * @return string
296
     */
297
    private function exportDateString($date = '', $from = true): string
298
    {
299
        if ($date !== '') {
300
            $dateParts = explode('/', $date);
301
            if (\count($dateParts) === 3) {
302
                $date = sprintf(
303
                    ' AND postdate %s %s ',
304
                    ($from ? '>' : '<'),
305
                    $this->pdo->escapeString(
306
                        $dateParts[2].'-'.$dateParts[1].'-'.$dateParts[0].
307
                        ($from ? ' 00:00:00' : ' 23:59:59')
308
                    )
309
                );
310
            }
311
        }
312
313
        return $date;
314
    }
315
316
    /**
317
     * Get date in this format : 01/01/2014 of the oldest release.
318
     *
319
     * @note Used for exporting NZB's.
320
     * @return mixed
321
     */
322
    public function getEarliestUsenetPostDate()
323
    {
324
        $row = Release::query()->selectRaw("DATE_FORMAT(min(postdate), '%d/%m/%Y') AS postdate")->first();
325
326
        return $row === null ? '01/01/2014' : $row['postdate'];
327
    }
328
329
    /**
330
     * Get date in this format : 01/01/2014 of the newest release.
331
     *
332
     * @note Used for exporting NZB's.
333
     * @return mixed
334
     */
335
    public function getLatestUsenetPostDate()
336
    {
337
        $row = Release::query()->selectRaw("DATE_FORMAT(max(postdate), '%d/%m/%Y') AS postdate")->first();
338
339
        return $row === null ? '01/01/2014' : $row['postdate'];
340
    }
341
342
    /**
343
     * Gets all groups for drop down selection on NZB-Export web page.
344
     *
345
     * @param bool $blnIncludeAll
346
     *
347
     * @note Used for exporting NZB's.
348
     * @return array
349
     */
350
    public function getReleasedGroupsForSelect($blnIncludeAll = true): array
351
    {
352
        $groups = Release::query()
353
            ->selectRaw('DISTINCT g.id, g.name')
354
            ->leftJoin('groups as g', 'g.id', '=', 'releases.groups_id')
355
            ->get();
356
        $temp_array = [];
357
358
        if ($blnIncludeAll) {
359
            $temp_array[-1] = '--All Groups--';
360
        }
361
362
        foreach ($groups as $group) {
363
            $temp_array[$group['id']] = $group['name'];
364
        }
365
366
        return $temp_array;
367
    }
368
369
    /**
370
     * Cache of concatenated category ID's used in queries.
371
     * @var null|array
372
     */
373
    private $concatenatedCategoryIDsCache = null;
374
375
    /**
376
     * Gets / sets a string of concatenated category ID's used in queries.
377
     *
378
     * @return array|null|string
379
     */
380
    public function getConcatenatedCategoryIDs()
381
    {
382
        if ($this->concatenatedCategoryIDsCache === null) {
383
            $this->concatenatedCategoryIDsCache = Cache::get('concatenatedcats');
0 ignored issues
show
Documentation Bug introduced by
It seems like Illuminate\Support\Facad...get('concatenatedcats') of type Illuminate\Contracts\Cache\Repository is incompatible with the declared type null|array of property $concatenatedCategoryIDsCache.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
384
            if ($this->concatenatedCategoryIDsCache !== null) {
385
                return $this->concatenatedCategoryIDsCache;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->concatenatedCategoryIDsCache returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the documented return type null|string|array.
Loading history...
386
            }
387
388
            $result = Category::query()
389
                ->whereNotNull('categories.parentid')
390
                ->whereNotNull('cp.id')
391
                ->selectRaw('CONCAT(cp.id, ", ", categories.id) AS category_ids')
392
                ->leftJoin('categories as cp', 'cp.id', '=', 'categories.parentid')
393
                ->get();
394
            if (isset($result[0]['category_ids'])) {
395
                $this->concatenatedCategoryIDsCache = $result[0]['category_ids'];
396
            }
397
        }
398
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_long'));
399
        Cache::put('concatenatedcats', $this->concatenatedCategoryIDsCache, $expiresAt);
400
401
        return $this->concatenatedCategoryIDsCache;
402
    }
403
404
    /**
405
     * Get TV for my shows page.
406
     *
407
     * @param          $userShows
408
     * @param int|bool $offset
409
     * @param int      $limit
410
     * @param string|array   $orderBy
411
     * @param int      $maxAge
412
     * @param array    $excludedCats
413
     *
414
     * @return array
415
     */
416
    public function getShowsRange($userShows, $offset, $limit, $orderBy, $maxAge = -1, array $excludedCats = []): array
417
    {
418
        $orderBy = $this->getBrowseOrder($orderBy);
419
420
        $sql = sprintf(
421
                "SELECT r.*,
422
					CONCAT(cp.title, '-', c.title) AS category_name,
423
					%s AS category_ids,
424
					g.name AS group_name,
425
					rn.releases_id AS nfoid, re.releases_id AS reid,
426
					tve.firstaired,
427
					(SELECT df.failed) AS failed
428
				FROM releases r
429
				LEFT OUTER JOIN video_data re ON re.releases_id = r.id
430
				LEFT JOIN groups g ON g.id = r.groups_id
431
				LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
432
				LEFT OUTER JOIN tv_episodes tve ON tve.videos_id = r.videos_id
433
				LEFT JOIN categories c ON c.id = r.categories_id
434
				LEFT JOIN categories cp ON cp.id = c.parentid
435
				LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
436
				WHERE r.categories_id BETWEEN 5000 AND 5999 %s %s
437
				AND r.nzbstatus = %d
438
				AND r.passwordstatus %s
439
				%s
440
				GROUP BY r.id
441
				ORDER BY %s %s %s",
442
                $this->getConcatenatedCategoryIDs(),
0 ignored issues
show
Bug introduced by
It seems like $this->getConcatenatedCategoryIDs() can also be of type array; 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

442
                /** @scrutinizer ignore-type */ $this->getConcatenatedCategoryIDs(),
Loading history...
443
                $this->uSQL($userShows, 'videos_id'),
444
                (\count($excludedCats) ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
445
                NZB::NZB_ADDED,
446
                $this->showPasswords,
447
                ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : ''),
448
                $orderBy[0],
449
                $orderBy[1],
450
                ($offset === false ? '' : (' LIMIT '.$limit.' OFFSET '.$offset))
0 ignored issues
show
Bug introduced by
Are you sure $offset of type integer|true can be used in concatenation? ( Ignorable by Annotation )

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

450
                ($offset === false ? '' : (' LIMIT '.$limit.' OFFSET './** @scrutinizer ignore-type */ $offset))
Loading history...
451
            );
452
        $releases = Cache::get(md5($sql));
453
        if ($releases !== null) {
454
            return $releases;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $releases returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return array.
Loading history...
455
        }
456
457
        $releases = $this->pdo->query($sql);
458
459
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
460
        Cache::put(md5($sql), $releases, $expiresAt);
461
462
        return $releases;
463
    }
464
465
    /**
466
     * Get count for my shows page pagination.
467
     *
468
     * @param       $userShows
469
     * @param int   $maxAge
470
     * @param array $excludedCats
471
     *
472
     * @return int
473
     */
474
    public function getShowsCount($userShows, $maxAge = -1, array $excludedCats = []): int
475
    {
476
        return $this->getPagerCount(
477
            sprintf(
478
                'SELECT r.id
479
				FROM releases r
480
				WHERE r.categories_id BETWEEN 5000 AND 5999 %s %s
481
				AND r.nzbstatus = %d
482
				AND r.passwordstatus %s
483
				%s',
484
                $this->uSQL($userShows, 'videos_id'),
485
                (\count($excludedCats) ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
486
                NZB::NZB_ADDED,
487
                $this->showPasswords,
488
                ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '')
489
            )
490
        );
491
    }
492
493
    /**
494
     * Get count for my shows page pagination.
495
     *
496
     * @param       $userMovies
497
     * @param int   $maxAge
498
     * @param array $excludedCats
499
     *
500
     * @return int
501
     */
502
    public function getMovieCount($userMovies, $maxAge = -1, array $excludedCats = []): int
503
    {
504
        return $this->getPagerCount(
505
            sprintf(
506
                'SELECT r.id
507
				FROM releases r
508
				WHERE r.categories_id BETWEEN 3000 AND 3999 %s %s
509
				AND r.nzbstatus = %d
510
				AND r.passwordstatus %s
511
				%s',
512
                $this->uSQL($userMovies, 'imdbid'),
513
                (\count($excludedCats) ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
514
                NZB::NZB_ADDED,
515
                $this->showPasswords,
516
                ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '')
517
            )
518
        );
519
    }
520
521
    /**
522
     * Delete multiple releases, or a single by ID.
523
     *
524
     * @param array|int|string $list   Array of GUID or ID of releases to delete.
525
     * @throws \Exception
526
     */
527
    public function deleteMultiple($list): void
528
    {
529
        $list = (array) $list;
530
531
        $nzb = new NZB();
532
        $releaseImage = new ReleaseImage();
533
534
        foreach ($list as $identifier) {
535
            $this->deleteSingle(['g' => $identifier, 'i' => false], $nzb, $releaseImage);
536
        }
537
    }
538
539
    /**
540
     * Deletes a single release by GUID, and all the corresponding files.
541
     *
542
     * @param array        $identifiers ['g' => Release GUID(mandatory), 'id => ReleaseID(optional, pass false)]
543
     * @param NZB          $nzb
544
     * @param ReleaseImage $releaseImage
545
     */
546
    public function deleteSingle($identifiers, $nzb, $releaseImage): void
547
    {
548
        // Delete NZB from disk.
549
        $nzbPath = $nzb->NZBPath($identifiers['g']);
550
        if ($nzbPath) {
551
            @unlink($nzbPath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

551
            /** @scrutinizer ignore-unhandled */ @unlink($nzbPath);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
552
        }
553
554
        // Delete images.
555
        $releaseImage->delete($identifiers['g']);
556
557
        // Delete from sphinx.
558
        $this->sphinxSearch->deleteRelease($identifiers);
559
560
        // Delete from DB.
561
        Release::query()->where('guid', $identifiers['g'])->delete();
562
    }
563
564
    /**
565
     * @param $guids
566
     * @param $category
567
     * @param $grabs
568
     * @param $videoId
569
     * @param $episodeId
570
     * @param $anidbId
571
     * @param $imdbId
572
     * @return bool|int
573
     */
574
    public function updateMulti($guids, $category, $grabs, $videoId, $episodeId, $anidbId, $imdbId)
575
    {
576
        if (! \is_array($guids) || \count($guids) < 1) {
577
            return false;
578
        }
579
580
        $update = [
581
            'categories_id'     => $category === -1 ? 'categories_id' : $category,
582
            'grabs'          => $grabs,
583
            'videos_id'      => $videoId,
584
            'tv_episodes_id' => $episodeId,
585
            'anidbid'        => $anidbId,
586
            'imdbid'         => $imdbId,
587
        ];
588
589
        return Release::query()->whereIn('guid', $guids)->update($update);
590
    }
591
592
    /**
593
     * Creates part of a query for some functions.
594
     *
595
     * @param array  $userQuery
596
     * @param string $type
597
     *
598
     * @return string
599
     */
600
    public function uSQL($userQuery, $type): string
601
    {
602
        $sql = '(1=2 ';
603
        foreach ($userQuery as $query) {
604
            $sql .= sprintf('OR (r.%s = %d', $type, $query[$type]);
605
            if ($query['categories'] !== '') {
606
                $catsArr = explode('|', $query['categories']);
607
                if (\count($catsArr) > 1) {
608
                    $sql .= sprintf(' AND r.categories_id IN (%s)', implode(',', $catsArr));
609
                } else {
610
                    $sql .= sprintf(' AND r.categories_id = %d', $catsArr[0]);
611
                }
612
            }
613
            $sql .= ') ';
614
        }
615
        $sql .= ') ';
616
617
        return $sql;
618
    }
619
620
    /**
621
     * Function for searching on the site (by subject, searchname or advanced).
622
     *
623
     * @param string|int $searchName
624
     * @param string|int $usenetName
625
     * @param string|int $posterName
626
     * @param string|int $fileName
627
     * @param string|int $groupName
628
     * @param int $sizeFrom
629
     * @param int $sizeTo
630
     * @param int $hasNfo
631
     * @param int $hasComments
632
     * @param int $daysNew
633
     * @param int $daysOld
634
     * @param int $offset
635
     * @param int $limit
636
     * @param string|array $orderBy
637
     * @param int $maxAge
638
     * @param int|array $excludedCats
639
     * @param string $type
640
     * @param array $cat
641
     *
642
     * @param int $minSize
643
     * @return array
644
     */
645
    public function search($searchName, $usenetName, $posterName, $fileName, $groupName, $sizeFrom, $sizeTo, $hasNfo, $hasComments, $daysNew, $daysOld, $offset = 0, $limit = 1000, $orderBy = '', $maxAge = -1, array $excludedCats = [], $type = 'basic', array $cat = [-1], $minSize = 0): array
646
    {
647
        $sizeRange = [
648
            1 => 1,
649
            2 => 2.5,
650
            3 => 5,
651
            4 => 10,
652
            5 => 20,
653
            6 => 30,
654
            7 => 40,
655
            8 => 80,
656
            9 => 160,
657
            10 => 320,
658
            11 => 640,
659
        ];
660
661
        if ($orderBy === '') {
662
            $orderBy = [];
663
            $orderBy[0] = 'postdate ';
664
            $orderBy[1] = 'desc ';
665
        } else {
666
            $orderBy = $this->getBrowseOrder($orderBy);
667
        }
668
669
        $searchOptions = [];
670
        if ($searchName !== -1) {
671
            $searchOptions['searchname'] = $searchName;
672
        }
673
        if ($usenetName !== -1) {
674
            $searchOptions['name'] = $usenetName;
675
        }
676
        if ($posterName !== -1) {
677
            $searchOptions['fromname'] = $posterName;
678
        }
679
        if ($fileName !== -1) {
680
            $searchOptions['filename'] = $fileName;
681
        }
682
683
        $catQuery = '';
684
        if ($type === 'basic') {
685
            $catQuery = Category::getCategorySearch($cat);
686
        } elseif ($type === 'advanced' && (int) $cat[0] !== -1) {
687
            $catQuery = sprintf('AND r.categories_id = %d', $cat[0]);
688
        }
689
690
        $whereSql = sprintf(
691
            '%s WHERE r.passwordstatus %s AND r.nzbstatus = %d %s %s %s %s %s %s %s %s %s %s %s %s',
692
            $this->releaseSearch->getFullTextJoinString(),
693
            $this->showPasswords,
694
            NZB::NZB_ADDED,
695
            ($maxAge > 0 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $maxAge) : ''),
696
            ((int) $groupName !== -1 ? sprintf(' AND r.groups_id = %d ', Group::getIDByName($groupName)) : ''),
697
            (array_key_exists($sizeFrom, $sizeRange) ? ' AND r.size > '.(string) (104857600 * (int) $sizeRange[$sizeFrom]).' ' : ''),
698
            (array_key_exists($sizeTo, $sizeRange) ? ' AND r.size < '.(string) (104857600 * (int) $sizeRange[$sizeTo]).' ' : ''),
699
            ((int) $hasNfo !== 0 ? ' AND r.nfostatus = 1 ' : ''),
700
            ((int) $hasComments !== 0 ? ' AND r.comments > 0 ' : ''),
701
            $catQuery,
702
            ((int) $daysNew !== -1 ? sprintf(' AND r.postdate < (NOW() - INTERVAL %d DAY) ', $daysNew) : ''),
703
            ((int) $daysOld !== -1 ? sprintf(' AND r.postdate > (NOW() - INTERVAL %d DAY) ', $daysOld) : ''),
704
            (\count($excludedCats) > 0 ? ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')' : ''),
705
            (\count($searchOptions) > 0 ? $this->releaseSearch->getSearchSQL($searchOptions) : ''),
706
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : '')
707
        );
708
709
        $baseSql = sprintf(
710
            "SELECT r.*,
711
				CONCAT(cp.title, ' > ', c.title) AS category_name,
712
				%s AS category_ids,
713
				df.failed AS failed,
714
				g.name AS group_name,
715
				rn.releases_id AS nfoid,
716
				re.releases_id AS reid,
717
				cp.id AS categoryparentid,
718
				v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb,
719
				tve.firstaired
720
			FROM releases r
721
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
722
			LEFT OUTER JOIN videos v ON r.videos_id = v.id
723
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
724
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
725
			LEFT JOIN groups g ON g.id = r.groups_id
726
			LEFT JOIN categories c ON c.id = r.categories_id
727
			LEFT JOIN categories cp ON cp.id = c.parentid
728
			LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
729
			%s",
730
            $this->getConcatenatedCategoryIDs(),
0 ignored issues
show
Bug introduced by
It seems like $this->getConcatenatedCategoryIDs() can also be of type array; 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

730
            /** @scrutinizer ignore-type */ $this->getConcatenatedCategoryIDs(),
Loading history...
731
            $whereSql
732
        );
733
734
        $sql = sprintf(
735
            'SELECT * FROM (
736
				%s
737
			) r
738
			ORDER BY r.%s %s
739
			LIMIT %d OFFSET %d',
740
            $baseSql,
741
            $orderBy[0],
742
            $orderBy[1],
743
            $limit,
744
            $offset
745
        );
746
747
        $releases = Cache::get(md5($sql));
748
        if ($releases !== null) {
749
            return $releases;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $releases returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return array.
Loading history...
750
        }
751
752
        $releases = $this->pdo->query($sql);
753
        if (! empty($releases) && \count($releases)) {
754
            $releases[0]['_totalrows'] = $this->getPagerCount($baseSql);
755
        }
756
757
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
758
        Cache::put(md5($sql), $releases, $expiresAt);
759
760
        return $releases;
761
    }
762
763
    /**
764
     * Search TV Shows via the API.
765
     *
766
     * @param array  $siteIdArr Array containing all possible TV Processing site IDs desired
767
     * @param string $series The series or season number requested
768
     * @param string $episode The episode number requested
769
     * @param string $airdate The airdate of the episode requested
770
     * @param int    $offset Skip this many releases
771
     * @param int    $limit Return this many releases
772
     * @param string $name The show name to search
773
     * @param array  $cat The category to search
774
     * @param int    $maxAge The maximum age of releases to be returned
775
     * @param int    $minSize The minimum size of releases to be returned
776
     *
777
     * @return array
778
     */
779
    public function tvSearch(
780
        array $siteIdArr = [],
781
        $series = '',
782
        $episode = '',
783
        $airdate = '',
784
        $offset = 0,
785
        $limit = 100,
786
        $name = '',
787
        array $cat = [-1],
788
        $maxAge = -1,
789
        $minSize = 0
790
    ): array {
791
        $siteSQL = [];
792
        $showSql = '';
793
794
        if (\is_array($siteIdArr)) {
0 ignored issues
show
introduced by
The condition is_array($siteIdArr) is always true.
Loading history...
795
            foreach ($siteIdArr as $column => $Id) {
796
                if ($Id > 0) {
797
                    $siteSQL[] = sprintf('v.%s = %d', $column, $Id);
798
                }
799
            }
800
        }
801
802
        if (\count($siteSQL) > 0) {
803
            // If we have show info, find the Episode ID/Video ID first to avoid table scans
804
            $showQry = sprintf(
805
                "
806
				SELECT
807
					v.id AS video,
808
					GROUP_CONCAT(tve.id SEPARATOR ',') AS episodes
809
				FROM videos v
810
				LEFT JOIN tv_episodes tve ON v.id = tve.videos_id
811
				WHERE (%s) %s %s %s
812
				GROUP BY v.id",
813
                implode(' OR ', $siteSQL),
814
                ($series !== '' ? sprintf('AND tve.series = %d', (int) preg_replace('/^s0*/i', '', $series)) : ''),
815
                ($episode !== '' ? sprintf('AND tve.episode = %d', (int) preg_replace('/^e0*/i', '', $episode)) : ''),
816
                ($airdate !== '' ? sprintf('AND DATE(tve.firstaired) = %s', $this->pdo->escapeString($airdate)) : '')
817
            );
818
            $show = $this->pdo->queryOneRow($showQry);
819
            if ($show !== false) {
820
                if ((! empty($series) || ! empty($episode) || ! empty($airdate)) && strlen((string) $show['episodes']) > 0) {
821
                    $showSql = sprintf('AND r.tv_episodes_id IN (%s)', $show['episodes']);
822
                } elseif ((int) $show['video'] > 0) {
823
                    $showSql = 'AND r.videos_id = '.$show['video'];
824
                    // If $series is set but episode is not, return Season Packs only
825
                    if (! empty($series) && empty($episode)) {
826
                        $showSql .= ' AND r.tv_episodes_id = 0';
827
                    }
828
                } else {
829
                    // If we were passed Episode Info and no match was found, do not run the query
830
                    return [];
831
                }
832
            } else {
833
                // If we were passed Site ID Info and no match was found, do not run the query
834
                return [];
835
            }
836
        }
837
838
        // If $name is set it is a fallback search, add available SxxExx/airdate info to the query
839
        if (! empty($name) && $showSql === '') {
840
            if (! empty($series) && (int) $series < 1900) {
841
                $name .= sprintf(' S%s', str_pad($series, 2, '0', STR_PAD_LEFT));
842
                if (! empty($episode) && strpos($episode, '/') === false) {
843
                    $name .= sprintf('E%s', str_pad($episode, 2, '0', STR_PAD_LEFT));
844
                }
845
            } elseif (! empty($airdate)) {
846
                $name .= sprintf(' %s', str_replace(['/', '-', '.', '_'], ' ', $airdate));
847
            }
848
        }
849
850
        $whereSql = sprintf(
851
            '%s
852
			WHERE r.nzbstatus = %d
853
			AND r.passwordstatus %s
854
			%s %s %s %s %s',
855
            ($name !== '' ? $this->releaseSearch->getFullTextJoinString() : ''),
856
            NZB::NZB_ADDED,
857
            $this->showPasswords,
858
            $showSql,
859
            ($name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : ''),
860
            Category::getCategorySearch($cat),
861
            ($maxAge > 0 ? sprintf('AND r.postdate > NOW() - INTERVAL %d DAY', $maxAge) : ''),
862
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : '')
863
        );
864
865
        $baseSql = sprintf(
866
            "SELECT r.*,
867
				v.title, v.countries_id, v.started, v.tvdb, v.trakt,
868
					v.imdb, v.tmdb, v.tvmaze, v.tvrage, v.source,
869
				tvi.summary, tvi.publisher, tvi.image,
870
				tve.series, tve.episode, tve.se_complete, tve.title, tve.firstaired, tve.summary,
871
				CONCAT(cp.title, ' > ', c.title) AS category_name,
872
				%s AS category_ids,
873
				g.name AS group_name,
874
				rn.releases_id AS nfoid,
875
				re.releases_id AS reid
876
			FROM releases r
877
			LEFT OUTER JOIN videos v ON r.videos_id = v.id AND v.type = 0
878
			LEFT OUTER JOIN tv_info tvi ON v.id = tvi.videos_id
879
			LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id
880
			LEFT JOIN categories c ON c.id = r.categories_id
881
			LEFT JOIN categories cp ON cp.id = c.parentid
882
			LEFT JOIN groups g ON g.id = r.groups_id
883
			LEFT OUTER JOIN video_data re ON re.releases_id = r.id
884
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
885
			%s",
886
            $this->getConcatenatedCategoryIDs(),
0 ignored issues
show
Bug introduced by
It seems like $this->getConcatenatedCategoryIDs() can also be of type array; 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

886
            /** @scrutinizer ignore-type */ $this->getConcatenatedCategoryIDs(),
Loading history...
887
            $whereSql
888
        );
889
890
        $sql = sprintf(
891
            '%s
892
			ORDER BY postdate DESC
893
			LIMIT %d OFFSET %d',
894
            $baseSql,
895
            $limit,
896
            $offset
897
        );
898
        $releases = Cache::get(md5($sql));
899
        if ($releases !== null) {
900
            return $releases;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $releases returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return array.
Loading history...
901
        }
902
903
        $releases = $this->pdo->query($sql);
904
        if (! empty($releases) && \count($releases)) {
905
            $releases[0]['_totalrows'] = $this->getPagerCount(
906
                preg_replace('#LEFT(\s+OUTER)?\s+JOIN\s+(?!tv_episodes)\s+.*ON.*=.*\n#i', ' ', $baseSql)
907
            );
908
        }
909
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
910
        Cache::put(md5($sql), $releases, $expiresAt);
911
912
        return $releases;
913
    }
914
915
    /**
916
     * @param        $aniDbID
917
     * @param int    $offset
918
     * @param int    $limit
919
     * @param string $name
920
     * @param array  $cat
921
     * @param int    $maxAge
922
     *
923
     * @return array
924
     */
925
    public function animeSearch($aniDbID, $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1): array
926
    {
927
        $whereSql = sprintf(
928
            '%s
929
			WHERE r.passwordstatus %s
930
			AND r.nzbstatus = %d
931
			%s %s %s %s',
932
            ($name !== '' ? $this->releaseSearch->getFullTextJoinString() : ''),
933
            $this->showPasswords,
934
            NZB::NZB_ADDED,
935
            ($aniDbID > -1 ? sprintf(' AND r.anidbid = %d ', $aniDbID) : ''),
936
            ($name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : ''),
937
            Category::getCategorySearch($cat),
938
            ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '')
939
        );
940
941
        $baseSql = sprintf(
942
            "SELECT r.*,
943
				CONCAT(cp.title, ' > ', c.title) AS category_name,
944
				%s AS category_ids,
945
				g.name AS group_name,
946
				rn.releases_id AS nfoid,
947
				re.releases_id AS reid
948
			FROM releases r
949
			LEFT JOIN categories c ON c.id = r.categories_id
950
			LEFT JOIN categories cp ON cp.id = c.parentid
951
			LEFT JOIN groups g ON g.id = r.groups_id
952
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
953
			LEFT OUTER JOIN releaseextrafull re ON re.releases_id = r.id
954
			%s",
955
            $this->getConcatenatedCategoryIDs(),
0 ignored issues
show
Bug introduced by
It seems like $this->getConcatenatedCategoryIDs() can also be of type array; 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

955
            /** @scrutinizer ignore-type */ $this->getConcatenatedCategoryIDs(),
Loading history...
956
            $whereSql
957
        );
958
959
        $sql = sprintf(
960
            '%s
961
			ORDER BY postdate DESC
962
			LIMIT %d OFFSET %d',
963
            $baseSql,
964
            $limit,
965
            $offset
966
        );
967
        $releases = Cache::get(md5($sql));
968
        if ($releases !== null) {
969
            return $releases;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $releases returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return array.
Loading history...
970
        }
971
972
        $releases = $this->pdo->query($sql);
973
974
        if (! empty($releases) && \count($releases)) {
975
            $releases[0]['_totalrows'] = $this->getPagerCount($baseSql);
976
        }
977
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
978
        Cache::put(md5($sql), $releases, $expiresAt);
979
980
        return $releases;
981
    }
982
983
    /**
984
     * @param int $imDbId
985
     * @param int $offset
986
     * @param int $limit
987
     * @param string $name
988
     * @param array $cat
989
     * @param int $maxAge
990
     * @param int $minSize
991
     *
992
     * @return array
993
     */
994
    public function moviesSearch($imDbId, $offset = 0, $limit = 100, $name = '', array $cat = [-1], $maxAge = -1, $minSize = 0): array
995
    {
996
        $whereSql = sprintf(
997
            '%s
998
            WHERE r.categories_id BETWEEN '.Category::MOVIE_ROOT.' AND '.Category::MOVIE_OTHER.'
999
			AND r.nzbstatus = %d
1000
			AND r.passwordstatus %s
1001
			%s %s %s %s %s',
1002
            ($name !== '' ? $this->releaseSearch->getFullTextJoinString() : ''),
1003
            NZB::NZB_ADDED,
1004
            $this->showPasswords,
1005
            ($name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : ''),
1006
            (($imDbId !== -1 && is_numeric($imDbId)) ? sprintf(' AND imdbid = %d ', str_pad($imDbId, 7, '0', STR_PAD_LEFT)) : ''),
1007
            Category::getCategorySearch($cat),
1008
            ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : ''),
1009
            ($minSize > 0 ? sprintf('AND r.size >= %d', $minSize) : '')
1010
        );
1011
1012
        $baseSql = sprintf(
1013
            "SELECT r.*,
1014
				concat(cp.title, ' > ', c.title) AS category_name,
1015
				%s AS category_ids,
1016
				g.name AS group_name,
1017
				rn.releases_id AS nfoid
1018
			FROM releases r
1019
			LEFT JOIN groups g ON g.id = r.groups_id
1020
			LEFT JOIN categories c ON c.id = r.categories_id
1021
			LEFT JOIN categories cp ON cp.id = c.parentid
1022
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
1023
			%s",
1024
            $this->getConcatenatedCategoryIDs(),
0 ignored issues
show
Bug introduced by
It seems like $this->getConcatenatedCategoryIDs() can also be of type array; 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

1024
            /** @scrutinizer ignore-type */ $this->getConcatenatedCategoryIDs(),
Loading history...
1025
            $whereSql
1026
        );
1027
1028
        $sql = sprintf(
1029
            '%s
1030
			ORDER BY postdate DESC
1031
			LIMIT %d OFFSET %d',
1032
            $baseSql,
1033
            $limit,
1034
            $offset
1035
        );
1036
1037
        $releases = Cache::get(md5($sql));
1038
        if ($releases !== null) {
1039
            return $releases;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $releases returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return array.
Loading history...
1040
        }
1041
1042
        $releases = $this->pdo->query($sql);
1043
1044
        if (! empty($releases) && \count($releases)) {
1045
            $releases[0]['_totalrows'] = $this->getPagerCount($baseSql);
1046
        }
1047
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
1048
        Cache::put(md5($sql), $releases, $expiresAt);
1049
1050
        return $releases;
1051
    }
1052
1053
    /**
1054
     * Get count of releases for pager.
1055
     *
1056
     * @param string $query The query to get the count from.
1057
     *
1058
     * @return int
1059
     */
1060
    private function getPagerCount($query): int
1061
    {
1062
        $sql = sprintf(
1063
                        'SELECT COUNT(z.id) AS count FROM (%s LIMIT %s) z',
1064
                        preg_replace('/SELECT.+?FROM\s+releases/is', 'SELECT r.id FROM releases', $query),
1065
                        config('nntmux.max_pager_results')
1066
        );
1067
1068
        $count = Cache::get(md5($sql));
1069
        if ($count !== null) {
1070
            return $count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $count returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the type-hinted return integer.
Loading history...
1071
        }
1072
1073
        $count = $this->pdo->query($sql);
1074
1075
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_short'));
1076
        Cache::put(md5($sql), $count[0]['count'], $expiresAt);
1077
1078
        return $count[0]['count'] ?? 0;
1079
    }
1080
1081
    /**
1082
     * @param       $currentID
1083
     * @param       $name
1084
     * @param int $limit
1085
     * @param array $excludedCats
1086
     *
1087
     * @return array
1088
     * @throws \Exception
1089
     */
1090
    public function searchSimilar($currentID, $name, $limit = 6, array $excludedCats = []): array
1091
    {
1092
        // Get the category for the parent of this release.
1093
        $currRow = Release::getCatByRelId($currentID);
1094
        $catRow = Category::find($currRow['categories_id']);
1095
        $parentCat = $catRow['parentid'];
1096
1097
        $results = $this->search(
1098
            getSimilarName($name),
1099
            -1,
1100
            -1,
1101
            -1,
1102
            -1,
1103
            -1,
1104
            -1,
1105
            0,
1106
            0,
1107
            -1,
1108
            -1,
1109
            0,
1110
            $limit,
1111
            '',
1112
            -1,
1113
            $excludedCats,
1114
            null,
1115
            [$parentCat]
1116
        );
1117
        if (! $results) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $results of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
1118
            return $results;
1119
        }
1120
1121
        $ret = [];
1122
        foreach ($results as $res) {
1123
            if ($res['id'] !== $currentID && $res['categoryparentid'] === $parentCat) {
1124
                $ret[] = $res;
1125
            }
1126
        }
1127
1128
        return $ret;
1129
    }
1130
1131
    /**
1132
     * @param array $guids
1133
     * @return string
1134
     * @throws \Exception
1135
     */
1136
    public function getZipped($guids): string
1137
    {
1138
        $nzb = new NZB();
1139
        $zipFile = new \ZipFile();
1140
1141
        foreach ($guids as $guid) {
1142
            $nzbPath = $nzb->NZBPath($guid);
1143
1144
            if ($nzbPath) {
1145
                $nzbContents = Utility::unzipGzipFile($nzbPath);
1146
1147
                if ($nzbContents) {
1148
                    $filename = $guid;
1149
                    $r = Release::getByGuid($guid);
1150
                    if ($r) {
1151
                        $filename = $r['searchname'];
1152
                    }
1153
                    $zipFile->addFile($nzbContents, $filename.'.nzb');
1154
                }
1155
            }
1156
        }
1157
1158
        return $zipFile->file();
1159
    }
1160
}
1161