Code Monkey home page Code Monkey logo

jsmediatags's Introduction

JS MediaTags

The next version of https://github.com/aadsm/JavaScript-ID3-Reader.

Donations

A few people have asked me about donations (or even crowdfunding). I would prefer you to consider making a donation to the "Girls Who Code" NPO. If you do please send me a message so I can add you as a contributor.

Current Support

  • File Readers
    • NodeJS
    • XMLHttpRequest
    • Blob
    • File
    • Buffers/Arrays
    • React Native
  • Tag Readers
    • ID3v1
    • ID3v2 (with unsynchronisation support!)
    • MP4
    • FLAC

How to use

NodeJS

Run npm install jsmediatags --save to install.

// Simple API - will fetch all tags
var jsmediatags = require("jsmediatags");

jsmediatags.read("./music-file.mp3", {
  onSuccess: function(tag) {
    console.log(tag);
  },
  onError: function(error) {
    console.log(':(', error.type, error.info);
  }
});
// Advanced API
var jsmediatags = require("jsmediatags");

new jsmediatags.Reader("http://www.example.com/music-file.mp3")
  .setTagsToRead(["title", "artist"])
  .read({
    onSuccess: function(tag) {
      console.log(tag);
    },
    onError: function(error) {
      console.log(':(', error.type, error.info);
    }
  });

Browser

Copy the dist/jsmediatags.min.js file into your web application directory and include it with a script tag. This library is also available on cdnjs at https://cdnjs.com/libraries/jsmediatags. UMD will give you multiple usage options to use it:

// As a global Object
var jsmediatags = window.jsmediatags;
// As a CommonJS Module
var jsmediatags = require("jsmediatags");

It supports loading files from remote hosts, Blob and File objects:

// From remote host
jsmediatags.read("http://www.example.com/music-file.mp3", {
  onSuccess: function(tag) {
    console.log(tag);
  },
  onError: function(error) {
    console.log(error);
  }
});

Note that the URI has to include the scheme (e.g.: https://), as relative URIs are not supported.

// From Blob
jsmediatags.read(blob, ...);
// From File
inputTypeFile.addEventListener("change", function(event) {
  var file = event.target.files[0];
  jsmediatags.read(file, ...);
}, false);

You can find more about UMD usage options here.

React Native

React Native support requires some additional dependencies:

npm install --save jsmediatags buffer react-native-fs

With these dependencies installed, usage with React Native should remain the same:

const jsmediatags = require('jsmediatags');

new jsmediatags.Reader('/path/to/song.mp3')
  .read({
    onSuccess: (tag) => {
      console.log('Success!');
      console.log(tag);
    },
    onError: (error) => {
      console.log('Error');
      console.log(error);
    }
});

// Or wrap it with a promise
new Promise((resolve, reject) => {
  new jsmediatags.Reader('/path/to/song.mp3')
    .read({
      onSuccess: (tag) => {
        console.log('Success!');
        resolve(tag);
      },
      onError: (error) => {
        console.log('Error');
        reject(error);
      }
  });
})
  .then(tagInfo => {
    // handle the onSuccess return
  })
  .catch(error => {
    // handle errors
  });

Articles

Documentation

The Output

This is an example of the object passed to the jsmediatags.read's onSuccess callback.

ID3v2

{
  type: "ID3",
  version: "2.4.0",
  major: 4,
  revision: 0,
  tags: {
    artist: "Sam, The Kid",
    album: "Pratica(mente)",
    track: "12",
    TPE1: {
      id: "TPE1",
      size: 14,
      description: "Lead performer(s)/Soloist(s)",
      data: "Sam, The Kid"
    },
    TALB: {
      id: "TALB",
      size: 16,
      description: "Album/Movie/Show title",
      data: "Pratica(mente)"
    },
    TRCK: {
      id: "TRCK",
      size: 3,
      description: "Track number/Position in set",
      data: "12",
    }
  },
  size: 34423,
  flags: {
    unsynchronisation: false,
    extended_header: false,
    experimental_indicator: false,
    footer_present: false
  }
}

MP4

{
  type: "MP4",
  ftyp: "M4A",
  version: 0,
  tags: {
    "©too": {
      id: "©too",
      size: 35,
      description: 'Encoding Tool',
      data: 'Lavf53.24.2'
    }
  }
}

FLAC

{
  type: "FLAC",
  version: "1",
  tags: {
    title: "16/12/95",
    artist: "Sam, The Kid",
    album: "Pratica(mente)",
    track: "12",
    picture: ...
  }
}

The tags property includes all tags that were found or specified to be read. Since each tag type (e.g.: ID3, MP4) uses different tag names for the same type of data (e.g.: the artist name) the most common tags are also available under human readable names (aka shortcuts). In this example, artist will point to TPE1.data, album to TALB.data and so forth.

The expected tag object depends on the type of tag read (ID3, MP4, etc.) but they all share a common structure:

{
  type: <the tag type: ID3, MP4, etc.>
  tags: {
    <shortcut name>: <points to a tags data>
    <tag name>: {
      id: <tag name>,
      data: <the actual tag data>
    }
  }
}

Shortcuts

These are the supported shortcuts.

  • title
  • artist
  • album
  • year
  • comment
  • track
  • genre
  • picture
  • lyrics

Picture data

The picture tag contains an array buffer of all the bytes of the album artwork image as well as the content type of the image. The data can be converted and displayed as an image using:

const { data, format } = result.tags.picture;
let base64String = "";
for (const i = 0; i < data.length; i++) {
  base64String += String.fromCharCode(data[i]);
}
img.src = `data:${data.format};base64,${window.btoa(base64String)}`;

HTTP Access Control (CORS)

When using HTTP CORS requests you need to make sure that the server is configured to receive If-Modified-Since and Range headers with the request. This can be configured by returning the Access-Control-Allow-Headers HTTP header with the OPTIONS request response.

Similarly, you should also allow for the browser to read the Content-Length and Content-Range headers. This can be configured by returning the Access-Control-Expose-Headers HTTP header.

In short, the following headers are expected:

Access-Control-Allow-Headers: If-Modified-Since, Range
Access-Control-Expose-Headers: Content-Length, Content-Range

This library still works without these options configured on the server. However it will download the entire file instead of only the necessary bytes for reading the tags.

File and Tag Readers

This library uses file readers (MediaFileReader API) to read the file itself and media tag readers (MediaTagReader API) to parse the tags in the file.

By default the library will automatically pick the most appropriate file reader depending on the file location. In the common case this will be the URL or local path where the file is located.

A similar approach is taken for the tag reader. The most appropriate tag reader will be selected depending on the tag signature found in the file.

However, you can specify exactly which file reader or tag reader to use using the advanced API.

New file and tag readers can be implemented by extending the MediaFileReader and MediaTagReader classes. Check the Development section down bellow for more information.

Reference

  • jsmediatags.Reader

    • setTagsToRead(tags: Array<string>) - Specify which tags to read
    • setFileReader(fileReader: typeof MediaFileReader) - Use this particular file reader
    • setTagReader(tagReader: typeof MediaTagReader) - Use this particular tag reader
    • read({onSuccess, onError}) - Read the tags.
  • jsmediatags.Config

    • addFileReader(fileReader: typeof MediaFileReader) - Add a new file reader to the automatic detection system.
    • addTagReader(tagReader: typeof MediaTagReader) - Add a new tag reader to the automatic detection system.
    • setDisallowedXhrHeaders(disallowedXhrHeaders: Array<string>) - Prevent the library from using specific http headers. This can be useful when dealing with CORS enabled servers you don't control.
    • setXhrTimeoutInSec(timeoutInSec: number) - Sets the timeout time for http requests. Set it to 0 for no timeout at all. It defaults to 30s.

Development

Source code uses Flow for type checking meaning that a compilation step is needed to remove all type annotations. When using this library with NodeJS you can use the runtime compilation that is supported by babel. It will be slightly slower but no compilation step is required.

NodeJS (With Runtime Compilation)

require('babel-core/register');

var NodeFileReader = require('./src/NodeFileReader');
var ID3v2TagReader = require('./src/ID3v2TagReader');
...

NodeJS (With Compiled Code (faster))

Run npm run build to generate proper JavaScript code into the build2 directory.

var NodeFileReader = require('./build2/NodeFileReader');
var ID3v2TagReader = require('./build2/ID3v2TagReader');
...

Run npm run watch to automatically recompile the source code whenever a file is changed.

Browser

Run npm run dist to generate a UMD version of this library that is ready to be used in a browser.

Two packages are created for the browser: dist/jsmediatags.min.js and dist/jsmediatags.js. One is a minimized version that is meant to be used in production and the other a regular version meant to be used for debugging.

Run npm run dist-watch to recompile and browserify the source code whenever a file is changed. This will only regenerate the dist/jsmediatags.js file.

New File Readers

Extend the MediaFileReader class to implement a new file reader. Methods to implement are:

  • init
  • loadRange
  • getBytesLoaded
  • getByteAt

Current Implementations:

New Tag Readers

Extend the MediaTagReader class to implement a new tag reader. Methods to implement are:

  • getTagIdentifierByteRange
  • canReadTagFormat
  • _loadData
  • _parseData

Current Implementations:

Unit Testing

Jest is the framework used. Run npm test to execute all the tests.

JavaScript-ID3-Reader

If you want to migrate your project from JavaScript-ID3-Reader to jsmediatags use the following guiding examples:

All tags

JavaScript-ID3-Reader:

ID3.loadTags("filename.mp3", function() {
  var tags = ID3.getAllTags("filename.mp3");
  alert(tags.artist + " - " + tags.title + ", " + tags.album);
});

jsmediatags:

jsmediatags.read("filename.mp3", {
  onSuccess: function(tag) {
    var tags = tag.tags;
    alert(tags.artist + " - " + tags.title + ", " + tags.album);
  }
});

Specific tags

JavaScript-ID3-Reader:

ID3.loadTags("filename.mp3", function() {
  var tags = ID3.getAllTags("filename.mp3");
  alert(tags.COMM.data + " - " + tags.TCON.data + ", " + tags.WXXX.data);
},
{tags: ["COMM", "TCON", "WXXX"]});

jsmediatags:

new jsmediatags.Reader("filename.mp3")
  .setTagsToRead(["COMM", "TCON", "WXXX"])
  .read({
    onSuccess: function(tag) {
      var tags = tag.tags;
      alert(tags.COMM.data + " - " + tags.TCON.data + ", " + tags.WXXX.data);
    }
  });

Error handling

JavaScript-ID3-Reader:

ID3.loadTags("http://localhost/filename.mp3", function() {
  var tags = ID3.getAllTags("http://localhost/filename.mp3");
  alert(tags.comment + " - " + tags.track + ", " + tags.lyrics);
},
{
  tags: ["comment", "track", "lyrics"],
  onError: function(reason) {
    if (reason.error === "xhr") {
      console.log("There was a network error: ", reason.xhr);
    }
  }
});

jsmediatags:

new jsmediatags.Reader("filename.mp3")
  .setTagsToRead(["comment", "track", "lyrics"])
  .read({
    onSuccess: function(tag) {
      var tags = tag.tags;
      alert(tags.comment + " - " + tags.track + ", " + tags.lyrics);
    },
    onError: function(error) {
      if (error.type === "xhr") {
        console.log("There was a network error: ", error.xhr);
      }
    }
  });

Goals

  • Improve the API of JavaScript-ID3-Reader
  • Improve the source code with readable code and Flow annotated types
  • Have unit tests
  • Support NodeJS

jsmediatags's People

Contributors

aadsm avatar andreasanheuser avatar chrisparton1991 avatar curtismenmuir avatar danii1 avatar davidroeca avatar dellagustin avatar emschwartz avatar jessuni avatar jhaber1 avatar jonhester avatar longzheng avatar lukehorvat avatar mrj avatar nils avatar pioug avatar szilveszterordog avatar tongdada avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsmediatags's Issues

Add support for ID3v2.4 at the end of file

With ID3v2.4 its allowed to add ID3 Tags at the end of a file (see http://id3.org/FAQ). ID3 Tags added at the end of a file currently cannot be parsed (tested with Version 3.2.2). Some big audio databases as Universal germany (http://www.unippm.de) add the ID3 Tag at the end of their files. It would be very helpful, if jsmediatags could parse these valid ID3 Tags.

Rename fileDate to frameData in test suite

Does this make more sense from a semantics point of view?

Let me know if I am completely off the mark here, as someone with not much knowledge of ID3 tags this was quite confusing.

Error: No suitable file reader found for...

I have your example with the file selection button working OK and it reads the TXXX tags in my mp3 fine.

If I try to use the example which specifies a filename
e.g. new jsmediatags.Reader("filename.mp3")

I get "Error: No suitable file reader found for filename.mp3"

What is the correct syntax for referencing
a) a file in the same directory as the html, and
b) a URL in the form file:// ?

I have tried everything I can think of, but I'm not pro so don't really know what I'm doing wrong!

Fail to fallback to "download the entire file" using remote URL's

I tried JavaScript ID3 Reader and this jsmediatags,js

They both fail to get tags from external websites that don't support HTTP Range feature or they don't allow If-Modified-Since header.

So I edited jsmediatags.js file:
#1977: Removed: xhr.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
#1813: Replaced with: var contentLength = null;

What I did ? I forced to download the entire file, which this should be automatically If required headers are not supported on the remote URL's. please fix the fallback ASAP

Example URL: https://crossorigin.me/http://s3.amazonaws.com/static.noisetrade.com/w/8a6a64e5-5c2c-4584-ad46-bba625de301e/hey-tree-streaming.mp3

Working with local mp3 files

Hi! I've been trying to load the tags of a local mp3 file on my Android device, I load de .js on my index:

<script src="lib/dist/jsmediatags.js"></script>

And, on my angular controller, I have this:
var jsmediatags = window.jsmediatags;
jsmediatags.read($scope.song, {
onSuccess: function(tag) {
console.log(tag);
},
onError: function(error) {
console.log(error);
}
});

The $scope.song has the file's localURL. When I run it, the jsmediatags shows me this on the js console:

info: "Unexpected HTTP status 0."
type: "xhr"

Could you help me? I really need my local files tags. Thanks!

Reading Files tags

Hi,

I'm trying to use the package inside a phonegap application. I started from the previous version and followed the Raymond Camden's article.

I observed that the package doesn't work anymore with Files. In BlobFileReader, l.25, returns false for Files :

static canReadFile(file: any): boolean {
    return (
      typeof Blob !== "undefined" &&
      file instanceof Blob
    );
  }

Shouldn't be changed to something like ?

return ((typeof Blob !== "undefined") && ( (file instanceof Blob) ||(file instanceof File) ));

Thanks !

cannot find module "fs"

Tried install v3.5 and v3.6 and I still get this error as soon as I require or import this package:

Error: cannot find module "fs".

What am I doing wrong? No other npm module gives me this.

Webpack version: 3.0

Integration jsmediatags and meteor

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 :
{ "jsmediatags": "3.0.0" }
And then I used jsmediatags like that :

var jsmediatags = Meteor.npmRequire('jsmediatags');
jsmediatags.read(url, {
    onSuccess: function(tag) {
        var tags = tag.tags;
        console.log(tags);
    }
});

And it crash like that :

I20160129-15:39:48.395(1)? Exception while invoking method 'podcastAdd' SyntaxError: Use of const in strict mode.
I20160129-15:39:48.395(1)?     at Module._compile (module.js:439:25)
I20160129-15:39:48.395(1)?     at Object.Module._extensions..js (module.js:474:10)
I20160129-15:39:48.396(1)?     at Module.load (module.js:356:32)
I20160129-15:39:48.396(1)?     at Function.Module._load (module.js:312:12)
I20160129-15:39:48.396(1)?     at Module.require (module.js:364:17)
I20160129-15:39:48.396(1)?     at require (module.js:380:17)
I20160129-15:39:48.396(1)?     at Object.Npm.require (/Users/ogre/Work/6102/ogre/from.brussels/.meteor/local/build/programs/server/boot.js:162:18)
I20160129-15:39:48.396(1)?     at Object.Meteor.npmRequire (packages/npm-container/index.js:2:1)
I20160129-15:39:48.396(1)?     at [object Object].Meteor.methods.podcastAdd (lib/methods/podcast.js:14:29)
I20160129-15:39:48.396(1)?     at maybeAuditArgumentChecks (livedata_server.js:1698:12)
W20160129-15:39:48.394(1)? (STDERR)
W20160129-15:39:48.395(1)? (STDERR) /Users/ogre/Work/6102/ogre/from.brussels/.meteor/local/isopacks/npm-container/npm/node_modules/jsmediatags/build/jsmediatags.js:4
W20160129-15:39:48.395(1)? (STDERR) const MediaFileReader = require("./MediaFileReader");
W20160129-15:39:48.395(1)? (STDERR) ^^^^^

Any idea to solve it properly ?

Can this be used for web radios?

I'd like to If I have a web radio stream, can I use jsmediatags in the browser to get the info about the currently played music? And will I get updates each time a new music plays?

What am I missing?

Hi, This is really awesome project. I am so happy to see this library.
But, unfortunately I can not use 'Browser version'
I always got an error msg like 'No suitable tag reader found.'
I believe I select correct mp4 files.
Here is my codepen,

http://codepen.io/HongSeokHwan/pen/QyqWqa

What am I missing? Is it work in your computer?

Can't read local mp3 file id3 info.

My requirement is try to get the id3 info of local mp3 file which in the same dir of the html page.
I know node.js could work, but I need to show these info in html page by js.
But these sample code seems didn't work, is there any possible solution on this?
Following code all can't work:
jsmediatags.read("1.mp3"...
jsmediatags.read("http://localhost/1.mp3"...

No sync method?

There's no syncRead? I'm trying to use anothers plugins to sync but that onSuccess is giving me trouble. Any solution or another plugin like jsmediatags?

Not able to read the ID3Tags from an S3 URL

I tried reading ID3 from s3url (private) and I got this error

{ type: 'xhr',
info: 'Unexpected HTTP status 403.',
xhr:
XMLHttpRequest {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: [Function],
onload: [Function],
ontimeout: [Function],
onloadend: null,
_listeners: {},
onreadystatechange: null,
_anonymous: undefined,
readyState: 4,
response: '',
responseText: '',
responseType: '',
responseURL: 'https://test.s3.amazonaws.com/AUDIO/content_AUDIO_b3935c52-8270-6ffb-8962-6b223fccf7dd_2017-03-27_en-US.mp3?Expires=1648285340&AWSAccessKeyId=AKIAISHV3ZSMOVZ3E2KQ&Signature=ddadadada%2FP81KZOKFOrXE2%2F%2BW0%3D',
status: 403,
statusText: 'Forbidden',
timeout: 30000,
upload:
XMLHttpRequestUpload {
onloadstart: null,
onprogress: null,
onabort: null,
onerror: null,
onload: null,
ontimeout: null,
onloadend: null,
_listeners: {},
_request: [Circular],
_contentType: null,
_body: },
_method: 'HEAD',
_url:
Url {
protocol: 'https:',
slashes: true,
auth: null,
host: 'test.s3.amazonaws.com',
port: null,
hostname: 'test.s3.amazonaws.com',
hash: null,
search: '?Expires=1648285340&AWSAccessKeyId=AKIAISHV3ZSMOVZ3E2KQ&Signature=ada%2FP81KZOKFOrXE2%2F%2BW0%3D',
query: 'Expires=1648285340&AWSAccessKeyId=AKIAISHV3ZSMOVZ3E2KQ&Signature=ad%2FP81KZOKFOrXE2%2F%2BW0%3D',
pathname: '/AUDIO/content_AUDIO_b3935c52-8270-6ffb-8962-6b223fccf7dd_2017-03-27_en-US.mp3',
path: '/AUDIO/content_AUDIO_b3935c52-8270-6ffb-8962-6b223fccf7dd_2017-03-27_en-US.mp3?Expires=1648285340&AWSAccessKeyId=AKIAISHV3ZSMOVZ3E2KQ&Signature=XJomiVok5%2FP81KZOKFOrXE2%2F%2BW0%3D',
href: 'https://airficsp.s3.amazonaws.com/AUDIO/content_AUDIO_b3935c52-8270-6ffb-8962-6b223fccf7dd_2017-03-27_en-US.mp3?Expires=1648285340&AWSAccessKeyId=jdhkdhadkjad&Signature=XJomiVok5%adad%2F%2BW0%3D' },
_sync: false,
_headers:
{ 'If-Modified-Since': 'Sat, 01 Jan 1970 00:00:00 GMT',
Connection: 'keep-alive',
Host: 'airficsp.s3.amazonaws.com',
'User-Agent': 'Mozilla/5.0 (Darwin x64) node.js/4.6.0 v8/4.5.103.37',
'Content-Length': '0' },
_loweredHeaders: { 'if-modified-since': 'If-Modified-Since' },
_mimeOverride: 'text/plain; charset=x-user-defined',
_request: null,
_response: null,
_responseParts: null,
_responseHeaders:
{ 'x-amz-request-id': 'CD7DE175689A1321',
'x-amz-id-2': 'gmYJnepCe2TQ5lsX11fn2CtQD1ip1YixGmcydmpalUL20AJiGn/6kNon7BN+oQFtBaJmez62Yy0=',
'content-type': 'text/plain; charset=x-user-defined',
'transfer-encoding': 'chunked',
date: 'Mon, 27 Mar 2017 10:50:09 GMT',
server: 'AmazonS3' },
_aborting: null,
_error: null,
_loadedBytes: 0,
_totalBytes: 0,
_lengthComputable: false } }
:( xhr Unexpected HTTP status 403.

Bug: Error in reading remote MP3 files - Offset 1025 hasn't been loaded yet error

There's an issue that I can't seem to get around when trying to read ID3 tags from any remote MP3 file.
Offset 1025 hasn't been loaded yet.
The issue occurs no matter which MP3 file I try and use (both the file size and duration of the MP3 do not seem to matter and it is always a 1025 offset error) and there have been some commits that attempt to solve issues like this issue like 92ccb23.

Here is an example of the issue using the version of jsmediatags.js (https://github.com/aadsm/jsmediatags/blob/1c528cfb49fb756a7068bbf53bcd7be67648905b/dist/jsmediatags.js) from commit (92ccb23) which has not yet been made part of an official release, but appears to be targeted at fixing an issue similar to this.

View this example on JS Bin and view the console output:
https://jsbin.com/larikexite/1/edit?html,console,output

image

var jsmediatags = window.jsmediatags;
    var mediaSrc = "https://<replace with remote url>";
    var reader = new jsmediatags.Reader(mediaSrc);
    reader.read({
      onSuccess: function(tag) {
        if (tag.tags) {
          tagsJson = JSON.stringify(tag.tags);
          console.log(tagsJson);
        }
      },
      onError: function(error) {
        // type: a parse data error will occur
        // info: "Offset 1025 hasn't been loaded yet."
        errorJson = JSON.stringify(error);
        console.log(errorJson);
      }
    });

Any help would be appreciated as this issue also likely occurs for others as well.

User defined URL link/text frames incorrectly parsed

User defined URL link frames are being incorrectly parsed. Code is assuming that the frame description value is the frame value, but the actual URL is actually right after the description. Results in output e.g.:

{
...
WXXX: { 
  id: 'WXXX',
  size: 83,
  description: 'User defined URL link frame',
  data: 'Description of the user defined link frame'
},
...
}

Haven't verified it, but am also positive that the same is happening for user defined text frames given that the code is very similar.

Support for writing tags?

Have you thought about adding support for writing tags? Right now I'm using the mutagen tool for doing this but that won't work in the browser. I understand that this would be a pretty complicated change, but I thought I'd ask anyway.

Getting this to work

I'm relatively new to JavaScript, so please excuse any errors I make in my explanation. So, I am trying to use the browser version of this, but I can't get the example code to work. Is anyone able to help a beginner out?

Can not get the album cover of some M4A

I just started using jsmediatags and unfortunately on the very first file I am trying to load, I couldn't get the album cover.

It can be tested here https://pioug.github.io/jsmediatags-issue/ (see in the dev tools). Link to the repository: https://github.com/pioug/jsmediatags-issue.

I digged a little around https://github.com/aadsm/jsmediatags/blob/master/dist/jsmediatags.js#L1249 and I found out that the atomName === 'covr' is identified as type === 'uint8' instead of jpeg or png.

jsmediatags

By setting manually type to 'jpeg' during the runtime, I can finally display the album cover.

I tried musicmetadata too and the result is similar.

musicmetadata

https://github.com/leetreveil/musicmetadata/blob/master/lib/id4.js#L106

I couldn't find a proper documentation for this (maybe my file is faulty?). However the album cover for this file is working in iTunes, VLC, MusicBrainz Picard (built with Mutagen), Mp3tag...

I can fix my issue in a dirty way 😅

if (atomName === 'covr' && type === 'uint8') {
  type = 'jpeg'
}

But before it would be cool if you @aadsm can shed some light on this. Thanks!

Disk number (iTunes .m4a)

Hey António,

I was wondering whether you knew what the problem here could be.
I'm trying to read the disc number from a iTunes m4a file.

I'm getting the following result:

disk: {
  data: 0,
  description: "Disc Number",
  id: "disk",
  size: 30
}

But I expect data to be 2 instead of 0.
The correct data looks like this (bottom left):

screen shot 2017-05-21 at 9 54 30 pm

You can find the file here:
http://ongaku-ryoho-test.s3.amazonaws.com/2-01-best_foot_forward_(alternate_version).m4a

Thanks! 🥇

PS. Please add a donate button to the readme 💰

No Suitable FileReader Found Apache Cordova/Angularjs

Hi,

I have written a file scanner for cordova android. It works as expexted and fetch me the files from both sdcard and internal memory.

But the problem is i am not able to extract the mp3 TAG info. This has become a real pain

Please find my code


scan : function(url,fileType)
		{
                   log = console.log.bind(console);
                   var defer = $q.defer();

			if(window.cordova)
			{

					var fileTypeCollection = [];

					url.forEach(function(element, index) 
					{
					//requestLocalFileSystemURL
					log(element);
					window.resolveLocalFileSystemURL(element,onRequestFileSystem, fail);

					//log("Ends resolve");
					});


					function onRequestFileSystem(fileSystem) 
					{
					//log(fileSystem.toURL());
					//log(fileSystem.toInternalURL());
					var directoryReader = fileSystem.createReader();
					directoryReader.readEntries(onReadEntries,fail);


					} /*onRequestFile Ends*/

					function onReadEntries(entries) 
					{
					


					entries.forEach( function(element, index) 
					{
						if (element.isDirectory === true) 
						{
						// Recursive -- call back into this subdirectory
							onRequestFileSystem(element);
						} 
						else if(element.isFile == true) 
						{

						fileType.forEach(function(type)
						{
							if(element.name.indexOf(type) != -1)
							{
								log(element.name);
								log(element.fullPath);
								 
                                jsmediatags.read(element.name, 
                                {
                                    onSuccess: function(tag) 
                                    {
                                      var title = tag.tags.title;
                                      var author = tag.tags.author;
                                      log(tag);
                                      // Pour obtenir la durée du son, cf après          
                                    },
                                    onError: function(error) 
                                    {
                                      log(error);
                                    }
                                });

								log(element.toURL());
								//callback(fileTypeCollection);
								fileTypeCollection.push(element);
								defer.resolve(fileTypeCollection);
							
							}

						 });	
					} /*is File ENds*/

					});  /*Entries For Each Ends*/

					}  /*OnRead Ends*/

					function fail(resp)
					{
					log(resp);
					defer.resolve(fileTypeCollection);

					}  /*Fail Ends*/

			}
			else
			{
				log("No Cordova Installed.Cannot Seek File");
				defer.reject();
				//callback(undefined);

			}
			//log(fileTypeCollection);
			//log("Before Resolve");
			return  defer.promise;

		},  //Scan Function Ends

I even tried to use JS-ID3-READER suggestion for cordova and it is also not working

ID3.loadTags(element.name, function() {
var tags = ID3.getAllTags(element.name);
log(tags.comment + " - " + tags.track + ", " + tags.lyrics);
}, {
dataReader: ID3.FileAPIReader(element)
});

This is the affected code. For my whole media scanner please refer to the below link
[https://github.com/siddmegadeth/Cordova-Media-Scanner]

Please suggest. The ID3 Reader does not read .

Remote file loading fail.

Remote host file loading doesn't work, even from example code.
See screenshot below:
2016-03-14 16-48-40

Using with browser JS.

Offset ... hasn't been loaded yet

Hello,

I've experienced a similar behaviour as the following issues:

https://github.com/aadsm/jsmediatags/issues/29
https://github.com/aadsm/jsmediatags/issues/49

Object {type: "parseData", info: "Offset 315 hasn't been loaded yet."}
04 - Turn! Turn! Turn! (To Everything There Is A Season).zip

or

Object {type: "parseData", info: "Offset 274 hasn't been loaded yet."}
01 - Volunteers.zip

For my use case I have fixed the files by re-writing the ID3 tags with winamp.
Maybe the files are helpful to debug the offset problems.

Thanks,
Enno

Support for MusicBrainz tags?

Hi,

Just started playing with this module. It works great. Thanks!

I'd love to be able to read any MusicBrainz tags on files, but it's not supported yet, right?

Any idea how difficult this would be to add? I'd try to do it myself, but I'm definitely a novice in JS and music metadata. Any help or pointers appreciated.

Missing Content-Length in HEAD response leads to invalid request range

I'm using the library in the browser and I'd like to see the tags of MP3 files. Doing so leads to the following error:

GET http://localhost:3001/sound/stella.mp3 416 (Requested Range Not Satisfiable)

This happens because the requested range is [NaN, NaN]. After a quick first debug session I think this is caused by the size of the file being reported as NaN. In the XHRFileReader you send a HEAD request in order to get the file size using Content-Length in the response header. Not all servers return Content-Length after a HEAD request, though. See RFC 7231:

The server SHOULD send the same header fields in response to a HEAD request as it would have sent if the request had been a GET, except that the payload header fields (Section 3.3) MAY be omitted.

SOULD, not MUST. In my case, there is no such information and thus the rest fails. I "verified" this by replacing the parseInt() expression with a constant number. The line in question is:

self._size = parseInt(xhr.getResponseHeader("Content-Length"), 10);

How should this be fixed correctly? Why do you need the file size? (I don't know much about ID3 tags, hence these questions)

Error: No suitable file reader found for

I was testing your script for usage in a browser (tested on Safari, Chrome, Firefox).
The following HTML file should just show a button, you select a file from your local disk and it puts the ID3 Tags etc. in the JavaScript Console (just for testing so far).

Try it yourself: https://jsfiddle.net/d68kww4v/

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
        <script src="https://github.com/aadsm/jsmediatags/raw/master/dist/jsmediatags.js"></script>
        <script>
            $(function(){
                var jsmediatags = window.jsmediatags;

                $("#filesToUpload").change(function(e){
                    //for every file...
                    for (var i = 0; i < e.target.files.length; i++) {
                        console.log('File ' + (i + 1) + ':  ' + e.target.files[i].name);
                        jsmediatags.read(e.target.files[i].name, {
                          onSuccess: function(tag) {
                            console.log(tag);
                          },
                          onError: function(error) {
                            console.log(error);
                          }
                        });
                    }
                });
            });
        </script>
    </head>
    <body>
        <form>
            <input name="filesToUpload[]" id="filesToUpload" type="file" multiple>
        </form>
    </body>
</html>

However it always results in an error like:

Error: No suitable file reader found for 
_findFileReaderjsmediatags.js:2181
_getFileReaderjsmediatags.js:2169
readjsmediatags.js:2147
readjsmediatags.js:2116
(anonyme Funktion)jsmediatags.html:14
dispatchjquery-2.2.3.min.js:2:7542
handlejquery-2.2.3.min.js:2:5625

Offset 110727 hasn't been loaded yet

Hello! I've used jsmediatags successfully with many mp3 files, but some files don't return any tags.
The files contain ID3v1.1 and ID3v2.3.0 tags. The 2.3.0 has an embedded image 500px x 500px.
The tags are read successfully in Kid3, WinAmp, and on my Phone audio player.

The info attribute of the tag object says "Offset 110727 hasn't been loaded yet.".

I found this, but can't be sure it's the same issue...
[https://github.com//issues/14]

Many thanks.

Rob

Uncaught Error: Offset 160 hasn't been loaded yet.

Hi @aadsm, thanks for the awesome work :)

Found this issue, that only happens to a few files. It doesn't fire the error handler, but instead blows up, and I can't 'catch' it. Let me know how I can help.

new jsmediatags.Reader(filePath)
            .read({
                onSuccess: function(tag) {
                },
                onError: function(error) {
                }
            });

Here's the stack:

Uncaught Error: Offset 160 hasn't been loaded yet
.getByteAt @ ChunkedFileData.js?7fb3:176
getByteAt @ NodeFileReader.js?72bc:25
getBytesAt @ MediaFileReader.js?47b0:70
getStringWithCharsetAt @ MediaFileReader.js?47b0:154
readTextFrame @ ID3v2FrameReader.js?cb45:84
_readFrames @ ID3v2TagReader.js?b38e:147
_parseData @ ID3v2TagReader.js?b38e:70
self._loadData.onSuccess @ MediaTagReader.js?b084:43

For the sake of copyright, I've cropped the offending music file to ~15 seconds.

Detroit Swindle - Figure of Speech_30secs.mp3.zip

How to retrieve data from chapters?

Hi!

First, thank you for the lib and the documentation, it was really helpful!
I'm trying to develop a browser side mp3 player (and to manage id3 v2.4.0 data to enhance the UX) but can't reach the data into chapters (we've provided pictures and titles):

[{"id":"CHAP","size":51749,"description":"Unknown","data":null},{"id":"CHAP","size":46,"description":"Unknown","data":null},{"id":"CHAP","size":516417,"description":"Unknown","data":null},{"id":"CHAP","size":176998,"description":"Unknown","data":null},{"id":"CHAP","size":219066,"description":"Unknown","data":null},{"id":"CHAP","size":50,"description":"Unknown","data":null}]

My question is: is this a limitation of the lib or is there a way to reach these data? Maybe on overloading one of the MediaTagReader class?

(My repo is here: https://github.com/seracio/sound-player/blob/master/src/index.js)

how to use picture.data?

i'm trying to show it by the code:

URL.createObjectURL(new Blob(tag.tags.picture.data, { type: tag.tags.picture.format }))

but fail, how to use it?

Is it possible to consume the package using webpack?

I've installed jsmediatags from npm and then I tried to use like this:
var jsmediatags = require("jsmediatags");

Which gives me an error like this:
./~/jsmediatags/build2/NodeFileReader.js Module not found: Error: Cannot resolve module 'fs'
I guess this is the version to be used in the backed.

When I use the downloaded jsmediatags.js or jsmediatags.min.js likes this:
var jsmediatags = require('./assets/js/jsmediatags');

It works but I get this warning:
./src/assets/js/jsmediatags.js Critical dependencies: 1:484-491 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results. @ ./src/assets/js/jsmediatags.js 1:484-491

So my question is, Is it possible to require the front-end version directly from the npm directory? If not, it will be great if you add these dist files with the npm package or some other way so we can require the package directly from node_modules directory something like this:
var jsmediatags = require('jsmediatags/dist/jsmediatags');

Error: Offset 87722 hasn't been loaded yet.

I don't know if this is any way related to issue #14

Code:

var tags = fs.readdir(dir, function (err, files) {
  if (!err) {
    files.forEach(function (element) {
      jsmediatags.read(dir + element, {
        onSuccess: function (tag) {
          console.log(tag)
        },
        onError: function (tagError) {
          console.log('tagError:(', tagError.type, tagError.info)
        }
      })
    })
  } else {
    console.log(err)
  }
})

Trace:

Error: Offset 87722 hasn't been loaded yet.
    at ChunkedFileData.getByteAt (~/node_modules/jsmediatags/build2/ChunkedFileData.js:185:11)
    at NodeFileReader.getByteAt (~/node_modules/jsmediatags/build2/NodeFileReader.js:25:27)
    at NodeFileReader.getBytesAt (~/node_modules/jsmediatags/build2/MediaFileReader.js:70:23)
    at NodeFileReader.getStringWithCharsetAt (~/node_modules/jsmediatags/build2/MediaFileReader.js:154:22)
    at readPictureFrame (~/node_modules/jsmediatags/build2/ID3v2FrameReader.js:37:25)
    at ID3v2TagReader._readFrames (~/node_modules/jsmediatags/build2/ID3v2TagReader.js:151:40)
    at ID3v2TagReader._parseData (~/node_modules/jsmediatags/build2/ID3v2TagReader.js:74:25)
    at self._loadData.onSuccess (~/node_modules/jsmediatags/build2/MediaTagReader.js:43:29)
    at processData (~/node_modules/jsmediatags/build2/NodeFileReader.js:83:7)

Is this my inexperience or an error with this library?

tag reading fails, breaking promise chain

I've encountered a rare error, when reading a large number (25k+) of unsanitized mp3 files, a few of those files throw an unrecoverable error which breaks my program.

Details:
MediaFileReader.js, line 67, throws an invalid array length exception on some mp3 files. The error is caused by variable "length" having a value of -2, which Array cannot be instantiated on.

Tracing the error further up the next point of interest is in ID3v2TagReader.js, line 160, framesize is 2, which is too low. Why it's this low I don't know.

Bigger picture :
From what I can tell you're missing an error check in MediaTagReader.js, line 42 :

var tags = self._parseData(self._mediaFileReader, self._tags);  

This line tries to load tags after a successful load of the file, but this is too optimistic, given that tag reading can still fail on rare occasions. I "fixed" it with

        try
        {
          var tags = self._parseData(self._mediaFileReader, self._tags);  
          callbacks.onSuccess(tags);
        }catch(ex){
          callbacks.onError({type : 'foo', info : 'bar' });  
        }

Which continues the promise chain in the event of an error happening inside onSuccess. I'm not super clued up on promise theory, but I'm guessing this is an acceptable fix? I'd be happy to write and pull request it.

How to retrieve image from a MP3 File?

I tried to get the image from a MP3 file with this code but it doesn't work, I get this error message in Console: "No suitable file reader found for" jsmediatags.min.js:64

Does anybody know how to get the image correctly from a MP3 file? I searched a lot on Google but couldn't find any examples for jsmediatags.

    jsmediatags.read("test.mp3", {
        onSuccess: function(tag) {
          var tags = tag.tags;
          console.log(tags);

          var image = tags.picture;
          if (image) {
            var base64String = "";
            for (var i = 0; i < image.data.length; i++) {
                base64String += String.fromCharCode(image.data[i]);
            }
            var base64 = "data:" + image.format + ";base64," +
                    window.btoa(base64String);
            document.getElementById('picture').setAttribute('src',base64);
          } else {
            document.getElementById('picture').style.display = "none";
          }

        }
    });

Is this right library for getting creation date of mp4?

Hi, I really want to attain creation date of mp4 file using pure javascript lib, and I hope this is right place for that. As I mentioned earlier, I have one sample mp4 file in my tmp web server, and I can get exif data using exiftool.

http://dev.qoontree.com:7001/sample-video.mp4
http://dev.qoontree.com:7001/metadata.txt

When I use your function, I got this.

{
ftp: “isom”,
type: “MP4”,
version: 512,
tags: {
©too: {
data: “Lavf53.24.2”,
description: “Encoding Tool”,
id: “©too”,
size: 35
}
}
}

But, in metadata.txt I can see the other infos like 'Modify Date: 2014:07:19 17:15:29'. Is there any chance to get creation or modify date info using your lib?

Is this right library to get exif data like creation date?

It will be great if you check this for me.

Add browser version to npm

Hello, I'm wondering why the dist folder is not included in npm package. I am using npm to manage my browser application and to keep it updated.. Can you please include the dist folder in npm package to make it easier for developers. Thanks in advance.

Regards,
Mike

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.