music-metadata 10.0.0 → 10.1.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/README.md +4 -3
- package/lib/ParserFactory.d.ts +20 -28
- package/lib/ParserFactory.js +204 -207
- package/lib/aiff/AiffParser.js +20 -18
- package/lib/aiff/AiffToken.d.ts +14 -2
- package/lib/aiff/AiffToken.js +12 -0
- package/lib/apev2/APEv2Parser.d.ts +4 -4
- package/lib/apev2/APEv2Parser.js +20 -12
- package/lib/apev2/APEv2Token.d.ts +2 -4
- package/lib/apev2/APEv2Token.js +1 -4
- package/lib/asf/AsfObject.d.ts +7 -16
- package/lib/asf/AsfObject.js +8 -34
- package/lib/asf/AsfParser.js +17 -10
- package/lib/asf/AsfTagMapper.d.ts +1 -1
- package/lib/asf/AsfTagMapper.js +3 -2
- package/lib/asf/AsfUtil.d.ts +3 -11
- package/lib/asf/AsfUtil.js +29 -30
- package/lib/asf/GUID.js +6 -9
- package/lib/common/BasicParser.d.ts +4 -4
- package/lib/common/BasicParser.js +6 -0
- package/lib/common/CaseInsensitiveTagMap.d.ts +1 -1
- package/lib/common/CombinedTagMapper.d.ts +5 -5
- package/lib/common/CombinedTagMapper.js +1 -1
- package/lib/common/FourCC.d.ts +1 -1
- package/lib/common/GenericTagMapper.d.ts +8 -8
- package/lib/common/GenericTagMapper.js +4 -4
- package/lib/common/GenericTagTypes.d.ts +5 -4
- package/lib/common/GenericTagTypes.js +2 -2
- package/lib/common/MetadataCollector.d.ts +9 -9
- package/lib/common/MetadataCollector.js +24 -17
- package/lib/common/RandomFileReader.d.ts +1 -1
- package/lib/common/RandomFileReader.js +1 -1
- package/lib/common/RandomUint8ArrayReader.d.ts +1 -1
- package/lib/common/Util.d.ts +2 -6
- package/lib/common/Util.js +9 -11
- package/lib/core.d.ts +7 -9
- package/lib/core.js +10 -7
- package/lib/dsdiff/DsdiffParser.js +26 -14
- package/lib/dsdiff/DsdiffToken.d.ts +2 -2
- package/lib/dsdiff/DsdiffToken.js +1 -0
- package/lib/dsf/DsfChunk.js +1 -0
- package/lib/dsf/DsfParser.js +4 -2
- package/lib/flac/FlacParser.d.ts +3 -3
- package/lib/flac/FlacParser.js +9 -12
- package/lib/id3v1/ID3v1Parser.d.ts +1 -1
- package/lib/id3v1/ID3v1Parser.js +7 -4
- package/lib/id3v2/AbstractID3Parser.d.ts +1 -1
- package/lib/id3v2/AbstractID3Parser.js +2 -1
- package/lib/id3v2/FrameParser.d.ts +28 -3
- package/lib/id3v2/FrameParser.js +50 -28
- package/lib/id3v2/ID3v22TagMapper.d.ts +1 -1
- package/lib/id3v2/ID3v24TagMapper.d.ts +2 -1
- package/lib/id3v2/ID3v24TagMapper.js +23 -16
- package/lib/id3v2/ID3v2Parser.d.ts +2 -2
- package/lib/id3v2/ID3v2Parser.js +19 -8
- package/lib/iff/index.js +1 -0
- package/lib/index.d.ts +5 -6
- package/lib/index.js +7 -8
- package/lib/lyrics3/Lyrics3.d.ts +1 -1
- package/lib/lyrics3/Lyrics3.js +1 -1
- package/lib/matroska/MatroskaDtd.d.ts +1 -1
- package/lib/matroska/MatroskaDtd.js +139 -138
- package/lib/matroska/MatroskaParser.d.ts +4 -4
- package/lib/matroska/MatroskaParser.js +12 -12
- package/lib/matroska/types.d.ts +6 -4
- package/lib/mp4/Atom.d.ts +3 -3
- package/lib/mp4/Atom.js +4 -7
- package/lib/mp4/AtomToken.js +2 -1
- package/lib/mp4/MP4Parser.js +29 -20
- package/lib/mp4/MP4TagMapper.d.ts +2 -2
- package/lib/mp4/MP4TagMapper.js +1 -1
- package/lib/mpeg/ExtendedLameHeader.d.ts +4 -4
- package/lib/mpeg/ExtendedLameHeader.js +2 -1
- package/lib/mpeg/MpegParser.d.ts +1 -1
- package/lib/mpeg/MpegParser.js +145 -96
- package/lib/mpeg/ReplayGainDataFormat.d.ts +1 -1
- package/lib/mpeg/ReplayGainDataFormat.js +1 -0
- package/lib/mpeg/XingTag.d.ts +4 -4
- package/lib/mpeg/XingTag.js +5 -4
- package/lib/musepack/index.js +1 -0
- package/lib/musepack/sv7/BitReader.js +14 -17
- package/lib/musepack/sv7/MpcSv7Parser.js +6 -1
- package/lib/musepack/sv7/StreamVersion7.js +1 -0
- package/lib/musepack/sv8/MpcSv8Parser.js +6 -2
- package/lib/musepack/sv8/StreamVersion8.d.ts +1 -1
- package/lib/musepack/sv8/StreamVersion8.js +1 -0
- package/lib/ogg/Ogg.d.ts +1 -1
- package/lib/ogg/Ogg.js +1 -0
- package/lib/ogg/OggParser.d.ts +3 -3
- package/lib/ogg/OggParser.js +25 -16
- package/lib/ogg/opus/Opus.d.ts +1 -1
- package/lib/ogg/opus/Opus.js +1 -0
- package/lib/ogg/opus/OpusParser.d.ts +4 -4
- package/lib/ogg/opus/OpusParser.js +2 -0
- package/lib/ogg/speex/Speex.js +1 -0
- package/lib/ogg/speex/SpeexParser.d.ts +4 -4
- package/lib/ogg/speex/SpeexParser.js +1 -0
- package/lib/ogg/theora/Theora.js +1 -0
- package/lib/ogg/theora/TheoraParser.d.ts +4 -4
- package/lib/ogg/theora/TheoraParser.js +1 -0
- package/lib/ogg/vorbis/Vorbis.d.ts +3 -3
- package/lib/ogg/vorbis/Vorbis.js +22 -11
- package/lib/ogg/vorbis/VorbisDecoder.d.ts +1 -1
- package/lib/ogg/vorbis/VorbisDecoder.js +1 -0
- package/lib/ogg/vorbis/VorbisParser.d.ts +4 -4
- package/lib/ogg/vorbis/VorbisParser.js +3 -2
- package/lib/ogg/vorbis/VorbisTagMapper.d.ts +2 -2
- package/lib/ogg/vorbis/VorbisTagMapper.js +2 -2
- package/lib/riff/RiffChunk.d.ts +3 -3
- package/lib/riff/RiffChunk.js +1 -0
- package/lib/riff/RiffInfoTagMap.d.ts +1 -1
- package/lib/type.d.ts +35 -25
- package/lib/wav/BwfChunk.js +1 -0
- package/lib/wav/WaveChunk.d.ts +1 -1
- package/lib/wav/WaveChunk.js +1 -0
- package/lib/wav/WaveParser.js +27 -17
- package/lib/wavpack/WavPackParser.d.ts +1 -1
- package/lib/wavpack/WavPackParser.js +22 -13
- package/lib/wavpack/WavPackToken.d.ts +13 -17
- package/lib/wavpack/WavPackToken.js +22 -23
- package/package.json +15 -28
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ITokenizer } from 'strtok3';
|
|
2
|
-
import { ITokenParser } from '../ParserFactory.js';
|
|
3
|
-
import { IOptions, IPrivateOptions } from '../type.js';
|
|
4
|
-
import { INativeMetadataCollector } from './MetadataCollector.js';
|
|
2
|
+
import type { ITokenParser } from '../ParserFactory.js';
|
|
3
|
+
import type { IOptions, IPrivateOptions } from '../type.js';
|
|
4
|
+
import type { INativeMetadataCollector } from './MetadataCollector.js';
|
|
5
5
|
export declare abstract class BasicParser implements ITokenParser {
|
|
6
6
|
protected metadata: INativeMetadataCollector;
|
|
7
7
|
protected tokenizer: ITokenizer;
|
|
@@ -13,5 +13,5 @@ export declare abstract class BasicParser implements ITokenParser {
|
|
|
13
13
|
* @param {IOptions} options Parsing options
|
|
14
14
|
*/
|
|
15
15
|
init(metadata: INativeMetadataCollector, tokenizer: ITokenizer, options: IOptions): ITokenParser;
|
|
16
|
-
abstract parse():
|
|
16
|
+
abstract parse(): Promise<void>;
|
|
17
17
|
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export class BasicParser {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.metadata = undefined;
|
|
4
|
+
this.tokenizer = undefined;
|
|
5
|
+
this.options = undefined;
|
|
6
|
+
}
|
|
2
7
|
/**
|
|
3
8
|
* Initialize parser with output (metadata), input (tokenizer) & parsing options (options).
|
|
4
9
|
* @param {INativeMetadataCollector} metadata Output
|
|
@@ -12,3 +17,4 @@ export class BasicParser {
|
|
|
12
17
|
return this;
|
|
13
18
|
}
|
|
14
19
|
}
|
|
20
|
+
//# sourceMappingURL=BasicParser.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { INativeTagMap, TagType } from './GenericTagTypes.js';
|
|
1
|
+
import type { INativeTagMap, TagType } from './GenericTagTypes.js';
|
|
2
2
|
import { CommonTagMapper } from './GenericTagMapper.js';
|
|
3
3
|
export declare class CaseInsensitiveTagMap extends CommonTagMapper {
|
|
4
4
|
constructor(tagTypes: TagType[], tagMap: INativeTagMap);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { IGenericTag, TagType } from './GenericTagTypes.js';
|
|
2
|
-
import { IGenericTagMapper } from './GenericTagMapper.js';
|
|
3
|
-
import { ITag } from '../type.js';
|
|
4
|
-
import { INativeMetadataCollector } from './MetadataCollector.js';
|
|
1
|
+
import type { IGenericTag, TagType } from './GenericTagTypes.js';
|
|
2
|
+
import type { IGenericTagMapper } from './GenericTagMapper.js';
|
|
3
|
+
import type { ITag } from '../type.js';
|
|
4
|
+
import type { INativeMetadataCollector } from './MetadataCollector.js';
|
|
5
5
|
export declare class CombinedTagMapper {
|
|
6
6
|
tagMappers: {
|
|
7
7
|
[index: string]: IGenericTagMapper;
|
|
@@ -14,6 +14,6 @@ export declare class CombinedTagMapper {
|
|
|
14
14
|
* @param warnings
|
|
15
15
|
* @return Generic tag result (output of this function)
|
|
16
16
|
*/
|
|
17
|
-
mapTag(tagType: TagType, tag: ITag, warnings: INativeMetadataCollector): IGenericTag;
|
|
17
|
+
mapTag(tagType: TagType, tag: ITag, warnings: INativeMetadataCollector): IGenericTag | null;
|
|
18
18
|
private registerTagMapper;
|
|
19
19
|
}
|
|
@@ -39,7 +39,7 @@ export class CombinedTagMapper {
|
|
|
39
39
|
if (tagMapper) {
|
|
40
40
|
return this.tagMappers[tagType].mapGenericTag(tag, warnings);
|
|
41
41
|
}
|
|
42
|
-
throw new Error(
|
|
42
|
+
throw new Error(`No generic tag mapper defined for tag-format: ${tagType}`);
|
|
43
43
|
}
|
|
44
44
|
registerTagMapper(genericTagMapper) {
|
|
45
45
|
for (const tagType of genericTagMapper.tagTypes) {
|
package/lib/common/FourCC.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as generic from './GenericTagTypes.js';
|
|
2
|
-
import { ITag } from '../type.js';
|
|
3
|
-
import { INativeMetadataCollector, IWarningCollector } from './MetadataCollector.js';
|
|
1
|
+
import type * as generic from './GenericTagTypes.js';
|
|
2
|
+
import type { ITag } from '../type.js';
|
|
3
|
+
import type { INativeMetadataCollector, IWarningCollector } from './MetadataCollector.js';
|
|
4
4
|
export interface IGenericTagMapper {
|
|
5
5
|
/**
|
|
6
6
|
* Which tagType is able to map to the generic mapping format
|
|
@@ -16,16 +16,16 @@ export interface IGenericTagMapper {
|
|
|
16
16
|
* @param warnings Register warnings
|
|
17
17
|
* @return Generic tag, if native tag could be mapped
|
|
18
18
|
*/
|
|
19
|
-
mapGenericTag(tag: ITag, warnings: INativeMetadataCollector): generic.IGenericTag;
|
|
19
|
+
mapGenericTag(tag: ITag, warnings: INativeMetadataCollector): generic.IGenericTag | null;
|
|
20
20
|
}
|
|
21
21
|
export declare class CommonTagMapper implements IGenericTagMapper {
|
|
22
22
|
tagTypes: generic.TagType[];
|
|
23
23
|
tagMap: generic.INativeTagMap;
|
|
24
24
|
static maxRatingScore: number;
|
|
25
|
-
static toIntOrNull(str: string): number;
|
|
25
|
+
static toIntOrNull(str: string): number | null;
|
|
26
26
|
static normalizeTrack(origVal: number | string): {
|
|
27
|
-
no: number;
|
|
28
|
-
of: number;
|
|
27
|
+
no: number | null;
|
|
28
|
+
of: number | null;
|
|
29
29
|
};
|
|
30
30
|
constructor(tagTypes: generic.TagType[], tagMap: generic.INativeTagMap);
|
|
31
31
|
/**
|
|
@@ -35,7 +35,7 @@ export declare class CommonTagMapper implements IGenericTagMapper {
|
|
|
35
35
|
* @param warnings Register warnings
|
|
36
36
|
* @return common name
|
|
37
37
|
*/
|
|
38
|
-
mapGenericTag(tag: ITag, warnings: IWarningCollector): generic.IGenericTag;
|
|
38
|
+
mapGenericTag(tag: ITag, warnings: IWarningCollector): generic.IGenericTag | null;
|
|
39
39
|
/**
|
|
40
40
|
* Convert native tag key to common tag key
|
|
41
41
|
* @param tag Native header tag
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export class CommonTagMapper {
|
|
2
2
|
static toIntOrNull(str) {
|
|
3
|
-
const cleaned = parseInt(str, 10);
|
|
4
|
-
return isNaN(cleaned) ? null : cleaned;
|
|
3
|
+
const cleaned = Number.parseInt(str, 10);
|
|
4
|
+
return Number.isNaN(cleaned) ? null : cleaned;
|
|
5
5
|
}
|
|
6
6
|
// TODO: a string of 1of1 would fail to be converted
|
|
7
7
|
// converts 1/10 to no : 1, of : 10
|
|
@@ -9,8 +9,8 @@ export class CommonTagMapper {
|
|
|
9
9
|
static normalizeTrack(origVal) {
|
|
10
10
|
const split = origVal.toString().split('/');
|
|
11
11
|
return {
|
|
12
|
-
no: parseInt(split[0], 10) || null,
|
|
13
|
-
of: parseInt(split[1], 10) || null
|
|
12
|
+
no: Number.parseInt(split[0], 10) || null,
|
|
13
|
+
of: Number.parseInt(split[1], 10) || null
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
constructor(tagTypes, tagMap) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { AnyTagValue, ICommonTagsResult } from '../type.js';
|
|
1
2
|
export type TagType = 'vorbis' | 'ID3v1' | 'ID3v2.2' | 'ID3v2.3' | 'ID3v2.4' | 'APEv2' | 'asf' | 'iTunes' | 'exif' | 'matroska' | 'AIFF';
|
|
2
3
|
export interface IGenericTag {
|
|
3
|
-
id:
|
|
4
|
-
value:
|
|
4
|
+
id: keyof ICommonTagsResult;
|
|
5
|
+
value: AnyTagValue;
|
|
5
6
|
}
|
|
6
7
|
export type GenericTagId = 'track' | 'disk' | 'year' | 'title' | 'artist' | 'artists' | 'albumartist' | 'album' | 'date' | 'originaldate' | 'originalyear' | 'releasedate' | 'comment' | 'genre' | 'picture' | 'composer' | 'lyrics' | 'albumsort' | 'titlesort' | 'work' | 'artistsort' | 'albumartistsort' | 'composersort' | 'lyricist' | 'writer' | 'conductor' | 'remixer' | 'arranger' | 'engineer' | 'technician' | 'producer' | 'djmixer' | 'mixer' | 'publisher' | 'label' | 'grouping' | 'subtitle' | 'discsubtitle' | 'totaltracks' | 'totaldiscs' | 'compilation' | 'rating' | 'bpm' | 'mood' | 'media' | 'catalognumber' | 'tvShow' | 'tvShowSort' | 'tvEpisode' | 'tvEpisodeId' | 'tvNetwork' | 'tvSeason' | 'podcast' | 'podcasturl' | 'releasestatus' | 'releasetype' | 'releasecountry' | 'script' | 'language' | 'copyright' | 'license' | 'encodedby' | 'encodersettings' | 'gapless' | 'barcode' | 'isrc' | 'asin' | 'musicbrainz_recordingid' | 'musicbrainz_trackid' | 'musicbrainz_albumid' | 'musicbrainz_artistid' | 'musicbrainz_albumartistid' | 'musicbrainz_releasegroupid' | 'musicbrainz_workid' | 'musicbrainz_trmid' | 'musicbrainz_discid' | 'acoustid_id' | 'acoustid_fingerprint' | 'musicip_puid' | 'musicip_fingerprint' | 'website' | 'performer:instrument' | 'peakLevel' | 'averageLevel' | 'notes' | 'key' | 'originalalbum' | 'originalartist' | 'discogs_artist_id' | 'discogs_label_id' | 'discogs_master_release_id' | 'discogs_rating' | 'discogs_release_id' | 'discogs_votes' | 'replaygain_track_gain' | 'replaygain_track_peak' | 'replaygain_album_gain' | 'replaygain_album_peak' | 'replaygain_track_minmax' | 'replaygain_album_minmax' | 'replaygain_undo' | 'description' | 'longDescription' | 'category' | 'hdVideo' | 'keywords' | 'movement' | 'movementIndex' | 'movementTotal' | 'podcastId' | 'showMovement' | 'stik';
|
|
7
8
|
export interface INativeTagMap {
|
|
@@ -25,9 +26,9 @@ export declare const commonTags: ITagInfoMap;
|
|
|
25
26
|
* @param alias Name of common tag
|
|
26
27
|
* @returns {boolean|*} true if given alias is mapped as a singleton', otherwise false
|
|
27
28
|
*/
|
|
28
|
-
export declare function isSingleton(alias:
|
|
29
|
+
export declare function isSingleton(alias: keyof ICommonTagsResult): boolean;
|
|
29
30
|
/**
|
|
30
31
|
* @param alias Common (generic) tag
|
|
31
32
|
* @returns {boolean|*} true if given alias is a singleton or explicitly marked as unique
|
|
32
33
|
*/
|
|
33
|
-
export declare function isUnique(alias:
|
|
34
|
+
export declare function isUnique(alias: keyof ICommonTagsResult): boolean;
|
|
@@ -116,13 +116,13 @@ export const commonTags = {
|
|
|
116
116
|
* @returns {boolean|*} true if given alias is mapped as a singleton', otherwise false
|
|
117
117
|
*/
|
|
118
118
|
export function isSingleton(alias) {
|
|
119
|
-
return commonTags
|
|
119
|
+
return commonTags[alias] && !commonTags[alias].multiple;
|
|
120
120
|
}
|
|
121
121
|
/**
|
|
122
122
|
* @param alias Common (generic) tag
|
|
123
123
|
* @returns {boolean|*} true if given alias is a singleton or explicitly marked as unique
|
|
124
124
|
*/
|
|
125
125
|
export function isUnique(alias) {
|
|
126
|
-
return !commonTags[alias].multiple || commonTags[alias].unique;
|
|
126
|
+
return !commonTags[alias].multiple || commonTags[alias].unique || false;
|
|
127
127
|
}
|
|
128
128
|
//# sourceMappingURL=GenericTagTypes.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FormatId, IAudioMetadata, ICommonTagsResult, IFormat, INativeTags, IOptions, IQualityInformation, ITrackInfo } from '../type.js';
|
|
2
|
-
import { IGenericTag, TagType } from './GenericTagTypes.js';
|
|
1
|
+
import { type FormatId, type IAudioMetadata, type ICommonTagsResult, type IFormat, type INativeTags, type IOptions, type IQualityInformation, type ITrackInfo, type AnyTagValue } from '../type.js';
|
|
2
|
+
import { type IGenericTag, type TagType } from './GenericTagTypes.js';
|
|
3
3
|
/**
|
|
4
4
|
* Combines all generic-tag-mappers for each tag type
|
|
5
5
|
*/
|
|
@@ -8,7 +8,7 @@ export interface IWarningCollector {
|
|
|
8
8
|
* Register parser warning
|
|
9
9
|
* @param warning
|
|
10
10
|
*/
|
|
11
|
-
addWarning(warning: string):
|
|
11
|
+
addWarning(warning: string): void;
|
|
12
12
|
}
|
|
13
13
|
export interface INativeMetadataCollector extends IWarningCollector {
|
|
14
14
|
/**
|
|
@@ -21,8 +21,8 @@ export interface INativeMetadataCollector extends IWarningCollector {
|
|
|
21
21
|
* @returns {boolean} true if one or more tags have been found
|
|
22
22
|
*/
|
|
23
23
|
hasAny(): boolean;
|
|
24
|
-
setFormat(key: FormatId, value:
|
|
25
|
-
addTag(tagType: TagType, tagId: string, value:
|
|
24
|
+
setFormat(key: FormatId, value: AnyTagValue): void;
|
|
25
|
+
addTag(tagType: TagType, tagId: string, value: AnyTagValue): Promise<void>;
|
|
26
26
|
addStreamInfo(streamInfo: ITrackInfo): void;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
@@ -30,7 +30,7 @@ export interface INativeMetadataCollector extends IWarningCollector {
|
|
|
30
30
|
* Responsible for triggering async updates
|
|
31
31
|
*/
|
|
32
32
|
export declare class MetadataCollector implements INativeMetadataCollector {
|
|
33
|
-
private opts
|
|
33
|
+
private opts?;
|
|
34
34
|
readonly format: IFormat;
|
|
35
35
|
readonly native: INativeTags;
|
|
36
36
|
readonly common: ICommonTagsResult;
|
|
@@ -44,14 +44,14 @@ export declare class MetadataCollector implements INativeMetadataCollector {
|
|
|
44
44
|
*/
|
|
45
45
|
private readonly originPriority;
|
|
46
46
|
private tagMapper;
|
|
47
|
-
constructor(opts
|
|
47
|
+
constructor(opts?: IOptions | undefined);
|
|
48
48
|
/**
|
|
49
49
|
* @returns {boolean} true if one or more tags have been found
|
|
50
50
|
*/
|
|
51
51
|
hasAny(): boolean;
|
|
52
52
|
addStreamInfo(streamInfo: ITrackInfo): void;
|
|
53
|
-
setFormat(key: FormatId, value:
|
|
54
|
-
addTag(tagType: TagType, tagId: string, value:
|
|
53
|
+
setFormat(key: FormatId, value: AnyTagValue): void;
|
|
54
|
+
addTag(tagType: TagType, tagId: string, value: AnyTagValue): Promise<void>;
|
|
55
55
|
addWarning(warning: string): void;
|
|
56
56
|
postMap(tagType: TagType | 'artificial', tag: IGenericTag): Promise<void>;
|
|
57
57
|
/**
|
|
@@ -22,7 +22,7 @@ export class MetadataCollector {
|
|
|
22
22
|
this.common = {
|
|
23
23
|
track: { no: null, of: null },
|
|
24
24
|
disk: { no: null, of: null },
|
|
25
|
-
movementIndex: {}
|
|
25
|
+
movementIndex: { no: null, of: null }
|
|
26
26
|
};
|
|
27
27
|
this.quality = {
|
|
28
28
|
warnings: []
|
|
@@ -50,13 +50,14 @@ export class MetadataCollector {
|
|
|
50
50
|
return Object.keys(this.native).length > 0;
|
|
51
51
|
}
|
|
52
52
|
addStreamInfo(streamInfo) {
|
|
53
|
-
debug(`streamInfo: type=${TrackType[streamInfo.type]}, codec=${streamInfo.codecName}`);
|
|
53
|
+
debug(`streamInfo: type=${streamInfo.type ? TrackType[streamInfo.type] : '?'}, codec=${streamInfo.codecName}`);
|
|
54
54
|
this.format.trackInfo.push(streamInfo);
|
|
55
55
|
}
|
|
56
56
|
setFormat(key, value) {
|
|
57
|
+
var _a;
|
|
57
58
|
debug(`format: ${key} = ${value}`);
|
|
58
59
|
this.format[key] = value; // as any to override readonly
|
|
59
|
-
if (this.opts.observer) {
|
|
60
|
+
if ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.observer) {
|
|
60
61
|
this.opts.observer({ metadata: this, tag: { type: 'format', id: key, value } });
|
|
61
62
|
}
|
|
62
63
|
}
|
|
@@ -117,29 +118,31 @@ export class MetadataCollector {
|
|
|
117
118
|
return;
|
|
118
119
|
case 'track':
|
|
119
120
|
case 'disk':
|
|
120
|
-
case 'movementIndex':
|
|
121
|
+
case 'movementIndex': {
|
|
121
122
|
const of = this.common[tag.id].of; // store of value, maybe maybe overwritten
|
|
122
123
|
this.common[tag.id] = CommonTagMapper.normalizeTrack(tag.value);
|
|
123
124
|
this.common[tag.id].of = of != null ? of : this.common[tag.id].of;
|
|
124
125
|
return;
|
|
126
|
+
}
|
|
125
127
|
case 'bpm':
|
|
126
128
|
case 'year':
|
|
127
129
|
case 'originalyear':
|
|
128
|
-
tag.value = parseInt(tag.value, 10);
|
|
130
|
+
tag.value = Number.parseInt(tag.value, 10);
|
|
129
131
|
break;
|
|
130
|
-
case 'date':
|
|
132
|
+
case 'date': {
|
|
131
133
|
// ToDo: be more strict on 'YYYY...'
|
|
132
|
-
const year = parseInt(tag.value.substr(0, 4), 10);
|
|
133
|
-
if (!isNaN(year)) {
|
|
134
|
+
const year = Number.parseInt(tag.value.substr(0, 4), 10);
|
|
135
|
+
if (!Number.isNaN(year)) {
|
|
134
136
|
this.common.year = year;
|
|
135
137
|
}
|
|
136
138
|
break;
|
|
139
|
+
}
|
|
137
140
|
case 'discogs_label_id':
|
|
138
141
|
case 'discogs_release_id':
|
|
139
142
|
case 'discogs_master_release_id':
|
|
140
143
|
case 'discogs_artist_id':
|
|
141
144
|
case 'discogs_votes':
|
|
142
|
-
tag.value = typeof tag.value === 'string' ? parseInt(tag.value, 10) : tag.value;
|
|
145
|
+
tag.value = typeof tag.value === 'string' ? Number.parseInt(tag.value, 10) : tag.value;
|
|
143
146
|
break;
|
|
144
147
|
case 'replaygain_track_gain':
|
|
145
148
|
case 'replaygain_track_peak':
|
|
@@ -148,25 +151,28 @@ export class MetadataCollector {
|
|
|
148
151
|
tag.value = toRatio(tag.value);
|
|
149
152
|
break;
|
|
150
153
|
case 'replaygain_track_minmax':
|
|
151
|
-
tag.value = tag.value.split(',').map(v => parseInt(v, 10));
|
|
154
|
+
tag.value = tag.value.split(',').map(v => Number.parseInt(v, 10));
|
|
152
155
|
break;
|
|
153
|
-
case 'replaygain_undo':
|
|
154
|
-
const minMix = tag.value.split(',').map(v => parseInt(v, 10));
|
|
156
|
+
case 'replaygain_undo': {
|
|
157
|
+
const minMix = tag.value.split(',').map(v => Number.parseInt(v, 10));
|
|
155
158
|
tag.value = {
|
|
156
159
|
leftChannel: minMix[0],
|
|
157
160
|
rightChannel: minMix[1]
|
|
158
161
|
};
|
|
159
162
|
break;
|
|
163
|
+
}
|
|
160
164
|
case 'gapless': // iTunes gap-less flag
|
|
161
165
|
case 'compilation':
|
|
162
166
|
case 'podcast':
|
|
163
167
|
case 'showMovement':
|
|
164
168
|
tag.value = tag.value === '1' || tag.value === 1; // boolean
|
|
165
169
|
break;
|
|
166
|
-
case 'isrc': // Only keep unique values
|
|
167
|
-
|
|
170
|
+
case 'isrc': { // Only keep unique values
|
|
171
|
+
const commonTag = this.common[tag.id];
|
|
172
|
+
if (commonTag && commonTag.indexOf(tag.value) !== -1)
|
|
168
173
|
return;
|
|
169
174
|
break;
|
|
175
|
+
}
|
|
170
176
|
case 'comment':
|
|
171
177
|
if (typeof tag.value === 'string') {
|
|
172
178
|
tag.value = { text: tag.value };
|
|
@@ -216,7 +222,7 @@ export class MetadataCollector {
|
|
|
216
222
|
}
|
|
217
223
|
return picture;
|
|
218
224
|
}
|
|
219
|
-
this.addWarning(
|
|
225
|
+
this.addWarning("Empty picture tag found");
|
|
220
226
|
return null;
|
|
221
227
|
}
|
|
222
228
|
/**
|
|
@@ -233,6 +239,7 @@ export class MetadataCollector {
|
|
|
233
239
|
* Set generic tag
|
|
234
240
|
*/
|
|
235
241
|
setGenericTag(tagType, tag) {
|
|
242
|
+
var _a;
|
|
236
243
|
debug(`common.${tag.id} = ${tag.value}`);
|
|
237
244
|
const prio0 = this.commonOrigin[tag.id] || 1000;
|
|
238
245
|
const prio1 = this.originPriority[tagType];
|
|
@@ -263,7 +270,7 @@ export class MetadataCollector {
|
|
|
263
270
|
return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`);
|
|
264
271
|
}
|
|
265
272
|
}
|
|
266
|
-
if (this.opts.observer) {
|
|
273
|
+
if ((_a = this.opts) === null || _a === void 0 ? void 0 : _a.observer) {
|
|
267
274
|
this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } });
|
|
268
275
|
}
|
|
269
276
|
// ToDo: trigger metadata event
|
|
@@ -271,7 +278,7 @@ export class MetadataCollector {
|
|
|
271
278
|
}
|
|
272
279
|
export function joinArtists(artists) {
|
|
273
280
|
if (artists.length > 2) {
|
|
274
|
-
return artists.slice(0, artists.length - 1).join(', ')
|
|
281
|
+
return `${artists.slice(0, artists.length - 1).join(', ')} & ${artists[artists.length - 1]}`;
|
|
275
282
|
}
|
|
276
283
|
return artists.join(' & ');
|
|
277
284
|
}
|
package/lib/common/Util.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import { IRatio } from '../type.js';
|
|
1
|
+
import type { IRatio } from '../type.js';
|
|
2
2
|
export type StringEncoding = 'ascii' | 'utf8' | 'utf-16le' | 'ucs2' | 'base64url' | 'latin1' | 'hex';
|
|
3
|
-
export interface ITextEncoding {
|
|
4
|
-
encoding: StringEncoding;
|
|
5
|
-
bom?: boolean;
|
|
6
|
-
}
|
|
7
3
|
export declare function getBit(buf: Uint8Array, off: number, bit: number): boolean;
|
|
8
4
|
/**
|
|
9
5
|
* Found delimiting zero in uint8Array
|
|
@@ -54,4 +50,4 @@ export declare function dbToRatio(dB: number): number;
|
|
|
54
50
|
* Convert replay gain to ratio and Decibel
|
|
55
51
|
* @param value string holding a ratio like '0.034' or '-7.54 dB'
|
|
56
52
|
*/
|
|
57
|
-
export declare function toRatio(value: string): IRatio;
|
|
53
|
+
export declare function toRatio(value: string): IRatio | undefined;
|
package/lib/common/Util.js
CHANGED
|
@@ -20,14 +20,12 @@ export function findZero(uint8Array, start, end, encoding) {
|
|
|
20
20
|
}
|
|
21
21
|
return i;
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
i++;
|
|
28
|
-
}
|
|
29
|
-
return i;
|
|
23
|
+
while (uint8Array[i] !== 0) {
|
|
24
|
+
if (i >= end)
|
|
25
|
+
return end;
|
|
26
|
+
i++;
|
|
30
27
|
}
|
|
28
|
+
return i;
|
|
31
29
|
}
|
|
32
30
|
export function trimRightNull(x) {
|
|
33
31
|
const pos0 = x.indexOf('\0');
|
|
@@ -53,7 +51,7 @@ export function decodeString(uint8Array, encoding) {
|
|
|
53
51
|
if (uint8Array[0] === 0xFF && uint8Array[1] === 0xFE) { // little endian
|
|
54
52
|
return decodeString(uint8Array.subarray(2), encoding);
|
|
55
53
|
}
|
|
56
|
-
|
|
54
|
+
if (encoding === 'utf-16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) {
|
|
57
55
|
// BOM, indicating big endian decoding
|
|
58
56
|
if ((uint8Array.length & 1) !== 0)
|
|
59
57
|
throw new Error('Expected even number of octets for 16-bit unicode string');
|
|
@@ -106,7 +104,7 @@ export function a2hex(str) {
|
|
|
106
104
|
const arr = [];
|
|
107
105
|
for (let i = 0, l = str.length; i < l; i++) {
|
|
108
106
|
const hex = Number(str.charCodeAt(i)).toString(16);
|
|
109
|
-
arr.push(hex.length === 1 ?
|
|
107
|
+
arr.push(hex.length === 1 ? `0${hex}` : hex);
|
|
110
108
|
}
|
|
111
109
|
return arr.join(' ');
|
|
112
110
|
}
|
|
@@ -122,7 +120,7 @@ export function ratioToDb(ratio) {
|
|
|
122
120
|
* db Decibels
|
|
123
121
|
*/
|
|
124
122
|
export function dbToRatio(dB) {
|
|
125
|
-
return
|
|
123
|
+
return 10 ** (dB / 10);
|
|
126
124
|
}
|
|
127
125
|
/**
|
|
128
126
|
* Convert replay gain to ratio and Decibel
|
|
@@ -132,7 +130,7 @@ export function toRatio(value) {
|
|
|
132
130
|
const ps = value.split(' ').map(p => p.trim().toLowerCase());
|
|
133
131
|
// @ts-ignore
|
|
134
132
|
if (ps.length >= 1) {
|
|
135
|
-
const v = parseFloat(ps[0]);
|
|
133
|
+
const v = Number.parseFloat(ps[0]);
|
|
136
134
|
return ps.length === 2 && ps[1] === 'db' ? {
|
|
137
135
|
dB: v,
|
|
138
136
|
ratio: dbToRatio(v)
|
package/lib/core.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Primary entry point, Node.js specific entry point is index.ts
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
4
|
+
import { type AnyWebByteStream, type IFileInfo, type ITokenizer } from 'strtok3';
|
|
5
5
|
import type { IAudioMetadata, INativeTagDict, IOptions, IPicture, IPrivateOptions, IRandomReader, ITag } from './type.js';
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
export { IAudioMetadata, IOptions, ITag, INativeTagDict, ICommonTagsResult, IFormat, IPicture, IRatio, IChapter, ILyricsTag, LyricsContentType, TimestampFormat } from './type.js';
|
|
9
|
-
export type AnyWebStream<G> = NodeReadableStream<G> | ReadableStream<G>;
|
|
6
|
+
export type { IFileInfo } from 'strtok3';
|
|
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';
|
|
10
8
|
/**
|
|
11
9
|
* Parse Web API File
|
|
12
10
|
* Requires Blob to be able to stream using a ReadableStreamBYOBReader, only available since Node.js ≥ 20
|
|
@@ -22,7 +20,7 @@ export declare function parseBlob(blob: Blob, options?: IOptions): Promise<IAudi
|
|
|
22
20
|
* @param fileInfo - File information object or MIME-type string
|
|
23
21
|
* @returns Metadata
|
|
24
22
|
*/
|
|
25
|
-
export declare function parseWebStream(webStream:
|
|
23
|
+
export declare function parseWebStream(webStream: AnyWebByteStream, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
|
|
26
24
|
/**
|
|
27
25
|
* Parse audio from Node Buffer
|
|
28
26
|
* @param uint8Array - Uint8Array holding audio data
|
|
@@ -31,14 +29,14 @@ export declare function parseWebStream(webStream: AnyWebStream<Uint8Array>, file
|
|
|
31
29
|
* @returns Metadata
|
|
32
30
|
* Ref: https://github.com/Borewit/strtok3/blob/e6938c81ff685074d5eb3064a11c0b03ca934c1d/src/index.ts#L15
|
|
33
31
|
*/
|
|
34
|
-
export declare function parseBuffer(uint8Array: Uint8Array, fileInfo?:
|
|
32
|
+
export declare function parseBuffer(uint8Array: Uint8Array, fileInfo?: IFileInfo | string, options?: IOptions): Promise<IAudioMetadata>;
|
|
35
33
|
/**
|
|
36
34
|
* Parse audio from ITokenizer source
|
|
37
35
|
* @param tokenizer - Audio source implementing the tokenizer interface
|
|
38
36
|
* @param options - Parsing options
|
|
39
37
|
* @returns Metadata
|
|
40
38
|
*/
|
|
41
|
-
export declare function parseFromTokenizer(tokenizer:
|
|
39
|
+
export declare function parseFromTokenizer(tokenizer: ITokenizer, options?: IOptions): Promise<IAudioMetadata>;
|
|
42
40
|
/**
|
|
43
41
|
* Create a dictionary ordered by their tag id (key)
|
|
44
42
|
* @param nativeTags list of tags
|
|
@@ -50,7 +48,7 @@ export declare function orderTags(nativeTags: ITag[]): INativeTagDict;
|
|
|
50
48
|
* @param rating Normalized rating [0..1] (common.rating[n].rating)
|
|
51
49
|
* @returns Number of stars: 1, 2, 3, 4 or 5 stars
|
|
52
50
|
*/
|
|
53
|
-
export declare function ratingToStars(rating: number): number;
|
|
51
|
+
export declare function ratingToStars(rating: number | undefined): number;
|
|
54
52
|
/**
|
|
55
53
|
* Select most likely cover image.
|
|
56
54
|
* @param pictures Usually metadata.common.picture
|
package/lib/core.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Primary entry point, Node.js specific entry point is index.ts
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import { fromWebStream, fromBuffer } from 'strtok3';
|
|
5
|
+
import { parseOnContentType } from './ParserFactory.js';
|
|
6
6
|
import { RandomUint8ArrayReader } from './common/RandomUint8ArrayReader.js';
|
|
7
7
|
import { APEv2Parser } from './apev2/APEv2Parser.js';
|
|
8
8
|
import { hasID3v1Header } from './id3v1/ID3v1Parser.js';
|
|
@@ -30,7 +30,7 @@ export async function parseBlob(blob, options = {}) {
|
|
|
30
30
|
* @returns Metadata
|
|
31
31
|
*/
|
|
32
32
|
export function parseWebStream(webStream, fileInfo, options = {}) {
|
|
33
|
-
return parseFromTokenizer(
|
|
33
|
+
return parseFromTokenizer(fromWebStream(webStream, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo }), options);
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Parse audio from Node Buffer
|
|
@@ -43,7 +43,7 @@ export function parseWebStream(webStream, fileInfo, options = {}) {
|
|
|
43
43
|
export async function parseBuffer(uint8Array, fileInfo, options = {}) {
|
|
44
44
|
const bufferReader = new RandomUint8ArrayReader(uint8Array);
|
|
45
45
|
await scanAppendingHeaders(bufferReader, options);
|
|
46
|
-
const tokenizer =
|
|
46
|
+
const tokenizer = fromBuffer(uint8Array, { fileInfo: typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo });
|
|
47
47
|
return parseFromTokenizer(tokenizer, options);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
@@ -53,7 +53,7 @@ export async function parseBuffer(uint8Array, fileInfo, options = {}) {
|
|
|
53
53
|
* @returns Metadata
|
|
54
54
|
*/
|
|
55
55
|
export function parseFromTokenizer(tokenizer, options) {
|
|
56
|
-
return
|
|
56
|
+
return parseOnContentType(tokenizer, options);
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* Create a dictionary ordered by their tag id (key)
|
|
@@ -62,8 +62,11 @@ export function parseFromTokenizer(tokenizer, options) {
|
|
|
62
62
|
*/
|
|
63
63
|
export function orderTags(nativeTags) {
|
|
64
64
|
const tags = {};
|
|
65
|
-
for (const
|
|
66
|
-
|
|
65
|
+
for (const { id, value } of nativeTags) {
|
|
66
|
+
if (!tags[id]) {
|
|
67
|
+
tags[id] = [];
|
|
68
|
+
}
|
|
69
|
+
tags[id].push(value);
|
|
67
70
|
}
|
|
68
71
|
return tags;
|
|
69
72
|
}
|