diff --git a/README.md b/README.md index abe1f22..cbebf2b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Audio files can use different formats, this package aims to provide a simple way ## Requirements -- PHP >= 8.1 +- PHP `8.1` minimum - Optional for update - `FLAC`: `flac` (with `apt`, `brew` or `scoop`) - `OGG`: `vorbis-tools` (with `apt` or `brew`) / `extras/icecast` (with `scoop`) @@ -58,15 +58,15 @@ $audio->getAlbumArtist(); // `?string` to get album artist $audio->getComposer(); // `?string` to get composer $audio->getDiscNumber(); // `?string` to get disc number $audio->isCompilation(); // `bool` to know if is compilation -$audio->getCreationDate(); // `?string` to get creation date (audiobook) -$audio->getCopyright(); // `?string` to get copyright (audiobook) +$audio->getCreationDate(); // `?string` to get creation date +$audio->getCopyright(); // `?string` to get copyright $audio->getEncoding(); // `?string` to get encoding -$audio->getDescription(); // `?string` to get description (audiobook) -$audio->getPodcastDescription(); // `?string` to get podcast description (audiobook) +$audio->getDescription(); // `?string` to get description +$audio->getSynopsis(); // `?string` to get synopsis $audio->getLanguage(); // `?string` to get language -$audio->getLyrics(); // `?string` (audiobook) -$audio->getStik(); // `?string` (audiobook) +$audio->getLyrics(); // `?string` $audio->getDuration(); // `?float` to get duration in seconds +$audio->getDurationHuman(); // `?string` to get duration in human readable format ``` Raw tags: @@ -76,13 +76,12 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); -$audio->getTags(); // `array` with all tags -$title = $audio->getTag('title'); // `?string` to get title same as `$audio->getTitle()` +$raw_all = $audio->getRawAll(); // `array` with all tags +$raw = $audio->getRaw(); // `array` with main tag +$title = $audio->getRawKey('title'); // `?string` to get title same as `$audio->getTitle()` -$formats = $audio->getAudioFormats(); // `array` with all audio formats - -$format = $audio->getTags('id3v2'); // `?array` with all tags with format `id3v2` -$title = $audio->getTag('title', 'id3v2'); // `?string` to get title with format `id3v2` +$format = $audio->getRaw('id3v2'); // `?array` with all tags with format `id3v2` +$title = $audio->getRawKey('title', 'id3v2'); // `?string` to get title with format `id3v2` ``` Additional metadata: @@ -93,18 +92,15 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); $audio->getPath(); // `string` to get path +$audio->getExtension(); // `string` to get extension $audio->hasCover(); // `bool` to know if has cover $audio->isValid(); // `bool` to know if file is valid audio file +$audio->isWritable(); // `bool` to know if file is writable $audio->getFormat(); // `AudioFormatEnum` to get format (mp3, m4a, ...) $audio->getType(); // `?AudioTypeEnum` ID3 type (id3, riff, asf, quicktime, matroska, ape, vorbiscomment) -$audio->getExtras(); // `array` with raw metadata (could contains some metadata not parsed) ``` -Raw audio: - -> [!NOTE] -> -> Cover is removed from `toArray()` method, you can use `getCover()` method to get cover metadata. +You can use `toArray()` method to get raw info: ```php use Kiwilan\Audio\Audio; @@ -121,10 +117,8 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); -$audio->getReader(); // `?Id3Reader` reader based on `getID3` -$audio->getWriter(); // `?Id3Writer` writer based on `getid3_writetags` -$audio->getStat(); // `AudioStat` (from `stat` function) -$audio->getAudio(); // `?AudioMetadata` with audio metadata +$audio->getId3Reader(); // `?Id3Reader` reader based on `getID3` +$audio->getMetadata(); // `?AudioMetadata` with audio metadata $audio->getCover(); // `?AudioCover` with cover metadata ``` @@ -142,7 +136,7 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); $audio->getTitle(); // `Title` -$tag = $audio->update() +$tag = $audio->write() ->title('New Title') ->artist('New Artist') ->album('New Album') @@ -154,12 +148,12 @@ $tag = $audio->update() ->composer('New Composer') ->creationDate('2021-01-01') ->description('New Description') + ->synopsis('New Synopsis') ->discNumber('2/2') ->encodingBy('New Encoding By') ->encoding('New Encoding') ->isCompilation() ->lyrics('New Lyrics') - ->stik('New Stik') ->cover('path/to/cover.jpg') // you can use file content `file_get_contents('path/to/cover.jpg')` ->save(); @@ -178,6 +172,7 @@ You can set tags manually with `tags` method, but you need to know the format of > > If you use `tags` method, you have to use key used by metadata container. For example, if you want to set album artist in `id3v2`, you have to use `band` key. If you want to know which key to use check `src/Models/AudioCore.php` file. > +> You can't use other methods with `tags()` method. > If your key is not supported, `save` method will throw an exception, unless you use `preventFailOnErrors`. ```php @@ -186,7 +181,7 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); $audio->getAlbumArtist(); // `Band` -$tag = $audio->update() +$tag = $audio->write() ->tags([ 'title' => 'New Title', 'band' => 'New Band', // `band` is used by `id3v2` to set album artist, method is `albumArtist` but `albumArtist` key will throw an exception with `id3v2` @@ -206,7 +201,7 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); $audio->getAlbumArtist(); // `Band` -$tag = $audio->update() +$tag = $audio->write() ->title('New Title') ->albumArtist('New Band') // `albumArtist` will set `band` for `id3v2`, exception safe ->save(); @@ -224,7 +219,7 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); -$tag = $audio->update() +$tag = $audio->write() ->tags([ 'title' => 'New Title', 'title2' => 'New title', // not supported by `id3v2`, will throw an exception @@ -240,7 +235,7 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); -$tag = $audio->update() +$tag = $audio->write() ->encoding('New encoding') // not supported by `id3v2`, BUT will not throw an exception ->preventFailOnError() // if you have some errors with unsupported format for example, you can prevent exception ->save(); @@ -262,7 +257,7 @@ $coverPicturetypeid = $image[2]; $coverDescription = 'cover'; $coverMime = $image['mime']; -$tag = $audio->update() +$tag = $audio->write() ->tags([ 'title' => 'New Title', 'band' => 'New Band', @@ -278,29 +273,6 @@ $tag = $audio->update() ->save(); ``` -#### Merge tags - -Merge `tags` with arrow functions. - -```php -use Kiwilan\Audio\Audio; - -$audio = Audio::read($path); - -$tag = $audio->update() - ->title('New Title') // will be merged with `tags` and override `title` key - ->tags([ - 'title' => 'New Title tag', - 'band' => 'New Band', - ]); - -$tag->save(); - -$audio = Audio::read($path); -expect($audio->getTitle())->toBe('New Title'); -expect($audio->getAlbumArtist())->toBe('New Band'); -``` - ### Extras Audio files format metadata with different methods, `JamesHeinrich/getID3` offer to check these metadatas by different methods. In `extras` property of `Audio::class`, you will find raw metadata from `JamesHeinrich/getID3` package, like `id3v2`, `id3v1`, `riff`, `asf`, `quicktime`, `matroska`, `ape`, `vorbiscomment`... @@ -322,20 +294,36 @@ $id3v2 = $extras['id3v2'] ?? []; use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); - -$audio->getAudio()->getFilesize(); // `?int` in bytes -$audio->getAudio()->getExtension(); // `?string` (mp3, m4a, ...) -$audio->getAudio()->getEncoding(); // `?string` (UTF-8...) -$audio->getAudio()->getMimeType(); // `?string` (audio/mpeg, audio/mp4, ...) -$audio->getAudio()->getDurationSeconds(); // `?float` in seconds -$audio->getAudio()->getDurationReadable(); // `?string` (00:00:00) -$audio->getAudio()->getBitrate(); // `?int` in kbps -$audio->getAudio()->getBitrateMode(); // `?string` (cbr, vbr, ...) -$audio->getAudio()->getSampleRate(); // `?int` in Hz -$audio->getAudio()->getChannels(); // `?int` (1, 2, ...) -$audio->getAudio()->getChannelMode(); // `?string` (mono, stereo, ...) -$audio->getAudio()->getLossless(); // `bool` to know if is lossless -$audio->getAudio()->getCompressionRatio(); // `?float` +$metadata = $audio->getMetadata(); + +$metadata->getFileSize(); // `?int` in bytes +$metadata->getSizeHuman(); // `?string` (1.2 MB, 1.2 GB, ...) +$metadata->getExtension(); // `?string` (mp3, m4a, ...) +$metadata->getEncoding(); // `?string` (UTF-8...) +$metadata->getMimeType(); // `?string` (audio/mpeg, audio/mp4, ...) +$metadata->getDurationSeconds(); // `?float` in seconds +$metadata->getDurationReadable(); // `?string` (00:00:00) +$metadata->getBitrate(); // `?int` in kbps +$metadata->getBitrateMode(); // `?string` (cbr, vbr, ...) +$metadata->getSampleRate(); // `?int` in Hz +$metadata->getChannels(); // `?int` (1, 2, ...) +$metadata->getChannelMode(); // `?string` (mono, stereo, ...) +$metadata->isLossless(); // `bool` to know if is lossless +$metadata->getCompressionRatio(); // `?float` +$metadata->getFilesize(); // `?int` in bytes +$metadata->getSizeHuman(); // `?string` (1.2 MB, 1.2 GB, ...) +$metadata->getDataFormat(); // `?string` (mp3, m4a, ...) +$metadata->getCodec(); // `?string` (mp3, aac, ...) +$metadata->getEncoderOptions(); // `?string` +$metadata->getVersion(); // `?string` +$metadata->getAvDataOffset(); // `?int` in bytes +$metadata->getAvDataEnd(); // `?int` in bytes +$metadata->getFilePath(); // `?string` +$metadata->getFilename(); // `?string` +$metadata->getLastAccessAt(); // `?DateTime` +$metadata->getCreatedAt(); // `?DateTime` +$metadata->getModifiedAt(); // `?DateTime` +$metadata->toArray(); ``` ### AudioCover @@ -344,11 +332,12 @@ $audio->getAudio()->getCompressionRatio(); // `?float` use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); +$cover = $audio->getCover(); -$audio->getCover()->getContents(); // `?string` raw file -$audio->getCover()->getMimeType(); // `?string` (image/jpeg, image/png, ...) -$audio->getCover()->getWidth(); // `?int` in pixels -$audio->getCover()->getHeight(); // `?int` in pixels +$cover->getContents(); // `?string` raw file +$cover->getMimeType(); // `?string` (image/jpeg, image/png, ...) +$cover->getWidth(); // `?int` in pixels +$cover->getHeight(); // `?int` in pixels ``` ## Supported formats @@ -475,10 +464,10 @@ In `Audio::class`, you have a property `extras` which contains all raw metadata, use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); -$extras = $audio->getExtras(); +$raw_all = $audio->getRawAll()); $custom = null; -$id3v2 = $extras['id3v2'] ?? []; +$id3v2 = $raw_all['id3v2'] ?? []; if ($id3v2) { $custom = $id3v2['custom'] ?? null; @@ -496,7 +485,7 @@ use Kiwilan\Audio\Audio; $audio = Audio::read('path/to/audio.mp3'); -$extras = $audio->getExtras(); +$extras = $audio->getRawAll(); var_dump($extras); ``` diff --git a/src/Audio.php b/src/Audio.php index 959a267..b3525fe 100755 --- a/src/Audio.php +++ b/src/Audio.php @@ -145,11 +145,21 @@ public function getId3Reader(): ?Id3Reader return Id3Reader::make($this->path); } - public function update(): Id3Writer + public function write(): Id3Writer { return Id3Writer::make($this); } + /** + * @deprecated Use `write()` method instead. + * + * Update audio file. + */ + public function update(): Id3Writer + { + return $this->write(); + } + /** * Get duration of the audio file in seconds, limited to 2 decimals, like `180.66` * @@ -444,14 +454,39 @@ public function getRawKey(string $key, ?string $format = null): string|int|bool| return $tags[$key] ?? null; } - /** - * Get raw tags as array with main format, same as `getRaw()`. - * - * @return string[] - */ - public function getExtras(): array - { - return $this->getRaw(); + public function toArray(): array + { + return [ + 'path' => $this->path, + 'extension' => $this->extension, + 'format' => $this->format, + 'type' => $this->type, + 'metadata' => $this->metadata?->toArray(), + 'cover' => $this->cover?->toArray(), + 'duration' => $this->duration, + 'is_writable' => $this->is_writable, + 'is_valid' => $this->is_valid, + 'has_cover' => $this->has_cover, + 'title' => $this->title, + 'artist' => $this->artist, + 'album' => $this->album, + 'genre' => $this->genre, + 'year' => $this->year, + 'track_number' => $this->track_number, + 'comment' => $this->comment, + 'album_artist' => $this->album_artist, + 'composer' => $this->composer, + 'disc_number' => $this->disc_number, + 'is_compilation' => $this->is_compilation, + 'creation_date' => $this->creation_date, + 'encoding_by' => $this->encoding_by, + 'encoding' => $this->encoding, + 'description' => $this->description, + 'synopsis' => $this->synopsis, + 'language' => $this->language, + 'lyrics' => $this->lyrics, + 'raw_tags_all' => $this->raw_tags_all, + ]; } private function parseTags(?\Kiwilan\Audio\Id3\Id3Reader $id3_reader): self diff --git a/src/Id3/Id3Writer.php b/src/Id3/Id3Writer.php index 279cdc0..533aa18 100644 --- a/src/Id3/Id3Writer.php +++ b/src/Id3/Id3Writer.php @@ -251,7 +251,7 @@ public function language(?string $language): self * Example: * * ```php - * $audio->update()->tag('series-part', '1'); + * $audio->write()->tag('series-part', '1'); * ``` */ public function tag(string $key, string|int|bool|null $value): self diff --git a/src/Models/AudioCover.php b/src/Models/AudioCover.php index 4bed270..fabe1b7 100644 --- a/src/Models/AudioCover.php +++ b/src/Models/AudioCover.php @@ -74,4 +74,14 @@ public function extractCover(string $path): void { file_put_contents($path, $this->getContents()); } + + public function toArray(): array + { + return [ + 'contents' => $this->contents, + 'mime_type' => $this->mime_type, + 'width' => $this->width, + 'height' => $this->height, + ]; + } } diff --git a/src/Models/AudioMetadata.php b/src/Models/AudioMetadata.php index 11d51b3..4e049dc 100644 --- a/src/Models/AudioMetadata.php +++ b/src/Models/AudioMetadata.php @@ -262,4 +262,32 @@ public function getModifiedAt(): ?DateTime { return $this->modified_at; } + + public function toArray(): array + { + return [ + 'file_size' => $this->file_size, + 'data_format' => $this->data_format, + 'encoding' => $this->encoding, + 'mime_type' => $this->mime_type, + 'duration_seconds' => $this->duration_seconds, + 'bitrate' => $this->bitrate, + 'bitrate_mode' => $this->bitrate_mode, + 'sample_rate' => $this->sample_rate, + 'channels' => $this->channels, + 'channel_mode' => $this->channel_mode, + 'is_lossless' => $this->is_lossless, + 'compression_ratio' => $this->compression_ratio, + 'codec' => $this->codec, + 'encoder_options' => $this->encoder_options, + 'version' => $this->version, + 'av_data_offset' => $this->av_data_offset, + 'av_data_end' => $this->av_data_end, + 'file_path' => $this->file_path, + 'filename' => $this->filename, + 'last_access_at' => $this->last_access_at?->format('Y-m-d H:i:s'), + 'created_at' => $this->created_at?->format('Y-m-d H:i:s'), + 'modified_at' => $this->modified_at?->format('Y-m-d H:i:s'), + ]; + } } diff --git a/tests/AudioCoverTest.php b/tests/AudioCoverTest.php index 39fe984..3d7e375 100644 --- a/tests/AudioCoverTest.php +++ b/tests/AudioCoverTest.php @@ -32,3 +32,14 @@ expect($cover)->toBeNull(); } })->with([...AUDIO]); + +it('can read as array', function (string $path) { + $audio = Audio::read($path); + $cover = $audio->getCover(); + + if ($cover) { + expect($cover->toArray())->toBeArray(); + } else { + expect($cover)->toBeNull(); + } +})->with([...AUDIO]); diff --git a/tests/AudioMetadataTest.php b/tests/AudioMetadataTest.php index 83ca080..ec5a0cc 100644 --- a/tests/AudioMetadataTest.php +++ b/tests/AudioMetadataTest.php @@ -85,3 +85,10 @@ expect($metadata->getEncoderOptions())->toBeString(); } })->with([...AUDIO]); + +it('can read as array', function (string $path) { + $audio = Audio::read($path); + $metadata = $audio->getMetadata(); + + expect($metadata->toArray())->toBeArray(); +})->with([...AUDIO]); diff --git a/tests/AudioMp3Test.php b/tests/AudioMp3Test.php index dd7fd70..36d8bb5 100644 --- a/tests/AudioMp3Test.php +++ b/tests/AudioMp3Test.php @@ -54,7 +54,6 @@ expect($audio->getRaw())->toHaveCount(11); expect($audio->getRaw('id3v2'))->toHaveCount(11); expect($audio->getRawKey('title'))->toBe('Introduction'); - expect($audio->getExtras())->toBeArray(); $cover = $audio->getCover(); expect($cover)->toBeInstanceOf(AudioCover::class); diff --git a/tests/AudioTest.php b/tests/AudioTest.php index 5b38efe..414fde7 100644 --- a/tests/AudioTest.php +++ b/tests/AudioTest.php @@ -80,7 +80,6 @@ expect($audio->getFormat())->toBe($format); expect($audio->getDuration())->toBeFloat(); expect($audio->getDurationHuman())->toBe('00:00:11'); - expect($audio->getExtras())->toBeArray(); expect($audio)->toBeInstanceOf(Audio::class); })->with([...AUDIO_ID3_V1]); @@ -90,3 +89,9 @@ expect($audio->isValid())->toBeFalse(); }); + +it('can read as array', function (string $path) { + $audio = Audio::read($path); + + expect($audio->toArray())->toBeArray(); +})->with([...AUDIO]); diff --git a/tests/AudiobookTest.php b/tests/AudiobookTest.php index be374ef..53eacfb 100644 --- a/tests/AudiobookTest.php +++ b/tests/AudiobookTest.php @@ -123,7 +123,6 @@ expect($audio->getLyrics())->toBe('Lyrics'); expect($audio->getDuration())->toBe(11.00); expect($audio->getDurationHuman())->toBe('00:00:11'); - expect($audio->getExtras())->toBeArray(); expect($audio->getRaw())->toBeArray(); expect($audio->getRawKey('title'))->toBe('P1PDD Saison 1'); diff --git a/tests/Pest.php b/tests/Pest.php index 45ed7dd..4bd0d54 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -189,7 +189,7 @@ function resetMp3Writer() { $audio = Audio::read(MP3_WRITER); - $audio->update() + $audio->write() ->title('Introduction') ->artist('Mr Piouf') ->album('P1PDD Le conclave de Troie') diff --git a/tests/WriterCoverTest.php b/tests/WriterCoverTest.php index 816b173..2f15c3b 100644 --- a/tests/WriterCoverTest.php +++ b/tests/WriterCoverTest.php @@ -8,7 +8,7 @@ it('can update cover', function (string $path) { $audio = Audio::read($path); - $audio->update() + $audio->write() ->cover(FOLDER) ->save(); @@ -22,7 +22,7 @@ it('can read use file content as cover', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->cover(file_get_contents(FOLDER)); $tag->save(); @@ -42,7 +42,7 @@ $coverPicturetypeid = $image[2]; $coverDescription = 'cover'; $coverMime = $image['mime']; - $tag = $audio->update() + $tag = $audio->write() ->tags([ 'title' => $random, 'attached_picture' => [ @@ -67,7 +67,7 @@ it('can use tags with cover', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->tags([ 'title' => 'New Title', ]) @@ -93,7 +93,7 @@ $audio->getCover()->extractCover($path); expect(file_exists($path))->toBeTrue(); - $audio->update() + $audio->write() ->cover(FOLDER) ->handleErrors() ->save(); @@ -110,7 +110,7 @@ it('can remove cover', function () { $audio = Audio::read(MP3_WRITER); - $audio->update() + $audio->write() ->removeCover() ->handleErrors() ->save(); diff --git a/tests/WriterMp3Test.php b/tests/WriterMp3Test.php index 67e2093..3c32ac9 100644 --- a/tests/WriterMp3Test.php +++ b/tests/WriterMp3Test.php @@ -10,7 +10,7 @@ $audio = Audio::read(MP3_WRITER); testMp3Writer($audio); - $audio->update() + $audio->write() ->title('New Title') ->artist('New Artist') ->album('New Album') @@ -44,7 +44,7 @@ $audio = Audio::read(MP3_WRITER); testMp3Writer($audio); - $audio->update() + $audio->write() ->title('New Title') ->save(); @@ -66,7 +66,7 @@ $audio = Audio::read(MP3_WRITER); testMp3Writer($audio); - $audio->update() + $audio->write() ->tags([ 'title' => 'New Title', 'artist' => 'New Artist', diff --git a/tests/WriterTest.php b/tests/WriterTest.php index 0e9e9ab..e40c572 100644 --- a/tests/WriterTest.php +++ b/tests/WriterTest.php @@ -11,7 +11,7 @@ it('can update file', function (string $path) { $audio = Audio::read($path); $random = (string) rand(1, 1000); - $audio->update() + $audio->write() ->title($random) ->artist('New Artist') ->album('New Album') @@ -64,7 +64,7 @@ $audio = Audio::read($path); $random = (string) rand(1, 1000); - $tag = $audio->update() + $tag = $audio->write() ->tags([ 'title' => $random, ]) @@ -79,7 +79,7 @@ it('can update with tags and handle native metadata', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->isCompilation() ->tags([ 'title' => 'New Title', @@ -98,7 +98,7 @@ it('can use arrow function safe with unsupported tags', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->title('New Title') ->encoding('New encoding'); @@ -111,7 +111,7 @@ it('can get core before save', function (string $path) { $audio = Audio::read($path); - $writer = $audio->update() + $writer = $audio->write() ->title('New Title') ->tags([ 'title' => 'New Title tag', @@ -124,7 +124,7 @@ it('can handle exceptions', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->tags([ 'title' => 'New Title', 'albumArtist' => 'New Album Artist', @@ -137,7 +137,7 @@ it('can skip exceptions', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->tags([ 'title' => 'New Title', 'albumArtist' => 'New Album Artist', @@ -154,7 +154,7 @@ $audio = Audio::read($path); $newPath = 'tests/output/new.mp3'; - $tag = $audio->update() + $tag = $audio->write() ->title('New Title') ->path($newPath); @@ -167,7 +167,7 @@ it('can update with merged tags and core methods', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->tags([ 'title' => 'New Title tag', 'band' => 'New Band', @@ -182,7 +182,7 @@ it('can use arrow function safe with unsupported formats', function (string $path) { $audio = Audio::read($path); - $tag = $audio->update() + $tag = $audio->write() ->handleErrors() ->title('New Title Alac'); @@ -193,7 +193,7 @@ $audio = Audio::read($path); $newPath = 'tests/output/new.mp3'; - $tag = $audio->update() + $tag = $audio->write() ->title('New Title') ->removeOtherTags() ->path($newPath);