mirror of
https://github.com/koel/koel
synced 2024-11-10 06:34:14 +00:00
Use cover/folder.jpg/png as album cover if found (fixes #380)
This commit is contained in:
parent
cb7cebe151
commit
7556ba79e0
4 changed files with 85 additions and 10 deletions
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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();
|
||||||
|
|
BIN
tests/songs/subdir/folder.png
Normal file
BIN
tests/songs/subdir/folder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
Loading…
Reference in a new issue