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

Music::fetchAmazonProperties()   F

Complexity

Conditions 13
Paths 16464

Size

Total Lines 83
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 56
nc 16464
nop 1
dl 0
loc 83
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
namespace Blacklight;
4
5
use ApaiIO\ApaiIO;
6
use App\Models\Genre;
7
use Blacklight\db\DB;
8
use GuzzleHttp\Client;
9
use App\Models\Release;
10
use App\Models\Category;
11
use App\Models\Settings;
12
use App\Models\MusicInfo;
13
use ApaiIO\Operations\Search;
14
use Illuminate\Support\Carbon;
15
use ApaiIO\Request\GuzzleRequest;
16
use Illuminate\Support\Facades\Cache;
17
use ApaiIO\Configuration\GenericConfiguration;
18
use ApaiIO\ResponseTransformer\XmlToSimpleXmlObject;
19
20
/**
21
 * Class Music.
22
 */
23
class Music
24
{
25
    protected const MATCH_PERCENT = 60;
26
    /**
27
     * @var \Blacklight\db\DB
28
     */
29
    public $pdo;
30
31
    /**
32
     * @var bool
33
     */
34
    public $echooutput;
35
36
    /**
37
     * @var array|bool|string
38
     */
39
    public $pubkey;
40
41
    /**
42
     * @var array|bool|string
43
     */
44
    public $privkey;
45
46
    /**
47
     * @var array|bool|string
48
     */
49
    public $asstag;
50
51
    /**
52
     * @var array|bool|int|string
53
     */
54
    public $musicqty;
55
56
    /**
57
     * @var array|bool|int|string
58
     */
59
    public $sleeptime;
60
61
    /**
62
     * @var string
63
     */
64
    public $imgSavePath;
65
66
    /**
67
     * @var bool
68
     */
69
    public $renamed;
70
71
    /**
72
     * Store names of failed Amazon lookup items.
73
     * @var array
74
     */
75
    public $failCache;
76
77
    /**
78
     * @param array $options Class instances/ echo to CLI.
79
     * @throws \Exception
80
     */
81
    public function __construct(array $options = [])
82
    {
83
        $defaults = [
84
            'Echo'     => false,
85
            'Settings' => null,
86
        ];
87
        $options += $defaults;
88
89
        $this->echooutput = ($options['Echo'] && config('nntmux.echocli'));
90
91
        $this->pdo = ($options['Settings'] instanceof DB ? $options['Settings'] : new DB());
92
        $this->pubkey = Settings::settingValue('APIs..amazonpubkey');
0 ignored issues
show
Bug introduced by
'APIs..amazonpubkey' 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

92
        $this->pubkey = Settings::settingValue(/** @scrutinizer ignore-type */ 'APIs..amazonpubkey');
Loading history...
93
        $this->privkey = Settings::settingValue('APIs..amazonprivkey');
94
        $this->asstag = Settings::settingValue('APIs..amazonassociatetag');
95
        $this->musicqty = Settings::settingValue('..maxmusicprocessed') !== '' ? (int) Settings::settingValue('..maxmusicprocessed') : 150;
96
        $this->sleeptime = Settings::settingValue('..amazonsleep') !== '' ? (int) Settings::settingValue('..amazonsleep') : 1000;
97
        $this->imgSavePath = NN_COVERS.'music'.DS;
0 ignored issues
show
Bug introduced by
The constant Blacklight\DS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
98
        $this->renamed = (int) Settings::settingValue('..lookupmusic') === 2;
99
100
        $this->failCache = [];
101
    }
102
103
    /**
104
     * @param $id
105
     * @return \Illuminate\Database\Eloquent\Model|null|static
106
     */
107
    public function getMusicInfo($id)
108
    {
109
        return MusicInfo::query()->with('genre')->where('id', $id)->first();
110
    }
111
112
    /**
113
     * @param $artist
114
     * @param $album
115
     * @return \Illuminate\Database\Eloquent\Model|null|static
116
     */
117
    public function getMusicInfoByName($artist, $album)
0 ignored issues
show
Unused Code introduced by
The parameter $artist is not used and could be removed. ( Ignorable by Annotation )

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

117
    public function getMusicInfoByName(/** @scrutinizer ignore-unused */ $artist, $album)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
118
    {
119
        //only used to get a count of words
120
        $searchwords = '';
121
        $album = preg_replace('/( - | -|\(.+\)|\(|\))/', ' ', $album);
122
        $album = preg_replace('/[^\w ]+/', '', $album);
123
        $album = preg_replace('/(WEB|FLAC|CD)/', '', $album);
124
        $album = trim(preg_replace('/\s\s+/i', ' ', $album));
125
        $album = trim($album);
126
        $words = explode(' ', $album);
127
128
        foreach ($words as $word) {
129
            $word = trim(rtrim(trim($word), '-'));
130
            if ($word !== '' && $word !== '-') {
131
                $word = '+'.$word;
132
                $searchwords .= sprintf('%s ', $word);
133
            }
134
        }
135
        $searchwords = trim($searchwords);
136
137
        return MusicInfo::search($searchwords)->first();
138
    }
139
140
    /**
141
     * @param       $cat
142
     * @param       $start
143
     * @param       $num
144
     * @param       $orderby
145
     * @param array $excludedcats
146
     *
147
     * @return array
148
     * @throws \Exception
149
     */
150
    public function getMusicRange($cat, $start, $num, $orderby, array $excludedcats = [])
151
    {
152
        $browseby = $this->getBrowseBy();
153
154
        $catsrch = '';
155
        if (\count($cat) > 0 && (int) $cat[0] !== -1) {
156
            $catsrch = Category::getCategorySearch($cat);
157
        }
158
159
        $exccatlist = '';
160
        if (\count($excludedcats) > 0) {
161
            $exccatlist = ' AND r.categories_id NOT IN ('.implode(',', $excludedcats).')';
162
        }
163
164
        $order = $this->getMusicOrder($orderby);
165
        $expiresAt = Carbon::now()->addSeconds(config('nntmux.cache_expiry_medium'));
166
167
        $musicSql =
168
                sprintf(
169
                    "
170
				SELECT SQL_CALC_FOUND_ROWS
171
					m.id,
172
					GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id
173
				FROM musicinfo m
174
				LEFT JOIN releases r ON r.musicinfo_id = m.id
175
				WHERE r.nzbstatus = 1
176
				AND m.title != ''
177
				AND m.cover = 1
178
				AND r.passwordstatus %s
179
				%s %s %s
180
				GROUP BY m.id
181
				ORDER BY %s %s %s",
182
                        Releases::showPasswords(),
183
                        $browseby,
184
                        $catsrch,
185
                        $exccatlist,
186
                        $order[0],
187
                        $order[1],
188
                        ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start)
189
                );
190
        $musicCache = Cache::get(md5($musicSql));
191
        if ($musicCache !== null) {
192
            $music = $musicCache;
193
        } else {
194
            $music = $this->pdo->queryCalc($musicSql);
195
            Cache::put(md5($musicSql), $music, $expiresAt);
196
        }
197
198
        $musicIDs = $releaseIDs = false;
199
200
        if (\is_array($music['result'])) {
201
            foreach ($music['result'] as $mus => $id) {
202
                $musicIDs[] = $id['id'];
203
                $releaseIDs[] = $id['grp_release_id'];
204
            }
205
        }
206
207
        $sql = sprintf(
208
            "
209
			SELECT
210
				GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id,
211
				GROUP_CONCAT(r.rarinnerfilecount ORDER BY r.postdate DESC SEPARATOR ',') as grp_rarinnerfilecount,
212
				GROUP_CONCAT(r.haspreview ORDER BY r.postdate DESC SEPARATOR ',') AS grp_haspreview,
213
				GROUP_CONCAT(r.passwordstatus ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_password,
214
				GROUP_CONCAT(r.guid ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_guid,
215
				GROUP_CONCAT(rn.releases_id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_nfoid,
216
				GROUP_CONCAT(g.name ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grpname,
217
				GROUP_CONCAT(r.searchname ORDER BY r.postdate DESC SEPARATOR '#') AS grp_release_name,
218
				GROUP_CONCAT(r.postdate ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_postdate,
219
				GROUP_CONCAT(r.size ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_size,
220
				GROUP_CONCAT(r.totalpart ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_totalparts,
221
				GROUP_CONCAT(r.comments ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_comments,
222
				GROUP_CONCAT(r.grabs ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_grabs,
223
				GROUP_CONCAT(df.failed ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_failed,
224
				m.*,
225
				r.musicinfo_id, r.haspreview,
226
				g.name AS group_name,
227
				rn.releases_id AS nfoid
228
			FROM releases r
229
			LEFT OUTER JOIN groups g ON g.id = r.groups_id
230
			LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
231
			LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
232
			INNER JOIN musicinfo m ON m.id = r.musicinfo_id
233
			WHERE m.id IN (%s)
234
			AND r.id IN (%s)
235
			%s
236
			GROUP BY m.id
237
			ORDER BY %s %s",
238
                (\is_array($musicIDs) ? implode(',', $musicIDs) : -1),
0 ignored issues
show
introduced by
The condition is_array($musicIDs) is always false.
Loading history...
239
                (\is_array($releaseIDs) ? implode(',', $releaseIDs) : -1),
0 ignored issues
show
introduced by
The condition is_array($releaseIDs) is always false.
Loading history...
240
                $catsrch,
241
                $order[0],
242
                $order[1]
243
        );
244
245
        $return = Cache::get(md5($sql));
246
        if ($return !== null) {
247
            return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return returns the type Illuminate\Contracts\Cache\Repository which is incompatible with the documented return type array.
Loading history...
248
        }
249
        $return = $this->pdo->query($sql);
250
        if (! empty($return)) {
251
            $return[0]['_totalcount'] = $music['total'] ?? 0;
252
        }
253
        Cache::put(md5($sql), $return, $expiresAt);
254
255
        return $return;
256
    }
257
258
    /**
259
     * @param $orderby
260
     *
261
     * @return array
262
     */
263
    public function getMusicOrder($orderby): array
264
    {
265
        $order = ($orderby === '') ? 'r.postdate' : $orderby;
266
        $orderArr = explode('_', $order);
267
        switch ($orderArr[0]) {
268
            case 'artist':
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...
269
                $orderfield = 'm.artist';
270
                break;
271
            case 'size':
272
                $orderfield = 'r.size';
273
                break;
274
            case 'files':
275
                $orderfield = 'r.totalpart';
276
                break;
277
            case 'stats':
278
                $orderfield = 'r.grabs';
279
                break;
280
            case 'year':
281
                $orderfield = 'm.year';
282
                break;
283
            case 'genre':
284
                $orderfield = 'm.genres_id';
285
                break;
286
            case 'posted':
287
            default:
288
                $orderfield = 'r.postdate';
289
                break;
290
        }
291
        $ordersort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
292
293
        return [$orderfield, $ordersort];
294
    }
295
296
    /**
297
     * @return array
298
     */
299
    public function getMusicOrdering(): array
300
    {
301
        return ['artist_asc', 'artist_desc', 'posted_asc', 'posted_desc', 'size_asc', 'size_desc', 'files_asc', 'files_desc', 'stats_asc', 'stats_desc', 'year_asc', 'year_desc', 'genre_asc', 'genre_desc'];
302
    }
303
304
    /**
305
     * @return array
306
     */
307
    public function getBrowseByOptions(): array
308
    {
309
        return ['artist' => 'artist', 'title' => 'title', 'genre' => 'genres_id', 'year' => 'year'];
310
    }
311
312
    /**
313
     * @return string
314
     */
315
    public function getBrowseBy(): string
316
    {
317
        $browseby = ' ';
318
        $browsebyArr = $this->getBrowseByOptions();
319
        foreach ($browsebyArr as $bbk => $bbv) {
320
            if (isset($_REQUEST[$bbk]) && ! empty($_REQUEST[$bbk])) {
321
                $bbs = stripslashes($_REQUEST[$bbk]);
322
                if (stripos($bbv, 'id') !== false) {
323
                    $browseby .= 'AND m.'.$bbv.' = '.$bbs;
324
                } else {
325
                    $browseby .= 'AND m.'.$bbv.' '.$this->pdo->likeString($bbs, true, true);
326
                }
327
            }
328
        }
329
330
        return $browseby;
331
    }
332
333
    /**
334
     * @param $id
335
     * @param $title
336
     * @param $asin
337
     * @param $url
338
     * @param $salesrank
339
     * @param $artist
340
     * @param $publisher
341
     * @param $releasedate
342
     * @param $year
343
     * @param $tracks
344
     * @param $cover
345
     * @param $genres_id
346
     */
347
    public function update($id, $title, $asin, $url, $salesrank, $artist, $publisher, $releasedate, $year, $tracks, $cover, $genres_id): void
348
    {
349
        MusicInfo::query()->where('id', $id)->update(
350
            [
351
                'title' => $title,
352
                'asin' => $asin,
353
                'url' => $url,
354
                'salesrank' => $salesrank,
355
                'artist' => $artist,
356
                'publisher' => $publisher,
357
                'releasedate' => $releasedate,
358
                'year' => $year,
359
                'tracks' => $tracks,
360
                'cover' => $cover,
361
                'genres_id' => $genres_id,
362
            ]
363
        );
364
    }
365
366
    /**
367
     * @param      $title
368
     * @param      $year
369
     * @param null $amazdata
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $amazdata is correct as it would always require null to be passed?
Loading history...
370
     *
371
     * @return int|mixed
372
     * @throws \Exception
373
     */
374
    public function updateMusicInfo($title, $year, $amazdata = null)
375
    {
376
        $gen = new Genres(['Settings' => $this->pdo]);
377
        $ri = new ReleaseImage();
378
        $titlepercent = 0;
379
380
        $mus = [];
381
        if ($title !== '') {
382
            $amaz = $this->fetchAmazonProperties($title);
383
        } elseif ($amazdata !== null) {
384
            $amaz = $amazdata;
385
        } else {
386
            $amaz = false;
387
        }
388
389
        if (! $amaz) {
390
            return false;
391
        }
392
393
        if (isset($amaz->ItemAttributes->Title)) {
394
            $mus['title'] = (string) $amaz->ItemAttributes->Title;
395
            if (empty($mus['title'])) {
396
                return false;
397
            }
398
        } else {
399
            return false;
400
        }
401
402
        // Load genres.
403
        $defaultGenres = $gen->getGenres(Genres::MUSIC_TYPE);
404
        $genreassoc = [];
405
        foreach ($defaultGenres as $dg) {
406
            $genreassoc[$dg['id']] = strtolower($dg['title']);
407
        }
408
409
        // Get album properties.
410
        $mus['coverurl'] = (string) $amaz->LargeImage->URL;
411
        if ($mus['coverurl'] !== '') {
412
            $mus['cover'] = 1;
413
        } else {
414
            $mus['cover'] = 0;
415
        }
416
417
        $mus['asin'] = (string) $amaz->ASIN;
418
419
        $mus['url'] = (string) $amaz->DetailPageURL;
420
        $mus['url'] = str_replace('%26tag%3Dws', '%26tag%3Dopensourceins%2D21', $mus['url']);
421
422
        $mus['salesrank'] = (string) $amaz->SalesRank;
423
        if ($mus['salesrank'] === '') {
424
            $mus['salesrank'] = 'null';
425
        }
426
427
        $mus['artist'] = (string) $amaz->ItemAttributes->Artist;
428
        if (empty($mus['artist'])) {
429
            $mus['artist'] = (string) $amaz->ItemAttributes->Creator;
430
            if (empty($mus['artist'])) {
431
                $mus['artist'] = '';
432
            }
433
        }
434
435
        $mus['publisher'] = (string) $amaz->ItemAttributes->Publisher;
436
437
        $mus['releasedate'] = $this->pdo->escapeString((string) $amaz->ItemAttributes->ReleaseDate);
438
        if ($mus['releasedate'] === "''") {
439
            $mus['releasedate'] = 'null';
440
        }
441
442
        $mus['review'] = '';
443
        if (isset($amaz->EditorialReviews)) {
444
            $mus['review'] = trim(strip_tags((string) $amaz->EditorialReviews->EditorialReview->Content));
445
        }
446
447
        $mus['year'] = $year;
448
        if ($mus['year'] === '') {
449
            $mus['year'] = ($mus['releasedate'] !== 'null' ? substr($mus['releasedate'], 1, 4) : date('Y'));
450
        }
451
452
        $mus['tracks'] = '';
453
        if (isset($amaz->Tracks)) {
454
            $tmpTracks = (array) $amaz->Tracks->Disc;
455
            $tracks = $tmpTracks['Track'];
456
            $mus['tracks'] = (\is_array($tracks) && ! empty($tracks)) ? implode('|', $tracks) : '';
457
        }
458
459
        similar_text($mus['artist'].' '.$mus['title'], $title, $titlepercent);
460
        if ($titlepercent < 60) {
461
            return false;
462
        }
463
464
        $genreKey = -1;
465
        $genreName = '';
466
        if (isset($amaz->BrowseNodes)) {
467
            // Had issues getting this out of the browsenodes obj.
468
            // Workaround is to get the xml and load that into its own obj.
469
            $amazGenresXml = $amaz->BrowseNodes->asXml();
470
            $amazGenresObj = simplexml_load_string($amazGenresXml);
471
            $amazGenres = $amazGenresObj->xpath('//BrowseNodeId');
472
473
            foreach ($amazGenres as $amazGenre) {
474
                $currNode = trim($amazGenre[0]);
475
                if (empty($genreName)) {
476
                    $genreMatch = $this->matchBrowseNode($currNode);
477
                    if ($genreMatch !== false) {
478
                        $genreName = $genreMatch;
479
                        break;
480
                    }
481
                }
482
            }
483
484
            if (\in_array(strtolower($genreName), $genreassoc, false)) {
485
                $genreKey = array_search(strtolower($genreName), $genreassoc, false);
486
            } else {
487
                $genreKey = Genre::query()->insertGetId(['title' => $genreName, 'type' => Genres::MUSIC_TYPE]);
488
            }
489
        }
490
        $mus['musicgenre'] = $genreName;
491
        $mus['musicgenres_id'] = $genreKey;
492
493
        $check = MusicInfo::query()->where('asin', $mus['asin'])->first(['id']);
494
        if ($check === null) {
495
            $musicId = MusicInfo::query()->insertGetId(
496
                [
497
                    'title' => $mus['title'],
498
                    'asin' =>$mus['asin'],
499
                    'url' => $mus['url'],
500
                    'salesrank' => $mus['salesrank'],
501
                    'artist' => $mus['artist'],
502
                    'publisher' => $mus['publisher'],
503
                    'releasedate' => $mus['releasedate'],
504
                    'review' => $mus['review'],
505
                    'year' => $mus['year'],
506
                    'genres_id' => (int) $mus['musicgenres_id'] === -1 ? 'null' : $mus['musicgenres_id'],
507
                    'tracks' => $mus['tracks'],
508
                    'cover' => $mus['cover'],
509
                    'created_at' => Carbon::now(),
510
                    'updated_at' => Carbon::now(),
511
                ]
512
            );
513
        } else {
514
            $musicId = $check['id'];
515
            MusicInfo::query()->where('id', $musicId)->update(
516
                [
517
                    'title' => $mus['title'],
518
                    'asin' => $mus['asin'],
519
                    'url' => $mus['url'],
520
                    'salesrank' => $mus['salesrank'],
521
                    'artist' => $mus['artist'],
522
                    'publisher' => $mus['publisher'],
523
                    'releasedate' => $mus['releasedate'],
524
                    'review' => $mus['review'],
525
                    'year' => $mus['year'],
526
                    'genres_id' => (int) $mus['musicgenres_id'] === -1 ? 'null' : $mus['musicgenres_id'],
527
                    'tracks' => $mus['tracks'],
528
                    'cover' => $mus['cover'],
529
                ]
530
            );
531
        }
532
533
        if ($musicId) {
534
            if ($this->echooutput) {
535
                ColorCLI::doEcho(
536
                    ColorCLI::header(PHP_EOL.'Added/updated album: ').
537
                    ColorCLI::alternateOver('   Artist: ').
538
                    ColorCLI::primary($mus['artist']).
539
                    ColorCLI::alternateOver('   Title:  ').
540
                    ColorCLI::primary($mus['title']).
541
                    ColorCLI::alternateOver('   Year:   ').
542
                    ColorCLI::primary($mus['year']), true
543
                );
544
            }
545
            $mus['cover'] = $ri->saveImage($musicId, $mus['coverurl'], $this->imgSavePath, 250, 250);
546
        } else {
547
            if ($this->echooutput) {
548
                if ($mus['artist'] === '') {
549
                    $artist = '';
550
                } else {
551
                    $artist = 'Artist: '.$mus['artist'].', Album: ';
552
                }
553
                ColorCLI::doEcho(
554
                    ColorCLI::headerOver('Nothing to update: ').
555
                    ColorCLI::primaryOver(
556
                        $artist.
557
                        $mus['title'].
558
                        ' ('.
559
                        $mus['year'].
560
                        ')'
561
                    ), true
562
                );
563
            }
564
        }
565
566
        return $musicId;
567
    }
568
569
    /**
570
     * @param $title
571
     *
572
     * @return bool|mixed
573
     * @throws \Exception
574
     */
575
    public function fetchAmazonProperties($title)
576
    {
577
        $responses = false;
578
        $conf = new GenericConfiguration();
579
        $client = new Client();
580
        $request = new GuzzleRequest($client);
581
582
        try {
583
            $conf
584
                ->setCountry('com')
585
                ->setAccessKey($this->pubkey)
0 ignored issues
show
Bug introduced by
It seems like $this->pubkey can also be of type array; however, parameter $accessKey of ApaiIO\Configuration\Gen...uration::setAccessKey() 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

585
                ->setAccessKey(/** @scrutinizer ignore-type */ $this->pubkey)
Loading history...
586
                ->setSecretKey($this->privkey)
0 ignored issues
show
Bug introduced by
It seems like $this->privkey can also be of type array; however, parameter $secretKey of ApaiIO\Configuration\Gen...uration::setSecretKey() 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

586
                ->setSecretKey(/** @scrutinizer ignore-type */ $this->privkey)
Loading history...
587
                ->setAssociateTag($this->asstag)
0 ignored issues
show
Bug introduced by
It seems like $this->asstag can also be of type array; however, parameter $associateTag of ApaiIO\Configuration\Gen...tion::setAssociateTag() 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

587
                ->setAssociateTag(/** @scrutinizer ignore-type */ $this->asstag)
Loading history...
588
                ->setRequest($request)
589
                ->setResponseTransformer(new XmlToSimpleXmlObject());
590
        } catch (\Exception $e) {
591
            echo $e->getMessage();
592
        }
593
594
        $apaiIo = new ApaiIO($conf);
595
        // Try Music category.
596
        try {
597
            $search = new Search();
598
            $search->setCategory('Music');
599
            $search->setKeywords($title);
600
            $search->setResponseGroup(['Large']);
601
            $responses = $apaiIo->runOperation($search);
602
        } catch (\Exception $e) {
603
            // Empty because we try another method.
604
        }
605
606
        // Try MP3 category.
607
        if ($responses === false) {
608
            usleep(700000);
609
            try {
610
                $search = new Search();
611
                $search->setCategory('MP3Downloads');
612
                $search->setKeywords($title);
613
                $search->setResponseGroup(['Large']);
614
                $responses = $apaiIo->runOperation($search);
615
            } catch (\Exception $e) {
616
                // Empty because we try another method.
617
            }
618
        }
619
620
        // Try Digital Music category.
621
        if ($responses === false) {
622
            usleep(700000);
623
            try {
624
                $search = new Search();
625
                $search->setCategory('DigitalMusic');
626
                $search->setKeywords($title);
627
                $search->setResponseGroup(['Large']);
628
                $responses = $apaiIo->runOperation($search);
629
            } catch (\Exception $e) {
630
                // Empty because we try another method.
631
            }
632
        }
633
634
        // Try Music Tracks category.
635
        if ($responses === false) {
636
            usleep(700000);
637
            try {
638
                $search = new Search();
639
                $search->setCategory('MusicTracks');
640
                $search->setKeywords($title);
641
                $search->setResponseGroup(['Large']);
642
                $responses = $apaiIo->runOperation($search);
643
            } catch (\Exception $e) {
644
                // Empty because we exhausted all possibilities.
645
            }
646
        }
647
        if ($responses === false) {
648
            throw new \RuntimeException('Could not connect to Amazon');
649
        }
650
        foreach ($responses->Items->Item as $response) {
651
            similar_text($title, $response->ItemAttributes->Title, $percent);
652
            if ($percent > self::MATCH_PERCENT && isset($response->ItemAttributes->Title)) {
653
                return $response;
654
            }
655
        }
656
657
        return false;
658
    }
659
660
    /**
661
     * @param bool $local
662
     * @throws \Exception
663
     */
664
    public function processMusicReleases($local = false)
665
    {
666
        $res = Release::query()->where(['musicinfo_id' => null, 'nzbstatus' => NZB::NZB_ADDED])->when($this->renamed === true, function ($query) {
667
            return $query->where('isrenamed', '=', 1);
668
        })->whereIn('categories_id', [Category::MUSIC_MP3, Category::MUSIC_LOSSLESS, Category::MUSIC_OTHER])->orderBy('postdate', 'DESC')->limit($this->musicqty)->get(['searchname', 'id']);
669
        if ($res instanceof \Traversable && ! empty($res)) {
670
            if ($this->echooutput) {
671
                ColorCLI::doEcho(
672
                    ColorCLI::header(
673
                        'Processing '.$res->count().' music release(s).'
0 ignored issues
show
Bug introduced by
The method count() does not exist on Traversable. It seems like you code against a sub-type of Traversable such as DOMNodeList or Threaded or MockeryTest_InterfaceWithTraversable or SimpleXMLElement or DOMNamedNodeMap or Thread or Worker or Stackable or MongoGridFSCursor or ResourceBundle or Symfony\Component\Routing\RouteCollection or Symfony\Component\VarDumper\Cloner\Data or Predis\Connection\Aggregate\RedisCluster or PharIo\Manifest\AuthorCollection or Doctrine\Common\Collections\Collection or Illuminate\Pagination\LengthAwarePaginator or Illuminate\Support\Collection or Illuminate\Http\Resources\Json\ResourceCollection or Predis\Connection\Aggregate\PredisCluster or GuzzleHttp\Cookie\CookieJarInterface or Symfony\Component\HttpFo...\Attribute\AttributeBag or Symfony\Component\HttpFoundation\Session\Session or Predis\Client or Http\Message\CookieJar or Tmdb\Common\ParameterBag or PharIo\Manifest\BundledComponentCollection or Illuminate\Pagination\Paginator or Symfony\Component\Finder\Finder or SebastianBergmann\CodeCoverage\Node\Directory or Tmdb\Model\Common\GenericCollection or Whoops\Exception\FrameCollection or Symfony\Component\HttpFoundation\ParameterBag or ArrayObject or PHPUnit\Framework\TestSuite or Symfony\Component\HttpFoundation\HeaderBag or PharIo\Manifest\RequirementCollection or Illuminate\Routing\RouteCollection or Foolz\SphinxQL\Drivers\ResultSetInterface or SplDoublyLinkedList or HttpMessage or HttpRequestPool or Foolz\SphinxQL\Drivers\MultiResultSetInterface or SplFixedArray or SplObjectStorage or SQLiteResult or Imagick or TheSeer\Tokenizer\TokenCollection or SplPriorityQueue or MongoCursor or Predis\Response\Iterator\MultiBulkIterator or SplHeap or MongoGridFSCursor or Predis\Response\Iterator\MultiBulkTuple or CachingIterator or PHP_Token_Stream or Phar or ArrayIterator or GlobIterator or Phar or Phar or RecursiveCachingIterator or RecursiveArrayIterator or SimpleXMLIterator or Phar. ( Ignorable by Annotation )

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

673
                        'Processing '.$res->/** @scrutinizer ignore-call */ count().' music release(s).'
Loading history...
674
                    ), true
675
                );
676
            }
677
678
            foreach ($res as $arr) {
679
                $startTime = microtime(true);
680
                $usedAmazon = false;
681
                $album = $this->parseArtist($arr['searchname']);
682
                if ($album !== false) {
683
                    $newname = $album['name'].' ('.$album['year'].')';
684
685
                    if ($this->echooutput) {
686
                        ColorCLI::doEcho(ColorCLI::headerOver('Looking up: ').ColorCLI::primary($newname), true);
687
                    }
688
689
                    // Do a local lookup first
690
                    $musicCheck = $this->getMusicInfoByName('', $album['name']);
691
692
                    if ($musicCheck === null && \in_array($album['name'].$album['year'], $this->failCache, false)) {
693
                        // Lookup recently failed, no point trying again
694
                        if ($this->echooutput) {
695
                            ColorCLI::doEcho(ColorCLI::headerOver('Cached previous failure. Skipping.'), true);
696
                        }
697
                        $albumId = -2;
698
                    } elseif ($musicCheck === null && $local === false) {
699
                        $albumId = $this->updateMusicInfo($album['name'], $album['year']);
700
                        $usedAmazon = true;
701
                        if ($albumId === false) {
702
                            $albumId = -2;
703
                            $this->failCache[] = $album['name'].$album['year'];
704
                        }
705
                    } else {
706
                        $albumId = $musicCheck['id'];
707
                    }
708
                    Release::query()->where('id', $arr['id'])->update(['musicinfo_id' => $albumId]);
709
                } // No album found.
710
                else {
711
                    Release::query()->where('id', $arr['id'])->update(['musicinfo_id' => -2]);
712
                    echo '.';
713
                }
714
715
                // Sleep to not flood amazon.
716
                $diff = floor((microtime(true) - $startTime) * 1000000);
717
                if ($this->sleeptime * 1000 - $diff > 0 && $usedAmazon === true) {
718
                    usleep($this->sleeptime * 1000 - $diff);
0 ignored issues
show
Bug introduced by
$this->sleeptime * 1000 - $diff of type double is incompatible with the type integer expected by parameter $micro_seconds of usleep(). ( Ignorable by Annotation )

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

718
                    usleep(/** @scrutinizer ignore-type */ $this->sleeptime * 1000 - $diff);
Loading history...
719
                }
720
            }
721
722
            if ($this->echooutput) {
723
                echo "\n";
724
            }
725
        } else {
726
            if ($this->echooutput) {
727
                ColorCLI::doEcho(ColorCLI::header('No music releases to process.'), true);
728
            }
729
        }
730
    }
731
732
    /**
733
     * @param $releasename
734
     *
735
     * @return array|bool
736
     */
737
    public function parseArtist($releasename)
738
    {
739
        if (preg_match('/(.+?)(\d{1,2} \d{1,2} )?\(?(19\d{2}|20[0-1][\d])\b/', $releasename, $name)) {
740
            $result = [];
741
            $result['year'] = $name[3];
742
743
            $a = preg_replace('/( |-)(\d{1,2} \d{1,2} )?(Bootleg|Boxset|Clean.+Version|Compiled by.+|\dCD|Digipak|DIRFIX|DVBS|FLAC|(Ltd )?(Deluxe|Limited|Special).+Edition|Promo|PROOF|Reissue|Remastered|REPACK|RETAIL(.+UK)?|SACD|Sampler|SAT|Summer.+Mag|UK.+Import|Deluxe.+Version|VINYL|WEB)/i', ' ', $name[1]);
744
            $b = preg_replace('/( |-)([a-z]+[\d]+[a-z]+[\d]+.+|[a-z]{2,}[\d]{2,}?.+|3FM|B00[a-z0-9]+|BRC482012|H056|UXM1DW086|(4WCD|ATL|bigFM|CDP|DST|ERE|FIM|MBZZ|MSOne|MVRD|QEDCD|RNB|SBD|SFT|ZYX)( |-)\d.+)/i', ' ', $a);
745
            $c = preg_replace('/( |-)(\d{1,2} \d{1,2} )?([A-Z])( ?$)|\(?[\d]{8,}\)?|( |-)(CABLE|FREEWEB|LINE|MAG|MCD|YMRSMILES)|\(([a-z]{2,}[\d]{2,}|ost)\)|-web-/i', ' ', $b);
746
            $d = preg_replace('/VA( |-)/', 'Various Artists ', $c);
747
            $e = preg_replace('/( |-)(\d{1,2} \d{1,2} )?(DAB|DE|DVBC|EP|FIX|IT|Jap|NL|PL|(Pure )?FM|SSL|VLS)( |-)/i', ' ', $d);
748
            $f = preg_replace('/( |-)(\d{1,2} \d{1,2} )?(CABLE|CD(A|EP|M|R|S)?|QEDCD|SAT|SBD)( |-)/i', ' ', $e);
749
            $g = str_replace(['_', '-'], ' ', $f);
750
            $h = trim(preg_replace('/\s\s+/', ' ', $g));
751
            $newname = trim(preg_replace('/ [a-z]{2}$| [a-z]{3} \d{2,}$|\d{5,} \d{5,}$|-WEB$/i', '', $h));
752
753
            if (! preg_match('/^[a-z0-9]+$/i', $newname) && strlen($newname) > 10) {
754
                $result['name'] = $newname;
755
756
                return $result;
757
            } else {
758
                return false;
759
            }
760
        } else {
761
            return false;
762
        }
763
    }
764
765
    /**
766
     * @param $nodeId
767
     *
768
     * @return bool|string
769
     */
770
    public function matchBrowseNode($nodeId)
771
    {
772
        $str = '';
773
774
        //music nodes above mp3 download nodes
775
        switch ($nodeId) {
776
            case '163420':
777
                $str = 'Music Video & Concerts';
778
                break;
779
            case '30':
780
            case '624869011':
781
                $str = 'Alternative Rock';
782
                break;
783
            case '31':
784
            case '624881011':
785
                $str = 'Blues';
786
                break;
787
            case '265640':
788
            case '624894011':
789
                $str = 'Broadway & Vocalists';
790
                break;
791
            case '173425':
792
            case '624899011':
793
                $str = "Children's Music";
794
                break;
795
            case '173429': //christian
796
            case '2231705011': //gospel
797
            case '624905011': //christian & gospel
798
                $str = 'Christian & Gospel';
799
                break;
800
            case '67204':
801
            case '624916011':
802
                $str = 'Classic Rock';
803
                break;
804
            case '85':
805
            case '624926011':
806
                $str = 'Classical';
807
                break;
808
            case '16':
809
            case '624976011':
810
                $str = 'Country';
811
                break;
812
            case '7': //dance & electronic
813
            case '624988011': //dance & dj
814
                $str = 'Dance & Electronic';
815
                break;
816
            case '32':
817
            case '625003011':
818
                $str = 'Folk';
819
                break;
820
            case '67207':
821
            case '625011011':
822
                $str = 'Hard Rock & Metal';
823
                break;
824
            case '33': //world music
825
            case '625021011': //international
826
                $str = 'World Music';
827
                break;
828
            case '34':
829
            case '625036011':
830
                $str = 'Jazz';
831
                break;
832
            case '289122':
833
            case '625054011':
834
                $str = 'Latin Music';
835
                break;
836
            case '36':
837
            case '625070011':
838
                $str = 'New Age';
839
                break;
840
            case '625075011':
841
                $str = 'Opera & Vocal';
842
                break;
843
            case '37':
844
            case '625092011':
845
                $str = 'Pop';
846
                break;
847
            case '39':
848
            case '625105011':
849
                $str = 'R&B';
850
                break;
851
            case '38':
852
            case '625117011':
853
                $str = 'Rap & Hip-Hop';
854
                break;
855
            case '40':
856
            case '625129011':
857
                $str = 'Rock';
858
                break;
859
            case '42':
860
            case '625144011':
861
                $str = 'Soundtracks';
862
                break;
863
            case '35':
864
            case '625061011':
865
                $str = 'Miscellaneous';
866
                break;
867
        }
868
869
        return ($str !== '') ? $str : false;
870
    }
871
}
872