benrr101 / node-taglib-sharp Goto Github PK
View Code? Open in Web Editor NEWA node.js port of mono/taglib-sharp
License: GNU Lesser General Public License v2.1
A node.js port of mono/taglib-sharp
License: GNU Lesser General Public License v2.1
Pull in mono/taglib-sharp#235 to get more INFO tags
Kinda similar to LINQ IEnumerable operations make it so that when you do .mid
on a ByteVector
, you get an object that simply stores the start/end index of an existing ByteVector
instead of copying it every time. The object provides ways to materialize the ByteVector
comprehension if it's necessary to make changes to it. This would have a marked improvement on performance since it would remove a lot of instances where we're copying 4 bytes here and there. It would also allow us to simplify the ByteVector
interface by removing offsets and length arguments from to*
methods.
is it possible to use in browser?
using File.createFromAbstraction()
?
Within file file.mjs
I have:
import { File } from 'node-taglib-sharp';
When trying to load that file I get this error:
TypeError: Cannot set property ByteVector of #<Object> which has only a getter
at Object.<anonymous> (/home/node/app/node_modules/node-taglib-sharp/dist/index.js:3:1200)
I'm able to get the file to load by changing file.mjs
to:
import { File } from 'node-taglib-sharp/dist/file.js';
but then it fails with:
/home/node/app/node_modules/node-taglib-sharp/dist/file.js:113
throw new Error(`Unsupported format: mimetype for ${abstraction.name} (${mimeType}) is not supported`);
because I'm guessing that File._fileTypes
gets set within the main module.
The file is being loaded directly (no pre-processing involved).
Running:
v20.6.0
5.1.0
I was going over the wiki on default tags and this error is coming up that I've noticed a few other times with the package.
import { File, Tag, Picture, TagTypes, MpegAudioFileSettings,} from "node-taglib-sharp";
SyntaxError: Named export 'MpegAudioFileSettings' not found.
The requested module 'node-taglib-sharp' is a CommonJS module,
which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export
I actually have a bunch of imports from the package that load / work fine. I'm using Node v. 20.0.0.
๐ฌ
Files that support multiple tags can have default tag types set. All files should get that option - either you get one tag or you get no tag.
Got this message on a few .mp3's , 'Argument out of range length must be a safe, positive JS integer'. I assume it is related to a bad tag. I removed the tag completely and then ran it back again with node-taglib-sharp, no errors. Could it be related to:
"The Node.js 12 fs library only supports integer types for position arguments, which safely goes up to 2^52 - 1."
I'm on Node 20.
This is my code
const tagger = (file, dir) => {
const myFile = File.createFromPath(file);
console.log(myFile.isPossiblyCorrupt); // returned false
console.log(myFile.position); // returned 0
try {
if (!myFile.tag.title) {
myFile.tag.title = path.basename(file);
}
myFile.save();
myFile.dispose();
} catch (err) {
console.error(err.message, file);
}
};
We're using UInt
and Uint
all over the place, standardize on Uint
which is the style javascript uses.
I hate musicbrainz. Make sure the AlbumArtistId field is using the right item key
Since upgrading from 5.2.2 to 5.2.3, reading of mp3 picture.data is broken for a select number of files. I've attached a file which has this behavior.
Sample.zip
Version 5.2.2 reads picture.data as an Uint8Array of 2083937 elements:
This results as an image showing correctly in a img tag after conversion to a Buffer:
Version 5.2.3 reads picture.data as an Uint8Array of 1394 elements:
This results as an image showing as broken in a img tag after conversion to a Buffer:
Not sure what is causing this, file tags read in 'music-metadata'. It's only happening on one file (right now) so let me know if you'd need to see the file. I'm using the properties class (ICode and IAudioCode) basically sending the properties individually to the console.
throw new Error(`Argument null: ${name} was not provided`); ^
Error: Argument null: id was not provided
at Guards.truthy (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\utils.js:86:19)
at new Id3v2FrameHeader (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\id3v2\frames\frameHeader.js:65:24)
at Id3v2FrameHeader.fromData (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\id3v2\frames\frameHeader.js:133:16)
at Object.createFrame (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\id3v2\frames\frameFactory.js:88:55)
at Id3v2Tag.parse (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\id3v2\id3v2Tag.js:1250:54)
at Id3v2Tag.readFromStart (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\id3v2\id3v2Tag.js:1274:14)
at Id3v2Tag.fromFileStart (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\id3v2\id3v2Tag.js:80:13)
at Object.action (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\sandwich\startTag.js:120:50)
at StartTagParser.read (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\sandwich\startTag.js:97:47)
at StartTag.read (C:\Users\sambi\Documents\nodeProjs\backup-cli\node_modules\node-taglib-sharp\dist\sandwich\startTag.js:70:23)
I discovered an ogg file in the wild that throws this exception when parsed: "Granular position is too large to be handled with this version of node-taglib-sharp".
When debugging, I found that the expression in const absoluteGranularPosition = data.subarray(6, 8).toUlong(false);
in oggPageHeader.ts returns 0n.
The check if (absoluteGranularPosition > Number.MAX_SAFE_INTEGER){}
considers 0n larger than Number.MAX_SAFE_INTEGER which throws the error. To resolve this problem and allow the file to be parsed, I removed the check if (absoluteGranularPosition > Number.MAX_SAFE_INTEGER){}
, for 2 reasons:
Number(absoluteGranularPosition)
Number.MAX_SAFE_INTEGER
, I assume that an error will be thrown anyway.Would this be an acceptable fix or did you add the check because of other risks that I'm missing?
I've attached the file in question.
calm3.zip
samples.zip
there are two audio files, the duration are all 3 seconds. but file.properties.durationMilliseconds
is 6110
for .mp3
and 6000
for .wav
but in https://audio-tag-analyzer.netlify.app/ they are correctly read
It would be nice to support lossless audio formats (biggest ones being aiff
, flac
and wav
).
Happy to help on this one, I'd just need directions to get started.
Hi,
First of all, thanks for that library that looks really promising.
Is there any reason why the node version is pinned to 12.16.1
?
Thanks!
Antoine
๐ค
Am trying to figure out how to read data from flac and mp3 files., encountering undefined fields such as 'date'. What am i missing here ? all data comes from MusicBrainz
Would be nice to have a 'tags' function for retrieving all available data as object.
const myFile = File.createFromPath(filePath); // flac or mp3
console.log(myFile.tag.title);
console.log(myFile.tag.date)
console.log(myFile.tag.artists);
I'm trying to set tags to a m4a file but I keep getting Argument null: ${name} was not provided
. It occurs when calling myFile.save()
import { File } from "node-taglib-sharp";
const myFile = File.createFromPath(`${process.cwd()}\\ong_bong_chong.m4a`);
myFile.tag.title = "Ong Bong Chong";
myFile.tag.performers = ["Firoze Jong"];
myFile.save();
myFile.dispose();
this is the error I get
Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\utils.js:53
throw new Error(`Argument null: ${name} was not provided`);
^
Error: Argument null: text was not provided
at Guards.notNullOrUndefined (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\utils.js:53:19)
at ByteVector.fromString (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\byteVector.js:382:24)
at get data [as data] (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\mpeg4\boxes\isoHandlerBox.js:62:173)
at Mpeg4BoxRenderer.renderBox (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\mpeg4\mpeg4BoxRenderer.js:33:22)
at Mpeg4BoxRenderer.renderBox (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\mpeg4\mpeg4BoxRenderer.js:29:45)
at Mpeg4BoxRenderer.renderBox (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\mpeg4\mpeg4BoxRenderer.js:29:45)
at Mpeg4File.save (Z:\Development\taglib\node_modules\.pnpm\node-taglib-sharp@5.2.3\node_modules\node-taglib-sharp\dist\mpeg4\mpeg4File.js:79:56)
at file:///Z:/Development/taglib/index.ts:5:8
at ModuleJob.run (node:internal/modules/esm/module_job:217:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:316:24)
Node.js v20.9.0
The file is a download from yt-dlp and does not have any tags. ong_bong_chong.zip
Sorry, can get how to add cover to aiff file?
I try this:
var pictureBuffer = fs.readFileSync(orderFolderName+'Front.png')
var pic = {
data: pictureBuffer,
mimeType: 'image/png'
}
const myFile = File.createFromPath(orderFolderName+'/test.aif');
myFile.tag.title = result.tracklist[0].title;
myFile.tag.album = result.title;
myFile.tag.performers = [result.artists_sort];
myFile.tag.pictures = [pic];
myFile.tag.genres = result.styles;
myFile.tag.year = result.year;
myFile.save();
myFile.dispose();
But i get error: Argument null: data was not provided
Hey mate! Sorry, but i'm back))
I have some strange with saving file after adding tags.
My code:
const myFile = File.createFromPath(path);
const pic = {
data: ByteVector.fromPath(pathToPic),
mimeType: 'image/png',
type: PictureType.FrontCover,
filename: 'Cover.png',
description: 'Cover.png'
}
myFile.tag.pictures = [pic];
myFile.tag.title = tagsData.trackTitle;
myFile.tag.album = tagsData.releaseAlbum;
myFile.tag.performers = [tagsData.artists];
myFile.tag.albumArtists = [tagsData.albumArtists];
myFile.tag.genres = tagsData.styleAsString;
if (tagsData.year) {
myFile.tag.year = tagsData.year;
}
myFile.tag.track = tagsData.indexTrack;
myFile.tag.trackCount = tagsData.trackCount;
myFile.save();
myFile.dispose();
After saving i don't see cover and tags in finder or preview. - http://prntscr.com/26bi92t
They are present, I can see they in players (itunes) or tag editors (kid3, meta) - http://prntscr.com/26bi9er
And then if I open this file in kid3 and save it - tags and cover will be visible in finder and preview - http://prntscr.com/26bia32
OS: Mac OS
Files type: aiff
Can you help me?
Regards!
Originally posted by @vk22 in #34 (comment)
As user of my software notified me that tags could not be read from some of his files (files attached). I did some debugging to try to help out, but I'm now stuck.
This Guard in the FrameHeader constructor throws an error Argument null: id was not provided
And indeed, frameId seems to be undefined:
I did the same test in TagLib#, and where node-taglib-sharp returns undefined, TagLib# returns a frameIdentifier of type RGAD:
I see that frameIdentifiers.ts does not contain a frameIdentifier of type RGAD. Is it just a matter of adding it?
former issue: #71
I finally reuse testStream.ts to implement IStream, but when save picture to large audio file, the write implemention is signaficantly slow in
same audio file (7.13 MB) and image (14 KB or 1.68 MB perform the same), larger file cost more time
Maybe caused by buffer allocation? Is there any way to fix that?
Hey, would also be great to have support for ".m4a"! Any plans to add this?
When attaching pictures to .mp3 files, the cover cannot display in windows file browser.
let cover = {
data: taglib.ByteVector.fromByteArray(data),
mimeType: 'image/jpeg',
type: taglib.PictureType.FrontCover,
}
let dest = taglib.File.createFromPath(save_path);
dest.tag.pictures = [cover];
dest.save();
dest.dispose();
As per investigation from #62, it's not necessary to have the safe integer check on granule position. The granule position is used differently for each codec, so it does not correspond to a file offset. Therefore, no need to store it as a number.
ID3v2 tags that are at the end of a file don't appear to be appearing in Foobar2000, VLC, or Windows explorer. They are readable by node-taglib-sharp, so it will need a bit of investigation with hex editor or something to figure out where the tags are being incorrectly set.
In this doc
In the constructor parameters this is a typo:
v4 | string | Identifier string to use on ID3v2.4 tags. If not supplied, frame type is not valid for ID3v2.4 tags.
v3 | string | Identifier string to use on ID3v2.3 tags. If not supplied, frame type is not valid for ID3v2.4 tags.
However in my code I have **new Id3v2FrameIdentifier("v3")**
and when I console.log the frame this is what I'm seeing -
TextInformationFrame {
_header: Id3v2FrameHeader {
_frameId: FrameIdentifier {
_version4: [ByteVector],
_version3: undefined,
_version2: undefined
},
_frameSize: 0,
_flags: 0
},
_encoding: 3,
_textFields: []
}
It looks like having the 'v3' identifier is still setting the tag for ID3v2.4 ?
Apparently there's an older ReplayGain frame identifier RGAD
that isn't being handled in the code. https://wiki.hydrogenaud.io/index.php?title=ReplayGain_legacy_metadata_formats
Hi, would be great to have support for ".webm". It is an free standard that is being used more and more as it has great compression while maintaining great quality!
It seems more common to have an artist value, than albumArtists. I am wrong because I do get returns with 'performers'.
Edit: Just tested, setting performers shows in the generic Artist field
This field is most commonly called "Artists" in audio media or "Actors" in video media, and should be used to represent each artist/actor appearing in the media.
Logic for converting frames between versions is really annoying and as I'm finding, not robust. To simplify things (and simplify the usage for users), make the version of ID3v2 tag objects immutable. In order to change versions, create a new tag and copy the old tag into it. The copy logic should handle any conversion between frame types.
I've been using TagLib# for years and in an audio player written in .NET, I was able to read and write to the PopularimeterFrame of MP3 files using Taglib#. My audio player has now been migrated to Electron, so I'm trying to read from and write to the PopularimeterFrame using your library. I've searched through the source code, but unfortunately it's not clear for me if this is possible.
Is this possible? If yes, how could I do this?
Thank you.
First, I want my tag to be id3v2.3 not v.2.4 so hopefully I am trying to use the correct classes.
Anyway, in this particular I have a sandwich tag with the start tags being a id3v2.3 and an end tag being id3v1.
I get the v2.3 tag like this:
const id3v2Tag = myFile.getTag(TagTypes.Id3v2, true);
and then set up the new frame:
const id = new Id3v2FrameIdentifier("v3");
const header = new Id3v2FrameHeader(id);
const frame = new Id3v2TextInformationFrame(header);
id3v2Tag.addFrame(frame);
but how / where to add in the (example) ('TIT2', 'mytitle') ?
Eg: I have an MP3 with an ID3v2, defaults tag types are set to ID3v2 + APE.
What happens: APE tag is added to file, APE tag is empty.
What should happen: APE tag is added to file, APE tag has copy of ID3v2 data. This should be the default behavior (to mirror TagLib#), but it should be configurable.
Bitrate can be roughly calculated by (file.fileAbstraction.size - file.tag.sizeOnDisk) * 8 / file.properties.duration
. Some files will return 0 when getting its bitrate, and make a fallback value for bitrate is needed IMO.
But that needs a new property on FileAbstraction
. Here is my implemention.
export class Stream {
// ...
public static getFileSize(path: string): number {
return fs.statSync(path).size
}
}
export interface IFileAbstraction {
// ...
/**
* Total size of file
*/
size: number;
}
export class FileAbstraction {
// ...
public get size(): number {
return Stream.getFileSize(this._name)
}
}
When I save i file that I have changed it's metadata and I try to open it, windows apps says that it's corrupted, but I can open it with VLC or chrome.
My code:
const myFile = taglib.File.createFromPath('path/to/audioFile.mp3');
const pic = {
data: taglib.ByteVector.fromPath('path/to/cover.jpg'),
mimeType: 'image/jpg',
type: taglib.PictureType.FrontCover,
};
myFile.tag.title = "Some Title";
myFile.tag.album = "Some Album";
myFile.tag.albumArtists = ["Some Artist"];
myFile.tag.comment = "Some comment";
myFile.tag.performers = ["Some Artist"];
myFile.tag.pictures = [pic];
myFile.tag.year = 2020;
myFile.tag.track = 3;
myFile.tag.trackCount = 7;
myFile.tag.lyrics = 'Some lyrics...';
myFile.save();
myFile.dispose();
Thanks!
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.