Issues (435)

app/Extensions/helper/helpers.php (21 issues)

1
<?php
2
3
use App\Models\Release;
4
use Blacklight\NZB;
5
use Blacklight\utility\Utility;
6
use Blacklight\XXX;
7
use Colors\Color;
8
use GuzzleHttp\Client;
9
use GuzzleHttp\Cookie\CookieJar;
10
use GuzzleHttp\Cookie\SetCookie;
11
use GuzzleHttp\Exception\RequestException;
12
use Illuminate\Support\Facades\DB;
13
use Illuminate\Support\Facades\Log;
14
use Illuminate\Support\Str;
15
use sspat\ESQuerySanitizer\Sanitizer;
16
use Symfony\Component\Process\Process;
17
use Zip as ZipStream;
18
19
if (! function_exists('getRawHtml')) {
20
    /**
21
     * @param  bool  $cookie
22
     * @return bool|mixed|string
23
     */
24
    function getRawHtml($url, $cookie = false)
25
    {
26
        $cookieJar = new CookieJar;
27
        $client = new Client(['headers' => ['User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246']]);
28
        if ($cookie !== false) {
29
            $cookie = $cookieJar->setCookie(SetCookie::fromString($cookie));
0 ignored issues
show
$cookie of type true is incompatible with the type string expected by parameter $cookie of GuzzleHttp\Cookie\SetCookie::fromString(). ( Ignorable by Annotation )

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

29
            $cookie = $cookieJar->setCookie(SetCookie::fromString(/** @scrutinizer ignore-type */ $cookie));
Loading history...
30
            $client = new Client(['cookies' => $cookie, 'headers' => ['User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246']]);
31
        }
32
        try {
33
            $response = $client->get($url)->getBody()->getContents();
34
            $jsonResponse = json_decode($response, true);
35
            if (json_last_error() === JSON_ERROR_NONE) {
36
                $response = $jsonResponse;
37
            }
38
        } catch (RequestException $e) {
39
            if (config('app.debug') === true) {
40
                Log::error($e->getMessage());
41
            }
42
            $response = false;
43
        } catch (RuntimeException $e) {
44
            if (config('app.debug') === true) {
45
                Log::error($e->getMessage());
46
            }
47
            $response = false;
48
        }
49
50
        return $response;
51
    }
52
}
53
54
if (! function_exists('makeFieldLinks')) {
55
    /**
56
     * @return string
57
     *
58
     * @throws Exception
59
     */
60
    function makeFieldLinks($data, $field, $type)
61
    {
62
        $tmpArr = explode(', ', $data[$field]);
63
        $newArr = [];
64
        $i = 0;
65
        foreach ($tmpArr as $ta) {
66
            if (trim($ta) === '') {
67
                continue;
68
            }
69
            if ($type === 'xxx' && $field === 'genre') {
70
                $ta = (new XXX)->getGenres(true, $ta);
71
                $ta = $ta['title'] ?? '';
72
            }
73
            if ($i > 7) {
74
                break;
75
            }
76
            $newArr[] = '<a href="'.url('/'.ucfirst($type).'?'.$field.'='.urlencode($ta)).'" title="'.$ta.'">'.$ta.'</a>';
77
            $i++;
78
        }
79
80
        return implode(', ', $newArr);
81
    }
82
}
83
84
if (! function_exists('getUserBrowseOrder')) {
85
    /**
86
     * @param  string  $orderBy
87
     */
88
    function getUserBrowseOrder($orderBy): array
89
    {
90
        $order = ($orderBy === '' ? 'username_desc' : $orderBy);
91
        $orderArr = explode('_', $order);
92
        $orderField = match ($orderArr[0]) {
93
            'email' => 'email',
94
            'host' => 'host',
95
            'createdat' => 'created_at',
96
            'lastlogin' => 'lastlogin',
97
            'apiaccess' => 'apiaccess',
98
            'apirequests' => 'apirequests',
99
            'grabs' => 'grabs',
100
            'roles_id' => 'users_role_id',
101
            'rolechangedate' => 'rolechangedate',
102
            default => 'username',
103
        };
104
        $orderSort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
105
106
        return [$orderField, $orderSort];
107
    }
108
}
109
110
if (! function_exists('getUserBrowseOrdering')) {
111
    function getUserBrowseOrdering(): array
112
    {
113
        return [
114
            'username_asc',
115
            'username_desc',
116
            'email_asc',
117
            'email_desc',
118
            'host_asc',
119
            'host_desc',
120
            'createdat_asc',
121
            'createdat_desc',
122
            'lastlogin_asc',
123
            'lastlogin_desc',
124
            'apiaccess_asc',
125
            'apiaccess_desc',
126
            'apirequests_asc',
127
            'apirequests_desc',
128
            'grabs_asc',
129
            'grabs_desc',
130
            'role_asc',
131
            'role_desc',
132
            'rolechangedate_asc',
133
            'rolechangedate_desc',
134
            'verification_asc',
135
            'verification_desc',
136
        ];
137
    }
138
}
139
140
if (! function_exists('getSimilarName')) {
141
    /**
142
     * @param  string  $name
143
     */
144
    function getSimilarName($name): string
145
    {
146
        return implode(' ', \array_slice(str_word_count(str_replace(['.', '_', '-'], ' ', $name), 2), 0, 2));
0 ignored issues
show
It seems like str_word_count(str_repla..., '-'), ' ', $name), 2) can also be of type integer; however, parameter $array of array_slice() does only seem to accept array, 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

146
        return implode(' ', \array_slice(/** @scrutinizer ignore-type */ str_word_count(str_replace(['.', '_', '-'], ' ', $name), 2), 0, 2));
Loading history...
147
    }
148
}
149
150
if (! function_exists('color')) {
151
    function color(string $string = ''): Color
152
    {
153
        return new Color($string);
154
    }
155
}
156
157
if (! function_exists('human_filesize')) {
158
    /**
159
     * @param  int  $decimals
160
     */
161
    function human_filesize($bytes, $decimals = 0): string
162
    {
163
        $size = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
164
        $factor = floor((\strlen($bytes) - 1) / 3);
165
166
        return round(sprintf("%.{$decimals}f", $bytes / (1024 ** $factor)), $decimals).@$size[$factor];
0 ignored issues
show
sprintf('%.'.$decimals.'...ytes / 1024 ** $factor) of type string is incompatible with the type double|integer expected by parameter $num of round(). ( Ignorable by Annotation )

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

166
        return round(/** @scrutinizer ignore-type */ sprintf("%.{$decimals}f", $bytes / (1024 ** $factor)), $decimals).@$size[$factor];
Loading history...
167
    }
168
}
169
170
if (! function_exists('bcdechex')) {
171
    /**
172
     * @return string
173
     */
174
    function bcdechex($dec)
175
    {
176
        $hex = '';
177
        do {
178
            $last = bcmod($dec, 16);
179
            $hex = dechex($last).$hex;
0 ignored issues
show
$last of type null|string is incompatible with the type integer expected by parameter $num of dechex(). ( Ignorable by Annotation )

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

179
            $hex = dechex(/** @scrutinizer ignore-type */ $last).$hex;
Loading history...
180
            $dec = bcdiv(bcsub($dec, $last), 16);
181
        } while ($dec > 0);
182
183
        return $hex;
184
    }
185
}
186
187
if (! function_exists('runCmd')) {
188
    /**
189
     * Run CLI command.
190
     *
191
     *
192
     * @param  string  $command
193
     * @param  bool  $debug
194
     * @return string
195
     */
196
    function runCmd($command, $debug = false)
197
    {
198
        if ($debug) {
199
            echo '-Running Command: '.PHP_EOL.'   '.$command.PHP_EOL;
200
        }
201
202
        $process = Process::fromShellCommandline('exec '.$command);
203
        $process->setTimeout(1800);
204
        $process->run();
205
        $output = $process->getOutput();
206
207
        if ($debug) {
208
            echo '-Command Output: '.PHP_EOL.'   '.$output.PHP_EOL;
209
        }
210
211
        return $output;
212
    }
213
}
214
215
if (! function_exists('escapeString')) {
216
    /**
217
     * @return string
218
     */
219
    function escapeString($string)
220
    {
221
        return DB::connection()->getPdo()->quote($string);
222
    }
223
}
224
225
if (! function_exists('realDuration')) {
226
    /**
227
     * @return string
228
     */
229
    function realDuration($milliseconds)
230
    {
231
        $time = round($milliseconds / 1000);
232
233
        return sprintf('%02dh:%02dm:%02ds', floor($time / 3600), floor($time / 60 % 60), $time % 60);
234
    }
235
}
236
237
if (! function_exists('is_it_json')) {
238
    /**
239
     * @param  array|string  $isIt
240
     * @return bool
241
     */
242
    function is_it_json($isIt)
243
    {
244
        if (is_array($isIt)) {
245
            return false;
246
        }
247
        json_decode($isIt, true);
248
249
        return json_last_error() === JSON_ERROR_NONE;
250
    }
251
}
252
253
/**
254
 * @throws Exception
255
 */
256
function getStreamingZip(array $guids = [])
257
{
258
    $nzb = new NZB;
259
    $zipped = ZipStream::create(now()->format('Ymdhis').'.zip');
260
    foreach ($guids as $guid) {
261
        $nzbPath = $nzb->NZBPath($guid);
262
263
        if ($nzbPath) {
264
            $nzbContents = Utility::unzipGzipFile($nzbPath);
265
266
            if ($nzbContents) {
267
                $filename = $guid;
268
                $r = Release::query()->where('guid', $guid)->first();
269
                if ($r !== null) {
270
                    $filename = $r->searchname;
0 ignored issues
show
The property searchname does not seem to exist on App\Models\Release. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
271
                }
272
                $zipped->addRaw($nzbContents, $filename.'.nzb');
273
            }
274
        }
275
    }
276
277
    return $zipped;
278
}
279
280
if (! function_exists('release_flag')) {
281
    // Function inspired by c0r3@newznabforums adds country flags on the browse page.
282
    /**
283
     * @param  string  $text  Text to match against.
284
     * @param  string  $page  Type of page. browse or search.
285
     * @return bool|string
286
     */
287
    function release_flag($text, $page)
288
    {
289
        $code = $language = '';
290
291
        switch (true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Korean|\bkr\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/German(bed)?|\bger\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/French|Vostfr|Multi/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Hebrew|Yiddish/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Japanese|\bjp\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/\bHindi\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/\bThai\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Tagalog|Filipino/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/\bCzech\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/\bGreek\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Flemish|\b(...|nl)\b|NlSub/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Swe(dish|sub)/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Italian|\bita\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Chinese|Man...in|\bc[hn]\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/Hungarian|\bhun\b/i', $text) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
292
            case stripos($text, 'Arabic') !== false:
293
                $code = 'PK';
294
                $language = 'Arabic';
295
                break;
296
            case stripos($text, 'Cantonese') !== false:
297
                $code = 'TW';
298
                $language = 'Cantonese';
299
                break;
300
            case preg_match('/Chinese|Mandarin|\bc[hn]\b/i', $text):
301
                $code = 'CN';
302
                $language = 'Chinese';
303
                break;
304
            case preg_match('/\bCzech\b/i', $text):
305
                $code = 'CZ';
306
                $language = 'Czech';
307
                break;
308
            case stripos($text, 'Danish') !== false:
309
                $code = 'DK';
310
                $language = 'Danish';
311
                break;
312
            case stripos($text, 'Finnish') !== false:
313
                $code = 'FI';
314
                $language = 'Finnish';
315
                break;
316
            case preg_match('/Flemish|\b(Dutch|nl)\b|NlSub/i', $text):
317
                $code = 'NL';
318
                $language = 'Dutch';
319
                break;
320
            case preg_match('/French|Vostfr|Multi/i', $text):
321
                $code = 'FR';
322
                $language = 'French';
323
                break;
324
            case preg_match('/German(bed)?|\bger\b/i', $text):
325
                $code = 'DE';
326
                $language = 'German';
327
                break;
328
            case preg_match('/\bGreek\b/i', $text):
329
                $code = 'GR';
330
                $language = 'Greek';
331
                break;
332
            case preg_match('/Hebrew|Yiddish/i', $text):
333
                $code = 'IL';
334
                $language = 'Hebrew';
335
                break;
336
            case preg_match('/\bHindi\b/i', $text):
337
                $code = 'IN';
338
                $language = 'Hindi';
339
                break;
340
            case preg_match('/Hungarian|\bhun\b/i', $text):
341
                $code = 'HU';
342
                $language = 'Hungarian';
343
                break;
344
            case preg_match('/Italian|\bita\b/i', $text):
345
                $code = 'IT';
346
                $language = 'Italian';
347
                break;
348
            case preg_match('/Japanese|\bjp\b/i', $text):
349
                $code = 'JP';
350
                $language = 'Japanese';
351
                break;
352
            case preg_match('/Korean|\bkr\b/i', $text):
353
                $code = 'KR';
354
                $language = 'Korean';
355
                break;
356
            case stripos($text, 'Norwegian') !== false:
357
                $code = 'NO';
358
                $language = 'Norwegian';
359
                break;
360
            case stripos($text, 'Polish') !== false:
361
                $code = 'PL';
362
                $language = 'Polish';
363
                break;
364
            case stripos($text, 'Portuguese') !== false:
365
                $code = 'PT';
366
                $language = 'Portugese';
367
                break;
368
            case stripos($text, 'Romanian') !== false:
369
                $code = 'RO';
370
                $language = 'Romanian';
371
                break;
372
            case stripos($text, 'Spanish') !== false:
373
                $code = 'ES';
374
                $language = 'Spanish';
375
                break;
376
            case preg_match('/Swe(dish|sub)/i', $text):
377
                $code = 'SE';
378
                $language = 'Swedish';
379
                break;
380
            case preg_match('/Tagalog|Filipino/i', $text):
381
                $code = 'PH';
382
                $language = 'Tagalog|Filipino';
383
                break;
384
            case preg_match('/\bThai\b/i', $text):
385
                $code = 'TH';
386
                $language = 'Thai';
387
                break;
388
            case stripos($text, 'Turkish') !== false:
389
                $code = 'TR';
390
                $language = 'Turkish';
391
                break;
392
            case stripos($text, 'Russian') !== false:
393
                $code = 'RU';
394
                $language = 'Russian';
395
                break;
396
            case stripos($text, 'Vietnamese') !== false:
397
                $code = 'VN';
398
                $language = 'Vietnamese';
399
                break;
400
        }
401
402
        if ($code !== '' && $page === 'browse') {
403
            return '<img title="'.$language.'" alt="'.$language.'" src="'.asset('/assets/images/flags/'.$code.'.png').'"/>';
404
        }
405
406
        if ($page === 'search') {
407
            if ($code === '') {
408
                return false;
409
            }
410
411
            return $code;
412
        }
413
414
        return '';
415
    }
416
}
417
418
if (! function_exists('getReleaseCover')) {
419
    /**
420
     * Get the cover image URL for a release based on its type and ID
421
     *
422
     * @param  object|array  $release  The release object or array
423
     * @return string The cover image URL or placeholder if no cover exists
424
     */
425
    function getReleaseCover($release): string
426
    {
427
        $coverType = null;
428
        $coverId = null;
429
430
        // Helper function to get value from object or array
431
        $getValue = function ($data, $key) {
432
            if (is_array($data)) {
433
                return $data[$key] ?? null;
434
            } elseif (is_object($data)) {
435
                return $data->$key ?? null;
436
            }
437
438
            return null;
439
        };
440
441
        // Determine cover type and ID based on category
442
        $imdbid = $getValue($release, 'imdbid');
443
        $musicinfo_id = $getValue($release, 'musicinfo_id');
444
        $consoleinfo_id = $getValue($release, 'consoleinfo_id');
445
        $bookinfo_id = $getValue($release, 'bookinfo_id');
446
        $gamesinfo_id = $getValue($release, 'gamesinfo_id');
447
        $xxxinfo_id = $getValue($release, 'xxxinfo_id');
448
        $anidbid = $getValue($release, 'anidbid');
449
450
        if (! empty($imdbid) && $imdbid > 0) {
451
            $coverType = 'movies';
452
            $coverId = str_pad($imdbid, 7, '0', STR_PAD_LEFT);
453
        } elseif (! empty($musicinfo_id)) {
454
            $coverType = 'music';
455
            $coverId = $musicinfo_id;
456
        } elseif (! empty($consoleinfo_id)) {
457
            $coverType = 'console';
458
            $coverId = $consoleinfo_id;
459
        } elseif (! empty($bookinfo_id)) {
460
            $coverType = 'book';
461
            $coverId = $bookinfo_id;
462
        } elseif (! empty($gamesinfo_id)) {
463
            $coverType = 'games';
464
            $coverId = $gamesinfo_id;
465
        } elseif (! empty($xxxinfo_id)) {
466
            $coverType = 'xxx';
467
            $coverId = $xxxinfo_id;
468
        } elseif (! empty($anidbid)) {
469
            $coverType = 'anime';
470
            $coverId = $anidbid;
471
        }
472
473
        // Return the cover URL if we have a type and ID
474
        // The CoverController will handle serving the file or returning a placeholder
475
        if ($coverType && $coverId) {
476
            return url("/covers/{$coverType}/{$coverId}-cover.jpg");
477
        }
478
479
        // Return placeholder image if no cover type/ID found
480
        return asset('assets/images/no-cover.png');
481
    }
482
}
483
484
if (! function_exists('sanitize')) {
485
    function sanitize(array|string $phrases, array $doNotSanitize = []): string
486
    {
487
        if (! is_array($phrases)) {
0 ignored issues
show
The condition is_array($phrases) is always true.
Loading history...
488
            $wordArray = explode(' ', str_replace('.', ' ', $phrases));
489
        } else {
490
            $wordArray = $phrases;
491
        }
492
493
        $keywords = [];
494
        $tempWords = [];
495
        foreach ($wordArray as $words) {
496
            $words = preg_split('/\s+/', $words);
497
            foreach ($words as $st) {
498
                if (Str::startsWith($st, ['!', '+', '-', '?', '*']) && Str::length($st) > 1 && ! preg_match('/([!+?\-*]){2,}/', $st)) {
499
                    $str = $st;
500
                } elseif (Str::endsWith($st, ['+', '-', '?', '*']) && Str::length($st) > 1 && ! preg_match('/([!+?\-*]){2,}/', $st)) {
501
                    $str = $st;
502
                } else {
503
                    $str = Sanitizer::escape($st, $doNotSanitize);
504
                }
505
                $tempWords[] = $str;
506
            }
507
508
            $keywords = $tempWords;
509
        }
510
511
        return implode(' ', $keywords);
512
    }
513
}
514
515
if (! function_exists('formatBytes')) {
516
    /**
517
     * Format bytes into human-readable file size.
518
     *
519
     * @param  int|float|null  $bytes
520
     */
521
    function formatBytes($bytes = 0): string
522
    {
523
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
524
        $bytes = max((int) $bytes, 0);
525
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
526
        $pow = min($pow, count($units) - 1);
527
528
        $bytes /= pow(1024, $pow);
529
530
        return round($bytes, 2).' '.$units[$pow];
531
    }
532
}
533