music-metadata 10.5.1 → 10.6.1
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/ParserFactory.js +8 -0
- package/lib/apev2/APEv2Parser.d.ts +4 -3
- package/lib/apev2/APEv2Parser.js +5 -3
- package/lib/asf/AsfObject.d.ts +7 -1
- package/lib/asf/AsfObject.js +0 -1
- package/lib/common/MetadataCollector.js +6 -0
- package/lib/core.d.ts +3 -3
- package/lib/core.js +6 -8
- package/lib/default.cjs +5 -5
- package/lib/dsdiff/DsdiffToken.d.ts +1 -1
- package/lib/id3v1/ID3v1Parser.d.ts +3 -3
- package/lib/id3v1/ID3v1Parser.js +5 -3
- package/lib/id3v2/FrameParser.js +4 -3
- package/lib/index.js +1 -9
- package/lib/lrc/LyricsParser.d.ts +7 -0
- package/lib/lrc/LyricsParser.js +32 -0
- package/lib/lyrics3/Lyrics3.d.ts +2 -2
- package/lib/lyrics3/Lyrics3.js +7 -3
- 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 -20
- package/package.json +150 -148
- package/lib/common/RandomFileReader.d.ts +0 -21
- package/lib/common/RandomFileReader.js +0 -30
- package/lib/common/RandomUint8ArrayReader.d.ts +0 -18
- package/lib/common/RandomUint8ArrayReader.js +0 -21
package/lib/ParserFactory.js
CHANGED
|
@@ -18,6 +18,7 @@ import { oggParserLoader } from './ogg/OggLoader.js';
|
|
|
18
18
|
import { wavpackParserLoader } from './wavpack/WavPackLoader.js';
|
|
19
19
|
import { riffParserLoader } from './wav/WaveLoader.js';
|
|
20
20
|
import { amrParserLoader } from './amr/AmrLoader.js';
|
|
21
|
+
import { scanAppendingHeaders } from './core.js';
|
|
21
22
|
const debug = initDebug('music-metadata:parser:factory');
|
|
22
23
|
export function parseHttpContentType(contentType) {
|
|
23
24
|
const type = ContentType.parse(contentType);
|
|
@@ -53,6 +54,13 @@ export class ParserFactory {
|
|
|
53
54
|
this.parsers.push(parser);
|
|
54
55
|
}
|
|
55
56
|
async parse(tokenizer, parserLoader, opts) {
|
|
57
|
+
if (tokenizer.supportsRandomAccess()) {
|
|
58
|
+
debug('tokenizer supports random-access, scanning for appending headers');
|
|
59
|
+
await scanAppendingHeaders(tokenizer, opts);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
debug('tokenizer does not support random-access, cannot scan for appending headers');
|
|
63
|
+
}
|
|
56
64
|
if (!parserLoader) {
|
|
57
65
|
const buf = new Uint8Array(4100);
|
|
58
66
|
if (tokenizer.fileInfo.mimeType) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as strtok3 from 'strtok3';
|
|
2
|
-
import type { IOptions,
|
|
2
|
+
import type { IOptions, IApeHeader } from '../type.js';
|
|
3
3
|
import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
|
|
4
4
|
import { BasicParser } from '../common/BasicParser.js';
|
|
5
5
|
import { type IFooter, type IHeader } from './APEv2Token.js';
|
|
6
|
+
import type { IRandomAccessTokenizer } from 'strtok3';
|
|
6
7
|
declare const ApeContentError_base: {
|
|
7
8
|
new (message: string): {
|
|
8
9
|
readonly fileType: string;
|
|
@@ -27,10 +28,10 @@ export declare class APEv2Parser extends BasicParser {
|
|
|
27
28
|
static calculateDuration(ah: IHeader): number;
|
|
28
29
|
/**
|
|
29
30
|
* Calculates the APEv1 / APEv2 first field offset
|
|
30
|
-
* @param
|
|
31
|
+
* @param tokenizer
|
|
31
32
|
* @param offset
|
|
32
33
|
*/
|
|
33
|
-
static findApeFooterOffset(
|
|
34
|
+
static findApeFooterOffset(tokenizer: IRandomAccessTokenizer, offset: number): Promise<IApeHeader | undefined>;
|
|
34
35
|
private static parseTagFooter;
|
|
35
36
|
private ape;
|
|
36
37
|
/**
|
package/lib/apev2/APEv2Parser.js
CHANGED
|
@@ -32,13 +32,15 @@ export class APEv2Parser extends BasicParser {
|
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Calculates the APEv1 / APEv2 first field offset
|
|
35
|
-
* @param
|
|
35
|
+
* @param tokenizer
|
|
36
36
|
* @param offset
|
|
37
37
|
*/
|
|
38
|
-
static async findApeFooterOffset(
|
|
38
|
+
static async findApeFooterOffset(tokenizer, offset) {
|
|
39
39
|
// Search for APE footer header at the end of the file
|
|
40
40
|
const apeBuf = new Uint8Array(TagFooter.len);
|
|
41
|
-
|
|
41
|
+
const position = tokenizer.position;
|
|
42
|
+
await tokenizer.readBuffer(apeBuf, { position: offset - TagFooter.len });
|
|
43
|
+
tokenizer.setPosition(position);
|
|
42
44
|
const tagFooter = TagFooter.get(apeBuf, 0);
|
|
43
45
|
if (tagFooter.ID === 'APETAGEX') {
|
|
44
46
|
if (tagFooter.flags.isHeader) {
|
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/core.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Primary entry point, Node.js specific entry point is MusepackParser.ts
|
|
3
3
|
*/
|
|
4
|
-
import { type AnyWebByteStream, type IFileInfo, type ITokenizer } from 'strtok3';
|
|
5
|
-
import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions,
|
|
4
|
+
import { type AnyWebByteStream, type IFileInfo, type ITokenizer, type IRandomAccessTokenizer } from 'strtok3';
|
|
5
|
+
import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, ITag } from './type.js';
|
|
6
6
|
export type { IFileInfo } from 'strtok3';
|
|
7
7
|
export { type IAudioMetadata, type IOptions, type ITag, type INativeTagDict, type ICommonTagsResult, type IFormat, type IPicture, type IRatio, type IChapter, type ILyricsTag, LyricsContentType, TimestampFormat, IMetadataEventTag, IMetadataEvent } from './type.js';
|
|
8
8
|
export type * from './ParseError.js';
|
|
@@ -56,5 +56,5 @@ export declare function ratingToStars(rating: number | undefined): number;
|
|
|
56
56
|
* @return Cover image, if any, otherwise null
|
|
57
57
|
*/
|
|
58
58
|
export declare function selectCover(pictures?: IPicture[]): IPicture | null;
|
|
59
|
-
export declare function scanAppendingHeaders(
|
|
59
|
+
export declare function scanAppendingHeaders(tokenizer: IRandomAccessTokenizer, options?: IPrivateOptions): Promise<void>;
|
|
60
60
|
export declare function loadMusicMetadata(): Promise<typeof import('music-metadata')>;
|
package/lib/core.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { fromWebStream, fromBuffer } from 'strtok3';
|
|
5
5
|
import { ParserFactory } from './ParserFactory.js';
|
|
6
|
-
import { RandomUint8ArrayReader } from './common/RandomUint8ArrayReader.js';
|
|
7
6
|
import { APEv2Parser } from './apev2/APEv2Parser.js';
|
|
8
7
|
import { hasID3v1Header } from './id3v1/ID3v1Parser.js';
|
|
9
8
|
import { getLyricsHeaderLength } from './lyrics3/Lyrics3.js';
|
|
@@ -41,8 +40,6 @@ export function parseWebStream(webStream, fileInfo, options = {}) {
|
|
|
41
40
|
* Ref: https://github.com/Borewit/strtok3/blob/e6938c81ff685074d5eb3064a11c0b03ca934c1d/src/index.ts#L15
|
|
42
41
|
*/
|
|
43
42
|
export async function parseBuffer(uint8Array, fileInfo, options = {}) {
|
|
44
|
-
const bufferReader = new RandomUint8ArrayReader(uint8Array);
|
|
45
|
-
await scanAppendingHeaders(bufferReader, options);
|
|
46
43
|
const tokenizer = fromBuffer(uint8Array, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo });
|
|
47
44
|
return parseFromTokenizer(tokenizer, options);
|
|
48
45
|
}
|
|
@@ -91,12 +88,13 @@ export function selectCover(pictures) {
|
|
|
91
88
|
return acc;
|
|
92
89
|
}) : null;
|
|
93
90
|
}
|
|
94
|
-
export async function scanAppendingHeaders(
|
|
95
|
-
let apeOffset =
|
|
96
|
-
if (await hasID3v1Header(
|
|
91
|
+
export async function scanAppendingHeaders(tokenizer, options = {}) {
|
|
92
|
+
let apeOffset = tokenizer.fileInfo.size;
|
|
93
|
+
if (await hasID3v1Header(tokenizer)) {
|
|
97
94
|
apeOffset -= 128;
|
|
98
|
-
const lyricsLen = await getLyricsHeaderLength(
|
|
95
|
+
const lyricsLen = await getLyricsHeaderLength(tokenizer);
|
|
99
96
|
apeOffset -= lyricsLen;
|
|
100
97
|
}
|
|
101
|
-
options.apeHeader = await APEv2Parser.findApeFooterOffset(
|
|
98
|
+
options.apeHeader = await APEv2Parser.findApeFooterOffset(tokenizer, apeOffset);
|
|
102
99
|
}
|
|
100
|
+
//# sourceMappingURL=core.js.map
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ITokenizer } from 'strtok3';
|
|
1
|
+
import type { IRandomAccessTokenizer, ITokenizer } from 'strtok3';
|
|
2
2
|
import { BasicParser } from '../common/BasicParser.js';
|
|
3
|
-
import type { IPrivateOptions
|
|
3
|
+
import type { IPrivateOptions } from '../type.js';
|
|
4
4
|
import type { INativeMetadataCollector } from '../common/MetadataCollector.js';
|
|
5
5
|
/**
|
|
6
6
|
* ID3v1 Genre mappings
|
|
@@ -14,4 +14,4 @@ export declare class ID3v1Parser extends BasicParser {
|
|
|
14
14
|
parse(): Promise<void>;
|
|
15
15
|
private addTag;
|
|
16
16
|
}
|
|
17
|
-
export declare function hasID3v1Header(
|
|
17
|
+
export declare function hasID3v1Header(tokenizer: IRandomAccessTokenizer): Promise<boolean>;
|
package/lib/id3v1/ID3v1Parser.js
CHANGED
|
@@ -124,10 +124,12 @@ export class ID3v1Parser extends BasicParser {
|
|
|
124
124
|
await this.metadata.addTag('ID3v1', id, value);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
export async function hasID3v1Header(
|
|
128
|
-
if (
|
|
127
|
+
export async function hasID3v1Header(tokenizer) {
|
|
128
|
+
if (tokenizer.fileInfo.size >= 128) {
|
|
129
129
|
const tag = new Uint8Array(3);
|
|
130
|
-
|
|
130
|
+
const position = tokenizer.position;
|
|
131
|
+
await tokenizer.readBuffer(tag, { position: tokenizer.fileInfo.size - 128 });
|
|
132
|
+
tokenizer.setPosition(position); // Restore tokenizer position
|
|
131
133
|
return new TextDecoder('latin1').decode(tag) === 'TAG';
|
|
132
134
|
}
|
|
133
135
|
return false;
|
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;
|
package/lib/index.js
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { fromFile, fromStream } from 'strtok3';
|
|
5
5
|
import initDebug from 'debug';
|
|
6
|
-
import { parseFromTokenizer,
|
|
6
|
+
import { parseFromTokenizer, } from './core.js';
|
|
7
7
|
import { ParserFactory } from './ParserFactory.js';
|
|
8
|
-
import { RandomFileReader } from './common/RandomFileReader.js';
|
|
9
8
|
export * from './core.js';
|
|
10
9
|
const debug = initDebug('music-metadata:parser');
|
|
11
10
|
/**
|
|
@@ -28,13 +27,6 @@ export async function parseStream(stream, fileInfo, options = {}) {
|
|
|
28
27
|
export async function parseFile(filePath, options = {}) {
|
|
29
28
|
debug(`parseFile: ${filePath}`);
|
|
30
29
|
const fileTokenizer = await fromFile(filePath);
|
|
31
|
-
const fileReader = await RandomFileReader.init(filePath, fileTokenizer.fileInfo.size);
|
|
32
|
-
try {
|
|
33
|
-
await scanAppendingHeaders(fileReader, options);
|
|
34
|
-
}
|
|
35
|
-
finally {
|
|
36
|
-
await fileReader.close();
|
|
37
|
-
}
|
|
38
30
|
const parserFactory = new ParserFactory();
|
|
39
31
|
try {
|
|
40
32
|
const parserLoader = parserFactory.findLoaderForExtension(filePath);
|
|
@@ -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/lyrics3/Lyrics3.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IRandomAccessTokenizer } from 'strtok3';
|
|
2
2
|
export declare const endTag2 = "LYRICS200";
|
|
3
|
-
export declare function getLyricsHeaderLength(
|
|
3
|
+
export declare function getLyricsHeaderLength(tokenizer: IRandomAccessTokenizer): Promise<number>;
|
package/lib/lyrics3/Lyrics3.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export const endTag2 = 'LYRICS200';
|
|
2
|
-
export async function getLyricsHeaderLength(
|
|
3
|
-
|
|
2
|
+
export async function getLyricsHeaderLength(tokenizer) {
|
|
3
|
+
const fileSize = tokenizer.fileInfo.size;
|
|
4
|
+
if (fileSize >= 143) {
|
|
4
5
|
const buf = new Uint8Array(15);
|
|
5
|
-
|
|
6
|
+
const position = tokenizer.position;
|
|
7
|
+
await tokenizer.readBuffer(buf, { position: fileSize - 143 });
|
|
8
|
+
tokenizer.setPosition(position); // Restore position
|
|
6
9
|
const txt = new TextDecoder('latin1').decode(buf);
|
|
7
10
|
const tag = txt.slice(6);
|
|
8
11
|
if (tag === endTag2) {
|
|
@@ -11,3 +14,4 @@ export async function getLyricsHeaderLength(reader) {
|
|
|
11
14
|
}
|
|
12
15
|
return 0;
|
|
13
16
|
}
|
|
17
|
+
//# sourceMappingURL=Lyrics3.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
|
@@ -595,26 +595,7 @@ export interface IMetadataEvent {
|
|
|
595
595
|
metadata: IAudioMetadata;
|
|
596
596
|
}
|
|
597
597
|
export type Observer = (update: IMetadataEvent) => void;
|
|
598
|
-
|
|
599
|
-
* Provides random data read access
|
|
600
|
-
* Used read operations on file of buffers
|
|
601
|
-
*/
|
|
602
|
-
export interface IRandomReader {
|
|
603
|
-
/**
|
|
604
|
-
* Total length of file or buffer
|
|
605
|
-
*/
|
|
606
|
-
fileSize: number;
|
|
607
|
-
/**
|
|
608
|
-
* Read from a given position of an abstracted file or buffer.
|
|
609
|
-
* @param {Uint8Array} buffer the buffer that the data will be written to.
|
|
610
|
-
* @param {number} offset the offset in the buffer to start writing at.
|
|
611
|
-
* @param {number} length an integer specifying the number of bytes to read.
|
|
612
|
-
* @param {number} position an argument specifying where to begin reading from in the file.
|
|
613
|
-
* @return {Promise<number>} bytes read
|
|
614
|
-
*/
|
|
615
|
-
randomRead(buffer: Uint8Array, offset: number, length: number, position: number): Promise<number>;
|
|
616
|
-
}
|
|
617
|
-
interface ILyricsText {
|
|
598
|
+
export interface ILyricsText {
|
|
618
599
|
text: string;
|
|
619
600
|
timestamp?: number;
|
|
620
601
|
}
|