zazama / node-id3 Goto Github PK
View Code? Open in Web Editor NEWPure JavaScript ID3 Tag library
License: MIT License
Pure JavaScript ID3 Tag library
License: MIT License
I'm dealing with images and had to write my own wrapper functions to deal with updating single tag in a file. More hassle when I have to deal with images. Would be nice to have update / upsert feature as part of this module.
I do a simple read, make some updates to title, album, then write back to MP3 file.
But once I write, the artwork is gone.
Even when I do a read then write exact content that I read, the art work is gone after the write.
Something like below makes the artwork disappear or unusable.
const tags: any = await nodeID3.read(fullPathNew);
await nodeID3.write(tags, fullPathNew);
I use WinAmp to check the tag contents including the artwork.
Before I run above code, the artwork shows, but after running above code, the artwork does not show. Please fix this problem or share how I can preserve the artwork. Other than this issue, this is a great module!
Hey guys im trying to create a webservice w/ nodejs and express. Basically i just want to respond the corresponding albumart for a specific file:
//... (in a express method)
var meta = NodeID3.read(path);
if(meta.image){
res.set('Content-Type', 'image/' + meta.image.mime);
res.send(meta.image.imageBuffer);
}
//...
I tried it on several mp3 files - all without success.
Postman shows just this "empty" image
And the corresponding header infos
I even exported the file onto my local fs with fs.writeFileSync("test.png", meta.image.imageBuffer, 'binary');
.
This is whats returned:
Before i forget, this album cover should look like this:
I have a need to build iD3 tags but not for file storage. Rather I need to send the tag data to an encoding service.
I refactored the code a bit to extract the iD3 creation code from the write
method. I'd like to submit a pull request but wanted to check with you guys first. ;-)
https://github.com/cjus/node-id3/blob/id3-buffer-create/index.js
The asynchronous update has no effect. No new tags are set.
I used (a piece) of the example code to reproduce it.
Could you please add support for mp3 chapters? The specs are here: http://id3.org/id3v2-chapters-1.0
The spec is 15 years old, and yet there's no js/node lib out there that can handle them, so yours would be the first. :)
Example file. The cover image extracted using mp3tag is this file.
I saw that release v0.1.6 was related to ID3 v2.4, but according to @kbuffington, is ID3 v2.4 actually not yet supported?
Originally posted by @hexrcs in #45 (comment)
The APIC frame in this file has n/p indicators set, which breaks the supported header length of node-id3.
See 4.1.2 http://id3.org/id3v2.4.0-structure
Hello,
Figured out any attempt to update a tag, deletes the album art (the picture of the file)
What is the solution?
I'm getting the following error when trying to read tags from a 9.7MB MP3:
RangeError: "size" argument must not be larger than 2147483647
at Function.Buffer.alloc (buffer.js:229:3)
at new Buffer (buffer.js:152:19)
at NodeID3.getTagsFromBuffer (.../node_modules/node-id3/index.js:318:31)
at NodeID3.read (.../node_modules/node-id3/index.js:226:25)
at Object.<anonymous> (.../index.js:40:24)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
Snippet:
const file = 'sample.mp3'
const buf = fs.readFileSync(file)
console.log(buf.length)
// 9673454
try {
let tags = NodeID3.read(file)
} catch (err) {
console.log(err)
}
Environment:
Update:
I added console.log(bodyFrameHeader.toString('utf8', 0, 4) + ' ' + bodyFrameSize)
to try to debug what was flagging the size limit; here's the output:
TPE2 29
TPOS 9
WCOP 17
WOAR 40
TLEN 4
TMED 29
TXXX 29
TXXX 31
TXXX 39
TXXX 59
TXXX 31
TXXX 37
TXXX 25
GEOB 100
TXXX 31
GEOB 110
PRIV 334456
�� 3363242937
When trying to save the following names on the Artist
tag of a file, broken characters appear.
Strings I'm trying to save:
分島花音
ナノ
Both get converted to, respectively:
�ö±ó
ÊÎ
When trying to save the following string to the Title
tag, same thing happens:
Dark Night Rhapsody~明けない夜の狂詩曲
This is being saved as:
Dark Night Rhapsody^�QjD�nÂiò
Any ideas?
if(SFrames[SRawToNameMap[tag]].multiple && currentTags[tag] && rawTags[tag])
^
TypeError: Cannot read property 'multiple' of undefined
at C:\test\nodejs-test\node_modules\node-id3\index.js:284:44
at Array.map (<anonymous>)
at NodeID3.update (C:\test\nodejs-test\node_modules\node-id3\index.js:283:30)
at Object.<anonymous> (C:\test\nodejs-test\test_node-id3.js:12:23)
test_node-id3.js:
var nodeID3 = require('node-id3');
var tags = {
title: 'title',
album: 'album'
};
var path = "test.mp3";
console.log( "\nWriting tags: %s to file %s", JSON.stringify(tags), path );
let success = nodeID3.update(tags, path);
console.log(success ? "Ok" : "Failed");
With the following file (generated with audacity version 2.1.3):
01.zip
Using the following code I can't read any tags from the file, updating the tags (commented out code) will destroy the tags in the file in both Nautilus file browser properties and Rythmbox.
// "dependencies": {
// "glob": "^7.1.2",
// "node-id3": "^0.1.5"
// }
//node version: v10.8.0
const NodeID3 = require('node-id3');
const glob = require("glob");
const getGlob = ()=>{
if(!process.argv[2]){
console.log("need to provide path to files");
process.exit(1);
}
const ret = `${process.argv[2]}/*.mp3`;
console.log("Using glob:",ret);
return ret;
};
readTags = file =>
new Promise(
(resolve,reject)=>
NodeID3.read(
file,
(err, tags) =>
err?reject(err):resolve(tags)
)
)
;
const createTag = tags =>
new Promise(
(resolve,reject)=>
NodeID3.create(
tags,
frame=>resolve(frame)
)
)
;
const updateTag = (tags,file)=>
new Promise(
(resolve,reject)=>
NodeID3.update(
tags,
file,
(err, buffer)=>err?reject(err):resolve(buffer)
)
)
;
const globPromise = (path,options)=>
new Promise(
(resolve,reject)=>
glob(
path,
options,
(err,files)=>
err
?reject(err)
:resolve(files))
)
;
globPromise(getGlob(), {})
.then(
files=>
// updateTag(NodeID3.create(tags[0]),files[0])
// updateTag(tags[0],files[0])
Promise.resolve()
.then(
()=>readTags(files[0])
)
).then(
result=>console.log("ok",result)//this logs: ok { raw: {} }
).catch(
error=>console.log("oops:",error)
);
const tags = [
[{
TIT2:"some title"
}]
]
Can you please add Synced lyrics (SYLT), upc/ean (BARCODE/UPC/EAN) and duration(Maybe there is duration already)?
http://id3.org/id3v2.3.0#Private_frame
Support more than one frame in a tag.
In line 192 of index.js:
if(descStart[i] == 0x00 && descStart[i + 1] == 0x00) {
descFound = i + 1;
descEnd = APICFrame.indexOf(APICFrame.indexOf(0x00, 1) + 2 + i + 1);
break;
}
descStart is not defined anywhere, so it throws an error.
Associated PR: #11
I want to use this library on the express server. Is there an option to add tag only in response stream?
Hi,
I'm wondering if there is a way to improve performance of reading the meta. I don't know if the file is entirely loaded or just the meta portion, I'm passing the path to NodeID3.read(). It seems slow considering the volume I'm reading. Greetings
buffer.js:269
throw err;
^
RangeError [ERR_INVALID_OPT_VALUE]: The value "4191390185" is invalid for option "size"
at Function.alloc (buffer.js:278:3)
at new Buffer (buffer.js:180:19)
at NodeID3.getTagsFromBuffer (C:\test\nodejs\node_modules\node-id3\index.js:328:31)
at NodeID3.read (C:\test\nodejs\node_modules\node-id3\index.js:226:25)
at NodeID3.update (C:\test\nodejs\node_modules\node-id3\index.js:269:32)
Test code:
var nodeID3 = require('node-id3');
let path = 'giuseppe-tomasi-di-lampedusa-der-leopard-1-4.mp3';
let tags = {
title: 'Giuseppe Tomasi di Lampedusa: Der Leopard (1/4)',
album: 'BR 2 | radioTexte'
};
let success = nodeID3.update(tags, path);
Found a bug where reading certain tags can cause node-id3 to crash the whole app (even in a try catch).
internal/buffer.js:75
throw new ERR_BUFFER_OUT_OF_BOUNDS();
^
RangeError [ERR_BUFFER_OUT_OF_BOUNDS]: Attempt to access memory outside buffer bounds
at boundsError (internal/buffer.js:75:11)
at Buffer.readUInt32BE (internal/buffer.js:300:5)
at NodeID3.readPopularimeterFrame (node_modules\node-id3\index.js:1078:38)
at NodeID3. (node_modules\node-id3\index.js:465:64)
at Array.map ()
at NodeID3. (node_modules\node-id3\index.js:463:40)
at Array.forEach ()
at NodeID3.getTagsFromBuffer (node_modules\node-id3\index.js:437:12)
at NodeID3. (node_modules\node-id3\index.js:292:37)
at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:63:3) {
code: 'ERR_BUFFER_OUT_OF_BOUNDS'
}
Even if the package failed to read the file properly, could we add some safety for the failure instead of just killing the app?
There's a console.log
statement in index.js on line 87.
NodeID3.prototype.write = function(tags, filepath) {
var frames = [];
frames.push(this.createTagHeader());
var tagNames = Object.keys(tags);
console.log(tagNames); // <-- its this one
var validRawTags = Object.keys(TIF).map(function(e) {
return TIF[e]
})
Will remove in a pull request later :)
Probably you're not developing this anymore but in my opinion this is the best node id3 parser/writer. Whatever, I noticed that when i try to write id3 tags to a m4a file, it breaks the file and doesn't write tags.
I converted one of the m4a files to mp3 with ffmpeg and run with same code and it worked.
I guess the problem is with m4a files. Can you add support for aac/m4a please?
It returns false when I try to read the file again using NodeID3.read
.
let tags = NodeID3.read(fileBuffer);
console.log("old tags:");
console.log(tags);
// displays tags properly
console.log("new tags:");
let newTags = {title: 'sample new title'};
console.log(NodeID3.read(NodeID3.update(newTags, fileBuffer)));
// displays 'false'
I can't add a custom tag.
For example
let metadata = {
USLT: "test",
TRCK: "3"
};
nodeID3.write(metadata, "test");
It adds the track number but not unsynced lyrics.
In the update
method you accept either a file path or a file buffer as input, however this method call the write
method for writing the tags which only accepts a file path as input. Calling update
with a file buffer will fail because write
will try to pass it to fs.writeFile
.
It is possible to set a flag in the chapter to add the current chap to the CTOC? There is a simple way to add a ctoc?
How can I use this library when uploading files to S3 using Multer?
When I run the script on any of my mp3 files, I only see the tags for raw, encodingTechnology, title and artist.
When I view my files in iTunes, there is info on BPM, a comment, and a genre.
Do you have any idea why these would not all be captured from the script?
It would be fantastic to be able to write on the 'comment' tag ;)
Thanks!
Currently the module is using callbacks, but I wanted it to use promises as I'm writing my app with ES6.
I wrote a little test like that :
import id3 from 'node-id3';
import {promisify} from 'util';
const file1 = '../img.mp3';
const file2 = '../noimg.mp3';
export function readID3(file) {
return promisify(id3.read)(file);
}
async function main() {
try {
const tags1 = await readID3(file1);
const tags2 = await readID3(file2);
console.log(tags1);
console.log(tags2);
} catch (err) {
console.log(err);
}
}
main().then(() => {
process.exit();
});
However, this fails with :
D:\perso\toyundamugen-app\node_modules\node-id3\index.js:234
let tags = this.getTagsFromBuffer(data, options)
^
TypeError: this.getTagsFromBuffer is not a function
at D:\perso\toyundamugen-app\node_modules\node-id3\index.js:234:37
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:504:3)
I had a friend look into it and he had to create its own promisify function. This allows to promisify your module :
export function readID3(fileBuffer, options) {
return new Promise(
(resolve, reject) =>
id3.read(
fileBuffer,
options,
(err, tags) => {
if (err) {
reject(err);
} else {
resolve(tags);
}
}
)
)
}
However this is not really satisfying. The best thing IMHO would be that node-id3 natively supports promises.
This is due to a binding problem with this
.
I'd be grateful if you could look into this.
Current file operations use synchronous fs api. Would be great to have async api.
WAV RIFF audio also uses ID3v2 comment specification,
Can you support the reading and writing of metadata in this audio format?
Thank you!
I have a data like this that I am using to call update() and write().
const newMp3Tags: any = {
title: "myTitle",
artist: "myArtist",
album: "myAlbum"
};
Calling update() and write() seems to have exact same behavior.
I would have thought that write() will remove all other tag data and just keep my data as tag data.
And update() would just update the tags that I have in my data and keep all others as is.
But whether or not I call update() or write(), I see all other data as if update() was called.
The following code will erase entire file when test on some mp3 file
var ID3v2 = require('.')
var path = '/home/jun/Desktop/Stronger.mp3'
var tags = ID3v2.read(path)
console.log(tags)
ID3v2.removeTags(path)
ID3v2.write({ title: 'Test' }, path)
var tags = ID3v2.read(path)
console.log(tags)
Check these outputs, the second time call removeTagsFromBuffer
, frame position == -1
{ raw:
{ TIT2: 'What Doesn\'t Kill You (Stronge',
TPE1: 'Kelly Clarkson',
TALB: 'Stronger (Deluxe Edition)',
TCOP: 'QQ音乐' },
title: 'What Doesn\'t Kill You (Stronge',
artist: 'Kelly Clarkson',
album: 'Stronger (Deluxe Edition)',
copyright: 'QQ音乐' }
frame position: 0
size: 1014
new data length: 8878759
8878759
frame position: -1
size: 171206389
new data length: 0
{ raw: { TIT2: 'Test' }, title: 'Test' }
Hi!
nodeID3.read() returns tag values with high bit on, like German umlauts, with high bit off. Thus the tag contents is destroyed.
äöüßÄÖÜ
is returned as
dv|_DV\\
or in hex:
a4 b6 bc 9f 84 96 9c
becomes
64 76 7c 5f 44 56 5c 5c
I'd rather expect that there is no conversion involved.
When NodeID3.read is used asynchronously, if the function is only give one parameter, it passes the error object, not the tags, as shown in the example.
The correct usage would be as follows (using es6 syntax):
NodeID3.read(filePath, (err, tags) => {
if (err) throw err
console.log(Object.keys(tags))
console.log(tags)
})
However, if you intend the behavior to actually be as shown in the readme, then the code does not behave as expected.
I am using node-ID3 for a yt playlist downloader.
I wan to try to add the thumbnail from the original video to the mp3.
Now I tried reading your code but I was having a hard time as I have never learned anything about how buffers work before.
I need to get the image from a url instead of filepath and I just can't get it working. Your code seems magical, as soon as I touch it everything dies. I tried replacing the fs.readFileSync with a http request with a buffer as response but no luck. For some reason the whole function already finished writing the tags to the file before the request is done, and I can't get it to go synchronous.
I also tried creating the buffer beforehand and then trying to write it as an image tag because looking at your code I thought that might've worked but I had no luck.
I am getting desperate and I need some help...
Hi there!
I wrote a Node.js application that batch downloads a series of podcasts, and uses node-id3
to overwrite the mp3's tags with dates, titles, etc. The application can be found here: https://github.com/garciadelcastillo/Documentos-RNE
The module works perfect when used on small files. However, when applying this on +50Mb files, I get this error:
buffer.js:74
throw new Error(
^
Error: If encoding is specified then the first argument must be a string
at new Buffer (buffer.js:74:13)
at NodeID3.createTextFrame (D:\Dropbox\Jose Luis\code\Documentos-RNE\node_modules\node-id3\index.js:229:25)
at NodeID3.write (D:\Dropbox\Jose Luis\code\Documentos-RNE\node_modules\node-id3\index.js:59:30)
at WriteStream.<anonymous> (D:\Dropbox\Jose Luis\code\Documentos-RNE\app.js:205:28)
at emitNone (events.js:91:20)
at WriteStream.emit (events.js:185:7)
at finishMaybe (_stream_writable.js:515:14)
at afterWrite (_stream_writable.js:389:3)
at onwrite (_stream_writable.js:379:7)
at WritableState.onwrite (_stream_writable.js:90:5)
Some googling led me to trying with older versions of Node. The error showed up with v6.9.2. The module works like a charm when downgrading to Node v.5.12.0!
I'd be happy to help or answer more questions when possible.
Thanks for a super helpful module! :)
Does this work with MP4 Videos?
Hello, @Zazama.
So, I want to get the genre field of the ID3 tag. When I set this field as a Pop genre, it returns (13).
Is it correct? How can I solve that?
I have another question... How can I get the time field of the tag? because I am trying to get it but it returns undefined and I am certain that this field is set.
Thanks.
Just discovered this library and fully enjoying it!
I have issue with read-only files though: they stay unchanged as they're not meant to be, but they still returns success flag when I try to update()
it.
Below is my implementation.
updateTags() {
// generate metadata for this track
const tags = this.getTags();
// file path
const file = this.path;
// assign new data
// *note*: returns true when the file is read-only
const success = NodeID3.update(tags, file);
if (success) {
logger.info(`Updated: ${file}`);
} else {
logger.error(`Failed to update: ${file}`);
}
}
Hello,
how to write ID3 tags to flac files with this lib?
Thanks!
Some music players such as foobar2000 can store metadata in the TXXX frame. The frame might contain statistics such as the timestamps for when the track was first played, etc. There may be multiple TXXX frames in a file, but the descriptions are unique.
The frame body is arranged a bit differently from ordinary text frames, like so:
<Header for 'User defined text information frame', ID: "TXXX">
Text encoding $xx
Description <text string according to encoding> $00 (00)
Value <text string according to encoding>
Here's an example of the TXXX frame in a file:
00000000 49 44 33 03 00 00 00 06 6b 15 54 49 54 32 00 00 |ID3.....k.TIT2..|
00000010 00 25 00 00 01 ff fe 44 00 65 00 6d 00 6f 00 6c |.%.....D.e.m.o.l|
00000020 00 69 00 74 00 69 00 6f 00 6e 00 20 00 53 00 71 |.i.t.i.o.n. .S.q|
00000030 00 75 00 61 00 64 00 00 00 54 50 45 31 00 00 00 |.u.a.d...TPE1...|
00000040 1b 00 00 01 ff fe 48 00 61 00 72 00 72 00 79 00 |......H.a.r.r.y.|
00000050 20 00 4a 00 75 00 64 00 64 00 61 00 00 00 54 58 | .J.u.d.d.a...TX| <--
00000060 58 58 00 00 00 39 00 00 01 ff fe 41 00 44 00 44 |XX...9.....A.D.D|
00000070 00 45 00 44 00 00 00 ff fe 32 00 30 00 31 00 37 |.E.D.....2.0.1.7|
00000080 00 2d 00 30 00 37 00 2d 00 32 00 39 00 20 00 31 |.-.0.7.-.2.9. .1|
00000090 00 36 00 3a 00 32 00 31 00 3a 00 30 00 30 00 00 |.6.:.2.1.:.0.0..|
000000a0 00 54 43 4f 4e 00 00 00 0d 00 00 01 ff fe 48 00 |.TCON.........H.|
000000b0 6f 00 75 00 73 00 65 00 41 50 49 43 00 01 ac 75 |o.u.s.e.APIC...u|
Is there a way to get & set the ID3 tags directly like TPE1 instead of "artist"?
It doesn't seem possible to read/write lyrics, I wrote a quick hack to write lyrics and it seems to work:
Can this be used in browser?
Hi there,
How do I use the script? I mean, what do i need to install, etc in order for this to work?
Do I just drag some js file and voila? Do I have to install something (ex. node js) and run a server based on that for it to work?
Thanks a bunch. I'm trying to learn :)
Hello!
I'm trying to use the code for my website to get audio files name, singer lyrics and album art.
which file do I take into my code? (<script src="**that file**"></script)
and just to be sure -- do I read the raw tags in order to display the information?
Thanks a lot.
If I put the mp3's in a music folder in the project directory and do
var read = nodeID3.read('./music/song.mp3)
It works perfectly but lets say I put them in the music folder in the linux home directory and do
var read = nodeID3.read('~/Music/song.mp3)
It doesn't work..
I've also tried other paths like '/home/USER/Music/song.mp3 and etc, any idea on how to fix?
let image = { image: '/home/jun/Downloads/cover.jpeg' }
let comment = {
comment: {
language: 'eng',
shortText: 'short text',
text: 'text'
}
}
NodeID3.update(image, '/home/jun/Downloads/Blue - All Rise.mp3')
NodeID3.update(comment, '/home/jun/Downloads/Blue - All Rise.mp3')
Check this line, it will throw exception when the second update
invoked.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.