MusicService::update()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
dl 0
loc 26
rs 9.8666
c 1
b 0
f 0
cc 1
nc 1
nop 12

How to fix   Many Parameters   

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace App\Services;
4
5
use App\Models\Category;
6
use App\Models\Genre;
7
use App\Models\MusicInfo;
8
use App\Models\Release;
9
use App\Models\Settings;
10
use App\Services\Releases\ReleaseBrowseService;
11
use Illuminate\Support\Facades\Cache;
12
use Illuminate\Support\Facades\DB;
13
14
/**
15
 * Music Service - Handles music browsing and lookup operations.
16
 */
17
class MusicService
18
{
19
    protected const MATCH_PERCENT = 85;
20
21
    public bool $echooutput;
22
23
    public ?string $pubkey;
24
25
    public ?string $privkey;
26
27
    public ?string $asstag;
28
29
    public int $musicqty;
30
31
    public int $sleeptime;
32
33
    public string $imgSavePath;
34
35
    public mixed $renamed;
36
37
    /**
38
     * Store names of failed lookup items.
39
     */
40
    public array $failCache;
41
42
    public function __construct()
43
    {
44
        $this->echooutput = config('nntmux.echocli');
45
46
        $this->pubkey = Settings::settingValue('amazonpubkey');
47
        $this->privkey = Settings::settingValue('amazonprivkey');
48
        $this->asstag = Settings::settingValue('amazonassociatetag');
49
        $this->musicqty = Settings::settingValue('maxmusicprocessed') !== '' ? (int) Settings::settingValue('maxmusicprocessed') : 150;
50
        $this->sleeptime = Settings::settingValue('amazonsleep') !== '' ? (int) Settings::settingValue('amazonsleep') : 1000;
51
        $this->imgSavePath = config('nntmux_settings.covers_path').'/music/';
52
        $this->renamed = (int) Settings::settingValue('lookupmusic') === 2 ? 'AND isrenamed = 1' : '';
53
54
        $this->failCache = [];
55
    }
56
57
    /**
58
     * Get music info by ID.
59
     */
60
    public function getMusicInfo(int $id): ?MusicInfo
61
    {
62
        return MusicInfo::query()->with('genre')->where('id', $id)->first();
63
    }
64
65
    /**
66
     * Get music info by name using full-text search.
67
     */
68
    public function getMusicInfoByName(string $artist, string $album): ?MusicInfo
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

68
    public function getMusicInfoByName(/** @scrutinizer ignore-unused */ string $artist, string $album): ?MusicInfo

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...
69
    {
70
        $searchwords = '';
71
        $album = preg_replace('/( - | -|\(.+\)|\(|\))/', ' ', $album);
72
        $album = preg_replace('/[^\w ]+/', '', $album);
73
        $album = preg_replace('/(WEB|FLAC|CD)/', '', $album);
74
        $album = trim(trim(preg_replace('/\s\s+/i', ' ', $album)));
75
76
        foreach (explode(' ', $album) as $word) {
77
            $word = trim(rtrim(trim($word), '-'));
78
            if ($word !== '' && $word !== '-') {
79
                $word = '+'.$word;
80
                $searchwords .= sprintf('%s ', $word);
81
            }
82
        }
83
        $searchwords = trim($searchwords);
84
85
        return MusicInfo::search($searchwords)->first();
86
    }
87
88
    /**
89
     * Get paginated music range for browsing.
90
     */
91
    public function getMusicRange(int $page, array $cat, int $start, int $num, string $orderBy, array $excludedCats = []): mixed
92
    {
93
        $page = max(1, $page);
94
        $start = max(0, $start);
95
96
        $browseby = $this->getBrowseBy();
97
        $catsrch = '';
98
        if (\count($cat) > 0 && (int) $cat[0] !== -1) {
99
            $catsrch = Category::getCategorySearch($cat);
100
        }
101
        $exccatlist = '';
102
        if (\count($excludedCats) > 0) {
103
            $exccatlist = ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')';
104
        }
105
        $order = $this->getMusicOrder($orderBy);
106
        $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium'));
107
108
        $releaseBrowseService = new ReleaseBrowseService;
109
        $passwordClause = $releaseBrowseService->showPasswords();
110
111
        $musicSql = sprintf(
112
            "
113
            SELECT SQL_CALC_FOUND_ROWS
114
                m.id,
115
                GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id
116
            FROM musicinfo m
117
            LEFT JOIN releases r ON r.musicinfo_id = m.id
118
            WHERE m.title != ''
119
            AND m.cover = 1
120
            AND r.passwordstatus %s
121
            %s %s %s
122
            GROUP BY m.id
123
            ORDER BY %s %s %s",
124
            $passwordClause,
125
            $browseby,
126
            $catsrch,
127
            $exccatlist,
128
            $order[0],
129
            $order[1],
130
            ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start)
131
        );
132
133
        $musicCache = Cache::get(md5($musicSql.$page));
134
        if ($musicCache !== null) {
135
            $music = $musicCache;
136
        } else {
137
            $data = DB::select($musicSql);
138
            $music = ['total' => DB::select('SELECT FOUND_ROWS() AS total'), 'result' => $data];
139
            Cache::put(md5($musicSql.$page), $music, $expiresAt);
140
        }
141
142
        $musicIDs = $releaseIDs = [];
143
        if (\is_array($music['result'])) {
144
            foreach ($music['result'] as $mus => $id) {
145
                $musicIDs[] = $id->id;
146
                $releaseIDs[] = $id->grp_release_id;
147
            }
148
        }
149
150
        if (empty($musicIDs) && empty($releaseIDs)) {
151
            return collect();
152
        }
153
154
        $sql = sprintf(
155
            '
156
            SELECT
157
                r.id, r.rarinnerfilecount, r.grabs, r.comments, r.totalpart, r.size, r.postdate, r.searchname, r.haspreview, r.passwordstatus, r.guid, df.failed AS failed,
158
                m.*,
159
                r.musicinfo_id, r.haspreview,
160
                g.name AS group_name,
161
                rn.releases_id AS nfoid
162
            FROM releases r
163
            LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id
164
            LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id
165
            LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id
166
            INNER JOIN musicinfo m ON m.id = r.musicinfo_id
167
            %s %s %s
168
            GROUP BY m.id
169
            ORDER BY %s %s',
170
            ! empty($musicIDs) ? 'WHERE m.id IN ('.implode(',', $musicIDs).')' : 'AND 1=1',
171
            (! empty($releaseIDs)) ? 'AND r.id in ('.implode(',', $releaseIDs).')' : '',
172
            $catsrch,
173
            $order[0],
174
            $order[1]
175
        );
176
177
        $return = Cache::get(md5($sql.$page));
178
        if ($return !== null) {
179
            return $return;
180
        }
181
182
        $return = MusicInfo::fromQuery($sql);
183
        if ($return->isNotEmpty()) {
184
            $return[0]->_totalcount = $music['total'][0]->total ?? 0;
185
        }
186
        Cache::put(md5($sql.$page), $return, $expiresAt);
187
188
        return $return;
189
    }
190
191
    /**
192
     * Parse order by parameter and return order field and direction.
193
     */
194
    public function getMusicOrder(string $orderBy): array
195
    {
196
        $order = ($orderBy === '') ? 'r.postdate' : $orderBy;
197
        $orderArr = explode('_', $order);
198
199
        switch ($orderArr[0]) {
200
            case 'artist':
201
                $orderfield = 'm.artist';
202
                break;
203
            case 'size':
204
                $orderfield = 'r.size';
205
                break;
206
            case 'files':
207
                $orderfield = 'r.totalpart';
208
                break;
209
            case 'stats':
210
                $orderfield = 'r.grabs';
211
                break;
212
            case 'year':
213
                $orderfield = 'm.year';
214
                break;
215
            case 'genre':
216
                $orderfield = 'm.genres_id';
217
                break;
218
            case 'posted':
219
            default:
220
                $orderfield = 'r.postdate';
221
                break;
222
        }
223
224
        $ordersort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc';
225
226
        return [$orderfield, $ordersort];
227
    }
228
229
    /**
230
     * Get available ordering options.
231
     */
232
    public function getMusicOrdering(): array
233
    {
234
        return [
235
            'artist_asc', 'artist_desc',
236
            'posted_asc', 'posted_desc',
237
            'size_asc', 'size_desc',
238
            'files_asc', 'files_desc',
239
            'stats_asc', 'stats_desc',
240
            'year_asc', 'year_desc',
241
            'genre_asc', 'genre_desc',
242
        ];
243
    }
244
245
    /**
246
     * Get browse by options.
247
     */
248
    public function getBrowseByOptions(): array
249
    {
250
        return ['artist' => 'artist', 'title' => 'title', 'genre' => 'genres_id', 'year' => 'year'];
251
    }
252
253
    /**
254
     * Build browse by SQL clause.
255
     */
256
    public function getBrowseBy(): string
257
    {
258
        $browseby = ' ';
259
        foreach ($this->getBrowseByOptions() as $bbk => $bbv) {
260
            if (! empty($_REQUEST[$bbk])) {
261
                $bbs = stripslashes($_REQUEST[$bbk]);
262
                if (stripos($bbv, 'id') !== false) {
263
                    $browseby .= ' AND m.'.$bbv.' = '.$bbs;
264
                } else {
265
                    $browseby .= ' AND m.'.$bbv.' '.'LIKE '.escapeString('%'.$bbs.'%');
266
                }
267
            }
268
        }
269
270
        return $browseby;
271
    }
272
273
    /**
274
     * Update music info record.
275
     */
276
    public function update(
277
        int $id,
278
        string $title,
279
        ?string $asin,
280
        ?string $url,
281
        ?int $salesrank,
282
        ?string $artist,
283
        ?string $publisher,
284
        ?string $releasedate,
285
        ?string $year,
286
        ?string $tracks,
287
        int $cover,
288
        ?int $genres_id
289
    ): void {
290
        MusicInfo::query()->where('id', $id)->update([
291
            'title' => $title,
292
            'asin' => $asin,
293
            'url' => $url,
294
            'salesrank' => $salesrank,
295
            'artist' => $artist,
296
            'publisher' => $publisher,
297
            'releasedate' => $releasedate,
298
            'year' => $year,
299
            'tracks' => $tracks,
300
            'cover' => $cover,
301
            'genres_id' => $genres_id,
302
        ]);
303
    }
304
305
    /**
306
     * Update or create music info from external data.
307
     *
308
     * @throws \Exception
309
     */
310
    public function updateMusicInfo(string $title, string $year, ?array $amazdata = null): int|false
311
    {
312
        $ri = new ReleaseImageService;
313
314
        $mus = [];
315
        if ($amazdata !== null) {
316
            $mus = $amazdata;
317
        } elseif ($title !== '') {
318
            $mus = $this->fetchItunesMusicProperties($title);
319
        }
320
321
        if ($mus === false) {
322
            return false;
323
        }
324
325
        $check = MusicInfo::query()->where('asin', $mus['asin'])->first(['id']);
326
327
        if ($check === null) {
328
            $musicId = MusicInfo::query()->insertGetId([
329
                'title' => $mus['title'],
330
                'asin' => $mus['asin'],
331
                'url' => $mus['url'],
332
                'salesrank' => $mus['salesrank'],
333
                'artist' => $mus['artist'],
334
                'publisher' => $mus['publisher'],
335
                'releasedate' => $mus['releasedate'],
336
                'review' => $mus['review'],
337
                'year' => $year,
338
                'genres_id' => (int) $mus['musicgenres_id'] === -1 ? null : $mus['musicgenres_id'],
339
                'tracks' => $mus['tracks'],
340
                'created_at' => now(),
341
                'updated_at' => now(),
342
            ]);
343
            $mus['cover'] = $ri->saveImage($musicId, $mus['coverurl'], $this->imgSavePath, 250, 250);
0 ignored issues
show
Bug introduced by
It seems like $musicId can also be of type Illuminate\Database\Eloquent\Builder; however, parameter $imgName of App\Services\ReleaseImageService::saveImage() 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

343
            $mus['cover'] = $ri->saveImage(/** @scrutinizer ignore-type */ $musicId, $mus['coverurl'], $this->imgSavePath, 250, 250);
Loading history...
344
            MusicInfo::query()->where('id', $musicId)->update(['cover' => $mus['cover']]);
345
        } else {
346
            $musicId = $check['id'];
347
            $mus['cover'] = $ri->saveImage($musicId, $mus['coverurl'], $this->imgSavePath, 250, 250);
348
            MusicInfo::query()->where('id', $musicId)->update([
349
                'title' => $mus['title'],
350
                'asin' => $mus['asin'],
351
                'url' => $mus['url'],
352
                'salesrank' => $mus['salesrank'],
353
                'artist' => $mus['artist'],
354
                'publisher' => $mus['publisher'],
355
                'releasedate' => $mus['releasedate'],
356
                'review' => $mus['review'],
357
                'year' => $year,
358
                'genres_id' => (int) $mus['musicgenres_id'] === -1 ? null : $mus['musicgenres_id'],
359
                'tracks' => $mus['tracks'],
360
                'cover' => $mus['cover'],
361
            ]);
362
        }
363
364
        if ($musicId) {
365
            if ($this->echooutput) {
366
                cli()->header(
367
                    PHP_EOL.'Added/updated album: '.PHP_EOL.
368
                    '   Artist: '.$mus['artist'].PHP_EOL.
369
                    '   Title:  '.$mus['title'].PHP_EOL.
370
                    '   Year:   '.$year
371
                );
372
            }
373
            $mus['cover'] = $ri->saveImage($musicId, $mus['coverurl'], $this->imgSavePath, 250, 250);
374
        } elseif ($this->echooutput) {
375
            if ($mus['artist'] === '') {
376
                $artist = '';
377
            } else {
378
                $artist = 'Artist: '.$mus['artist'].', Album: ';
379
            }
380
381
            cli()->headerOver(
382
                'Nothing to update: '.$artist.$mus['title'].' ('.$year.')'
383
            );
384
        }
385
386
        return $musicId;
387
    }
388
389
    /**
390
     * Process music releases and lookup metadata.
391
     *
392
     * @throws \Exception
393
     */
394
    public function processMusicReleases(bool $local = false): void
395
    {
396
        $res = DB::select(
397
            sprintf(
398
                '
399
                SELECT searchname, id
400
                FROM releases
401
                WHERE musicinfo_id IS NULL
402
                %s
403
                AND categories_id IN (%s, %s, %s)
404
                ORDER BY postdate DESC
405
                LIMIT %d',
406
                $this->renamed,
407
                Category::MUSIC_MP3,
408
                Category::MUSIC_LOSSLESS,
409
                Category::MUSIC_OTHER,
410
                $this->musicqty
411
            )
412
        );
413
414
        if (! empty($res)) {
415
            foreach ($res as $arr) {
416
                $startTime = now();
417
                $usedAmazon = false;
418
                $album = $this->parseArtist($arr->searchname);
419
420
                if ($album !== false) {
421
                    $newname = $album['name'].' ('.$album['year'].')';
422
423
                    if ($this->echooutput) {
424
                        cli()->info('Looking up: '.$newname);
425
                    }
426
427
                    // Do a local lookup first
428
                    $musicCheck = $this->getMusicInfoByName('', $album['name']);
429
430
                    if ($musicCheck === null && \in_array($album['name'].$album['year'], $this->failCache, false)) {
431
                        // Lookup recently failed, no point trying again
432
                        if ($this->echooutput) {
433
                            cli()->headerOver('Cached previous failure. Skipping.');
434
                        }
435
                        $albumId = -2;
436
                    } elseif ($musicCheck === null && $local === false) {
437
                        $albumId = $this->updateMusicInfo($album['name'], $album['year']);
438
                        $usedAmazon = true;
439
                        if ($albumId === false) {
440
                            $albumId = -2;
441
                            $this->failCache[] = $album['name'].$album['year'];
442
                        }
443
                    } else {
444
                        $albumId = $musicCheck['id'];
445
                    }
446
                    Release::query()->where('id', $arr->id)->update(['musicinfo_id' => $albumId]);
447
                } else {
448
                    // No album found.
449
                    Release::query()->where('id', $arr->id)->update(['musicinfo_id' => -2]);
450
                    echo '.';
451
                }
452
453
                // Sleep to not flood the API.
454
                $sleeptime = $this->sleeptime / 1000;
455
                $diff = now()->diffInSeconds($startTime, true);
456
                if ($sleeptime - $diff > 0 && $usedAmazon === true) {
457
                    sleep($sleeptime - $diff);
458
                }
459
            }
460
461
            if ($this->echooutput) {
462
                echo PHP_EOL;
463
            }
464
        } elseif ($this->echooutput) {
465
            cli()->header('No music releases to process.');
466
        }
467
    }
468
469
    /**
470
     * Parse artist and album name from release name.
471
     *
472
     * @return array|false
473
     */
474
    public function parseArtist(string $releaseName): array|false
475
    {
476
        if (preg_match('/(.+?)(\d{1,2} \d{1,2} )?\(?(19\d{2}|20[0-1][\d])\b/', $releaseName, $name)) {
477
            $result = [];
478
            $result['year'] = $name[3];
479
480
            $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]);
481
            $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);
482
            $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);
483
            $d = preg_replace('/VA([ |-])/', 'Various Artists ', $c);
484
            $e = preg_replace('/([ |-])(\d{1,2} \d{1,2} )?(DAB|DE|DVBC|EP|FIX|IT|Jap|NL|PL|(Pure )?FM|SSL|VLS)([ |-])/i', ' ', $d);
485
            $f = preg_replace('/([ |-])(\d{1,2} \d{1,2} )?(CABLE|CD(A|EP|M|R|S)?|QEDCD|SAT|SBD)([ |-])/i', ' ', $e);
486
            $g = str_replace(['_', '-'], ' ', $f);
487
            $h = trim(preg_replace('/\s\s+/', ' ', $g));
488
            $newname = trim(preg_replace('/ [a-z]{2}$| [a-z]{3} \d{2,}$|\d{5,} \d{5,}$|-WEB$/i', '', $h));
489
490
            if (! preg_match('/^[a-z0-9]+$/i', $newname) && strlen($newname) > 10) {
491
                $result['name'] = $newname;
492
493
                return $result;
494
            }
495
496
            return false;
497
        }
498
499
        return false;
500
    }
501
502
    /**
503
     * Match browse node ID to genre name.
504
     *
505
     * @return string|false
506
     */
507
    public function matchBrowseNode(string $nodeId): string|false
508
    {
509
        $str = '';
510
511
        // music nodes above mp3 download nodes
512
        switch ($nodeId) {
513
            case '163420':
514
                $str = 'Music Video & Concerts';
515
                break;
516
            case '30':
517
            case '624869011':
518
                $str = 'Alternative Rock';
519
                break;
520
            case '31':
521
            case '624881011':
522
                $str = 'Blues';
523
                break;
524
            case '265640':
525
            case '624894011':
526
                $str = 'Broadway & Vocalists';
527
                break;
528
            case '173425':
529
            case '624899011':
530
                $str = "Children's Music";
531
                break;
532
            case '173429': // christian
533
            case '2231705011': // gospel
534
            case '624905011': // christian & gospel
535
                $str = 'Christian & Gospel';
536
                break;
537
            case '67204':
538
            case '624916011':
539
                $str = 'Classic Rock';
540
                break;
541
            case '85':
542
            case '624926011':
543
                $str = 'Classical';
544
                break;
545
            case '16':
546
            case '624976011':
547
                $str = 'Country';
548
                break;
549
            case '7': // dance & electronic
550
            case '624988011': // dance & dj
551
                $str = 'Dance & Electronic';
552
                break;
553
            case '32':
554
            case '625003011':
555
                $str = 'Folk';
556
                break;
557
            case '67207':
558
            case '625011011':
559
                $str = 'Hard Rock & Metal';
560
                break;
561
            case '33': // world music
562
            case '625021011': // international
563
                $str = 'World Music';
564
                break;
565
            case '34':
566
            case '625036011':
567
                $str = 'Jazz';
568
                break;
569
            case '289122':
570
            case '625054011':
571
                $str = 'Latin Music';
572
                break;
573
            case '36':
574
            case '625070011':
575
                $str = 'New Age';
576
                break;
577
            case '625075011':
578
                $str = 'Opera & Vocal';
579
                break;
580
            case '37':
581
            case '625092011':
582
                $str = 'Pop';
583
                break;
584
            case '39':
585
            case '625105011':
586
                $str = 'R&B';
587
                break;
588
            case '38':
589
            case '625117011':
590
                $str = 'Rap & Hip-Hop';
591
                break;
592
            case '40':
593
            case '625129011':
594
                $str = 'Rock';
595
                break;
596
            case '42':
597
            case '625144011':
598
                $str = 'Soundtracks';
599
                break;
600
            case '35':
601
            case '625061011':
602
                $str = 'Miscellaneous';
603
                break;
604
        }
605
606
        return ($str !== '') ? $str : false;
607
    }
608
609
    /**
610
     * Fetch music properties from iTunes.
611
     *
612
     * @return array|false
613
     */
614
    protected function fetchItunesMusicProperties(string $title): array|false
615
    {
616
        // Load genres.
617
        $defaultGenres = (new GenreService)->loadGenres((string) GenreService::MUSIC_TYPE);
0 ignored issues
show
Bug introduced by
The type App\Services\GenreService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
618
619
        $itunes = new ItunesService;
620
621
        // Try to find album first
622
        $album = $itunes->findAlbum($title);
623
624
        if ($album === null) {
625
            // Try finding a track instead
626
            $track = $itunes->findTrack($title);
627
            if ($track === null) {
628
                return false;
629
            }
630
            // Use track info to build album-like data
631
            $album = [
632
                'name' => $track['album'] ?? $track['name'],
633
                'id' => $track['album_id'] ?? $track['id'],
634
                'artist' => $track['artist'],
635
                'artist_id' => $track['artist_id'],
636
                'genre' => $track['genre'],
637
                'release_date' => $track['release_date'],
638
                'cover' => $track['cover'],
639
                'store_url' => $track['store_url'],
640
            ];
641
        }
642
643
        $genreName = $album['genre'] ?? '';
644
645
        if (! empty($genreName)) {
646
            if (\in_array(strtolower($genreName), $defaultGenres, false)) {
647
                $genreKey = array_search(strtolower($genreName), $defaultGenres, false);
648
            } else {
649
                $genreKey = Genre::query()->insertGetId(['title' => $genreName, 'type' => GenreService::MUSIC_TYPE]);
650
            }
651
        } else {
652
            $genreKey = -1;
653
        }
654
655
        // Get artist name - either from album data or lookup
656
        $artistName = $album['artist'] ?? '';
657
        if (empty($artistName) && ! empty($album['artist_id'])) {
658
            $artistData = $itunes->lookupArtist($album['artist_id']);
659
            $artistName = $artistData['artistName'] ?? '';
660
        }
661
662
        return [
663
            'title' => $album['name'],
664
            'asin' => $album['id'],
665
            'url' => $album['store_url'] ?? '',
666
            'salesrank' => '',
667
            'artist' => $artistName,
668
            'publisher' => $album['copyright'] ?? '',
669
            'releasedate' => $album['release_date'],
670
            'review' => '',
671
            'coverurl' => $album['cover'],
672
            'tracks' => $album['track_count'] ?? '',
673
            'musicgenre' => $genreName,
674
            'musicgenres_id' => $genreKey,
675
        ];
676
    }
677
}
678
679