|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace App\Models; |
|
4
|
|
|
|
|
5
|
|
|
use App\Facades\Lastfm; |
|
6
|
|
|
use App\Facades\Util; |
|
7
|
|
|
use App\Traits\SupportsDeleteWhereIDsNotIn; |
|
8
|
|
|
use Exception; |
|
9
|
|
|
use Illuminate\Database\Eloquent\Collection; |
|
10
|
|
|
use Illuminate\Database\Eloquent\Model; |
|
11
|
|
|
use Illuminate\Database\Eloquent\Relations\HasMany; |
|
12
|
|
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough; |
|
13
|
|
|
use Log; |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* @property int id The model ID |
|
17
|
|
|
* @property string name The artist name |
|
18
|
|
|
* @property string image |
|
19
|
|
|
* @property bool is_unknown |
|
20
|
|
|
* @property bool is_various |
|
21
|
|
|
* @property Collection songs |
|
22
|
|
|
*/ |
|
23
|
|
|
class Artist extends Model |
|
24
|
|
|
{ |
|
25
|
|
|
use SupportsDeleteWhereIDsNotIn; |
|
26
|
|
|
|
|
27
|
|
|
const UNKNOWN_ID = 1; |
|
28
|
|
|
const UNKNOWN_NAME = 'Unknown Artist'; |
|
29
|
|
|
const VARIOUS_ID = 2; |
|
30
|
|
|
const VARIOUS_NAME = 'Various Artists'; |
|
31
|
|
|
|
|
32
|
|
|
protected $guarded = ['id']; |
|
33
|
|
|
|
|
34
|
|
|
protected $hidden = ['created_at', 'updated_at']; |
|
35
|
|
|
|
|
36
|
|
|
/** |
|
37
|
|
|
* An artist can have many albums. |
|
38
|
|
|
* |
|
39
|
|
|
* @return HasMany |
|
40
|
|
|
*/ |
|
41
|
|
|
public function albums() |
|
42
|
|
|
{ |
|
43
|
|
|
return $this->hasMany(Album::class); |
|
44
|
|
|
} |
|
45
|
|
|
|
|
46
|
|
|
/** |
|
47
|
|
|
* An artist can have many songs. |
|
48
|
|
|
* Unless he is Rick Astley. |
|
49
|
|
|
* |
|
50
|
|
|
* @return HasManyThrough |
|
51
|
|
|
*/ |
|
52
|
|
|
public function songs() |
|
53
|
|
|
{ |
|
54
|
|
|
return $this->hasManyThrough(Song::class, Album::class); |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* Indicate if the artist is unknown. |
|
59
|
|
|
* |
|
60
|
|
|
* @return bool |
|
61
|
|
|
*/ |
|
62
|
|
|
public function getIsUnknownAttribute() |
|
63
|
|
|
{ |
|
64
|
|
|
return $this->id === self::UNKNOWN_ID; |
|
65
|
|
|
} |
|
66
|
|
|
|
|
67
|
|
|
/** |
|
68
|
|
|
* Indicate if the artist is the special "Various Artists" |
|
69
|
|
|
* |
|
70
|
|
|
* @return bool |
|
71
|
|
|
*/ |
|
72
|
|
|
public function getIsVariousAttribute() |
|
73
|
|
|
{ |
|
74
|
|
|
return $this->id === self::VARIOUS_ID; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* Get the "Various Artists" object. |
|
79
|
|
|
* |
|
80
|
|
|
* @return Artist |
|
81
|
|
|
*/ |
|
82
|
|
|
public static function getVariousArtist() |
|
83
|
|
|
{ |
|
84
|
|
|
return self::find(self::VARIOUS_ID); |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* Sometimes the tags extracted from getID3 are HTML entity encoded. |
|
89
|
|
|
* This makes sure they are always sane. |
|
90
|
|
|
* |
|
91
|
|
|
* @param $value |
|
92
|
|
|
* |
|
93
|
|
|
* @return string |
|
94
|
|
|
*/ |
|
95
|
|
|
public function getNameAttribute($value) |
|
96
|
|
|
{ |
|
97
|
|
|
return html_entity_decode($value ?: self::UNKNOWN_NAME); |
|
98
|
|
|
} |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* Get an Artist object from their name. |
|
102
|
|
|
* If such is not found, a new artist will be created. |
|
103
|
|
|
* |
|
104
|
|
|
* @param string $name |
|
105
|
|
|
* |
|
106
|
|
|
* @return Artist |
|
107
|
|
|
*/ |
|
108
|
|
|
public static function get($name) |
|
109
|
|
|
{ |
|
110
|
|
|
// Remove the BOM from UTF-8/16/32, as it will mess up the database constraints. |
|
111
|
|
|
if ($encoding = Util::detectUTFEncoding($name)) { |
|
112
|
|
|
$name = mb_convert_encoding($name, 'UTF-8', $encoding); |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
$name = trim($name) ?: self::UNKNOWN_NAME; |
|
116
|
|
|
|
|
117
|
|
|
return self::firstOrCreate(compact('name'), compact('name')); |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
|
|
* Get extra information about the artist from Last.fm. |
|
122
|
|
|
* |
|
123
|
|
|
* @return array|false |
|
124
|
|
|
*/ |
|
125
|
|
View Code Duplication |
public function getInfo() |
|
|
|
|
|
|
126
|
|
|
{ |
|
127
|
|
|
if ($this->is_unknown) { |
|
128
|
|
|
return false; |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
$info = Lastfm::getArtistInfo($this->name); |
|
132
|
|
|
$image = array_get($info, 'image'); |
|
133
|
|
|
|
|
134
|
|
|
// If our current artist has no image, and Last.fm has one, copy the image for our local use. |
|
135
|
|
|
if (!$this->image && is_string($image) && ini_get('allow_url_fopen')) { |
|
136
|
|
|
try { |
|
137
|
|
|
$extension = explode('.', $image); |
|
138
|
|
|
$this->writeImageFile(file_get_contents($image), last($extension)); |
|
139
|
|
|
$info['image'] = $this->image; |
|
140
|
|
|
} catch (Exception $e) { |
|
141
|
|
|
Log::error($e); |
|
142
|
|
|
} |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
return $info; |
|
146
|
|
|
} |
|
147
|
|
|
|
|
148
|
|
|
/** |
|
149
|
|
|
* Write an artist image file with binary data and update the Artist with the new cover file. |
|
150
|
|
|
* |
|
151
|
|
|
* @param string $binaryData |
|
152
|
|
|
* @param string $extension The file extension |
|
153
|
|
|
* @param string $destination The destination path. Automatically generated if empty. |
|
154
|
|
|
*/ |
|
155
|
|
View Code Duplication |
public function writeImageFile($binaryData, $extension, $destination = '') |
|
|
|
|
|
|
156
|
|
|
{ |
|
157
|
|
|
$extension = trim(strtolower($extension), '. '); |
|
158
|
|
|
$destination = $destination ?: $this->generateRandomImagePath($extension); |
|
159
|
|
|
file_put_contents($destination, $binaryData); |
|
160
|
|
|
|
|
161
|
|
|
$this->update(['image' => basename($destination)]); |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* Generate a random path for the artist's image. |
|
166
|
|
|
* |
|
167
|
|
|
* @param string $extension The extension of the cover (without dot) |
|
168
|
|
|
* |
|
169
|
|
|
* @return string |
|
170
|
|
|
*/ |
|
171
|
|
|
private function generateRandomImagePath($extension) |
|
172
|
|
|
{ |
|
173
|
|
|
return app()->publicPath().'/public/img/artists/'.uniqid('', true).".$extension"; |
|
174
|
|
|
} |
|
175
|
|
|
|
|
176
|
|
|
/** |
|
177
|
|
|
* Turn the image name into its absolute URL. |
|
178
|
|
|
* |
|
179
|
|
|
* @param mixed $value |
|
180
|
|
|
* |
|
181
|
|
|
* @return string|null |
|
182
|
|
|
*/ |
|
183
|
|
|
public function getImageAttribute($value) |
|
184
|
|
|
{ |
|
185
|
|
|
return $value ? app()->staticUrl("public/img/artists/$value") : null; |
|
186
|
|
|
} |
|
187
|
|
|
} |
|
188
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.