Use cover/folder.jpg/png as album cover if found (fixes #380)

This commit is contained in:
An Phan 2016-08-07 17:30:55 +07:00
parent cb7cebe151
commit 7556ba79e0
No known key found for this signature in database
GPG key ID: 05536BB4BCDC02A2
4 changed files with 85 additions and 10 deletions

View file

@ -123,12 +123,36 @@ class Album extends Model
public function writeCoverFile($binaryData, $extension) public function writeCoverFile($binaryData, $extension)
{ {
$extension = trim(strtolower($extension), '. '); $extension = trim(strtolower($extension), '. ');
$fileName = uniqid('', true).".$extension"; $destPath = $this->generateRandomCoverPath($extension);
$coverPath = app()->publicPath().'/public/img/covers/'.$fileName; file_put_contents($destPath, $binaryData);
file_put_contents($coverPath, $binaryData); $this->update(['cover' => basename($destPath)]);
}
$this->update(['cover' => $fileName]); /**
* Copy a cover file from an existing image on the system.
*
* @param string $srcPath The original image's full path.
*/
public function copyCoverFile($srcPath)
{
$extension = pathinfo($srcPath, PATHINFO_EXTENSION);
$destPath = $this->generateRandomCoverPath($extension);
copy($srcPath, $destPath);
$this->update(['cover' => basename($destPath)]);
}
/**
* Generate a random path for the cover image.
*
* @param string $extension The extension of the cover (without dot)
*
* @return string
*/
private function generateRandomCoverPath($extension)
{
return app()->publicPath().'/public/img/covers/'.uniqid('', true).".$extension";
} }
public function setCoverAttribute($value) public function setCoverAttribute($value)

View file

@ -2,7 +2,9 @@
namespace App\Models; namespace App\Models;
use Cache;
use Exception; use Exception;
use Symfony\Component\Finder\Finder;
use getID3; use getID3;
use getid3_lib; use getid3_lib;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@ -99,7 +101,7 @@ class File
'comments.track_number', 'comments.track_number',
]; ];
for ($i = 0; $i < count($trackIndices) && $track === 0; $i++) { for ($i = 0; $i < count($trackIndices) && $track === 0; ++$i) {
$track = array_get($info, $trackIndices[$i], [0])[0]; $track = array_get($info, $trackIndices[$i], [0])[0];
} }
@ -227,11 +229,18 @@ class File
$album = Album::get($artist, $info['album'], $isCompilation); $album = Album::get($artist, $info['album'], $isCompilation);
} }
if (!empty($info['cover']) && !$album->has_cover) { if (!$album->has_cover) {
try { // If the album has no cover, we try to get the cover image from existing tag data
$album->generateCover($info['cover']); if (!empty($info['cover'])) {
} catch (Exception $e) { try {
Log::error($e); $album->generateCover($info['cover']);
} catch (Exception $e) {
Log::error($e);
}
}
// or, if there's a cover image under the same directory, use it.
elseif ($cover = $this->getCoverFileUnderSameDirectory()) {
$album->copyCoverFile($cover);
} }
} }
@ -303,6 +312,42 @@ class File
return $this->path; return $this->path;
} }
/**
* Issue #380.
* Some albums have its own cover image under the same directory as cover|folder.jpg/png.
* We'll check if such a cover file is found, and use it if positive.
*
* @return string|false The cover file's full path, or false if none found
*/
private function getCoverFileUnderSameDirectory()
{
// As directory scanning can be expensive, we cache and reuse the result.
$cacheKey = md5($this->path.'_cover');
if (!is_null($cover = Cache::get($cacheKey))) {
return $cover;
}
$matches = array_keys(iterator_to_array(
Finder::create()
->depth(0)
->ignoreUnreadableDirs()
->files()
->name('/(cov|fold)er\.(jpe?g|png)$/i')
->in(dirname($this->path))
));
$cover = $matches ? $matches[0] : false;
// Even if a file is found, make sure it's a real image.
if ($cover && exif_imagetype($cover) === false) {
$cover = false;
}
Cache::put($cacheKey, $cover, 24 * 60);
return $cover;
}
/** /**
* Get a unique hash from a file path. * Get a unique hash from a file path.
* *

View file

@ -32,6 +32,11 @@ class MediaTest extends TestCase
// Ogg files and audio files in subdirectories should be recognized // Ogg files and audio files in subdirectories should be recognized
$this->seeInDatabase('songs', ['path' => $this->mediaPath.'/subdir/back-in-black.ogg']); $this->seeInDatabase('songs', ['path' => $this->mediaPath.'/subdir/back-in-black.ogg']);
// GitHub issue #380. folder.png should be copied and used as the cover for files
// under subdir/
$song = Song::wherePath($this->mediaPath.'/subdir/back-in-black.ogg')->first();
$this->assertNotNull($song->album->cover);
// File search shouldn't be case-sensitive. // File search shouldn't be case-sensitive.
$this->seeInDatabase('songs', ['path' => $this->mediaPath.'/subdir/no-name.MP3']); $this->seeInDatabase('songs', ['path' => $this->mediaPath.'/subdir/no-name.MP3']);
@ -58,6 +63,7 @@ class MediaTest extends TestCase
$this->assertTrue($song->album->is_compilation); $this->assertTrue($song->album->is_compilation);
$this->assertEquals(Artist::VARIOUS_ID, $song->album->artist_id); $this->assertEquals(Artist::VARIOUS_ID, $song->album->artist_id);
$currentCover = $album->cover; $currentCover = $album->cover;
$song = Song::orderBy('id', 'desc')->first(); $song = Song::orderBy('id', 'desc')->first();

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB