Browser ID3 Writer

Pure JS library for writing ID3 (v2.3) tag to MP3 files in browsers and Node.js.
It can't read the tag so use another lib to do it.
Note: the library removes existing ID3 tag (v2.2, v2.3 and v2.4).
Works in Node.js 4+, IE10+ and all modern browsers.
Here is an online demonstration: egoroof.ru/browser-id3-writer/
Table of Contents
Installation
For browsers you can include library via unpkg CDN (2.5 KiB gzip) or save it to local machine:
<script src="https://unpkg.com/browser-id3-writer@3.0.8" crossorigin="anonymous" integrity="sha384-Vu4x2MLn2tvsjtNzj/QUzhEV40nh0LVOOfbAyPiFuskxPbR4242zDbI2F1PAl+i1"></script>
For Node.js and browser module loaders like webpack
, browserify
, etc. install it via npm:
npm install browser-id3-writer --save
Then you will be able to use it:
const ID3Writer = require('browser-id3-writer');
Usage
Browser
Get ArrayBuffer of song
You should first get
ArrayBuffer
of the song you would like to add ID3 tag.
FileReader
For example you can create file input and use
FileReader:
<input type="file" id="file" accept="audio/mpeg">
<script>
document.getElementById('file').addEventListener('change', function () {
if (!this.files.length) {
return;
}
const reader = new FileReader();
reader.onload = function () {
const arrayBuffer = reader.result;
};
reader.onerror = function () {
console.error('Reader error', reader.error);
};
reader.readAsArrayBuffer(this.files[0]);
});
</script>
XMLHttpRequest
To get arrayBuffer from remote server you can use
XMLHttpRequest:
const xhr = new XMLHttpRequest();
xhr.open('GET', urlToSongFile, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
if (xhr.status === 200) {
const arrayBuffer = xhr.response;
} else {
console.error(xhr.statusText + ' (' + xhr.status + ')');
}
};
xhr.onerror = function() {
console.error('Network error');
};
xhr.send();
Add a tag
Create new ID3Writer
instance with arrayBuffer of your song, set frames and add a tag:
const writer = new ID3Writer(arrayBuffer);
writer.setFrame('TIT2', 'Home')
.setFrame('TPE1', ['Eminem', '50 Cent'])
.setFrame('TALB', 'Friday Night Lights')
.setFrame('TYER', 2004)
.setFrame('TRCK', '6/8')
.setFrame('TCON', ['Soundtrack'])
.setFrame('TBPM', 128)
.setFrame('WPAY', 'https://google.com')
.setFrame('TKEY', 'Fbm')
.setFrame('APIC', {
type: 3,
data: coverArrayBuffer,
description: 'Super picture'
});
writer.addTag();
Save file
Now you can save it to file as you want:
const taggedSongBuffer = writer.arrayBuffer;
const blob = writer.getBlob();
const url = writer.getURL();
For example you can save file using FileSaver.js:
saveAs(blob, 'song with tags.mp3');
If you are writing chromium extension you can save file using
Downloads API:
chrome.downloads.download({
url: url,
filename: 'song with tags.mp3'
});
Memory control
When you generate URLs via writer.getURL()
you should know
that whole file is kept in memory until you close the page or move to another one.
So if you generate lots of URLs in a single page you should manually free memory
after you finish downloading file:
URL.revokeObjectURL(url);
writer.revokeURL();
Node.js
Simple example with blocking IO:
const ID3Writer = require('browser-id3-writer');
const fs = require('fs');
const songBuffer = fs.readFileSync('path_to_song.mp3');
const coverBuffer = fs.readFileSync('path_to_cover.jpg');
const writer = new ID3Writer(songBuffer);
writer.setFrame('TIT2', 'Home')
.setFrame('TPE1', ['Eminem', '50 Cent'])
.setFrame('TALB', 'Friday Night Lights')
.setFrame('TYER', 2004)
.setFrame('APIC', {
type: 3,
data: coverBuffer,
description: 'Super picture'
});
writer.addTag();
const taggedSongBuffer = Buffer.from(writer.arrayBuffer);
fs.writeFileSync('song_with_tags.mp3', taggedSongBuffer);
You can also create only ID3 tag without song and use it as you want:
const writer = new ID3Writer(Buffer.alloc(0));
writer.padding = 0;
writer.setFrame('TIT2', 'Home');
writer.addTag();
const id3Buffer = Buffer.from(writer.arrayBuffer);
Supported frames
Have not found needed frame? Open a new issue and we'll discuss it.
array of strings:
- TPE1 (song artists)
- TCOM (song composers)
- TCON (song genres)
string
- TIT2 (song title)
- TALB (album title)
- TPE2 (album artist)
- TPE3 (conductor/performer refinement)
- TPE4 (interpreted, remixed, or otherwise modified by)
- TRCK (song number in album): '5' or '5/10'
- TPOS (album disc number): '1' or '1/3'
- TPUB (label name)
- TKEY (initial key)
- TMED (media type)
- WCOM (commercial information)
- WCOP (copyright/Legal information)
- WOAF (official audio file webpage)
- WOAR (official artist/performer webpage)
- WOAS (official audio source webpage)
- WORS (official internet radio station homepage)
- WPAY (payment)
- WPUB (publishers official webpage)
integer
- TLEN (song duration in milliseconds)
- TYER (album release year)
- TBPM (beats per minute)
object
writer.setFrame('COMM', {
description: 'description here',
text: 'text here'
});
- USLT (unsychronised lyrics):
writer.setFrame('USLT', {
description: 'description here',
lyrics: 'lyrics here'
});
- TXXX (user defined text):
writer.setFrame('TXXX', {
description: 'description here',
value: 'value here'
});
writer.setFrame('APIC', {
type: 3,
data: coverArrayBuffer,
description: 'description here'
});
APIC picture types
Type | Name |
---|
0 | Other |
1 | 32x32 pixels 'file icon' (PNG only) |
2 | Other file icon |
3 | Cover (front) |
4 | Cover (back) |
5 | Leaflet page |
6 | Media (e.g. lable side of CD) |
7 | Lead artist/lead performer/soloist |
8 | Artist/performer |
9 | Conductor |
10 | Band/Orchestra |
11 | Composer |
12 | Lyricist/text writer |
13 | Recording Location |
14 | During recording |
15 | During performance |
16 | Movie/video screen capture |
17 | A bright coloured fish |
18 | Illustration |
19 | Band/artist logotype |
20 | Publisher/Studio logotype |