776 lines
14 KiB
TypeScript
776 lines
14 KiB
TypeScript
import type { TagType } from './common/GenericTagTypes.js';
|
|
import type { IFooter } from './apev2/APEv2Token.js';
|
|
import type { TrackType } from './matroska/types.js';
|
|
import type { LyricsContentType, TimestampFormat } from './id3v2/ID3v2Token.js';
|
|
|
|
export { TrackType, TrackTypeValueToKeyMap } from './matroska/types.js';
|
|
export { LyricsContentType, TimestampFormat } from './id3v2/ID3v2Token.js';
|
|
|
|
export type AnyTagValue = unknown;
|
|
|
|
/**
|
|
* Attached picture, typically used for cover art
|
|
*/
|
|
export interface IPicture {
|
|
/**
|
|
* Image mime type
|
|
*/
|
|
format: string;
|
|
/**
|
|
* Image data
|
|
*/
|
|
data: Uint8Array;
|
|
/**
|
|
* Optional description
|
|
*/
|
|
description?: string;
|
|
/**
|
|
* Picture type
|
|
*/
|
|
type?: string;
|
|
/**
|
|
* File name
|
|
*/
|
|
name?: string;
|
|
}
|
|
|
|
/**
|
|
* Abstract interface to access rating information
|
|
*/
|
|
export interface IRating {
|
|
/**
|
|
* Rating source, could be an e-mail address
|
|
*/
|
|
source?: string;
|
|
/**
|
|
* Rating [0..1]
|
|
*/
|
|
rating?: number;
|
|
}
|
|
|
|
export interface ICommonTagsResult {
|
|
track: { no: number | null, of: number | null };
|
|
disk: { no: number | null, of: number | null };
|
|
/**
|
|
* Release year
|
|
*/
|
|
year?: number;
|
|
/**
|
|
* Track title
|
|
*/
|
|
title?: string;
|
|
/**
|
|
* Track, maybe several artists written in a single string.
|
|
*/
|
|
artist?: string;
|
|
/**
|
|
* Track artists, aims to capture every artist in a different string.
|
|
*/
|
|
artists?: string[];
|
|
/**
|
|
* Track album artist/s. Contains the first album artist if multiple tags exist, or maybe several album artists written in a single string.
|
|
*/
|
|
albumartist?: string;
|
|
/**
|
|
* Track album artists, aims to capture every album artist in a different string.
|
|
*/
|
|
albumartists?: string[];
|
|
/**
|
|
* Album title
|
|
*/
|
|
album?: string;
|
|
/**
|
|
* Date
|
|
*/
|
|
date?: string;
|
|
/**
|
|
* Original release date
|
|
*/
|
|
originaldate?: string;
|
|
/**
|
|
* Original release year
|
|
*/
|
|
originalyear?: number;
|
|
/**
|
|
* Release date
|
|
*/
|
|
releasedate?: string;
|
|
/**
|
|
* List of comments
|
|
*/
|
|
comment?: IComment[];
|
|
/**
|
|
* Genre
|
|
*/
|
|
genre?: string[];
|
|
/**
|
|
* Embedded album art
|
|
*/
|
|
picture?: IPicture[];
|
|
/**
|
|
* Track composer
|
|
*/
|
|
composer?: string[];
|
|
/**
|
|
* Synchronized lyrics
|
|
*/
|
|
lyrics?: ILyricsTag[];
|
|
/**
|
|
* Album title, formatted for alphabetic ordering
|
|
*/
|
|
albumsort?: string;
|
|
/**
|
|
* Track title, formatted for alphabetic ordering
|
|
*/
|
|
titlesort?: string;
|
|
/**
|
|
* The canonical title of the work
|
|
*/
|
|
work?: string;
|
|
/**
|
|
* Track artist, formatted for alphabetic ordering
|
|
*/
|
|
artistsort?: string;
|
|
/**
|
|
* Album artist, formatted for alphabetic ordering
|
|
*/
|
|
albumartistsort?: string;
|
|
/**
|
|
* Composer, formatted for alphabetic ordering
|
|
*/
|
|
composersort?: string;
|
|
/**
|
|
* Lyricist(s)
|
|
*/
|
|
lyricist?: string[];
|
|
/**
|
|
* Writer(s)
|
|
*/
|
|
writer?: string[];
|
|
/**
|
|
* Conductor(s)
|
|
*/
|
|
conductor?: string[];
|
|
/**
|
|
* Remixer(s)
|
|
*/
|
|
remixer?: string[];
|
|
/**
|
|
* Arranger(s)
|
|
*/
|
|
arranger?: string[];
|
|
/**
|
|
* Engineer(s)
|
|
*/
|
|
engineer?: string[];
|
|
/**
|
|
* Publisher(s)
|
|
*/
|
|
publisher?: string[];
|
|
/**
|
|
* Producer(s)
|
|
*/
|
|
producer?: string[];
|
|
/**
|
|
* Mix-DJ(s)
|
|
*/
|
|
djmixer?: string[];
|
|
/**
|
|
* Mixed by
|
|
*/
|
|
mixer?: string[];
|
|
technician?: string[];
|
|
label?: string[];
|
|
grouping?: string;
|
|
subtitle?: string[];
|
|
description?: string[];
|
|
longDescription?: string;
|
|
discsubtitle?: string[];
|
|
totaltracks?: string;
|
|
totaldiscs?: string;
|
|
movementTotal?: number;
|
|
compilation?: boolean;
|
|
rating?: IRating[];
|
|
bpm?: number;
|
|
/**
|
|
* Keywords to reflect the mood of the audio, e.g. 'Romantic' or 'Sad'
|
|
*/
|
|
mood?: string;
|
|
/**
|
|
* Release format, e.g. 'CD'
|
|
*/
|
|
media?: string;
|
|
/**
|
|
* Release catalog number(s)
|
|
*/
|
|
catalognumber?: string[];
|
|
/**
|
|
* TV show title
|
|
*/
|
|
tvShow?: string;
|
|
/**
|
|
* TV show title, formatted for alphabetic ordering
|
|
*/
|
|
tvShowSort?: string;
|
|
/**
|
|
* TV season title sequence number
|
|
*/
|
|
tvSeason?: number;
|
|
/**
|
|
* TV Episode sequence number
|
|
*/
|
|
tvEpisode?: number;
|
|
/**
|
|
* TV episode ID
|
|
*/
|
|
tvEpisodeId?: string,
|
|
/**
|
|
* TV network
|
|
*/
|
|
tvNetwork?: string,
|
|
podcast?: boolean;
|
|
podcasturl?: string;
|
|
releasestatus?: string;
|
|
releasetype?: string[];
|
|
releasecountry?: string;
|
|
script?: string;
|
|
language?: string;
|
|
copyright?: string;
|
|
license?: string;
|
|
encodedby?: string;
|
|
encodersettings?: string;
|
|
gapless?: boolean;
|
|
barcode?: string; // ToDo: multiple??
|
|
// International Standard Recording Code
|
|
isrc?: string[];
|
|
asin?: string;
|
|
musicbrainz_recordingid?: string;
|
|
musicbrainz_trackid?: string;
|
|
musicbrainz_albumid?: string;
|
|
musicbrainz_artistid?: string[];
|
|
musicbrainz_albumartistid?: string[];
|
|
musicbrainz_releasegroupid?: string;
|
|
musicbrainz_workid?: string;
|
|
musicbrainz_trmid?: string;
|
|
musicbrainz_discid?: string;
|
|
acoustid_id?: string;
|
|
acoustid_fingerprint?: string;
|
|
musicip_puid?: string;
|
|
musicip_fingerprint?: string;
|
|
website?: string;
|
|
'performer:instrument'?: string[];
|
|
averageLevel?: number;
|
|
peakLevel?: number;
|
|
notes?: string[];
|
|
originalalbum?: string;
|
|
originalartist?: string;
|
|
// Discogs:
|
|
discogs_artist_id?: number[];
|
|
discogs_release_id?: number;
|
|
discogs_label_id?: number;
|
|
discogs_master_release_id?: number;
|
|
discogs_votes?: number;
|
|
discogs_rating?: number;
|
|
|
|
/**
|
|
* Track gain ratio [0..1]
|
|
*/
|
|
replaygain_track_gain_ratio?: number;
|
|
/**
|
|
* Track peak ratio [0..1]
|
|
*/
|
|
replaygain_track_peak_ratio?: number;
|
|
|
|
/**
|
|
* Track gain ratio
|
|
*/
|
|
replaygain_track_gain?: IRatio;
|
|
|
|
/**
|
|
* Track peak ratio
|
|
*/
|
|
replaygain_track_peak?: IRatio;
|
|
|
|
/**
|
|
* Album gain ratio
|
|
*/
|
|
replaygain_album_gain?: IRatio;
|
|
|
|
/**
|
|
* Album peak ratio
|
|
*/
|
|
replaygain_album_peak?: IRatio;
|
|
|
|
/**
|
|
* minimum & maximum global gain values across a set of files scanned as an album
|
|
*/
|
|
replaygain_undo?: {
|
|
leftChannel: number,
|
|
rightChannel: number
|
|
};
|
|
|
|
/**
|
|
* minimum & maximum global gain values across a set of file
|
|
*/
|
|
replaygain_track_minmax?: number[];
|
|
|
|
/**
|
|
* minimum & maximum global gain values across a set of files scanned as an album
|
|
*/
|
|
replaygain_album_minmax?: number[];
|
|
|
|
/**
|
|
* The initial key of the music in the file, e.g. "A Minor".
|
|
* Ref: https://docs.microsoft.com/en-us/windows/win32/wmformat/wm-initialkey
|
|
*/
|
|
key?: string;
|
|
|
|
/**
|
|
* Podcast Category
|
|
*/
|
|
category?: string[];
|
|
/**
|
|
* iTunes Video Quality
|
|
*
|
|
* 2: Full HD
|
|
* 1: HD
|
|
* 0: SD
|
|
*/
|
|
hdVideo?: number;
|
|
/**
|
|
* Podcast Keywords
|
|
*/
|
|
keywords?: string[];
|
|
/**
|
|
* Movement
|
|
*/
|
|
movement?: string;
|
|
/**
|
|
* Movement Index/Total
|
|
*/
|
|
movementIndex: { no: number | null, of: number | null };
|
|
/**
|
|
* Podcast Identifier
|
|
*/
|
|
podcastId?: string;
|
|
/**
|
|
* Show Movement
|
|
*/
|
|
showMovement?: boolean;
|
|
/**
|
|
* iTunes Media Type
|
|
*
|
|
* 1: Normal
|
|
* 2: Audiobook
|
|
* 6: Music Video
|
|
* 9: Movie
|
|
* 10: TV Show
|
|
* 11: Booklet
|
|
* 14: Ringtone
|
|
*
|
|
* https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata#user-content-media-type-stik
|
|
*/
|
|
stik?: number;
|
|
|
|
playCounter?: number;
|
|
}
|
|
|
|
export interface IRatio {
|
|
/**
|
|
* [0..1]
|
|
*/
|
|
ratio: number;
|
|
|
|
/**
|
|
* Decibel
|
|
*/
|
|
dB: number;
|
|
}
|
|
|
|
export type FormatId =
|
|
'container'
|
|
| 'duration'
|
|
| 'bitrate'
|
|
| 'sampleRate'
|
|
| 'bitsPerSample'
|
|
| 'codec'
|
|
| 'tool'
|
|
| 'codecProfile'
|
|
| 'lossless'
|
|
| 'numberOfChannels'
|
|
| 'numberOfSamples'
|
|
| 'audioMD5'
|
|
| 'chapters'
|
|
| 'modificationTime'
|
|
| 'creationTime'
|
|
| 'trackPeakLevel'
|
|
| 'trackGain'
|
|
| 'albumGain'
|
|
| 'hasAudio'
|
|
| 'hasVideo';
|
|
|
|
export interface IAudioTrack {
|
|
samplingFrequency?: number;
|
|
outputSamplingFrequency?: number;
|
|
channels?: number;
|
|
channelPositions?: Uint8Array;
|
|
bitDepth?: number;
|
|
}
|
|
|
|
export interface IVideoTrack {
|
|
flagInterlaced?: boolean;
|
|
stereoMode?: number;
|
|
pixelWidth?: number;
|
|
pixelHeight?: number;
|
|
displayWidth?: number;
|
|
displayHeight?: number;
|
|
displayUnit?: number;
|
|
aspectRatioType?: number;
|
|
colourSpace?: Uint8Array;
|
|
gammaValue?: number;
|
|
}
|
|
|
|
export interface ITrackInfo {
|
|
type?: TrackType;
|
|
codecName?: string;
|
|
codecSettings?: string;
|
|
flagEnabled?: boolean;
|
|
flagDefault?: boolean;
|
|
flagLacing?: boolean;
|
|
name?: string;
|
|
language?: string;
|
|
audio?: IAudioTrack;
|
|
video?: IVideoTrack;
|
|
}
|
|
|
|
export interface IFormat {
|
|
|
|
readonly trackInfo: ITrackInfo[]
|
|
|
|
/**
|
|
* E.g.: 'flac'
|
|
*/
|
|
readonly container?: string, // ToDo: make mandatory
|
|
|
|
/**
|
|
* List of tags found in parsed audio file
|
|
*/
|
|
readonly tagTypes: TagType[],
|
|
|
|
/**
|
|
* Duration in seconds
|
|
*/
|
|
readonly duration?: number,
|
|
|
|
/**
|
|
* Number bits per second of encoded audio file
|
|
*/
|
|
readonly bitrate?: number,
|
|
|
|
/**
|
|
* Sampling rate in Samples per second (S/s)
|
|
*/
|
|
readonly sampleRate?: number,
|
|
|
|
/**
|
|
* Audio bit depth
|
|
*/
|
|
readonly bitsPerSample?: number,
|
|
|
|
/**
|
|
* Encoder brand, e.g.: LAME3.99r
|
|
*/
|
|
readonly tool?: string,
|
|
|
|
/**
|
|
* Encoder name / compressionType, e.g.: 'PCM', 'ITU-T G.711 mu-law'
|
|
*/
|
|
readonly codec?: string,
|
|
|
|
/**
|
|
* Codec profile
|
|
*/
|
|
readonly codecProfile?: string,
|
|
|
|
readonly lossless?: boolean,
|
|
|
|
/**
|
|
* Number of audio channels
|
|
*/
|
|
readonly numberOfChannels?: number,
|
|
|
|
/**
|
|
* Number of samples frames.
|
|
* One sample contains all channels
|
|
* The duration is: numberOfSamples / sampleRate
|
|
*/
|
|
readonly numberOfSamples?: number
|
|
|
|
/**
|
|
* 16-byte MD5 of raw audio
|
|
*/
|
|
readonly audioMD5?: Uint8Array;
|
|
|
|
/**
|
|
* Chapters in audio stream
|
|
*/
|
|
readonly chapters?: IChapter[]
|
|
|
|
/**
|
|
* Time file was created
|
|
*/
|
|
readonly creationTime?: Date;
|
|
|
|
/**
|
|
* Time file was modified
|
|
*/
|
|
readonly modificationTime?: Date;
|
|
|
|
readonly trackGain?: number;
|
|
readonly trackPeakLevel?: number;
|
|
readonly albumGain?: number;
|
|
|
|
/**
|
|
* Indicates if the audio files contains an audio stream
|
|
*/
|
|
hasAudio?: boolean;
|
|
|
|
/**
|
|
* Indicates if the media files contains a video stream
|
|
*/
|
|
hasVideo?: boolean;
|
|
}
|
|
|
|
export interface ITag {
|
|
id: string;
|
|
value: AnyTagValue;
|
|
}
|
|
|
|
export interface IUrl {
|
|
url: string;
|
|
description: string;
|
|
}
|
|
|
|
export interface IChapter {
|
|
|
|
/**
|
|
* Internal chapter reference
|
|
*/
|
|
id?: string;
|
|
|
|
/**
|
|
* Chapter title
|
|
*/
|
|
title: string;
|
|
|
|
/**
|
|
* URL
|
|
*/
|
|
url?: IUrl;
|
|
|
|
/**
|
|
* Audio offset in sample number, 0 is the first sample.
|
|
* Duration offset is sampleOffset / format.sampleRate
|
|
*/
|
|
sampleOffset?: number;
|
|
/**
|
|
* Timestamp where the chapter starts
|
|
* Chapter timestamp is start/timeScale in seconds.
|
|
*/
|
|
start: number;
|
|
|
|
/**
|
|
* Timestamp where the chapter end
|
|
* Chapter timestamp is start/timeScale in seconds.
|
|
*/
|
|
end?: number;
|
|
|
|
/**
|
|
* Time value that indicates the timescale for chapter tracks, the number of time units that pass per second in its time coordinate system.
|
|
*/
|
|
timeScale?: number;
|
|
|
|
/**
|
|
* Picture
|
|
*/
|
|
image?: IPicture;
|
|
}
|
|
|
|
/**
|
|
* Flat list of tags
|
|
*/
|
|
export interface INativeTags {
|
|
[tagType: string]: ITag[];
|
|
}
|
|
|
|
/**
|
|
* Tags ordered by tag-ID
|
|
*/
|
|
export interface INativeTagDict {
|
|
[tagId: string]: AnyTagValue[];
|
|
}
|
|
|
|
export interface INativeAudioMetadata {
|
|
format: IFormat,
|
|
native: INativeTags
|
|
quality: IQualityInformation;
|
|
}
|
|
|
|
export interface IQualityInformation {
|
|
/**
|
|
* Warnings
|
|
*/
|
|
warnings: IParserWarning[];
|
|
|
|
}
|
|
|
|
export interface IParserWarning {
|
|
message: string;
|
|
}
|
|
|
|
export interface IAudioMetadata extends INativeAudioMetadata {
|
|
/**
|
|
* Metadata, form independent interface
|
|
*/
|
|
common: ICommonTagsResult;
|
|
}
|
|
|
|
/**
|
|
* Corresponds with parser module name
|
|
*/
|
|
export type ParserType =
|
|
'mpeg'
|
|
| 'apev2'
|
|
| 'mp4'
|
|
| 'asf'
|
|
| 'flac'
|
|
| 'ogg'
|
|
| 'aiff'
|
|
| 'wavpack'
|
|
| 'riff'
|
|
| 'musepack'
|
|
| 'dsf'
|
|
| 'dsdiff'
|
|
| 'adts'
|
|
| 'matroska'
|
|
;
|
|
|
|
export interface IOptions {
|
|
|
|
/**
|
|
* default: `false`, if set to `true`, it will parse the whole media file if required to determine the duration.
|
|
*/
|
|
duration?: boolean;
|
|
|
|
/**
|
|
* default: `false`, if set to `true`, it will skip parsing covers.
|
|
*/
|
|
skipCovers?: boolean;
|
|
|
|
/**
|
|
* default: `false`, if set to `true`, it will not search all the entire track for additional headers.
|
|
* Only recommenced to use in combination with streams.
|
|
*/
|
|
skipPostHeaders?: boolean;
|
|
|
|
/**
|
|
* default: `false`, if set to `true`, it will include MP4 chapters
|
|
*/
|
|
includeChapters?: boolean;
|
|
|
|
/**
|
|
* Set observer for async callbacks to common or format.
|
|
*/
|
|
observer?: Observer;
|
|
|
|
/**
|
|
* In Matroska based files, use the _SeekHead_ element index to skip _segment/cluster_ elements.
|
|
* By default, disabled
|
|
* Can have a significant performance impact if enabled.
|
|
* Possible side effect can be that certain metadata maybe skipped, depending on the index.
|
|
* If there is no _SeekHead_ element present in the Matroska file, this flag has no effect
|
|
* Ref: https://www.matroska.org/technical/diagram.html
|
|
*/
|
|
mkvUseIndex?: boolean;
|
|
}
|
|
|
|
export interface IApeHeader extends IOptions {
|
|
|
|
/**
|
|
* Offset of APE-header
|
|
*/
|
|
offset: number;
|
|
|
|
/**
|
|
* APEv1 / APEv2 header offset
|
|
*/
|
|
footer: IFooter;
|
|
|
|
}
|
|
|
|
export interface IPrivateOptions extends IOptions {
|
|
|
|
apeHeader?: IApeHeader;
|
|
}
|
|
|
|
export interface IMetadataEventTag {
|
|
|
|
/**
|
|
* Either `common` if it is a generic tag event, or `format` for format related updates
|
|
*/
|
|
type: 'common' | 'format';
|
|
|
|
/**
|
|
* Tag id
|
|
*/
|
|
id: keyof ICommonTagsResult | FormatId;
|
|
|
|
/**
|
|
* Tag value
|
|
*/
|
|
value: AnyTagValue;
|
|
}
|
|
|
|
|
|
/**
|
|
* Event definition send after each change to common/format metadata change to observer.
|
|
*/
|
|
export interface IMetadataEvent {
|
|
|
|
/**
|
|
* Tag which has been updated.
|
|
*/
|
|
tag: IMetadataEventTag;
|
|
|
|
/**
|
|
* Metadata model including the attached tag
|
|
*/
|
|
metadata: IAudioMetadata;
|
|
}
|
|
|
|
export type Observer = (update: IMetadataEvent) => void;
|
|
|
|
export interface ILyricsText {
|
|
text: string;
|
|
timestamp?: number;
|
|
}
|
|
|
|
export interface IComment {
|
|
descriptor?: string;
|
|
language?: string;
|
|
text?: string;
|
|
}
|
|
|
|
export interface ILyricsTag extends IComment {
|
|
contentType: LyricsContentType;
|
|
timeStampFormat: TimestampFormat;
|
|
/**
|
|
* Un-synchronized lyrics
|
|
*/
|
|
text?: string;
|
|
/**
|
|
* Synchronized lyrics
|
|
*/
|
|
syncText: ILyricsText[];
|
|
}
|