From b0407504cd5175388d392c7b1cbfa402e06b7c29 Mon Sep 17 00:00:00 2001 From: Digimezzo Date: Sat, 13 Dec 2025 14:47:54 +0100 Subject: [PATCH 1/5] Fixes #120: ID3v2.3 genres are trimmed --- src/id3v2/frames/textInformationFrame.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/id3v2/frames/textInformationFrame.ts b/src/id3v2/frames/textInformationFrame.ts index c5b4e4d..56cbbd2 100644 --- a/src/id3v2/frames/textInformationFrame.ts +++ b/src/id3v2/frames/textInformationFrame.ts @@ -459,7 +459,7 @@ export class TextInformationFrame extends Frame { if (value.length > 0) { // Split the remaining genre value by dividers if the setting is turned on let splitValue = Id3v2Settings.useNonStandardV2V3GenreSeparators - ? value.split(/[\/;]/).map((v) => v.trim()).filter((v) => !!v) + ? value.split(/[\/;]/).filter((v) => !!v) : [value]; splitValue = splitValue.map((v) => { From 368fb6c744f072c8c0124a05d062819a3e335791 Mon Sep 17 00:00:00 2001 From: Digimezzo Date: Wed, 24 Dec 2025 22:10:21 +0100 Subject: [PATCH 2/5] Fix #120 and #122 --- src/id3v2/frames/textInformationFrame.ts | 70 ++++-------------------- src/utils.ts | 2 +- 2 files changed, 11 insertions(+), 61 deletions(-) diff --git a/src/id3v2/frames/textInformationFrame.ts b/src/id3v2/frames/textInformationFrame.ts index 56cbbd2..c3872a4 100644 --- a/src/id3v2/frames/textInformationFrame.ts +++ b/src/id3v2/frames/textInformationFrame.ts @@ -410,74 +410,24 @@ export class TextInformationFrame extends Frame { // Some frames are designed to be split into multiple parts by a / fieldList.push(... value.split("/")); } else if (this.frameId === FrameIdentifiers.TCON) { - // @TODO: Can we just make a separate class for TCON? - // TCON in ID3v2.2 and ID3v2.3 is specified as - // * (xx) - where xx is a number from the ID3v1 genre list - // * (xx)yy - where xx is a number from the ID3v1 genre list and yyy is a - // "refinement" of the genre - // * (RX) - "Remix" - // * (CR) - "Cover" - // * (( - used to escape a "(" in a refinement/genre name - - // NOTE: This encoding has an inherent flaw around how multiple genres should be - // encoded. Since multiple genres are already an edge case, I'm just going to - // say yolo to this whole block of code copied over from the .NET implementation - while (value.length > 1 && value[0] === "(") { - const closing = value.indexOf(")"); - if (closing < 0) { - break; - } + while (value.length > 1 && value[0] === '(') { + const closing = value.indexOf(')'); + if (closing < 0) break; const number = value.substring(1, closing); + fieldList.push(number); - let text: string; - if (number === TextInformationFrame.COVER_ABBREV) { - text = TextInformationFrame.COVER_STRING; - } else if (number === TextInformationFrame.REMIX_ABBREV) { - text = TextInformationFrame.REMIX_STRING; - } else { - text = Genres.indexToAudio(number, true); - } + value = StringUtils.trimStart(value.substring(closing + 1), ' ').replace(/^\/+/, ''); - if (!text) { - // Number in parentheses was not a numeric genre but part of a larger bit - // of text? - break; - } - - // Number in parentheses was a numeric genre - fieldList.push(text); - value = StringUtils.trimStart(value.substring(closing + 1), "/ "); - - // Ignore genre if the same genre appears after the numeric genre - if (value.startsWith(text)) { - value = StringUtils.trimStart(value.substring(text.length), "/ "); + const text = Genres.indexToAudio(number, true); + if (text && value.startsWith(text)) { + value = StringUtils.trimStart(value.substring(text.length),' ').replace(/^\/+/, ''); } } - // Process whatever's left if (value.length > 0) { - // Split the remaining genre value by dividers if the setting is turned on - let splitValue = Id3v2Settings.useNonStandardV2V3GenreSeparators - ? value.split(/[\/;]/).filter((v) => !!v) - : [value]; - - splitValue = splitValue.map((v) => { - // Unescape escaped opening parenthesis - let v2 = v.replace(/\(\(/, "("); - - // If non-standard numeric genres is enabled, parse them - if (Id3v2Settings.useNonStandardV2V3NumericGenres) { - const text = Genres.indexToAudio(v2, false); - if (text) { - v2 = text; - } - } - - return v2; - }); - - fieldList.push(...splitValue); + const remainingGenres = value.split(/[\/;]/); + fieldList.push(...remainingGenres); } } else { fieldList.push(value); diff --git a/src/utils.ts b/src/utils.ts index a3353a3..1aa8318 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -344,7 +344,7 @@ export class StringUtils { public static trimStart(toTrim: string, chars: string): string { while (toTrim.length > 0 && chars.indexOf(toTrim[0]) > -1) { - toTrim = toTrim.substring(0); + toTrim = toTrim.substring(1); } return toTrim; } From 49792258ac8991c4d5dc17bc0d1122bad33d645e Mon Sep 17 00:00:00 2001 From: Digimezzo Date: Mon, 9 Feb 2026 13:45:54 +0100 Subject: [PATCH 3/5] Update package details and add CHANGELOG for versioning --- CHANGELOG.md | 11 ++++++++ README.md | 71 ++++++++++++++++++++++++++++------------------------ package.json | 13 ++++++---- 3 files changed, 57 insertions(+), 38 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..3da1828 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Dopamine change log + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2026-02-09 + +### Changed + +- Based on https://github.com/benrr101/node-taglib-sharp/releases/tag/v6.0.1 +- First attempt at NPM package. diff --git a/README.md b/README.md index 488808e..3cd408c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # TagLib# for Node -| Master | Develop | Latest | -|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [![Build Status](https://ci.appveyor.com/api/projects/status/7hdfrbc4ecvvruwv/branch/master?svg=true)](https://ci.appveyor.com/project/benrr101/node-taglib-sharp/branch/master) | [![Build Status](https://ci.appveyor.com/api/projects/status/7hdfrbc4ecvvruwv/branch/develop?svg=true)](https://ci.appveyor.com/project/benrr101/node-taglib-sharp/branch/develop) | [![Build Status](https://ci.appveyor.com/api/projects/status/7hdfrbc4ecvvruwv?svg=true)](https://ci.appveyor.com/project/benrr101/node-taglib-sharp) | -| [![Coverage Status](https://coveralls.io/repos/github/benrr101/node-taglib-sharp/badge.svg?branch=master)](https://coveralls.io/github/benrr101/node-taglib-sharp?branch=master) | [![Coverage Status](https://coveralls.io/repos/github/benrr101/node-taglib-sharp/badge.svg?branch=develop)](https://coveralls.io/github/benrr101/node-taglib-sharp?branch=develop) | [![Coverage Status](https://coveralls.io/repos/github/benrr101/node-taglib-sharp/badge.svg?latest)](https://coveralls.io/github/benrr101/node-taglib-sharp) | +## Maintenance Notice + +This is a fork of node-taglib-sharp containing extra bug fixes. All credit goes to the original author. The original project can be found here: https://github.com/benrr101/node-taglib-sharp ## Description + TagLib# is a .NET library that has been around for years. It provides a unified interface for accessing metadata from a vast selection of media files. Until now there hasn't been a port of this library for Node.js. This project is a mostly wholesale translation of the original TagLib#. @@ -15,44 +15,48 @@ is substantially lacking in the variety of media formats that can be handled. Ta improved on the original TagLib, hence why this project exists. ## Supported Tagging Formats -* [APE](http://wiki.hydrogenaud.io/index.php?title=APE_key): `AAC`, `APE`, `FLAC`, `M2A`, `MP1`, `MP2`, `MP3` -* [Apple QuickTime/iTunes](https://developer.apple.com/documentation/quicktime-file-format/metadata_atoms_and_types) MPEG4: `M4A`, `M4B`, `M4P`, `M4V`, `MP4` -* [ASF](https://docs.microsoft.com/en-us/windows/win32/wmformat/overview-of-the-asf-format): `ASF`, `WMA`, `WMV` -* DIVX: `AVI`, `DIVX`, `WAV` -* [ID3v1](https://id3.org/ID3v1): `AAC`, `FLAC`, `M2A`, `MP1`, `MP2`, `MP3` -* [ID3v2](https://id3.org/Developer%20Information): `AAC`, `AIF`, `AIFF`, `AVI`, `DIVX`, `FLAC`, `M2A`, `MP1`, `MP2`, `MP3`, `WAV` -* [Matroska/WebM](https://www.matroska.org/technical/tagging.html): `MK3D`, `MKA`, `MKS`, `MKV`, `WEBM` _read-only_ -* MovieID: `AVI`, `DIVX`, `WAV` -* [RIFF Info](https://www.exiftool.org/TagNames/RIFF.html#Info): `AVI`, `DIVX`, `WAV` -* [Xiph Comment](https://www.xiph.org/vorbis/doc/v-comment.html): `FLAC`, `OGA`, `OGG`, `OGV`, `OPUS` -* ... More coming soon + +- [APE](http://wiki.hydrogenaud.io/index.php?title=APE_key): `AAC`, `APE`, `FLAC`, `M2A`, `MP1`, `MP2`, `MP3` +- [Apple QuickTime/iTunes](https://developer.apple.com/documentation/quicktime-file-format/metadata_atoms_and_types) MPEG4: `M4A`, `M4B`, `M4P`, `M4V`, `MP4` +- [ASF](https://docs.microsoft.com/en-us/windows/win32/wmformat/overview-of-the-asf-format): `ASF`, `WMA`, `WMV` +- DIVX: `AVI`, `DIVX`, `WAV` +- [ID3v1](https://id3.org/ID3v1): `AAC`, `FLAC`, `M2A`, `MP1`, `MP2`, `MP3` +- [ID3v2](https://id3.org/Developer%20Information): `AAC`, `AIF`, `AIFF`, `AVI`, `DIVX`, `FLAC`, `M2A`, `MP1`, `MP2`, `MP3`, `WAV` +- [Matroska/WebM](https://www.matroska.org/technical/tagging.html): `MK3D`, `MKA`, `MKS`, `MKV`, `WEBM` _read-only_ +- MovieID: `AVI`, `DIVX`, `WAV` +- [RIFF Info](https://www.exiftool.org/TagNames/RIFF.html#Info): `AVI`, `DIVX`, `WAV` +- [Xiph Comment](https://www.xiph.org/vorbis/doc/v-comment.html): `FLAC`, `OGA`, `OGG`, `OGV`, `OPUS` +- ... More coming soon ## Supported File Formats -* Advanced Audio Codec (AAC): `AAC` -* Advanced Systems Format (ASF): `ASF`, `WMA`, `WMV` -* Audio Interchange Format (AIFF): `AIF`, `AIFF` -* Free Lossless Audio Codec (FLAC): `FLAC` -* Matroska: `MK3D`, `MKA`, `MKS`, `MKV` -* MPEG-1/2 Audio: `M2A`, `MP1`, `MP2`, `MP3` -* MPEG-1/2 Video: `M2V`, `MPE`, `MPEG`, `MPG`, `MPV2` -* MPEG4: `M4A`, `M4B`, `M4P`, `M4V`, `MP4` -* Monkey's Audio: `APE` -* Ogg: `OGA`, `OGG`, `OGV`, `OPUS` -* Resource Interchange File Format (RIFF): `AVI`, `DIVX`, `WAV` -* WebM: `WEBM` -* ... More coming soon + +- Advanced Audio Codec (AAC): `AAC` +- Advanced Systems Format (ASF): `ASF`, `WMA`, `WMV` +- Audio Interchange Format (AIFF): `AIF`, `AIFF` +- Free Lossless Audio Codec (FLAC): `FLAC` +- Matroska: `MK3D`, `MKA`, `MKS`, `MKV` +- MPEG-1/2 Audio: `M2A`, `MP1`, `MP2`, `MP3` +- MPEG-1/2 Video: `M2V`, `MPE`, `MPEG`, `MPG`, `MPV2` +- MPEG4: `M4A`, `M4B`, `M4P`, `M4V`, `MP4` +- Monkey's Audio: `APE` +- Ogg: `OGA`, `OGG`, `OGV`, `OPUS` +- Resource Interchange File Format (RIFF): `AVI`, `DIVX`, `WAV` +- WebM: `WEBM` +- ... More coming soon ## Installation + ``` npm install --save node-taglib-sharp ``` ## Getting Started + Getting started with node-taglib-sharp is surprisingly easy. The main entry point into the library is via the `File` class. ```typescript -import {File} from "node-taglib-sharp"; +import { File } from "node-taglib-sharp"; const myFile = File.createFromPath("path/to/my/file.mp3"); ``` @@ -60,7 +64,7 @@ const myFile = File.createFromPath("path/to/my/file.mp3"); The `File` class provides factory methods for generating instances of classes that inherit from `File` to provide implementation specific to a file format (such as `ApeFile` providing support for Monkey's Audio files). The `File` class has exposes the `properties` and `tag` properties to -allow manipulation of the tagging information and reading audio/video properties. +allow manipulation of the tagging information and reading audio/video properties. See the docs for [the File class](docs/classes/File.md) for complete details of the available properties. @@ -75,7 +79,7 @@ object. Set tag properties as needed and they will be stored in a tagging format by the file type. The changes can be easily written back to the file with `save()`. See the docs for [the Tag class](docs/classes/Tag.md) for complete details of the fields -supported by the format-agnostic `Tag` class. +supported by the format-agnostic `Tag` class. ```typescript myFile.tag.title = "Time Won't Let Me Go"; @@ -86,9 +90,10 @@ myFile.dispose(); ``` ## Known Issues -* Maximum supported file size is 8192TB + +- Maximum supported file size is 8192TB - Why is this an issue? 8192TB is yuuuuge, but .NET implementation supports 8192PB file sizes. - - The Node.js 12 [fs](https://nodejs.org/docs/latest-v12.x/api/fs.html) library only supports + - The Node.js 12 [fs](https://nodejs.org/docs/latest-v12.x/api/fs.html) library only supports `integer` types for position arguments, which safely goes up to `2^52 - 1`. Node 15 supports `number` or `biginteger` for position arguments which would increase supported sizes to 64-bit integers. Please create issue if this is a blocker. diff --git a/package.json b/package.json index 8f3da47..453d356 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,14 @@ { - "name": "node-taglib-sharp", - "description": "Read and write audio/video/picture tags using a similar interface to TagLib#", - "version": "6.0.1", + "name": "@digimezzo/node-taglib-sharp", + "description": "Fork of node-taglib-sharp with extra bug fixes", + "version": "1.0.0", "license": "LGPL-2.1-or-later", "author": "Ben Russell (https://github.com/benrr101)", - "repository": "github:benrr101/node-taglib-sharp", - "bugs": "https://github.com/benrr101/node-taglib-sharp/issues", + "maintainers": [ + "Digimezzo (https://github.com/digimezzo)" + ], + "repository": "github:digimezzo/node-taglib-sharp", + "bugs": "https://github.com/digimezzo/node-taglib-sharp/issues", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { From 42400da01f8593b71b825d3bcb616c2f879d2ca9 Mon Sep 17 00:00:00 2001 From: Digimezzo Date: Mon, 9 Feb 2026 14:08:42 +0100 Subject: [PATCH 4/5] Update version to 1.0.1 and add changelog entries for NPM build --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3da1828..97b4ae0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.1] - 2026-02-09 + +### Changed + +- Based on https://github.com/benrr101/node-taglib-sharp/releases/tag/v6.0.1 +- Executed build before publish to NPM. + ## [1.0.0] - 2026-02-09 ### Changed diff --git a/package.json b/package.json index 453d356..05624bb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@digimezzo/node-taglib-sharp", "description": "Fork of node-taglib-sharp with extra bug fixes", - "version": "1.0.0", + "version": "1.0.1", "license": "LGPL-2.1-or-later", "author": "Ben Russell (https://github.com/benrr101)", "maintainers": [ From 1487cd96fd128d6aee048d1e06683d302ca528c6 Mon Sep 17 00:00:00 2001 From: Digimezzo Date: Mon, 9 Feb 2026 20:11:51 +0100 Subject: [PATCH 5/5] Update version to 1.0.2 and add changelog entries for ID3v2.3 genre fixes --- CHANGELOG.md | 13 ++++++++++++- package.json | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b4ae0..6ce7a59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,19 @@ -# Dopamine change log +# Change log The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.2] - 2026-02-09 + +### Changed + +- Based on https://github.com/benrr101/node-taglib-sharp/releases/tag/v6.0.1 + +### Fixed + +- ID3v2.3 genres are trimmed: https://github.com/benrr101/node-taglib-sharp/issues/120 +- node-taglib-sharp incorrectly parses genres if it starts with numbers: https://github.com/benrr101/node-taglib-sharp/issues/122 + ## [1.0.1] - 2026-02-09 ### Changed diff --git a/package.json b/package.json index 05624bb..808e5d8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@digimezzo/node-taglib-sharp", "description": "Fork of node-taglib-sharp with extra bug fixes", - "version": "1.0.1", + "version": "1.0.2", "license": "LGPL-2.1-or-later", "author": "Ben Russell (https://github.com/benrr101)", "maintainers": [