kiwilan / php-audio
PHP package to parse and update audio files metadata, with `JamesHeinrich/getID3`.
Fund package maintenance!
kiwilan
Installs: 1 363
Dependents: 1
Suggesters: 0
Security: 0
Stars: 1
Watchers: 1
Forks: 0
Open Issues: 0
Requires
- php: ^8.1
- james-heinrich/getid3: ^1.9
Requires (Dev)
- laravel/pint: ^1.2
- pestphp/pest: ^1.20
- spatie/ray: ^1.28
README
PHP package to parse and update audio files metadata, with JamesHeinrich/getID3
.
Note
You can check formats supported on Supported formats section.
About
Audio files can use different formats, this package aims to provide a simple way to read them with JamesHeinrich/getID3
. The JamesHeinrich/getID3
package is excellent to read metadata from audio files, but output is just an array, current package aims to provide a simple way to read audio files with a beautiful API.
Requirements
- PHP >= 8.1
- Optional for update
FLAC
:flac
(withapt
,brew
orscoop
)OGG
:vorbis-tools
(withapt
orbrew
) /extras/icecast
(withscoop
)
Roadmap
- Add support for more formats with external packages
Installation
You can install the package via composer:
composer require kiwilan/php-audio
Usage
Core metadata:
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $audio->getTitle(); // `?string` to get title $audio->getArtist(); // `?string` to get artist $audio->getAlbum(); // `?string` to get album $audio->getGenre(); // `?string` to get genre $audio->getYear(); // `?int` to get year $audio->getTrackNumber(); // `?string` to get track number $audio->getComment(); // `?string` to get comment $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->getEncoding(); // `?string` to get encoding $audio->getDescription(); // `?string` to get description (audiobook) $audio->getLyrics(); // `?string` (audiobook) $audio->getStik(); // `?string` (audiobook) $audio->getDuration(); // `?float` to get duration in seconds
Additional metadata:
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $audio->getPath(); // `string` to get path $audio->hasCover(); // `bool` to know if has cover $audio->isValid(); // `bool` to know if file is valid audio file $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)
Advanced properties:
use Kiwilan\Audio\Audio; $audio = Audio::get('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->getCover(); // `?AudioCover` with cover metadata
Update
You can update audio files metadata with Audio::class
, but not all formats are supported. See supported formats
Warning
You can use any property of Audio::class
but if you use a property not supported by the format, it will be ignored.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $audio->getTitle(); // `Title` $tag = $audio->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') ->creationDate('2021-01-01') ->description('New Description') ->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(); $audio = Audio::get('path/to/audio.mp3'); $audio->getTitle(); // `New Title` $audio->getCreationDate(); // `null` because `creationDate` is not supported by `MP3`
Some properties are not supported by all formats, for example MP3
can't handle some properties like lyrics
or stik
, if you try to update these properties, they will be ignored.
Set tags manually
You can set tags manually with tags
method, but you need to know the format of the tag, you could use tagFormats
to set formats of tags (if you don't know the format, it will be automatically detected).
Warning
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.
If your key is not supported, save
method will throw an exception, unless you use preventFailOnErrors
.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $audio->getAlbumArtist(); // `Band` $tag = $audio->update() ->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` ]) ->tagFormats(['id3v1', 'id3v2.4']) // optional ->save(); $audio = Audio::get('path/to/audio.mp3'); $audio->getAlbumArtist(); // `New Band`
Arrow functions
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $audio->getAlbumArtist(); // `Band` $tag = $audio->update() ->title('New Title') ->albumArtist('New Band') // `albumArtist` will set `band` for `id3v2`, exception safe ->save(); $audio = Audio::get('path/to/audio.mp3'); $audio->getAlbumArtist(); // `New Band`
Prevent fail on errors
You can use preventFailOnError
to prevent exception if you use unsupported format.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $tag = $audio->update() ->tags([ 'title' => 'New Title', 'title2' => 'New title', // not supported by `id3v2`, will throw an exception ]) ->preventFailOnError() // will prevent exception ->save();
Arrow functions are exception safe for properties but not for unsupported formats.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $tag = $audio->update() ->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();
Tags and cover
Of course you can add cover with tags
method.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $cover = 'path/to/cover.jpg'; $image = getimagesize($cover); $coverData = file_get_contents($cover); $coverPicturetypeid = $image[2]; $coverDescription = 'cover'; $coverMime = $image['mime']; $tag = $audio->update() ->tags([ 'title' => 'New Title', 'band' => 'New Band', 'attached_picture' => [ [ 'data' => $coverData, 'picturetypeid' => $coverPicturetypeid, 'description' => $coverDescription, 'mime' => $coverMime, ], ], ]) ->save();
Merge tags
Merge tags
with arrow functions.
use Kiwilan\Audio\Audio; $audio = Audio::get($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::get($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
...
If you want to extract specific field which can be skipped by Audio::class
, you can use extras
property.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $extras = $audio->getExtras(); $id3v2 = $extras['id3v2'] ?? [];
AudioMetadata
use Kiwilan\Audio\Audio; $audio = Audio::get('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`
AudioCover
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $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
Supported formats
Readable formats
id3v2
will be selected beforeid3v1
orriff
if both are available.
Format | Supported | About | ID3 type | Notes |
---|---|---|---|---|
AAC | ❌ | Advanced Audio Coding | ||
ALAC | ✅ | Apple Lossless Audio Codec | quicktime |
|
AIF | ✅ | Audio Interchange File Format (aif) | id3v2 ,riff |
|
AIFC | ✅ | Audio Interchange File Format (aifc) | id3v2 ,riff |
|
AIFF | ✅ | Audio Interchange File Format (aiff) | id3v2 ,riff |
|
DSF | ❌ | Direct Stream Digital Audio | ||
FLAC | ✅ | Free Lossless Audio Codec | vorbiscomment |
|
MKA | ✅ | Matroska | matroska |
Cover not supported |
MKV | ✅ | Matroska | matroska |
Cover not supported |
APE | ❌ | Monkey's Audio | ||
MP3 | ✅ | MPEG audio layer 3 | id3v2 ,id3v1 |
|
MP4 | ✅ | Digital multimedia container format | quicktime |
|
M4A | ✅ | mpeg-4 audio | quicktime |
|
M4B | ✅ | Audiobook | quicktime |
|
M4V | ✅ | mpeg-4 video | quicktime |
|
MPC | ❌ | Musepack | ||
OGG | ✅ | Open container format | vorbiscomment |
|
OPUS | ✅ | IETF Opus audio | vorbiscomment |
|
OFR | ❌ | OptimFROG | ||
OFS | ❌ | OptimFROG | ||
SPX | ✅ | Speex | vorbiscomment |
Cover not supported |
TAK | ❌ | Tom's Audio Kompressor | ||
TTA | ✅ | True Audio | ape |
Cover not supported |
WMA | ✅ | Windows Media Audio | asf |
Cover not supported |
WV | ✅ | WavPack | ape |
|
WAV | ✅ | Waveform Audio | id3v2 ,riff |
|
WEBM | ✅ | WebM | matroska |
Cover not supported |
You want to add a format? See FAQ
Updatable formats
JamesHeinrich/getID3
can update some formats, but not all.
- ID3v1 (v1 & v1.1)
- ID3v2 (v2.3, v2.4)
- APE (v2)
- Ogg Vorbis comments (need
vorbis-tools
)- FLAC comments (need
flac
)
Format | Notes | Requires |
---|---|---|
FLAC | Cover not supported | flac |
MP3 | ||
OGG | Cover not supported | vorbis-tools |
flac
: withapt
,brew
orscoop
vorbis-tools
: withapt
,brew
orscoop
- With
scoop
,vorbis-tools
is not available, you can useextras/icecast
instead.
- With
Convert properties
Audio::class
convert some properties to be more readable.
ID3 type | Original | New property |
---|---|---|
id3v2 |
band |
albumArtist |
id3v2 |
track_number |
trackNumber |
id3v2 |
part_of_a_set |
discNumber |
id3v2 |
part_of_a_compilation |
isCompilation |
quicktime |
track_number |
trackNumber |
quicktime |
disc_number |
discNumber |
quicktime |
compilation |
isCompilation |
quicktime |
creation_date |
creationDate |
quicktime |
album_artist |
albumArtist |
quicktime |
encoded_by |
encodingBy |
quicktime |
encoding_tool |
encoding |
quicktime |
description_long |
description * |
asf |
albumartist |
albumArtist |
asf |
partofset |
discNumber |
asf |
track_number |
trackNumber |
asf |
encodingsettings |
encoding |
vorbiscomment |
encoder |
encoding |
vorbiscomment |
albumartist |
albumArtist |
vorbiscomment |
discnumber |
discNumber |
vorbiscomment |
compilation |
isCompilation |
vorbiscomment |
tracknumber |
trackNumber |
matroska |
album_artist |
albumArtist |
matroska |
disc |
discNumber |
matroska |
part_number |
trackNumber |
matroska |
date |
year |
matroska |
compilation |
isCompilation |
matroska |
encoder |
encoding |
ape |
album_artist |
albumArtist |
ape |
disc |
discNumber |
ape |
compilation |
isCompilation |
ape |
track |
trackNumber |
ape |
date |
year |
ape |
encoder |
encoding |
*: if description_long
has more content than description
, it replaces description
.
Testing
composer test
Tools
- ffmpeg: free and open-source software project consisting of a suite of libraries and programs for handling video, audio, and other multimedia files and streams.
- MP3TAG: powerful and easy-to-use tool to edit metadata of audio files (free on Windows).
- Audiobook Builder: makes it easy to turn audio CDs and files into audiobooks (only macOS and paid).
- Tag Editor: A tag editor with Qt GUI and command-line interface supporting MP4/M4A/AAC (iTunes), ID3, Vorbis, Opus, FLAC and Matroska.
- Tag Editor: a spreadsheet application for editing audio metadata in a simple, fast, and flexible way.
FAQ
I have a specific metadata field in my audio files, what can I do?
In Audio::class
, you have a property extras
which contains all raw metadata, if JamesHeinrich/getID3
support this field, you will find it in this property.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $extras = $audio->getExtras(); $custom = null; $id3v2 = $extras['id3v2'] ?? []; if ($id3v2) { $custom = $id3v2['custom'] ?? null; }
If your field could be added to global properties of Audio::class
, you could create an an issue.
Metadata are null
, what can I do?
You can check extras
property to know if some metadata are available.
use Kiwilan\Audio\Audio; $audio = Audio::get('path/to/audio.mp3'); $extras = $audio->getExtras(); var_dump($extras);
If you find metadata which are not parsed by Audio::class
, you can create an issue, otherwise JamesHeinrich/getID3
doesn't support this metadata.z
My favorite format is not supported, what can I do?
You can create an issue with the format name and a link to the format documentation. If JamesHeinrich/getID3
support this format, I will add it to this package but if you want to contribute, you can create a pull request with the format implementation.
Please give me an example file to test the format.
I have an issue with a supported format, what can I do?
You can create an issue with informations.
How to convert audio files?
This package doesn't provide a way to convert audio files, but you can use ffmpeg to convert audio files and PHP-FFMpeg/PHP-FFMpeg.
Changelog
Please see CHANGELOG for more information on what has changed recently.
Credits
- Ewilan Rivière: package author
- JamesHeinrich/getID3: parser used to read audio files
- spatie/package-skeleton-php: package skeleton used to create this package
- Tests files from p1pdd.com (episode 00)
License
The MIT License (MIT). Please see License File for more information.