music-metadata 10.5.1 → 10.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +9 -9
- package/README.md +850 -845
- package/lib/asf/AsfObject.d.ts +7 -1
- package/lib/asf/AsfObject.js +0 -1
- package/lib/common/MetadataCollector.js +6 -0
- package/lib/default.cjs +5 -5
- package/lib/dsdiff/DsdiffToken.d.ts +1 -1
- package/lib/id3v2/FrameParser.js +4 -3
- package/lib/lrc/LyricsParser.d.ts +7 -0
- package/lib/lrc/LyricsParser.js +32 -0
- package/lib/mpeg/MpegParser.js +2 -2
- package/lib/node.cjs +5 -5
- package/lib/riff/RiffChunk.d.ts +1 -1
- package/lib/type.d.ts +1 -1
- package/package.json +150 -148
package/lib/asf/AsfObject.d.ts
CHANGED
|
@@ -10,7 +10,13 @@ declare const AsfContentParseError_base: {
|
|
|
10
10
|
stack?: string;
|
|
11
11
|
};
|
|
12
12
|
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
13
|
-
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite
|
|
13
|
+
prepareStackTrace?: ((err: Error, stackTraces: NodeJS.CallSite /**
|
|
14
|
+
* Specifies the amount of time to buffer data before starting to play the file, in millisecond units.
|
|
15
|
+
* If this value is nonzero, the Play Duration field and all of the payload Presentation Time fields have been offset
|
|
16
|
+
* by this amount. Therefore, player software must subtract the value in the preroll field from the play duration and
|
|
17
|
+
* presentation times to calculate their actual values. It follows that all payload Presentation Time fields need to
|
|
18
|
+
* be at least this value.
|
|
19
|
+
*/[]) => any) | undefined;
|
|
14
20
|
stackTraceLimit: number;
|
|
15
21
|
};
|
|
16
22
|
export declare class AsfContentParseError extends AsfContentParseError_base {
|
package/lib/asf/AsfObject.js
CHANGED
|
@@ -310,7 +310,6 @@ export class MetadataObjectState extends State {
|
|
|
310
310
|
}
|
|
311
311
|
MetadataObjectState.guid = GUID.MetadataObject;
|
|
312
312
|
// 4.8 Metadata Library Object (optional, 0 or 1)
|
|
313
|
-
// biome-ignore lint/complexity/noStaticOnlyClass: Extends a non-static class
|
|
314
313
|
export class MetadataLibraryObjectState extends MetadataObjectState {
|
|
315
314
|
}
|
|
316
315
|
MetadataLibraryObjectState.guid = GUID.MetadataLibraryObject;
|
|
@@ -5,6 +5,7 @@ import { CombinedTagMapper } from './CombinedTagMapper.js';
|
|
|
5
5
|
import { CommonTagMapper } from './GenericTagMapper.js';
|
|
6
6
|
import { toRatio } from './Util.js';
|
|
7
7
|
import { fileTypeFromBuffer } from 'file-type';
|
|
8
|
+
import { parseLrc } from '../lrc/LyricsParser.js';
|
|
8
9
|
const debug = initDebug('music-metadata:collector');
|
|
9
10
|
const TagPriority = ['matroska', 'APEv2', 'vorbis', 'ID3v2.4', 'ID3v2.3', 'ID3v2.2', 'exif', 'asf', 'iTunes', 'AIFF', 'ID3v1'];
|
|
10
11
|
/**
|
|
@@ -180,6 +181,11 @@ export class MetadataCollector {
|
|
|
180
181
|
this.setGenericTag(tagType, { id: 'gapless', value: tag.value.text === '1' });
|
|
181
182
|
}
|
|
182
183
|
break;
|
|
184
|
+
case 'lyrics':
|
|
185
|
+
if (typeof tag.value === 'string') {
|
|
186
|
+
tag.value = parseLrc(tag.value);
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
183
189
|
default:
|
|
184
190
|
// nothing to do
|
|
185
191
|
}
|
package/lib/default.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// CommonJS core (default) entry point
|
|
2
|
-
"use strict";
|
|
3
|
-
module.exports = {
|
|
4
|
-
loadMusicMetadata: () => import('./core.js'),
|
|
5
|
-
};
|
|
1
|
+
// CommonJS core (default) entry point
|
|
2
|
+
"use strict";
|
|
3
|
+
module.exports = {
|
|
4
|
+
loadMusicMetadata: () => import('./core.js'),
|
|
5
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IGetToken } from 'strtok3';
|
|
2
2
|
import type { IChunkHeader64 } from '../iff/index.js';
|
|
3
|
-
export {
|
|
3
|
+
export type { IChunkHeader64 } from '../iff/index.js';
|
|
4
4
|
/**
|
|
5
5
|
* DSDIFF chunk header
|
|
6
6
|
* The data-size encoding is deviating from EA-IFF 85
|
package/lib/id3v2/FrameParser.js
CHANGED
|
@@ -248,16 +248,17 @@ export class FrameParser {
|
|
|
248
248
|
fzero = util.findZero(uint8Array, offset + 1, length, encoding);
|
|
249
249
|
const mimeType = util.decodeString(uint8Array.slice(offset + 1, fzero), defaultEnc);
|
|
250
250
|
offset = fzero + 1;
|
|
251
|
-
fzero = util.findZero(uint8Array, offset, length
|
|
251
|
+
fzero = util.findZero(uint8Array, offset, length, encoding);
|
|
252
252
|
const filename = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc);
|
|
253
253
|
offset = fzero + 1;
|
|
254
|
-
fzero = util.findZero(uint8Array, offset, length
|
|
254
|
+
fzero = util.findZero(uint8Array, offset, length, encoding);
|
|
255
255
|
const description = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc);
|
|
256
|
+
offset = fzero + 1;
|
|
256
257
|
const geob = {
|
|
257
258
|
type: mimeType,
|
|
258
259
|
filename,
|
|
259
260
|
description,
|
|
260
|
-
data: uint8Array.slice(offset
|
|
261
|
+
data: uint8Array.slice(offset, length)
|
|
261
262
|
};
|
|
262
263
|
output = geob;
|
|
263
264
|
break;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LyricsContentType, TimestampFormat } from '../type.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse LRC (Lyrics) formatted text
|
|
4
|
+
* Ref: https://en.wikipedia.org/wiki/LRC_(file_format)
|
|
5
|
+
* @param lrcString
|
|
6
|
+
*/
|
|
7
|
+
export function parseLrc(lrcString) {
|
|
8
|
+
const lines = lrcString.split('\n');
|
|
9
|
+
const syncText = [];
|
|
10
|
+
// Regular expression to match LRC timestamps (e.g., [00:45.52])
|
|
11
|
+
const timestampRegex = /\[(\d{2}):(\d{2})\.(\d{2})\]/;
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const match = line.match(timestampRegex);
|
|
14
|
+
if (match) {
|
|
15
|
+
const minutes = Number.parseInt(match[1], 10);
|
|
16
|
+
const seconds = Number.parseInt(match[2], 10);
|
|
17
|
+
const hundredths = Number.parseInt(match[3], 10);
|
|
18
|
+
// Convert the timestamp to milliseconds, as per TimestampFormat.milliseconds
|
|
19
|
+
const timestamp = (minutes * 60 + seconds) * 1000 + hundredths * 10;
|
|
20
|
+
// Get the text portion of the line (e.g., "あの蝶は自由になれたかな")
|
|
21
|
+
const text = line.replace(timestampRegex, '').trim();
|
|
22
|
+
syncText.push({ timestamp, text });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Creating the ILyricsTag object
|
|
26
|
+
return {
|
|
27
|
+
contentType: LyricsContentType.lyrics,
|
|
28
|
+
timeStampFormat: TimestampFormat.milliseconds,
|
|
29
|
+
syncText,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=LyricsParser.js.map
|
package/lib/mpeg/MpegParser.js
CHANGED
|
@@ -296,12 +296,12 @@ export class MpegParser extends AbstractID3Parser {
|
|
|
296
296
|
this.metadata.setFormat('bitrate', mpegSize * 8 / format.duration);
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
|
-
|
|
299
|
+
if (this.tokenizer.fileInfo.size && format.codecProfile === 'CBR') {
|
|
300
300
|
const mpegSize = this.tokenizer.fileInfo.size - this.mpegOffset - (hasID3v1 ? 128 : 0);
|
|
301
301
|
if (this.frame_size !== null && this.samplesPerFrame !== null) {
|
|
302
302
|
const numberOfSamples = Math.round(mpegSize / this.frame_size) * this.samplesPerFrame;
|
|
303
303
|
this.metadata.setFormat('numberOfSamples', numberOfSamples);
|
|
304
|
-
if (format.sampleRate) {
|
|
304
|
+
if (format.sampleRate && !format.duration) {
|
|
305
305
|
const duration = numberOfSamples / format.sampleRate;
|
|
306
306
|
debug("Calculate CBR duration based on file size: %s", duration);
|
|
307
307
|
this.metadata.setFormat('duration', duration);
|
package/lib/node.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// CommonJS Node entry point
|
|
2
|
-
"use strict";
|
|
3
|
-
module.exports = {
|
|
4
|
-
loadMusicMetadata: () => import('./index.js'),
|
|
5
|
-
};
|
|
1
|
+
// CommonJS Node entry point
|
|
2
|
+
"use strict";
|
|
3
|
+
module.exports = {
|
|
4
|
+
loadMusicMetadata: () => import('./index.js'),
|
|
5
|
+
};
|
package/lib/riff/RiffChunk.d.ts
CHANGED
package/lib/type.d.ts
CHANGED
|
@@ -614,7 +614,7 @@ export interface IRandomReader {
|
|
|
614
614
|
*/
|
|
615
615
|
randomRead(buffer: Uint8Array, offset: number, length: number, position: number): Promise<number>;
|
|
616
616
|
}
|
|
617
|
-
interface ILyricsText {
|
|
617
|
+
export interface ILyricsText {
|
|
618
618
|
text: string;
|
|
619
619
|
timestamp?: number;
|
|
620
620
|
}
|
package/package.json
CHANGED
|
@@ -1,148 +1,150 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "music-metadata",
|
|
3
|
-
"description": "Music metadata parser for Node.js, supporting virtual any audio and tag format.",
|
|
4
|
-
"version": "10.
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Borewit",
|
|
7
|
-
"url": "https://github.com/Borewit"
|
|
8
|
-
},
|
|
9
|
-
"funding": [
|
|
10
|
-
{
|
|
11
|
-
"type": "github",
|
|
12
|
-
"url": "https://github.com/sponsors/Borewit"
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"type": "buymeacoffee",
|
|
16
|
-
"url": "https://buymeacoffee.com/borewit"
|
|
17
|
-
}
|
|
18
|
-
],
|
|
19
|
-
"type": "module",
|
|
20
|
-
"exports": {
|
|
21
|
-
".": {
|
|
22
|
-
"node": {
|
|
23
|
-
"import": "./lib/index.js",
|
|
24
|
-
"require": "./lib/node.cjs",
|
|
25
|
-
"types": "./lib/index.d.ts"
|
|
26
|
-
},
|
|
27
|
-
"default": {
|
|
28
|
-
"import": "./lib/core.js",
|
|
29
|
-
"require": "./lib/default.cjs",
|
|
30
|
-
"types": "./lib/core.d.ts"
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"types": "lib/index.d.ts",
|
|
35
|
-
"files": [
|
|
36
|
-
"lib/**/*.js",
|
|
37
|
-
"lib/**/*.d.ts",
|
|
38
|
-
"lib/*.cjs"
|
|
39
|
-
],
|
|
40
|
-
"keywords": [
|
|
41
|
-
"music",
|
|
42
|
-
"metadata",
|
|
43
|
-
"meta",
|
|
44
|
-
"audio",
|
|
45
|
-
"tag",
|
|
46
|
-
"tags",
|
|
47
|
-
"duration",
|
|
48
|
-
"MusicBrainz",
|
|
49
|
-
"Discogs",
|
|
50
|
-
"Picard",
|
|
51
|
-
"ID3",
|
|
52
|
-
"ID3v1",
|
|
53
|
-
"ID3v2",
|
|
54
|
-
"m4a",
|
|
55
|
-
"m4b",
|
|
56
|
-
"mp3",
|
|
57
|
-
"mp4",
|
|
58
|
-
"Vorbis",
|
|
59
|
-
"ogg",
|
|
60
|
-
"flac",
|
|
61
|
-
"Matroska",
|
|
62
|
-
"WebM",
|
|
63
|
-
"EBML",
|
|
64
|
-
"asf",
|
|
65
|
-
"wma",
|
|
66
|
-
"wmv",
|
|
67
|
-
"ape",
|
|
68
|
-
"MonkeyAudio",
|
|
69
|
-
"aiff",
|
|
70
|
-
"wav",
|
|
71
|
-
"WavPack",
|
|
72
|
-
"Opus",
|
|
73
|
-
"speex",
|
|
74
|
-
"musepack",
|
|
75
|
-
"mpc",
|
|
76
|
-
"dsd",
|
|
77
|
-
"dsf",
|
|
78
|
-
"mpc",
|
|
79
|
-
"dff",
|
|
80
|
-
"dsdiff",
|
|
81
|
-
"aac",
|
|
82
|
-
"adts",
|
|
83
|
-
"length",
|
|
84
|
-
"chapter",
|
|
85
|
-
"info",
|
|
86
|
-
"parse",
|
|
87
|
-
"parser",
|
|
88
|
-
"bwf"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
"compile-
|
|
95
|
-
"compile": "
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"lint": "
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"test
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"@
|
|
119
|
-
"@types/
|
|
120
|
-
"@types/
|
|
121
|
-
"@types/
|
|
122
|
-
"@types/
|
|
123
|
-
"@types/
|
|
124
|
-
"
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "music-metadata",
|
|
3
|
+
"description": "Music metadata parser for Node.js, supporting virtual any audio and tag format.",
|
|
4
|
+
"version": "10.6.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Borewit",
|
|
7
|
+
"url": "https://github.com/Borewit"
|
|
8
|
+
},
|
|
9
|
+
"funding": [
|
|
10
|
+
{
|
|
11
|
+
"type": "github",
|
|
12
|
+
"url": "https://github.com/sponsors/Borewit"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"type": "buymeacoffee",
|
|
16
|
+
"url": "https://buymeacoffee.com/borewit"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"node": {
|
|
23
|
+
"import": "./lib/index.js",
|
|
24
|
+
"require": "./lib/node.cjs",
|
|
25
|
+
"types": "./lib/index.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"default": {
|
|
28
|
+
"import": "./lib/core.js",
|
|
29
|
+
"require": "./lib/default.cjs",
|
|
30
|
+
"types": "./lib/core.d.ts"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"types": "lib/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"lib/**/*.js",
|
|
37
|
+
"lib/**/*.d.ts",
|
|
38
|
+
"lib/*.cjs"
|
|
39
|
+
],
|
|
40
|
+
"keywords": [
|
|
41
|
+
"music",
|
|
42
|
+
"metadata",
|
|
43
|
+
"meta",
|
|
44
|
+
"audio",
|
|
45
|
+
"tag",
|
|
46
|
+
"tags",
|
|
47
|
+
"duration",
|
|
48
|
+
"MusicBrainz",
|
|
49
|
+
"Discogs",
|
|
50
|
+
"Picard",
|
|
51
|
+
"ID3",
|
|
52
|
+
"ID3v1",
|
|
53
|
+
"ID3v2",
|
|
54
|
+
"m4a",
|
|
55
|
+
"m4b",
|
|
56
|
+
"mp3",
|
|
57
|
+
"mp4",
|
|
58
|
+
"Vorbis",
|
|
59
|
+
"ogg",
|
|
60
|
+
"flac",
|
|
61
|
+
"Matroska",
|
|
62
|
+
"WebM",
|
|
63
|
+
"EBML",
|
|
64
|
+
"asf",
|
|
65
|
+
"wma",
|
|
66
|
+
"wmv",
|
|
67
|
+
"ape",
|
|
68
|
+
"MonkeyAudio",
|
|
69
|
+
"aiff",
|
|
70
|
+
"wav",
|
|
71
|
+
"WavPack",
|
|
72
|
+
"Opus",
|
|
73
|
+
"speex",
|
|
74
|
+
"musepack",
|
|
75
|
+
"mpc",
|
|
76
|
+
"dsd",
|
|
77
|
+
"dsf",
|
|
78
|
+
"mpc",
|
|
79
|
+
"dff",
|
|
80
|
+
"dsdiff",
|
|
81
|
+
"aac",
|
|
82
|
+
"adts",
|
|
83
|
+
"length",
|
|
84
|
+
"chapter",
|
|
85
|
+
"info",
|
|
86
|
+
"parse",
|
|
87
|
+
"parser",
|
|
88
|
+
"bwf",
|
|
89
|
+
"slt",
|
|
90
|
+
"lyrics"
|
|
91
|
+
],
|
|
92
|
+
"scripts": {
|
|
93
|
+
"clean": "del-cli 'lib/**/*.js' 'lib/**/*.js.map' 'lib/**/*.d.ts' 'src/**/*.d.ts' 'test/**/*.js' 'test/**/*.js.map' 'test/**/*.js' 'test/**/*.js.map' 'doc-gen/**/*.js' 'doc-gen/**/*.js.map'",
|
|
94
|
+
"compile-src": "tsc -p lib",
|
|
95
|
+
"compile-test": "tsc -p test",
|
|
96
|
+
"compile-doc": "tsc -p doc-gen",
|
|
97
|
+
"compile": "yarn run compile-src && yarn compile-test && yarn compile-doc",
|
|
98
|
+
"lint-ts": "biome check",
|
|
99
|
+
"lint-md": "yarn run remark -u remark-preset-lint-consistent .",
|
|
100
|
+
"lint": "yarn run lint-ts && yarn run lint-md",
|
|
101
|
+
"test": "mocha",
|
|
102
|
+
"build": "yarn run clean && yarn compile && yarn run doc-gen",
|
|
103
|
+
"test-coverage": "c8 yarn run test",
|
|
104
|
+
"send-codacy": "c8 report --reporter=text-lcov | codacy-coverage",
|
|
105
|
+
"doc-gen": "yarn node doc-gen/gen.js"
|
|
106
|
+
},
|
|
107
|
+
"dependencies": {
|
|
108
|
+
"@tokenizer/token": "^0.3.0",
|
|
109
|
+
"content-type": "^1.0.5",
|
|
110
|
+
"debug": "^4.3.7",
|
|
111
|
+
"file-type": "^19.6.0",
|
|
112
|
+
"media-typer": "^1.1.0",
|
|
113
|
+
"strtok3": "^9.0.1",
|
|
114
|
+
"token-types": "^6.0.0",
|
|
115
|
+
"uint8array-extras": "^1.4.0"
|
|
116
|
+
},
|
|
117
|
+
"devDependencies": {
|
|
118
|
+
"@biomejs/biome": "1.9.4",
|
|
119
|
+
"@types/chai": "^5.0.1",
|
|
120
|
+
"@types/chai-as-promised": "^8.0.1",
|
|
121
|
+
"@types/content-type": "^1.1.8",
|
|
122
|
+
"@types/debug": "^4.1.12",
|
|
123
|
+
"@types/media-typer": "^1.1.3",
|
|
124
|
+
"@types/mocha": "^10.0.9",
|
|
125
|
+
"@types/node": "^22.9.0",
|
|
126
|
+
"c8": "^10.1.2",
|
|
127
|
+
"chai": "^5.1.2",
|
|
128
|
+
"chai-as-promised": "^8.0.0",
|
|
129
|
+
"del-cli": "^6.0.0",
|
|
130
|
+
"mime": "^4.0.4",
|
|
131
|
+
"mocha": "^10.8.2",
|
|
132
|
+
"prettier": "^3.3.3",
|
|
133
|
+
"remark-cli": "^12.0.1",
|
|
134
|
+
"remark-preset-lint-consistent": "^6.0.0",
|
|
135
|
+
"ts-node": "^10.9.2",
|
|
136
|
+
"typescript": "^5.6.3"
|
|
137
|
+
},
|
|
138
|
+
"engines": {
|
|
139
|
+
"node": ">=16.0.0"
|
|
140
|
+
},
|
|
141
|
+
"repository": {
|
|
142
|
+
"type": "git",
|
|
143
|
+
"url": "git+https://github.com/borewit/music-metadata.git"
|
|
144
|
+
},
|
|
145
|
+
"license": "MIT",
|
|
146
|
+
"bugs": {
|
|
147
|
+
"url": "https://github.com/Borewit/music-metadata/issues"
|
|
148
|
+
},
|
|
149
|
+
"packageManager": "yarn@4.3.1"
|
|
150
|
+
}
|