['extension' => 'flac', 'tag_format' => 'metaflac', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/flac', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec flac -aq 8 -f flac {$target}'],
'MP3' => ['extension' => 'mp3', 'tag_format' => 'id3v2.3', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/mpeg', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libmp3lame -ab 320k -f mp3 {$target}'],
'OGG Vorbis' => ['extension' => 'ogg', 'tag_format' => 'vorbiscomment', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/ogg', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libvorbis -aq 7 -f ogg {$target}'],
'AAC' => ['extension' => 'm4a', 'tag_format' => 'AtomicParsley', 'tag_method' => 'updateTagsWithAtomicParsley', 'mime_type' => 'audio/mp4', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libfaac -ab 256k -f mp4 {$target}'],
'ALAC' => ['extension' => 'alac.m4a', 'tag_format' => 'AtomicParsley', 'tag_method' => 'updateTagsWithAtomicParsley', 'mime_type' => 'audio/mp4', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec alac {$target}'],
];
public static function summary() {
return self::select('id', 'title', 'user_id', 'slug', 'is_vocal', 'is_explicit', 'created_at', 'published_at', 'duration', 'is_downloadable', 'genre_id', 'track_type_id', 'cover_id', 'album_id');
}
public static function mapPublicTrackShow($track) {
$returnValue = self::mapPublicTrackSummary($track);
$returnValue['description'] = $track->description;
$returnValue['lyrics'] = $track->lyrics;
return $returnValue;
}
public static function mapPublicTrackSummary($track) {
return [
'id' => $track->id,
'title' => $track->title,
'user' => [
'id' => $track->user->id,
'name' => $track->user->display_name,
'url' => $track->user->url
],
'url' => $track->url,
'slug' => $track->slug,
'is_vocal' => $track->is_vocal,
'is_explicit' => $track->is_explicit,
'is_downloadable' => $track->is_downloadable,
'is_published' => $track->isPublished(),
'published_at' => $track->published_at,
'duration' => $track->duration,
'genre' => $track->genre != null
?
[
'id' => $track->genre->id,
'slug' => $track->genre->slug,
'name' => $track->genre->name
] : null,
'track_type_id' => $track->track_type_id,
'covers' => [
'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL),
'small' => $track->getCoverUrl(Image::SMALL),
'normal' => $track->getCoverUrl(Image::NORMAL)
]
];
}
public static function mapPrivateTrackShow($track) {
$showSongs = [];
foreach ($track->showSongs as $showSong) {
$showSongs[] = ['id' => $showSong->id, 'title' => $showSong->title];
}
$returnValue = self::mapPrivateTrackSummary($track);
$returnValue['album_id'] = $track->album_id;
$returnValue['show_songs'] = $showSongs;
$returnValue['real_cover_url'] = $track->getCoverUrl(Image::NORMAL);
$returnValue['cover_url'] = $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null;
$returnValue['released_at'] = $track->released_at;
$returnValue['lyrics'] = $track->lyrics;
$returnValue['description'] = $track->description;
$returnValue['is_downloadable'] = !$track->isPublished() ? true : (bool)$track->is_downloadable;
$returnValue['license_id'] = $track->license_id != null ? $track->license_id : 3;
return $returnValue;
}
public static function mapPrivateTrackSummary($track) {
return [
'id' => $track->id,
'title' => $track->title,
'user_id' => $track->user_id,
'slug' => $track->slug,
'is_vocal' => $track->is_vocal,
'is_explicit' => $track->is_explicit,
'is_downloadable' => $track->is_downloadable,
'is_published' => $track->isPublished(),
'created_at' => $track->created_at,
'published_at' => $track->published_at,
'duration' => $track->duration,
'genre_id' => $track->genre_id,
'track_type_id' => $track->track_type_id,
'cover_url' => $track->getCoverUrl(Image::SMALL)
];
}
protected $table = 'tracks';
public function genre() {
return $this->belongsTo('Entities\Genre');
}
public function cover() {
return $this->belongsTo('Entities\Image');
}
public function showSongs() {
return $this->belongsToMany('Entities\ShowSong');
}
public function user() {
return $this->belongsTo('Entities\User');
}
public function album() {
return $this->belongsTo('Entities\Album');
}
public function getYear() {
return date('Y', strtotime($this->release_date));
}
public function canView($user) {
if ($this->isPublished())
return true;
return $this->user_id == $user->id;
}
public function getUrlAttribute() {
return URL::to('/tracks/' . $this->id . '-' . $this->slug);
}
public function getReleaseDate() {
if($this->attributes['released_at'] !== NULL)
return $this->attributes['released_at'];
if ($this->attributes['published_at'] !== NULL)
return Str::limit($this->$this->attributes['published_at'], 10, '');
return Str::limit($this->attributes['created_at'], 10, '');
}
public function ensureDirectoryExists() {
$destination = $this->getDirectory();
if (!is_dir($destination))
mkdir($destination, 755);
}
public function hasCover() {
return $this->cover_id != null;
}
public function isPublished() {
return $this->published_at != null && $this->deleted_at == null;
}
public function getCoverUrl($type = Image::NORMAL) {
if (!$this->hasCover()) {
if ($this->album_id != null)
return $this->album->getCoverUrl($type);
return $this->user->getAvatarUrl($type);
}
return $this->cover->getUrl($type);
}
public function getDirectory() {
$dir = (string) ( floor( $this->id / 100 ) * 100 );
return \Config::get('app.files_directory') . '/tracks/' . $dir;
}
public function getDates() {
return ['created_at', 'deleted_at', 'published_at', 'released_at'];
}
public function getFilenameFor($format) {
if (!isset(self::$Formats[$format]))
throw new Exception("$format is not a valid format!");
$format = self::$Formats[$format];
return "{$this->id}.{$format['extension']}";
}
public function getFileFor($format) {
if (!isset(self::$Formats[$format]))
throw new Exception("$format is not a valid format!");
$format = self::$Formats[$format];
return "{$this->getDirectory()}/{$this->id}.{$format['extension']}";
}
public function updateTags() {
foreach (self::$Formats as $format => $data) {
$this->{$data['tag_method']}($format);
}
}
/** @noinspection PhpUnusedPrivateMethodInspection */
private function updateTagsWithAtomicParsley($format) {
$command = 'AtomicParsley "' . $this->getFileFor($format) . '" ';
$command .= '--title ' . escapeshellarg($this->title) . ' ';
$command .= '--artist ' . escapeshellarg($this->user->display_name) . ' ';
$command .= '--year "' . $this->year . '" ';
$command .= '--genre ' . escapeshellarg($this->genre != null ? $this->genre->title : '') . ' ';
$command .= '--copyright ' . escapeshellarg('© '.$this->year.' '.$this->user->display_name).' ';
$command .= '--comment "' . 'Downloaded from: https://pony.fm/' . '" ';
$command .= '--encodingTool "' . 'Pony.fm' . '" ';
$command .= '--encodedBy "' . 'Pony.fm - https://pony.fm/' . '" ';
if ($this->album_id !== NULL) {
$command .= '--album ' . escapeshellarg($this->album->title) . ' ';
$command .= '--tracknum ' . $this->track_number . ' ';
}
if ($this->cover !== NULL) {
$command .= '--artwork ' . $this->getCoverUrl() . ' ';
}
$command .= '--overWrite';
External::execute($command);
}
/** @noinspection PhpUnusedPrivateMethodInspection */
private function updateTagsWithGetId3($format) {
require_once(app_path() . '/library/getid3/getid3.php');
require_once(app_path() . '/library/getid3/write.php');
$tagWriter = new getid3_writetags;
$tagWriter->overwrite_tags = true;
$tagWriter->tag_encoding = 'UTF-8';
$tagWriter->remove_other_tags = true;
$tagWriter->tag_data = [
'title' => [$this->title],
'artist' => [$this->user->display_name],
'year' => ['' . $this->year],
'genre' => [$this->genre != null ? $this->genre->title : ''],
'comment' => ['Downloaded from: https://pony.fm/'],
'copyright' => ['© ' . $this->year . ' ' . $this->user->display_name],
'publisher' => ['Pony.fm - https://pony.fm/'],
'encoded_by' => ['https://pony.fm/'],
// 'url_artist' => [$this->user->url],
// 'url_source' => [$this->url],
// 'url_file' => [$this->url],
'url_publisher' => ['https://pony.fm/']
];
if ($this->album_id !== NULL) {
$tagWriter->tag_data['album'] = [$this->album->title];
$tagWriter->tag_data['track'] = [$this->track_number];
}
if ($format == 'MP3' && $this->cover_id != NULL && is_file($this->cover->file)) {
$tagWriter->tag_data['attached_picture'][0] = [
'data' => file_get_contents($this->cover->file),
'picturetypeid' => 2,
'description' => 'cover',
'mime' => 'image/png'
];
}
$tagWriter->filename = $this->getFileFor($format);
$tagWriter->tagformats = [self::$Formats[$format]['tag_format']];
if ($tagWriter->WriteTags()) {
if (!empty($tagWriter->warnings)) {
Log::warning('There were some warnings:
' . implode('
', $tagWriter->warnings));
}
} else {
Log::error('Failed to write tags!
' . implode('
', $tagWriter->errors));
}
}
}