diff --git a/src/Id3/Id3Writer.php b/src/Id3/Id3Writer.php index 4b66525..279cdc0 100644 --- a/src/Id3/Id3Writer.php +++ b/src/Id3/Id3Writer.php @@ -28,6 +28,9 @@ protected function __construct( protected array $warnings = [], protected array $errors = [], protected bool $remove_old_tags = false, + protected ?array $cover = null, + protected bool $has_new_cover = false, + protected bool $delete_cover = false, protected bool $skip_errors = true, protected array $tag_formats = [], protected bool $success = false, @@ -46,6 +49,11 @@ public static function make(Audio $audio): self return $self; } + public function getCore(): AudioCore + { + return $this->core; + } + /** * Allow to remove other tags when writing tags. */ @@ -254,11 +262,51 @@ public function tag(string $key, string|int|bool|null $value): self } /** + * To update path to save file. + */ + public function path(string $path): self + { + if (file_exists($path)) { + unlink($path); + } + copy($this->audio->getPath(), $path); + + $this->writer->filename = $path; + + return $this; + } + + /** + * Advanced usage only to save manually tags. + * + * @param string[] $tag_formats + */ + public function tagFormats(array $tag_formats): self + { + $this->tag_formats = $tag_formats; + + return $this; + } + + /** + * Update cover is only supported by `id3` format. + * * @param string $pathOrData Path to cover image or binary data */ public function cover(string $pathOrData): self { $this->core->cover = AudioCoreCover::make($pathOrData); + $this->has_new_cover = true; + + return $this; + } + + /** + * Remove cover from tags. + */ + public function removeCover(): self + { + $this->delete_cover = true; return $this; } @@ -266,6 +314,8 @@ public function cover(string $pathOrData): self /** * Set manually tags, to know which key used for which tag, you have to refer to documentation. * + * WARNING: This method is for advanced usage only, if you use it, this will override all other tags. + * * @docs https://github.com/kiwilan/php-audio#convert-properties * * For example, album artist for `id3` encoded files, is `band` key. @@ -292,6 +342,7 @@ public function handleErrors(): self public function save(): bool { + $this->attachCover(); $this->parseTagFormats(); if (! $this->is_manual) { $this->assignTags(); @@ -324,6 +375,7 @@ private function parseErrors(): void AudioFormatEnum::flac => true, AudioFormatEnum::mp3 => true, AudioFormatEnum::ogg => true, + AudioFormatEnum::m4b => true, default => false }; @@ -378,12 +430,21 @@ private function assignTags(): self return $this; } + $oldTags = []; + if (! $this->writer->remove_other_tags) { + $oldTags = $this->audio->getRaw(); + } + $this->new_tags = [ - ...$this->audio->getRaw(), // old tags + ...$oldTags, // old tags ...$convert->toArray(), // new tags ]; $this->new_tags = $this->convertTags($this->new_tags); + if ($this->cover && ! $this->delete_cover) { + $this->new_tags['attached_picture'][0] = $this->cover; + } + return $this; } @@ -437,25 +498,37 @@ private function parseTagFormats(): self return $this; } - // private function attachCover(array &$tags): void - // { - // $coverFormatsAllowed = [AudioFormatEnum::mp3]; - // if ($this->core->cover && in_array($this->audio->getFormat(), $coverFormatsAllowed)) { - // // $tags = [ - // // ...$tags, - // // 'CTOC' => $old_tags['id3v2']['CTOC'], - // // 'CHAP' => $old_tags['id3v2']['CHAP'], - // // 'chapters' => $old_tags['id3v2']['chapters'], - // // ]; - // $tags['attached_picture'][0] = [ - // 'data' => base64_decode($this->core->cover->data), - // 'picturetypeid' => $this->core->cover->picture_type_id, - // 'description' => $this->core->cover->description, - // 'mime' => $this->core->cover->mime, - // ]; - // $this->core->has_cover = true; - // } - // } + private function attachCover(): void + { + if ($this->audio->hasCover() && ! $this->has_new_cover && ! $this->delete_cover) { + $this->core->cover = new AudioCoreCover( + data: $this->audio->getCover()->getContents(base64: true), + mime: $this->audio->getCover()->getMimeType(), + ); + } + + $coverFormatsAllowed = [AudioFormatEnum::mp3]; + if ($this->core->cover && in_array($this->audio->getFormat(), $coverFormatsAllowed)) { + // $tags = [ + // ...$tags, + // 'CTOC' => $old_tags['id3v2']['CTOC'], + // 'CHAP' => $old_tags['id3v2']['CHAP'], + // 'chapters' => $old_tags['id3v2']['chapters'], + // ]; + $this->cover = [ + 'data' => base64_decode($this->core->cover->data), + 'picturetypeid' => $this->core->cover->picture_type_id ?? 1, + 'description' => $this->core->cover->description ?? 'cover', + 'mime' => $this->core->cover->mime, + ]; + $this->core->has_cover = true; + } + + if ($this->delete_cover) { + $this->cover = null; + $this->core->has_cover = false; + } + } /** * @param array $tags diff --git a/src/Models/AudioCover.php b/src/Models/AudioCover.php index 24ff8df..4bed270 100644 --- a/src/Models/AudioCover.php +++ b/src/Models/AudioCover.php @@ -66,4 +66,12 @@ public function getHeight(): ?int { return $this->height; } + + /** + * Extract the cover to a file. + */ + public function extractCover(string $path): void + { + file_put_contents($path, $this->getContents()); + } } diff --git a/tests/Pest.php b/tests/Pest.php index 53b07b8..45ed7dd 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -6,6 +6,7 @@ define('AUDIOBOOK', __DIR__.'/media/audiobook.m4b'); define('AUDIOBOOK_MP3', __DIR__.'/media/audiobook.mp3'); define('MD', __DIR__.'/media/test.md'); +define('DEFAULT_FOLDER', __DIR__.'/media/default-folder.jpg'); define('FOLDER', __DIR__.'/media/folder.jpg'); function addWriterFilesForTests() @@ -178,3 +179,28 @@ function testMp3Writed(Audio $audio) expect($audio->getDiscNumber())->toBe('2/2'); expect($audio->isCompilation())->toBeFalse(); } + +function pathTo(string $filename, string $subDirectory = 'output'): string +{ + return __DIR__.'/'.$subDirectory.'/'.$filename; +} + +function resetMp3Writer() +{ + $audio = Audio::read(MP3_WRITER); + + $audio->update() + ->title('Introduction') + ->artist('Mr Piouf') + ->album('P1PDD Le conclave de Troie') + ->genre('Roleplaying game') + ->year(2016) + ->trackNumber('1') + ->comment('http://www.p1pdd.com') + ->albumArtist('P1PDD & Mr Piouf') + ->composer('P1PDD & Piouf') + ->discNumber('1') + ->isCompilation() + ->cover(DEFAULT_FOLDER) + ->save(); +} diff --git a/tests/WriterCoverTest.php b/tests/WriterCoverTest.php new file mode 100644 index 0000000..816b173 --- /dev/null +++ b/tests/WriterCoverTest.php @@ -0,0 +1,122 @@ +update() + ->cover(FOLDER) + ->save(); + + $audio = Audio::read($path); + expect($audio->getTitle())->toBe('Introduction'); + + $content = base64_encode(file_get_contents(FOLDER)); + expect($audio->getCover()->getContents(true))->toBe($content); +})->with([MP3_WRITER]); + +it('can read use file content as cover', function (string $path) { + $audio = Audio::read($path); + + $tag = $audio->update() + ->cover(file_get_contents(FOLDER)); + + $tag->save(); + + $audio = Audio::read($path); + + $content = file_get_contents(FOLDER); + expect($audio->getCover()->getContents(true))->toBe(base64_encode($content)); +})->with([MP3_WRITER]); + +it('can read use tags', function (string $path) { + $audio = Audio::read($path); + + $random = (string) rand(1, 1000); + $image = getimagesize(FOLDER); + $coverData = file_get_contents(FOLDER); + $coverPicturetypeid = $image[2]; + $coverDescription = 'cover'; + $coverMime = $image['mime']; + $tag = $audio->update() + ->tags([ + 'title' => $random, + 'attached_picture' => [ + [ + 'data' => $coverData, + 'picturetypeid' => $coverPicturetypeid, + 'description' => $coverDescription, + 'mime' => $coverMime, + ], + ], + ]); + + $tag->save(); + + $audio = Audio::read($path); + expect($audio->getTitle())->toBe($random); + + $content = file_get_contents(FOLDER); + expect($audio->getCover()->getContents())->toBe($content); +})->with([MP3_WRITER]); + +it('can use tags with cover', function (string $path) { + $audio = Audio::read($path); + + $tag = $audio->update() + ->tags([ + 'title' => 'New Title', + ]) + ->cover(FOLDER); + + $tag->save(); + + $audio = Audio::read($path); + + $content = file_get_contents(FOLDER); + expect($audio->getTitle())->toBe('New Title'); + expect($tag->getCore()->cover->data)->toBe(base64_encode($content)); +})->with([MP3_WRITER]); + +it('can update cover with path', function () { + $audio = Audio::read(MP3_WRITER); + + $path = pathTo('cover.jpg', 'media'); + + if (file_exists($path)) { + unlink($path); + } + $audio->getCover()->extractCover($path); + expect(file_exists($path))->toBeTrue(); + + $audio->update() + ->cover(FOLDER) + ->handleErrors() + ->save(); + + $audio = Audio::read(MP3_WRITER); + unlink($path); + $audio->getCover()->extractCover($path); + expect(file_exists($path))->toBeTrue(); + + $content = file_get_contents(FOLDER); + expect($audio->getCover()->getContents(true))->toBe(base64_encode($content)); +}); + +it('can remove cover', function () { + $audio = Audio::read(MP3_WRITER); + + $audio->update() + ->removeCover() + ->handleErrors() + ->save(); + + $audio = Audio::read(MP3_WRITER); + + expect($audio->hasCover())->toBeFalse(); + expect($audio->getCover())->toBeNull(); +}); diff --git a/tests/WriterMp3Test.php b/tests/WriterMp3Test.php new file mode 100644 index 0000000..67e2093 --- /dev/null +++ b/tests/WriterMp3Test.php @@ -0,0 +1,92 @@ +update() + ->title('New Title') + ->artist('New Artist') + ->album('New Album') + ->genre('New Genre') + ->year(2022) + ->trackNumber('2/10') + ->albumArtist('New Album Artist') + ->comment('New Comment') + ->composer('New Composer') + ->discNumber('2/2') + ->isNotCompilation() + ->lyrics('New Lyrics') + ->creationDate('2021-01-01') + ->copyright('New Copyright') + ->encodingBy('New Encoding By') + ->encoding('New Encoding') + ->description('New Description') + ->synopsis('New Synopsis') + ->language('en') + ->copyright('New Copyright') + ->handleErrors() + ->save(); + + $audio = Audio::read(MP3_WRITER); + testMp3Writed($audio); + expect($audio->getLanguage())->toBe('en'); + expect($audio->getCopyright())->toBe('New Copyright'); +}); + +it('can update only one tag', function () { + $audio = Audio::read(MP3_WRITER); + testMp3Writer($audio); + + $audio->update() + ->title('New Title') + ->save(); + + $audio = Audio::read(MP3_WRITER); + expect($audio->getTitle())->toBe('New Title'); + expect($audio->getArtist())->toBe('Mr Piouf'); + expect($audio->getAlbum())->toBe('P1PDD Le conclave de Troie'); + expect($audio->getGenre())->toBe('Roleplaying game'); + expect($audio->getYear())->toBe(2016); + expect($audio->getTrackNumber())->toBe('1'); + expect($audio->getComment())->toBe('http://www.p1pdd.com'); + expect($audio->getAlbumArtist())->toBe('P1PDD & Mr Piouf'); + expect($audio->getComposer())->toBe('P1PDD & Piouf'); + expect($audio->getDiscNumber())->toBe('1'); + expect($audio->isCompilation())->toBeTrue(); +}); + +it('can update tags manually', function () { + $audio = Audio::read(MP3_WRITER); + testMp3Writer($audio); + + $audio->update() + ->tags([ + 'title' => 'New Title', + 'artist' => 'New Artist', + 'album' => 'New Album', + 'genre' => 'New Genre', + 'year' => '2022', + 'track_number' => '2/10', + 'band' => 'New Album Artist', + 'comment' => 'New Comment', + 'composer' => 'New Composer', + 'part_of_a_set' => '2/2', + 'part_of_a_compilation' => false, + 'unsynchronised_lyric' => 'New Lyrics', + 'language' => 'en', + 'copyright' => 'New Copyright', + ]) + ->save(); + + $audio = Audio::read(MP3_WRITER); + testMp3Writed($audio); + expect($audio->getLanguage())->toBe('en'); + expect($audio->getCopyright())->toBe('New Copyright'); +}); diff --git a/tests/WriterTest.php b/tests/WriterTest.php index 9ed21d7..0e9e9ab 100644 --- a/tests/WriterTest.php +++ b/tests/WriterTest.php @@ -1,402 +1,206 @@ update() - ->title('Introduction') - ->artist('Mr Piouf') - ->album('P1PDD Le conclave de Troie') - ->genre('Roleplaying game') - ->year(2016) - ->trackNumber('1') - ->comment('http://www.p1pdd.com') - ->albumArtist('P1PDD & Mr Piouf') - ->composer('P1PDD & Piouf') - ->discNumber('1') - ->isCompilation() - ->save(); + resetMp3Writer(); }); -it('can update tags', function () { - $audio = Audio::read(MP3_WRITER); - testMp3Writer($audio); - +it('can update file', function (string $path) { + $audio = Audio::read($path); + $random = (string) rand(1, 1000); $audio->update() - ->title('New Title') + ->title($random) ->artist('New Artist') ->album('New Album') ->genre('New Genre') - ->year(2022) + ->year('2022') ->trackNumber('2/10') ->albumArtist('New Album Artist') ->comment('New Comment') ->composer('New Composer') - ->discNumber('2/2') - ->isNotCompilation() - ->lyrics('New Lyrics') ->creationDate('2021-01-01') - ->copyright('New Copyright') + ->description('New Description') + ->discNumber('2/2') ->encodingBy('New Encoding By') ->encoding('New Encoding') - ->description('New Description') - ->synopsis('New Synopsis') - ->language('en') - ->copyright('New Copyright') - ->cover(FOLDER) + ->isNotCompilation() + ->lyrics('New Lyrics') ->save(); - $audio = Audio::read(MP3_WRITER); - testMp3Writed($audio); - expect($audio->getLanguage())->toBe('en'); - expect($audio->getCopyright())->toBe('New Copyright'); -}); - -it('can update only one tag', function () { - $audio = Audio::read(MP3_WRITER); - testMp3Writer($audio); + $audio = Audio::read($path); + + expect($audio->getTitle())->toBe($random); + expect($audio->getArtist())->toBe('New Artist'); + expect($audio->getAlbum())->toBe('New Album'); + expect($audio->getGenre())->toBe('New Genre'); + expect($audio->getYear())->toBe(2022); + expect($audio->getAlbumArtist())->toBe('New Album Artist'); + expect($audio->getComment())->toBe('New Comment'); + expect($audio->getComposer())->toBe('New Composer'); + expect($audio->getDiscNumber())->toBe('2/2'); + expect($audio->isCompilation())->toBeFalse(); + + expect($audio->getCreationDate())->toBeNull(); + if ($audio->getFormat() === AudioFormatEnum::mp3) { + expect($audio->getDescription())->toBeNull(); + expect($audio->getEncoding())->toBeNull(); + } + expect($audio->getEncodingBy())->toBeNull(); + if ($audio->getLyrics()) { + expect($audio->getLyrics())->toBe('New Lyrics'); + } + + if ($audio->getFormat() !== AudioFormatEnum::mp3) { + expect($audio->getTrackNumber())->toBe('2/10'); + } else { + expect($audio->getTrackNumber())->toBe('2'); + } +})->with(AUDIO_WRITER); + +it('can update use tags with tag formats', function (string $path) { + $audio = Audio::read($path); + + $random = (string) rand(1, 1000); + $tag = $audio->update() + ->tags([ + 'title' => $random, + ]) + ->tagFormats(['id3v1', 'id3v2.4']); - $audio->update() - ->title('New Title') - ->save(); + $tag->save(); - $audio = Audio::read(MP3_WRITER); - expect($audio->getTitle())->toBe('New Title'); - expect($audio->getArtist())->toBe('Mr Piouf'); - expect($audio->getAlbum())->toBe('P1PDD Le conclave de Troie'); - expect($audio->getGenre())->toBe('Roleplaying game'); - expect($audio->getYear())->toBe(2016); - expect($audio->getTrackNumber())->toBe('1'); - expect($audio->getComment())->toBe('http://www.p1pdd.com'); - expect($audio->getAlbumArtist())->toBe('P1PDD & Mr Piouf'); - expect($audio->getComposer())->toBe('P1PDD & Piouf'); - expect($audio->getDiscNumber())->toBe('1'); - expect($audio->isCompilation())->toBeTrue(); -}); + $audio = Audio::read($path); + expect($audio->getTitle())->toBe($random); +})->with([MP3_WRITER]); -it('can update tags manually', function () { - $audio = Audio::read(MP3_WRITER); - testMp3Writer($audio); +it('can update with tags and handle native metadata', function (string $path) { + $audio = Audio::read($path); - $audio->update() + $tag = $audio->update() + ->isCompilation() ->tags([ 'title' => 'New Title', - 'artist' => 'New Artist', - 'album' => 'New Album', - 'genre' => 'New Genre', - 'year' => '2022', - 'track_number' => '2/10', - 'band' => 'New Album Artist', - 'comment' => 'New Comment', - 'composer' => 'New Composer', - 'part_of_a_set' => '2/2', - 'part_of_a_compilation' => false, - 'unsynchronised_lyric' => 'New Lyrics', - 'language' => 'en', - 'copyright' => 'New Copyright', + 'band' => 'New Band', ]) - ->save(); + ->tagFormats(['id3v1', 'id3v2.4']); - $audio = Audio::read(MP3_WRITER); - testMp3Writed($audio); - expect($audio->getLanguage())->toBe('en'); - expect($audio->getCopyright())->toBe('New Copyright'); -}); + $tag->save(); -// it('can update file', function (string $path) { -// $audio = Audio::read($path); -// $random = (string) rand(1, 1000); -// $tag = $audio->update() -// ->title($random) -// ->artist('New Artist') -// ->album('New Album') -// ->genre('New Genre') -// ->year('2022') -// ->trackNumber('2/10') -// ->albumArtist('New Album Artist') -// ->comment('New Comment') -// ->composer('New Composer') -// ->creationDate('2021-01-01') -// ->description('New Description') -// ->discNumber('2/2') -// ->encodingBy('New Encoding By') -// ->encoding('New Encoding') -// ->isNotCompilation() -// ->lyrics('New Lyrics') -// ->stik('New Stik') -// ->cover(FOLDER); - -// $core = $tag->getCore(); -// $tag->save(); - -// $audio = Audio::read($path); - -// expect($audio->getTitle())->toBe($random); -// expect($audio->getArtist())->toBe('New Artist'); -// expect($audio->getAlbum())->toBe('New Album'); -// expect($audio->getGenre())->toBe('New Genre'); -// expect($audio->getYear())->toBe(2022); -// expect($audio->getAlbumArtist())->toBe('New Album Artist'); -// expect($audio->getComment())->toBe('New Comment'); -// expect($audio->getComposer())->toBe('New Composer'); -// expect($audio->getDiscNumber())->toBe('2/2'); -// expect($audio->isCompilation())->toBeFalse(); - -// expect($audio->getCreationDate())->toBeNull(); -// if ($audio->getFormat() === AudioFormatEnum::mp3) { -// expect($audio->getDescription())->toBeNull(); -// expect($audio->getEncoding())->toBeNull(); -// } -// expect($audio->getEncodingBy())->toBeNull(); -// if ($audio->getLyrics()) { -// expect($audio->getLyrics())->toBe('New Lyrics'); -// } -// expect($audio->getStik())->toBeNull(); - -// if ($audio->getFormat() !== AudioFormatEnum::mp3) { -// expect($audio->getTrackNumber())->toBe('2/10'); -// } else { -// expect($audio->getTrackNumber())->toBe('2'); -// } - -// if ($tag->getCore()->hasCover()) { -// $content = file_get_contents(FOLDER); -// expect($tag->getCore()->getCover()->data())->toBe(base64_encode($content)); -// } -// })->with(AUDIO_WRITER); - -// it('can read use file content as cover', function (string $path) { -// $audio = Audio::read($path); - -// $tag = $audio->update() -// ->cover(file_get_contents(FOLDER)); - -// $tag->save(); - -// $audio = Audio::read($path); - -// $content = file_get_contents(FOLDER); -// expect($tag->getCore()->getCover()->data())->toBe(base64_encode($content)); -// })->with([MP3_WRITER]); - -// it('can read use tags', function (string $path) { -// $audio = Audio::read($path); - -// $random = (string) rand(1, 1000); -// $image = getimagesize(FOLDER); -// $coverData = file_get_contents(FOLDER); -// $coverPicturetypeid = $image[2]; -// $coverDescription = 'cover'; -// $coverMime = $image['mime']; -// $tag = $audio->update() -// ->tags([ -// 'title' => $random, -// 'attached_picture' => [ -// [ -// 'data' => $coverData, -// 'picturetypeid' => $coverPicturetypeid, -// 'description' => $coverDescription, -// 'mime' => $coverMime, -// ], -// ], -// ]); - -// $tag->save(); - -// $audio = Audio::read($path); -// expect($audio->getTitle())->toBe($random); - -// $content = file_get_contents(FOLDER); -// expect($audio->getCover()->getContents())->toBe($content); -// })->with([MP3_WRITER]); - -// it('can update use tags with tag formats', function (string $path) { -// $audio = Audio::read($path); - -// $random = (string) rand(1, 1000); -// $tag = $audio->update() -// ->tags([ -// 'title' => $random, -// ]) -// ->tagFormats(['id3v1', 'id3v2.4']); - -// $tag->save(); - -// $audio = Audio::read($path); -// expect($audio->getTitle())->toBe($random); -// })->with([MP3_WRITER]); - -// it('can update with tags and handle native metadata', function (string $path) { -// $audio = Audio::read($path); - -// $tag = $audio->update() -// ->isCompilation() -// ->tags([ -// 'title' => 'New Title', -// 'band' => 'New Band', -// ]) -// ->tagFormats(['id3v1', 'id3v2.4']); - -// $tag->save(); - -// $audio = Audio::read($path); -// expect($audio->getTitle())->toBe('New Title'); -// expect($audio->getAlbumArtist())->toBe('New Band'); -// expect($audio->isCompilation())->toBeTrue(); -// })->with([MP3_WRITER]); - -// it('can update with new path', function (string $path) { -// $audio = Audio::read($path); -// $newPath = 'tests/output/new.mp3'; - -// $tag = $audio->update() -// ->title('New Title') -// ->path($newPath); - -// $tag->save(); - -// $audio = Audio::read($newPath); -// expect($audio->getTitle())->toBe('New Title'); -// })->with([MP3_WRITER]); + $audio = Audio::read($path); + expect($audio->getTitle())->toBe('New Title'); + expect($audio->getAlbumArtist())->toBe('New Band'); + expect($audio->isCompilation())->toBeFalse(); +})->with([MP3_WRITER]); -// it('can update with merged tags and core methods', function (string $path) { -// $audio = Audio::read($path); - -// $tag = $audio->update() -// ->title('New Title') -// ->tags([ -// 'title' => 'New Title tag', -// 'band' => 'New Band', -// ]); +it('can use arrow function safe with unsupported tags', function (string $path) { + $audio = Audio::read($path); -// $tag->save(); + $tag = $audio->update() + ->title('New Title') + ->encoding('New encoding'); + + expect(fn () => $tag->save())->not()->toThrow(Exception::class); -// $audio = Audio::read($path); -// expect($audio->getTitle())->toBe('New Title'); -// expect($audio->getAlbumArtist())->toBe('New Band'); -// })->with([MP3_WRITER]); - -// it('can use arrow function safe with unsupported tags', function (string $path) { -// $audio = Audio::read($path); - -// $tag = $audio->update() -// ->title('New Title') -// ->encoding('New encoding'); - -// expect(fn () => $tag->save())->not()->toThrow(Exception::class); - -// $audio = Audio::read($path); -// expect($audio->getTitle())->toBe('New Title'); -// })->with([MP3_WRITER]); - -// it('can use arrow function safe with unsupported formats', function (string $path) { -// $audio = Audio::read($path); - -// $tag = $audio->update() -// ->title('New Title Alac'); + $audio = Audio::read($path); + expect($audio->getTitle())->toBe('New Title'); +})->with([MP3_WRITER]); -// expect(fn () => $tag->save())->toThrow(Exception::class); -// })->with([ALAC_WRITER]); +it('can get core before save', function (string $path) { + $audio = Audio::read($path); -// it('can get core before save', function (string $path) { -// $audio = Audio::read($path); + $writer = $audio->update() + ->title('New Title') + ->tags([ + 'title' => 'New Title tag', + 'band' => 'New Band', + ]); -// $tag = $audio->update() -// ->title('New Title') -// ->tags([ -// 'title' => 'New Title tag', -// 'band' => 'New Band', -// ]); + expect($writer->getCore())->toBeInstanceOf(AudioCore::class); +})->with([MP3_WRITER]); -// expect($tag->getCore())->toBeInstanceOf(AudioCore::class); -// })->with([MP3_WRITER]); +it('can handle exceptions', function (string $path) { + $audio = Audio::read($path); -// it('can handle exceptions', function (string $path) { -// $audio = Audio::read($path); + $tag = $audio->update() + ->tags([ + 'title' => 'New Title', + 'albumArtist' => 'New Album Artist', + ]) + ->handleErrors(); -// $tag = $audio->update() -// ->tags([ -// 'title' => 'New Title', -// 'albumArtist' => 'New Album Artist', -// ]) -// ->options(['encoding' => 'UTF-8']); + expect(fn () => $tag->save())->toThrow(Exception::class); +})->with([MP3_WRITER]); -// expect(fn () => $tag->save())->toThrow(Exception::class); -// })->with([MP3_WRITER]); +it('can skip exceptions', function (string $path) { + $audio = Audio::read($path); -// it('can skip exceptions', function (string $path) { -// $audio = Audio::read($path); + $tag = $audio->update() + ->tags([ + 'title' => 'New Title', + 'albumArtist' => 'New Album Artist', + ]); -// $tag = $audio->update() -// ->tags([ -// 'title' => 'New Title', -// 'albumArtist' => 'New Album Artist', -// ]) -// ->preventFailOnError(); + $tag->save(); -// $tag->save(); + $audio = Audio::read($path); + expect($audio->getTitle())->toBe('New Title'); + expect($audio->getAlbumArtist())->toBeNull(); +})->with([MP3_WRITER]); -// $audio = Audio::read($path); -// expect($audio->getTitle())->toBe('New Title'); -// expect($audio->getAlbumArtist())->toBeNull(); -// })->with([MP3_WRITER]); +it('can update with new path', function (string $path) { + $audio = Audio::read($path); + $newPath = 'tests/output/new.mp3'; -// it('can remove old tags', function (string $path) { -// $audio = Audio::read($path); + $tag = $audio->update() + ->title('New Title') + ->path($newPath); -// $tag = $audio->update() -// ->title('New Title') -// ->removeOldTags() -// ->path('tests/output/new.mp3'); + $tag->save(); -// $tag->save(); + $audio = Audio::read($newPath); + expect($audio->getTitle())->toBe('New Title'); +})->with([MP3_WRITER]); -// $audio = Audio::read('tests/output/new.mp3'); -// expect($audio->getTitle())->toBe('New Title'); -// expect($audio->getAlbumArtist())->toBeNull(); -// })->with([MP3]); +it('can update with merged tags and core methods', function (string $path) { + $audio = Audio::read($path); -// it('can use tags with cover', function (string $path) { -// $audio = Audio::read($path); + $tag = $audio->update() + ->tags([ + 'title' => 'New Title tag', + 'band' => 'New Band', + ]); + $tag->save(); -// $tag = $audio->update() -// ->tags([ -// 'title' => 'New Title', -// ]) -// ->cover(FOLDER); + $audio = Audio::read($path); + expect($audio->getTitle())->toBe('New Title tag'); + expect($audio->getAlbumArtist())->toBe('New Band'); +})->with([MP3_WRITER]); -// $tag->save(); +it('can use arrow function safe with unsupported formats', function (string $path) { + $audio = Audio::read($path); -// $audio = Audio::read($path); + $tag = $audio->update() + ->handleErrors() + ->title('New Title Alac'); -// $content = file_get_contents(FOLDER); -// expect($audio->getTitle())->toBe('New Title'); -// expect($tag->getCore()->getCover()->data())->toBe(base64_encode($content)); -// })->with([MP3_WRITER]); + expect(fn () => $tag->save())->toThrow(Exception::class); +})->with([ALAC_WRITER]); -// it('can change podcast description and language', function () { -// $audio = Audio::read(AUDIOBOOK); -// $tag = $audio->update() -// ->title('New Title') -// ->podcastDescription('New Podcast Description') -// ->language('New Language') -// ->save(); -// }); +it('can remove old tags', function (string $path) { + $audio = Audio::read($path); + $newPath = 'tests/output/new.mp3'; -// it('can not override tags', function (string $path) { -// $audio = Audio::read($path); + $tag = $audio->update() + ->title('New Title') + ->removeOtherTags() + ->path($newPath); -// $tag = $audio->update() -// ->getTitle('New Title') -// ->notOverrideTags() -// ->path('tests/output/new.mp3'); + $tag->save(); -// $tag->save(); - -// $audio = Audio::read('tests/output/new.mp3'); -// expect($audio->getTitle())->toBe('Introduction'); -// })->with([MP3]); + $audio = Audio::read($newPath); + expect($audio->getTitle())->toBe('New Title'); + expect($audio->getAlbumArtist())->toBeNull(); +})->with([MP3]); diff --git a/tests/media/cover.jpg b/tests/media/cover.jpg new file mode 100644 index 0000000..4eb8fa2 Binary files /dev/null and b/tests/media/cover.jpg differ diff --git a/tests/media/default-folder.jpg b/tests/media/default-folder.jpg new file mode 100644 index 0000000..2a2de69 Binary files /dev/null and b/tests/media/default-folder.jpg differ