43081j / id3 Goto Github PK
View Code? Open in Web Editor NEWA JavaScript ID3 tags parser for Node & browsers.
License: MIT License
A JavaScript ID3 tags parser for Node & browsers.
License: MIT License
TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
at makeCallback (fs.js:143:11)
at Object.close (fs.js:401:20)
at Reader.close (/server/node_modules/id3js/dist/id3.js:69:7)
at /server/node_modules/id3js/dist/id3.js:967:12
at process (/server/node_modules/id3js/dist/id3.js:837:7)
at /server/node_modules/id3js/dist/id3.js:950:6
at /server/node_modules/id3js/dist/id3.js:118:4
at FSReqCallback.wrapper [as oncomplete] (fs.js:480:5)
Running against Node 11.5, but according to fs docs, a callback was required since 10.
To test, I inserted a noop function and it worked fine.
Hi!
Pretty much as described in this previous issue I get an exception thrown when tags contain special characters like french accents (e.g. "Interprètes").
I read about decodeURIComponent
causing issues with some UTF-8 characters, which is the reason why escape()
is used in the first place, but can't seem to reproduce them as of now.
Any update on this?
Thanks!
id3() creates a new Reader and calls its .open method but never closes it. If you don't cycle through lots of files quickly, this does not seem to be a problem (presumably because the Reader eventually gets destroyed and the file handle along with it), but if you churn through a lot of files very quickly, this can cause you to run out of file handles and id3 eventually starts failing with "Could not open specified file." The fix is simply to put a call to handle.close() inside the ID3Tag.parse callback.
Hello,
I'm trying to integrate this lib to a Meteor project.
To do this I added meteorhacks package :
meteor add meteorhacks:npm
Then in the packages.json I wrote :
{ "id3js": "1.1.3" }
And then I used id3js like that :
var id3js = Meteor.npmRequire('id3js');
id3js({
file: url,
type: id3js.OPEN_URI
}, function(err, tags) {
if(err) console.log(err);
console.log(tags);
});
And it crash like that :
I20160129-14:45:21.813(1)? Exception while invoking method 'podcastAdd' ReferenceError: XMLHttpRequest is not defined
I20160129-14:45:21.814(1)? at [object Object].Reader.ajax (/Users/ogre/Work/6102/ogre/from.brussels/.meteor/local/isopacks/npm-container/npm/node_modules/id3js/dist/id3.js:137:17)
I20160129-14:45:21.814(1)? at [object Object].Reader.open (/Users/ogre/Work/6102/ogre/from.brussels/.meteor/local/isopacks/npm-container/npm/node_modules/id3js/dist/id3.js:50:10)
I20160129-14:45:21.814(1)? at id3 (/Users/ogre/Work/6102/ogre/from.brussels/.meteor/local/isopacks/npm-container/npm/node_modules/id3js/dist/id3.js:961:10)
I20160129-14:45:21.814(1)? at [object Object].Meteor.methods.podcastAdd (lib/methods/podcast.js:14:4)
I20160129-14:45:21.814(1)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20160129-14:45:21.815(1)? at livedata_server.js:708:19
I20160129-14:45:21.815(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20160129-14:45:21.815(1)? at livedata_server.js:706:40
I20160129-14:45:21.815(1)? at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20160129-14:45:21.815(1)? at livedata_server.js:704
Any idea to solve it properly ?
This library seems to read most tags fine, but always returns a year: null
field, whether or not the song has a year in its tags.
Hi,
When I was trying to use this library I noticed that the image tag contains a different image than I expected to see. Correct me if I'm wrong, but what I think is happening is that each APIC or PIC record is getting read but only the last one is saved. I think this is because there is only one image property on the tags object.
// Code snippet from id3.js
} else if(header.id === 'APIC') {
var encoding = dv.getUint8(10),
image = {
type: null,
mime: null,
description: null,
data: null
};
var variableStart = 11, variableLength = 0;
for(var i = variableStart;;i++) {
if(dv.getUint8(i) === 0x00) {
variableLength = i - variableStart;
break;
}
}
image.mime = dv.getString(variableLength, variableStart);
image.type = ID3Frame.imageTypes[dv.getUint8(variableStart + variableLength + 1)] || 'other';
variableStart += variableLength + 2;
variableLength = 0;
for(var i = variableStart;; i++) {
if(dv.getUint8(i) === 0x00) {
variableLength = i - variableStart;
break;
}
}
image.description = (variableLength === 0 ? null : dv.getString(variableLength, variableStart));
image.data = buffer.slice(variableStart + 1);
result.value = image;
}
Anyone have a workaround for this?
d:\Code\mp3\node_modules\id3js\dist\id3.js:928
frameBit = dv.getUint8(p
osition + i);
^
RangeError: Offset is outside the bounds of the DataView
at DataView.getUint8 (native)
at d:\Code\mp3\node_modules\id3js\dist\id3.js:928:22
at d:\Code\mp3\node_modules\id3js\dist\id3.js:118:4
at FSReqWrap.wrapper [as oncomplete] (fs.js:529:17)
This issue looks like it's fairly simple: getStringUtf16 builds an array of 16-bit character values in an array and then attempts to create an output string using new Buffer(str)
. Unfortunately that expects an array of octets and discards the high byte in each of the two-byte values given. This means the method works if every character is actually ASCII, but fails if any UTF-16 pairs are found.
The simple solution I went with was:
// str is an array of two-byte pairs
var buf = new Buffer(str.length*2);
for (var i = 0; i < str.length; i++) {
buf.writeUInt16LE(str[i], i*2);
}
return buf.toString('utf16le');
And that solved my problem.
Hi,
I'm trying to create a small app, using webpack, with an audio file located in my project folder. Here is my code:
import fs from 'fs'
import id3 from 'id3js'
tagReader: () => {
id3('./../data/test.ogg', function(err, tags) {
console.log('tags: ', tags)
})
}
I checked the file which is correctly tagged (it is an .ogg), but for some reason I can't understand, all properties remains 'null'... Someone having the same issue, and/or able to give me some help? Thnak you in advance!
This error came from the line var bomInt = this.getUint16(offset);
. Not sure what else I should put into this ticket to help debug. If you can think of anything I could do, just say :-)
Processing files having a long name, the following error appears:
/home/pi/nodejs/snjsp/node_modules/id3js/dist/id3.js:231
var bomInt = this.getUint16(offset);
^
Error: Index out of range.
at DataView.getStringUtf16 (/home/pi/nodejs/snjsp/node_modules/id3js/dist/id3.js:231:22)
at Object.ID3Frame.parse (/home/pi/nodejs/snjsp/node_modules/id3js/dist/id3.js:668:24)
at /home/pi/nodejs/snjsp/node_modules/id3js/dist/id3.js:943:24
at /home/pi/nodejs/snjsp/node_modules/id3js/dist/id3.js:118:4
at Object.wrapper [as oncomplete] (fs.js:454:17)
By example, this error occurs while reading tags for file in:
/home/pi/music/dd/Aphrodites Child/1968 - End of the World/01 - End Of The World.mp3
Renaming the file of the folder with a shorter name solves the issue.
Regards,
kvalium
I think the fromFile() method parameter should accept the Blob type, I tried to pass in a Blob object and it works
https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader/readAsArrayBuffer
Thanks for you wonderful library, I've already tested this and this before, but yours is way faster.
I've got a question about how to use the returned image data. I'm currently doing it that way:
var arrayBufferView = new Uint8Array(tags.v2.image.data);
tags.v2.image.mime = tags.v2.image.mime || 'image/jpeg';
var blob = new Blob([arrayBufferView], {type: tags.v2.image.mime});
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
This works sometimes, however most of the time it fails. Sometimes it just doesn't create a valid file URL, most of the time it creates only parts of the picture and rarely it works perfectly:
All of these mp3 covers are shown correctly in my windows explorer.
The ones that have a nice placeholder image don't have a tags.v2.image attribute. (which is alright, better have nothing then something wrong...)
The last one somehow created an invalid URL, the others show only a part of the image.
Interestingly the Beatles one doesn't show up in my explorer, but your library parses it correctly.
Am I doing this wrong?
When using node.js to get album covers, ArrayBuffer in tags.v2.image.data is only part of the file.
Like this :
Using another Library https://github.com/leetreveil/musicmetadata , I got a correct result :
The parser freaks out on some embedded images, it seems completely random as to what images do and don't trip it:
Uncaught node.js Error
Error: Index out of range.
at Object.ID3Frame.parse (/home/damon/projects/tunes/node_modules/id3js/dist/id3.js:696:13)
at eval (/home/damon/projects/tunes/node_modules/id3js/dist/id3.js:943:24)
at eval (/home/damon/projects/tunes/node_modules/id3js/dist/id3.js:118:4)
at Object.wrapper [as oncomplete] (fs.js:454:17)
An example of one it's breaking on: http://pastebin.com/1RRDqknW
As you can see it kinda just cuts off part way through parsing the image.
If I delete the image from the ID3 tag, it parses that file fine and then breaks on a later one.
The only thing the breaking images seem to have had in common is that they're mostly fairly high res (both this and the previous one were 800x800) though there have been ones smaller such as 400x360 which have broken in the same way.
There should really be an option to skip parsing images so those getting this issue can just bypass the image parsing and so this module will still be usable.
If I have a number of script files, normally I include them as:
<script src="js/foo.js"></script>
<script src="js/bar.js"></script>
but if one of those files needs to use the module, I can't figure out how to import everything so it works.
If I do it this way:
<script type="module">
import * as id3 from './js/vendor/id3js/id3.js';
</script>
<script src="js/foo.js"></script>
<script src="js/bar.js"></script>
id3 isn't visible in the script files
while if I include the script files in the module:
<script type="module">
import * as id3 from './js/vendor/id3js/id3.js';
import './js/foo.js';
import './js/bar.js';
</script>
I can't use any of their code (I suspect I would have to rewrite everything to be a module)
Is there a way to use this in non-modular javascript?
With some files it return this error to the console
Here's one of the file that got the error: http://www.mediafire.com/listen/13evge2b3nw5l1o/Muzzy_Insignia.mp3
I need id3js in Nodered inside Docker container.
I installed id3 running npm i -S id3js
in /data directory. According to Nodered manual (https://nodered.org/docs/user-guide/writing-functions#loading-additional-modules)
I have added id3js:require('id3js')
to functionGlobalContext section. After container retsart I have this on logs:
> [email protected] start /usr/src/node-red
> node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS "--userDir" "/data"
Error loading settings file: /data/settings.js
/data/node_modules/id3js/lib/id3.js:1
import { parse } from './id3Tag.js';
^
SyntaxError: Unexpected token {
at Module._compile (internal/modules/cjs/loader.js:723:23)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Module.require (internal/modules/cjs/loader.js:692:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object.<anonymous> (/data/settings.js:220:8)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
Hello,
First off I want to complement you on a very good library however there is one rather serious error.
In a ID3V2 tag you can have any genre, not just the ones you listed in the array. If you read a file that has a genre that is not in your array then the app crashses.
/id3js/dist/id3.js:231
var bomInt = this.getUint16(offset);
Is there any plans to extract the actual id3v2 genre string instead of converting it to a number?
Hi there,
I just found your nice ID3 Parser and started a similar project for parsing MP4 Tags using your DataView extensions and the Reader interface.
It would be awesome if we could extract these two to a generic module both id3js and mp4js could depend on (or the other way around, like grunt-plugins via npm's peer dependencies) so one did not have to maintain the same code twice.
I had to make minor changes to your DataView#getString method as the values extracted from MP4 in nodejs could not be decoded via decodeURIComponent (Malformed URI errors). I hope I can shed some light on the why, so there are no differences in neither dataview.js nor reader.js.
Most of all I wanted to start writing a parser for FLAC and OGG Metadata and again I'd be needing your Reader for it, as the browser compatibility is really nice!
All in all this looks like a project like taglib, that could provide a generic interface for reading tags from different file types. Tell me what you think about it.
Kindly,
Lennart
P.S.: mp4js is here
I have been gone a long time and have had very little time to maintain this repo (I still do lack time, in fact). However, I am going to give 2.0 a go.
This won't be a release of any new functionality but rather a major cleanup/refactor and improvement of build process, along with any possible bug fixes brought up since I was last around.
DataView
decodeURIComponent(escape(...))
callsThe current branch being used for this is feature/browserify-cleanup
, not so appropriately named but it'll do for now.
The browserify output needs testing. I have tried it quickly with an mp3 in my browser and it worked fine.
Please do help if you can, this is not such a simple task and I do not have the capacity to do it alone in an acceptable time frame
J
id3.js
has no associated type definitions so TS consumers must import id3js/lib/id3.js
instead.
This is a pain, we should instead ship a tiny types file (id3.d.ts
) which exports lib/id3.d.ts
.
Any idea why I keep getting this error, or how I could fix it?
Thanks!
i got problem with id3js when i try to get tags
i ask the question on stack you can check it here
and i solve it by changing thsose lines
fs.open(self.file, 'r', function(err, fd) {
if(err) {
return callback(err);
}
self.fd = fd;
callback();
});
to
fs.openSync(self.file, 'r', function(err, fd) {
if(err) {
return callback(err);
}
self.fd = fd;
callback();
});
node_modules/id3js/dist/id3.js:696
if(dv.getUint8(i) === 0x00) {
^
Error: Index out of range.
at Object.ID3Frame.parse (./node_modules/id3js/dist/id3.js:696:13)
I can repeat this with one mp3 I have. I'm currently trying to figure out what in the mp3 is failing.
Tags with a major version of 2 of less use a slightly different format for frame headers and such.
As the >2.3 docs state for a frame header:
Frame ID $xx xx xx xx (four characters)
Size 4 * %0xxxxxxx
Flags $xx xx
Whereas a <=2.2 frame will be like so:
Frame ID $xx xx xx
Size 3 * %0xxxxxxx
fs.close() in id3.js is without callback function and causes "DeprecationWarning: Calling an asynchronous function without callback is deprecated"!
Currently strings are read as-is, byte by byte using a Uint8Array
. The downside of this is that characters in high UTF-16/UTF-8 ranges will likely break or be malformed.
I'm not too sure about this but I'll assume it is an issue anyhow.
See here.
Edit: This was not a UTF-8 issue, it was an issue ID3v2.4 tracks not being read correctly
I have mp3s where ID3 is not finding the embedded image. Win Explorer, TagScanner, Quintessential, all find the artwork.
I see that part of the problem, is that when ID3 finds the PRIV tag, it treats it as SynchSafe, when it shouldn't. The APIC tag comes right after the PRIV tag. The size calculation is correct if not treated as SynchSafe.
Hi,
I am trying to get the text encoding of the ID3 and also the text encoding of each tag.
How do I do that?
Thanks
In rare cases the callback is called twice due to the fact that v1 and v2 tags are processed asynchronously, in parallel essentially.
If parsing of v1 tags fails and v2 tags have been processed, it should call the callback with an error, otherwise it should silently fail.
This way the v1 tag will be empty and the v2 tag can still parse, or not.
Thanks for the great project. Are there any plans for write support?
Hi,
Can i used this library to somehow to read a file stored in gridfs and give me the tags?
I tried giving a stream in both mode
So any other way to do this?
I get this error when I join the server with default configurations.
This happens on (index):400
Here's an image: http://gyazo.com/27e49bac301652418d7343ffd08a3664
Interested in making this library support promises to allow for using async
/await
. Wanted to start a discussion over whether it's worth the effort support both callbacks and Promises, or whether to do a semver major version change and support only promises going forward?
Thought?
v2 removed the trim.
it should instead stop reading at 0x00
(rather than trim)
Hi.
The readme provides an example of using this library in a web browser via a <script/>
tag:
<input type="file">
<script type="module">
import * as id3 from '//unpkg.com/id3js@^2/lib/id3.js';
document
.querySelector('input[type="file"]')
.addEventListener('change', async (e) => {
const tags = await id3.fromFile(e.currentTarget.files[0]);
// tags now contains v1, v2 and merged tags
});
</script>
That's not the most conventional way of using packages in a web browser.
The most conventional one is using a "bundler" like Webpack and importing directly from npm packages.
Example:
import { fromFile } from 'id3js'
const tags = await fromFile(file)
// tags now contains v1, v2 and merged tags
But it throws an error:
Module not found: Can't resolve 'fs' in '...\node_modules\id3js\lib'
node_modules/id3js/lib/localReader.js
So the main
file of the library looks like this:
https://unpkg.com/browse/[email protected]/lib/id3.js
{
"name": "id3js",
"version": "2.1.1",
"main": "./lib/id3.js",
"types": "./lib/id3.d.ts",
"type": "module",
...
}
...
export async function fromPath(path) {
const mod = await import('./localReader.js');
return fromReader(new mod.LocalReader(path));
}
...
For some reason, it seems to execute that await import()
statement even though I didn't call that specific function called fromPath()
.
The error happens before calling any function, already at the import
level:
import * as Id3 from 'id3js'
I've fixed that in my fork by introducing two separate exports: /browser
and /node
.
See the updated README:
https://github.com/catamphetamine/id3
It now works in my setup (Webpack).
I've also added a function for getting an album cover image data URL.
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.