From 439e78ad82ff6c1042a5b4b428787d22304c2164 Mon Sep 17 00:00:00 2001 From: Alexander Zinchuk Date: Fri, 8 Apr 2022 20:59:49 +0200 Subject: [PATCH] [Dev] Bundle `music-metadata-browser` with deps to a single file (#1820) --- .eslintignore | 2 + package-lock.json | 262 +- package.json | 2 - src/lib/music-metadata-browser/index.d.ts | 33 + src/lib/music-metadata-browser/index.js | 19378 ++++++++++++++++++++ src/util/audio.ts | 2 +- webpack.config.js | 1 - 7 files changed, 19448 insertions(+), 232 deletions(-) create mode 100644 src/lib/music-metadata-browser/index.d.ts create mode 100644 src/lib/music-metadata-browser/index.js diff --git a/.eslintignore b/.eslintignore index 27792b67b..42b957dc0 100644 --- a/.eslintignore +++ b/.eslintignore @@ -10,6 +10,8 @@ src/lib/gramjs/tl/schemaTl.js src/lib/lovely-chart +src/lib/music-metadata-browser + webpack.config.js jest.config.js src/lib/secret-sauce/ diff --git a/package-lock.json b/package-lock.json index 1b0c9d0dd..405fbad16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,10 @@ "emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#54443d1938ec1c157e74d2a95e9103dcb3f5c6dd", "events": "^3.3.0", "idb-keyval": "^6.1.0", - "music-metadata-browser": "^2.5.5", "opus-recorder": "github:Ajaxy/opus-recorder", "os-browserify": "^0.3.0", "pako": "^2.0.4", "path-browserify": "^1.0.1", - "process": "^0.11.10", "qr-code-styling": "github:zubiden/qr-code-styling#10f7cf3", "websocket": "^1.0.34" }, @@ -3316,11 +3314,6 @@ "node": ">=8" } }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, "node_modules/@tootallnate/once": { "version": "1.1.2", "dev": true, @@ -4756,6 +4749,7 @@ }, "node_modules/base64-js": { "version": "1.5.1", + "dev": true, "funding": [ { "type": "github", @@ -4928,6 +4922,7 @@ }, "node_modules/buffer": { "version": "6.0.3", + "dev": true, "funding": [ { "type": "github", @@ -5459,6 +5454,7 @@ }, "node_modules/content-type": { "version": "1.0.4", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -5951,6 +5947,7 @@ }, "node_modules/debug": { "version": "4.3.3", + "dev": true, "license": "MIT", "dependencies": { "ms": "2.1.2" @@ -7482,22 +7479,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/file-type": { - "version": "16.5.3", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.3.tgz", - "integrity": "sha512-uVsl7iFhHSOY4bEONLlTK47iAHtNsFHWP5YE4xJfZ4rnX7S1Q3wce09XgqSC7E/xh8Ncv/be1lNoyprlUH/x6A==", - "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, "node_modules/fill-range": { "version": "7.0.1", "dev": true, @@ -8293,6 +8274,7 @@ }, "node_modules/ieee754": { "version": "1.2.1", + "dev": true, "funding": [ { "type": "github", @@ -8390,6 +8372,7 @@ }, "node_modules/inherits": { "version": "2.0.4", + "dev": true, "license": "ISC" }, "node_modules/ini": { @@ -11514,6 +11497,7 @@ }, "node_modules/ms": { "version": "2.1.2", + "dev": true, "license": "MIT" }, "node_modules/multicast-dns": { @@ -11533,51 +11517,6 @@ "dev": true, "license": "MIT" }, - "node_modules/music-metadata": { - "version": "7.12.2", - "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-7.12.2.tgz", - "integrity": "sha512-KO1L6q30b6HfGlDQk1VAdrZqCKi4Gy7pN7eZOZ0YZQkhF/KCLHxKCjKKli9ao9kIBC/9s+uXHvjW3bDIBWuGew==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "content-type": "^1.0.4", - "debug": "^4.3.3", - "file-type": "16.5.3", - "media-typer": "^1.1.0", - "strtok3": "^6.2.4", - "token-types": "^4.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/music-metadata-browser": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/music-metadata-browser/-/music-metadata-browser-2.5.5.tgz", - "integrity": "sha512-38A/q1fz7LOIDxpi2fAzPGMNZQ0YyQUfErizK/rbWRIKC7E4N2BQpqCHq38nHlb7+Iv/wEHgwVoIwbUAXtphEA==", - "dependencies": { - "buffer": "^6.0.3", - "debug": "^4.3.3", - "music-metadata": "^7.12.0", - "readable-stream": "^3.6.0", - "readable-web-to-node-stream": "^3.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/music-metadata/node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/nanoid": { "version": "3.3.1", "dev": true, @@ -12077,7 +12016,8 @@ }, "node_modules/path-browserify": { "version": "1.0.1", - "license": "MIT" + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" }, "node_modules/path-exists": { "version": "3.0.0", @@ -12121,18 +12061,6 @@ "node": ">=8" } }, - "node_modules/peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/picocolors": { "version": "1.0.0", "dev": true, @@ -13019,14 +12947,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "dev": true, @@ -13349,6 +13269,7 @@ }, "node_modules/readable-stream": { "version": "3.6.0", + "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.3", @@ -13359,21 +13280,6 @@ "node": ">= 6" } }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/readdirp": { "version": "3.6.0", "dev": true, @@ -14332,6 +14238,7 @@ }, "node_modules/string_decoder": { "version": "1.3.0", + "dev": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" @@ -14339,6 +14246,7 @@ }, "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.2.1", + "dev": true, "funding": [ { "type": "github", @@ -14517,22 +14425,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/style-loader": { "version": "3.3.1", "dev": true, @@ -15488,22 +15380,6 @@ "node": ">=0.6" } }, - "node_modules/token-types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.0.tgz", - "integrity": "sha512-P0rrp4wUpefLncNamWIef62J0v0kQR/GfDVji9WKY7GDCWy5YbVSrKUTam07iWPZQGy0zWNOfstYTykMmPNR7w==", - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, "node_modules/tough-cookie": { "version": "4.0.0", "dev": true, @@ -15830,6 +15706,7 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", + "dev": true, "license": "MIT" }, "node_modules/utila": { @@ -18836,11 +18713,6 @@ } } }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" - }, "@tootallnate/once": { "version": "1.1.2", "dev": true @@ -19825,7 +19697,8 @@ "dev": true }, "base64-js": { - "version": "1.5.1" + "version": "1.5.1", + "dev": true }, "batch": { "version": "0.6.1", @@ -19938,6 +19811,7 @@ }, "buffer": { "version": "6.0.3", + "dev": true, "requires": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -20269,7 +20143,8 @@ } }, "content-type": { - "version": "1.0.4" + "version": "1.0.4", + "dev": true }, "convert-source-map": { "version": "1.8.0", @@ -20576,6 +20451,7 @@ }, "debug": { "version": "4.3.3", + "dev": true, "requires": { "ms": "2.1.2" } @@ -21583,16 +21459,6 @@ "flat-cache": "^3.0.4" } }, - "file-type": { - "version": "16.5.3", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.3.tgz", - "integrity": "sha512-uVsl7iFhHSOY4bEONLlTK47iAHtNsFHWP5YE4xJfZ4rnX7S1Q3wce09XgqSC7E/xh8Ncv/be1lNoyprlUH/x6A==", - "requires": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" - } - }, "fill-range": { "version": "7.0.1", "dev": true, @@ -22081,7 +21947,8 @@ } }, "ieee754": { - "version": "1.2.1" + "version": "1.2.1", + "dev": true }, "ignore": { "version": "5.2.0", @@ -22128,7 +21995,8 @@ } }, "inherits": { - "version": "2.0.4" + "version": "2.0.4", + "dev": true }, "ini": { "version": "1.3.8", @@ -24088,7 +23956,8 @@ } }, "ms": { - "version": "2.1.2" + "version": "2.1.2", + "dev": true }, "multicast-dns": { "version": "6.2.3", @@ -24102,39 +23971,6 @@ "version": "1.1.0", "dev": true }, - "music-metadata": { - "version": "7.12.2", - "resolved": "https://registry.npmjs.org/music-metadata/-/music-metadata-7.12.2.tgz", - "integrity": "sha512-KO1L6q30b6HfGlDQk1VAdrZqCKi4Gy7pN7eZOZ0YZQkhF/KCLHxKCjKKli9ao9kIBC/9s+uXHvjW3bDIBWuGew==", - "requires": { - "@tokenizer/token": "^0.3.0", - "content-type": "^1.0.4", - "debug": "^4.3.3", - "file-type": "16.5.3", - "media-typer": "^1.1.0", - "strtok3": "^6.2.4", - "token-types": "^4.2.0" - }, - "dependencies": { - "media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" - } - } - }, - "music-metadata-browser": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/music-metadata-browser/-/music-metadata-browser-2.5.5.tgz", - "integrity": "sha512-38A/q1fz7LOIDxpi2fAzPGMNZQ0YyQUfErizK/rbWRIKC7E4N2BQpqCHq38nHlb7+Iv/wEHgwVoIwbUAXtphEA==", - "requires": { - "buffer": "^6.0.3", - "debug": "^4.3.3", - "music-metadata": "^7.12.0", - "readable-stream": "^3.6.0", - "readable-web-to-node-stream": "^3.0.2" - } - }, "nanoid": { "version": "3.3.1", "dev": true @@ -24446,7 +24282,9 @@ } }, "path-browserify": { - "version": "1.0.1" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" }, "path-exists": { "version": "3.0.0", @@ -24472,11 +24310,6 @@ "version": "4.0.0", "dev": true }, - "peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==" - }, "picocolors": { "version": "1.0.0", "dev": true @@ -24993,11 +24826,6 @@ } } }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, "process-nextick-args": { "version": "2.0.1", "dev": true @@ -25207,20 +25035,13 @@ }, "readable-stream": { "version": "3.6.0", + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "requires": { - "readable-stream": "^3.6.0" - } - }, "readdirp": { "version": "3.6.0", "dev": true, @@ -25845,12 +25666,14 @@ }, "string_decoder": { "version": "1.3.0", + "dev": true, "requires": { "safe-buffer": "~5.2.0" }, "dependencies": { "safe-buffer": { - "version": "5.2.1" + "version": "5.2.1", + "dev": true } } }, @@ -25952,15 +25775,6 @@ "version": "3.1.1", "dev": true }, - "strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" - } - }, "style-loader": { "version": "3.3.1", "dev": true, @@ -26586,15 +26400,6 @@ "version": "1.0.1", "dev": true }, - "token-types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.0.tgz", - "integrity": "sha512-P0rrp4wUpefLncNamWIef62J0v0kQR/GfDVji9WKY7GDCWy5YbVSrKUTam07iWPZQGy0zWNOfstYTykMmPNR7w==", - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, "tough-cookie": { "version": "4.0.0", "dev": true, @@ -26786,7 +26591,8 @@ } }, "util-deprecate": { - "version": "1.0.2" + "version": "1.0.2", + "dev": true }, "utila": { "version": "0.4.0", diff --git a/package.json b/package.json index 9316d031d..a62afce79 100644 --- a/package.json +++ b/package.json @@ -109,12 +109,10 @@ "emoji-data-ios": "git+https://github.com/korenskoy/emoji-data-ios#54443d1938ec1c157e74d2a95e9103dcb3f5c6dd", "events": "^3.3.0", "idb-keyval": "^6.1.0", - "music-metadata-browser": "^2.5.5", "opus-recorder": "github:Ajaxy/opus-recorder", "os-browserify": "^0.3.0", "pako": "^2.0.4", "path-browserify": "^1.0.1", - "process": "^0.11.10", "qr-code-styling": "github:zubiden/qr-code-styling#10f7cf3", "websocket": "^1.0.34" }, diff --git a/src/lib/music-metadata-browser/index.d.ts b/src/lib/music-metadata-browser/index.d.ts new file mode 100644 index 000000000..c38f1278e --- /dev/null +++ b/src/lib/music-metadata-browser/index.d.ts @@ -0,0 +1,33 @@ +interface ICommonTagsResult { + title?: string; + artist?: string; + picture?: IPicture[]; +} + +interface IFormat { + duration?: number; +} + +interface IAudioMetadata extends INativeAudioMetadata { + common: ICommonTagsResult; + format: IFormat; +} + +interface IPicture { + format: string; + data: Buffer; + description?: string; + type?: string; + name?: string; +} + +interface IOptions { + duration?: boolean; + skipCovers?: boolean; + skipPostHeaders?: boolean; + includeChapters?: boolean; +} + +export declare function selectCover(pictures?: IPicture[]): IPicture | null; + +export declare function fetchFromUrl(audioTrackUrl: string, options?: IOptions): Promise; diff --git a/src/lib/music-metadata-browser/index.js b/src/lib/music-metadata-browser/index.js new file mode 100644 index 000000000..bd491ba48 --- /dev/null +++ b/src/lib/music-metadata-browser/index.js @@ -0,0 +1,19378 @@ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ + +/*! + * content-type + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + +/*! + * media-typer + * Copyright(c) 2014-2017 Douglas Christopher Wilson + * MIT Licensed + */ + +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ + +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["music_metadata_browser"] = factory(); + else + root["music_metadata_browser"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 9742: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +exports.byteLength = byteLength +exports.toByteArray = toByteArray +exports.fromByteArray = fromByteArray + +var lookup = [] +var revLookup = [] +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array + +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 + +function getLens (b64) { + var len = b64.length + + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len + + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen + + var i + for (i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF + } + + return arr +} + +function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] +} + +function encodeChunk (uint8, start, end) { + var tmp + var output = [] + for (var i = start; i < end; i += 3) { + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) + output.push(tripletToBase64(tmp)) + } + return output.join('') +} + +function fromByteArray (uint8) { + var tmp + var len = uint8.length + var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes + var parts = [] + var maxChunkLength = 16383 // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk( + uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) + )) + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1] + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) + } + + return parts.join('') +} + + +/***/ }), + +/***/ 8764: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + + + +const base64 = __webpack_require__(9742) +const ieee754 = __webpack_require__(645) +const customInspectSymbol = + (typeof Symbol === 'function' && typeof Symbol['for'] === 'function') // eslint-disable-line dot-notation + ? Symbol['for']('nodejs.util.inspect.custom') // eslint-disable-line dot-notation + : null + +exports.Buffer = Buffer +exports.SlowBuffer = SlowBuffer +exports.INSPECT_MAX_BYTES = 50 + +const K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() + +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} + +function typedArraySupport () { + // Can typed array instances can be augmented? + try { + const arr = new Uint8Array(1) + const proto = { foo: function () { return 42 } } + Object.setPrototypeOf(proto, Uint8Array.prototype) + Object.setPrototypeOf(arr, proto) + return arr.foo() === 42 + } catch (e) { + return false + } +} + +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer + } +}) + +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + const buf = new Uint8Array(length) + Object.setPrototypeOf(buf, Buffer.prototype) + return buf +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer (arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError( + 'The "string" argument must be of type string. Received type number' + ) + } + return allocUnsafe(arg) + } + return from(arg, encodingOrOffset, length) +} + +Buffer.poolSize = 8192 // not used by this implementation + +function from (value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset) + } + + if (ArrayBuffer.isView(value)) { + return fromArrayView(value) + } + + if (value == null) { + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof SharedArrayBuffer !== 'undefined' && + (isInstance(value, SharedArrayBuffer) || + (value && isInstance(value.buffer, SharedArrayBuffer)))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + const valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + const b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from(value[Symbol.toPrimitive]('string'), encodingOrOffset, length) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length) +} + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype) +Object.setPrototypeOf(Buffer, Uint8Array) + +function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') + } +} + +function alloc (size, fill, encoding) { + assertSize(size) + if (size <= 0) { + return createBuffer(size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpreted as a start offset. + return typeof encoding === 'string' + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) + } + return createBuffer(size) +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding) +} + +function allocUnsafe (size) { + assertSize(size) + return createBuffer(size < 0 ? 0 : checked(size) | 0) +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size) +} +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size) +} + +function fromString (string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8' + } + + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + + const length = byteLength(string, encoding) | 0 + let buf = createBuffer(length) + + const actual = buf.write(string, encoding) + + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) + } + + return buf +} + +function fromArrayLike (array) { + const length = array.length < 0 ? 0 : checked(array.length) | 0 + const buf = createBuffer(length) + for (let i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf +} + +function fromArrayView (arrayView) { + if (isInstance(arrayView, Uint8Array)) { + const copy = new Uint8Array(arrayView) + return fromArrayBuffer(copy.buffer, copy.byteOffset, copy.byteLength) + } + return fromArrayLike(arrayView) +} + +function fromArrayBuffer (array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds') + } + + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds') + } + + let buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) + } else { + buf = new Uint8Array(array, byteOffset, length) + } + + // Return an augmented `Uint8Array` instance + Object.setPrototypeOf(buf, Buffer.prototype) + + return buf +} + +function fromObject (obj) { + if (Buffer.isBuffer(obj)) { + const len = checked(obj.length) | 0 + const buf = createBuffer(len) + + if (buf.length === 0) { + return buf + } + + obj.copy(buf, 0, 0, len) + return buf + } + + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) + } + return fromArrayLike(obj) + } + + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } +} + +function checked (length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') + } + return length | 0 +} + +function SlowBuffer (length) { + if (+length != length) { // eslint-disable-line eqeqeq + length = 0 + } + return Buffer.alloc(+length) +} + +Buffer.isBuffer = function isBuffer (b) { + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false +} + +Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) + } + + if (a === b) return 0 + + let x = a.length + let y = b.length + + for (let i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i] + y = b[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } +} + +Buffer.concat = function concat (list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + + if (list.length === 0) { + return Buffer.alloc(0) + } + + let i + if (length === undefined) { + length = 0 + for (i = 0; i < list.length; ++i) { + length += list[i].length + } + } + + const buffer = Buffer.allocUnsafe(length) + let pos = 0 + for (i = 0; i < list.length; ++i) { + let buf = list[i] + if (isInstance(buf, Uint8Array)) { + if (pos + buf.length > buffer.length) { + if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf) + buf.copy(buffer, pos) + } else { + Uint8Array.prototype.set.call( + buffer, + buf, + pos + ) + } + } else if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } else { + buf.copy(buffer, pos) + } + pos += buf.length + } + return buffer +} + +function byteLength (string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) + } + + const len = string.length + const mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 + + // Use a for loop to avoid recursion + let loweredCase = false + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} +Buffer.byteLength = byteLength + +function slowToString (encoding, start, end) { + let loweredCase = false + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0 + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' + } + + if (end === undefined || end > this.length) { + end = this.length + } + + if (end <= 0) { + return '' + } + + // Force coercion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0 + start >>>= 0 + + if (end <= start) { + return '' + } + + if (!encoding) encoding = 'utf8' + + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) + + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + + case 'ascii': + return asciiSlice(this, start, end) + + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) + + case 'base64': + return base64Slice(this, start, end) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase() + loweredCase = true + } + } +} + +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true + +function swap (b, n, m) { + const i = b[n] + b[n] = b[m] + b[m] = i +} + +Buffer.prototype.swap16 = function swap16 () { + const len = this.length + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (let i = 0; i < len; i += 2) { + swap(this, i, i + 1) + } + return this +} + +Buffer.prototype.swap32 = function swap32 () { + const len = this.length + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (let i = 0; i < len; i += 4) { + swap(this, i, i + 3) + swap(this, i + 1, i + 2) + } + return this +} + +Buffer.prototype.swap64 = function swap64 () { + const len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (let i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + +Buffer.prototype.toString = function toString () { + const length = this.length + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) +} + +Buffer.prototype.toLocaleString = Buffer.prototype.toString + +Buffer.prototype.equals = function equals (b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 +} + +Buffer.prototype.inspect = function inspect () { + let str = '' + const max = exports.INSPECT_MAX_BYTES + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' + return '' +} +if (customInspectSymbol) { + Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect +} + +Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } + if (!Buffer.isBuffer(target)) { + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) + } + + if (start === undefined) { + start = 0 + } + if (end === undefined) { + end = target ? target.length : 0 + } + if (thisStart === undefined) { + thisStart = 0 + } + if (thisEnd === undefined) { + thisEnd = this.length + } + + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } + + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 + } + + start >>>= 0 + end >>>= 0 + thisStart >>>= 0 + thisEnd >>>= 0 + + if (this === target) return 0 + + let x = thisEnd - thisStart + let y = end - start + const len = Math.min(x, y) + + const thisCopy = this.slice(thisStart, thisEnd) + const targetCopy = target.slice(start, end) + + for (let i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i] + y = targetCopy[i] + break + } + } + + if (x < y) return -1 + if (y < x) return 1 + return 0 +} + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [val], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + let indexSize = 1 + let arrLength = arr.length + let valLength = val.length + + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase() + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2 + arrLength /= 2 + valLength /= 2 + byteOffset /= 2 + } + } + + function read (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } + + let i + if (dir) { + let foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + let found = true + for (let j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i + } + } + + return -1 +} + +Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 +} + +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + +function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0 + const remaining = buf.length - offset + if (!length) { + length = remaining + } else { + length = Number(length) + if (length > remaining) { + length = remaining + } + } + + const strLen = string.length + + if (length > strLen / 2) { + length = strLen / 2 + } + let i + for (i = 0; i < length; ++i) { + const parsed = parseInt(string.substr(i * 2, 2), 16) + if (numberIsNaN(parsed)) return i + buf[offset + i] = parsed + } + return i +} + +function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) +} + +function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) +} + +function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) +} + +function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) +} + +Buffer.prototype.write = function write (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8' + length = this.length + offset = 0 + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset + length = this.length + offset = 0 + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0 + if (isFinite(length)) { + length = length >>> 0 + if (encoding === undefined) encoding = 'utf8' + } else { + encoding = length + length = undefined + } + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } + + const remaining = this.length - offset + if (length === undefined || length > remaining) length = remaining + + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } + + if (!encoding) encoding = 'utf8' + + let loweredCase = false + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) + + case 'ascii': + case 'latin1': + case 'binary': + return asciiWrite(this, string, offset, length) + + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) + + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) + + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase() + loweredCase = true + } + } +} + +Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } +} + +function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf) + } else { + return base64.fromByteArray(buf.slice(start, end)) + } +} + +function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end) + const res = [] + + let i = start + while (i < end) { + const firstByte = buf[i] + let codePoint = null + let bytesPerSequence = (firstByte > 0xEF) + ? 4 + : (firstByte > 0xDF) + ? 3 + : (firstByte > 0xBF) + ? 2 + : 1 + + if (i + bytesPerSequence <= end) { + let secondByte, thirdByte, fourthByte, tempCodePoint + + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte + } + break + case 2: + secondByte = buf[i + 1] + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint + } + } + break + case 3: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint + } + } + break + case 4: + secondByte = buf[i + 1] + thirdByte = buf[i + 2] + fourthByte = buf[i + 3] + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint + } + } + } + } + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD + bytesPerSequence = 1 + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000 + res.push(codePoint >>> 10 & 0x3FF | 0xD800) + codePoint = 0xDC00 | codePoint & 0x3FF + } + + res.push(codePoint) + i += bytesPerSequence + } + + return decodeCodePointsArray(res) +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +const MAX_ARGUMENTS_LENGTH = 0x1000 + +function decodeCodePointsArray (codePoints) { + const len = codePoints.length + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + let res = '' + let i = 0 + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ) + } + return res +} + +function asciiSlice (buf, start, end) { + let ret = '' + end = Math.min(buf.length, end) + + for (let i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F) + } + return ret +} + +function latin1Slice (buf, start, end) { + let ret = '' + end = Math.min(buf.length, end) + + for (let i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]) + } + return ret +} + +function hexSlice (buf, start, end) { + const len = buf.length + + if (!start || start < 0) start = 0 + if (!end || end < 0 || end > len) end = len + + let out = '' + for (let i = start; i < end; ++i) { + out += hexSliceLookupTable[buf[i]] + } + return out +} + +function utf16leSlice (buf, start, end) { + const bytes = buf.slice(start, end) + let res = '' + // If bytes.length is odd, the last 8 bits must be ignored (same as node.js) + for (let i = 0; i < bytes.length - 1; i += 2) { + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) + } + return res +} + +Buffer.prototype.slice = function slice (start, end) { + const len = this.length + start = ~~start + end = end === undefined ? len : ~~end + + if (start < 0) { + start += len + if (start < 0) start = 0 + } else if (start > len) { + start = len + } + + if (end < 0) { + end += len + if (end < 0) end = 0 + } else if (end > len) { + end = len + } + + if (end < start) end = start + + const newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + Object.setPrototypeOf(newBuf, Buffer.prototype) + + return newBuf +} + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') +} + +Buffer.prototype.readUintLE = +Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + let val = this[offset] + let mul = 1 + let i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + + return val +} + +Buffer.prototype.readUintBE = +Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + checkOffset(offset, byteLength, this.length) + } + + let val = this[offset + --byteLength] + let mul = 1 + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul + } + + return val +} + +Buffer.prototype.readUint8 = +Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + return this[offset] +} + +Buffer.prototype.readUint16LE = +Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return this[offset] | (this[offset + 1] << 8) +} + +Buffer.prototype.readUint16BE = +Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + return (this[offset] << 8) | this[offset + 1] +} + +Buffer.prototype.readUint32LE = +Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) +} + +Buffer.prototype.readUint32BE = +Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) +} + +Buffer.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE (offset) { + offset = offset >>> 0 + validateNumber(offset, 'offset') + const first = this[offset] + const last = this[offset + 7] + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8) + } + + const lo = first + + this[++offset] * 2 ** 8 + + this[++offset] * 2 ** 16 + + this[++offset] * 2 ** 24 + + const hi = this[++offset] + + this[++offset] * 2 ** 8 + + this[++offset] * 2 ** 16 + + last * 2 ** 24 + + return BigInt(lo) + (BigInt(hi) << BigInt(32)) +}) + +Buffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE (offset) { + offset = offset >>> 0 + validateNumber(offset, 'offset') + const first = this[offset] + const last = this[offset + 7] + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8) + } + + const hi = first * 2 ** 24 + + this[++offset] * 2 ** 16 + + this[++offset] * 2 ** 8 + + this[++offset] + + const lo = this[++offset] * 2 ** 24 + + this[++offset] * 2 ** 16 + + this[++offset] * 2 ** 8 + + last + + return (BigInt(hi) << BigInt(32)) + BigInt(lo) +}) + +Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + let val = this[offset] + let mul = 1 + let i = 0 + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) checkOffset(offset, byteLength, this.length) + + let i = byteLength + let mul = 1 + let val = this[offset + --i] + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul + } + mul *= 0x80 + + if (val >= mul) val -= Math.pow(2, 8 * byteLength) + + return val +} + +Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 1, this.length) + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) +} + +Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + const val = this[offset] | (this[offset + 1] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 2, this.length) + const val = this[offset + 1] | (this[offset] << 8) + return (val & 0x8000) ? val | 0xFFFF0000 : val +} + +Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) +} + +Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) +} + +Buffer.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE (offset) { + offset = offset >>> 0 + validateNumber(offset, 'offset') + const first = this[offset] + const last = this[offset + 7] + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8) + } + + const val = this[offset + 4] + + this[offset + 5] * 2 ** 8 + + this[offset + 6] * 2 ** 16 + + (last << 24) // Overflow + + return (BigInt(val) << BigInt(32)) + + BigInt(first + + this[++offset] * 2 ** 8 + + this[++offset] * 2 ** 16 + + this[++offset] * 2 ** 24) +}) + +Buffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE (offset) { + offset = offset >>> 0 + validateNumber(offset, 'offset') + const first = this[offset] + const last = this[offset + 7] + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8) + } + + const val = (first << 24) + // Overflow + this[++offset] * 2 ** 16 + + this[++offset] * 2 ** 8 + + this[++offset] + + return (BigInt(val) << BigInt(32)) + + BigInt(this[++offset] * 2 ** 24 + + this[++offset] * 2 ** 16 + + this[++offset] * 2 ** 8 + + last) +}) + +Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, true, 23, 4) +} + +Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 4, this.length) + return ieee754.read(this, offset, false, 23, 4) +} + +Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, true, 52, 8) +} + +Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 + if (!noAssert) checkOffset(offset, 8, this.length) + return ieee754.read(this, offset, false, 52, 8) +} + +function checkInt (buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') +} + +Buffer.prototype.writeUintLE = +Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + const maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + let mul = 1 + let i = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUintBE = +Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + byteLength = byteLength >>> 0 + if (!noAssert) { + const maxBytes = Math.pow(2, 8 * byteLength) - 1 + checkInt(this, value, offset, byteLength, maxBytes, 0) + } + + let i = byteLength - 1 + let mul = 1 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeUint8 = +Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeUint16LE = +Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeUint16BE = +Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeUint32LE = +Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeUint32BE = +Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +function wrtBigUInt64LE (buf, value, offset, min, max) { + checkIntBI(value, min, max, buf, offset, 7) + + let lo = Number(value & BigInt(0xffffffff)) + buf[offset++] = lo + lo = lo >> 8 + buf[offset++] = lo + lo = lo >> 8 + buf[offset++] = lo + lo = lo >> 8 + buf[offset++] = lo + let hi = Number(value >> BigInt(32) & BigInt(0xffffffff)) + buf[offset++] = hi + hi = hi >> 8 + buf[offset++] = hi + hi = hi >> 8 + buf[offset++] = hi + hi = hi >> 8 + buf[offset++] = hi + return offset +} + +function wrtBigUInt64BE (buf, value, offset, min, max) { + checkIntBI(value, min, max, buf, offset, 7) + + let lo = Number(value & BigInt(0xffffffff)) + buf[offset + 7] = lo + lo = lo >> 8 + buf[offset + 6] = lo + lo = lo >> 8 + buf[offset + 5] = lo + lo = lo >> 8 + buf[offset + 4] = lo + let hi = Number(value >> BigInt(32) & BigInt(0xffffffff)) + buf[offset + 3] = hi + hi = hi >> 8 + buf[offset + 2] = hi + hi = hi >> 8 + buf[offset + 1] = hi + hi = hi >> 8 + buf[offset] = hi + return offset + 8 +} + +Buffer.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE (value, offset = 0) { + return wrtBigUInt64LE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff')) +}) + +Buffer.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE (value, offset = 0) { + return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff')) +}) + +Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + const limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + let i = 0 + let mul = 1 + let sub = 0 + this[offset] = value & 0xFF + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + const limit = Math.pow(2, (8 * byteLength) - 1) + + checkInt(this, value, offset, byteLength, limit - 1, -limit) + } + + let i = byteLength - 1 + let mul = 1 + let sub = 0 + this[offset + i] = value & 0xFF + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1 + } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF + } + + return offset + byteLength +} + +Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) + if (value < 0) value = 0xff + value + 1 + this[offset] = (value & 0xff) + return offset + 1 +} + +Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + return offset + 2 +} + +Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) + return offset + 2 +} + +Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) + return offset + 4 +} + +Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) + if (value < 0) value = 0xffffffff + value + 1 + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) + return offset + 4 +} + +Buffer.prototype.writeBigInt64LE = defineBigIntMethod(function writeBigInt64LE (value, offset = 0) { + return wrtBigUInt64LE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff')) +}) + +Buffer.prototype.writeBigInt64BE = defineBigIntMethod(function writeBigInt64BE (value, offset = 0) { + return wrtBigUInt64BE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff')) +}) + +function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') +} + +function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) + } + ieee754.write(buf, value, offset, littleEndian, 23, 4) + return offset + 4 +} + +Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) +} + +function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) + } + ieee754.write(buf, value, offset, littleEndian, 52, 8) + return offset + 8 +} + +Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) +} + +Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) +} + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') + if (!start) start = 0 + if (!end && end !== 0) end = this.length + if (targetStart >= target.length) targetStart = target.length + if (!targetStart) targetStart = 0 + if (end > 0 && end < start) end = start + + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') + if (end < 0) throw new RangeError('sourceEnd out of bounds') + + // Are we oob? + if (end > this.length) end = this.length + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start + } + + const len = end - start + + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, end), + targetStart + ) + } + + return len +} + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start + start = 0 + end = this.length + } else if (typeof end === 'string') { + encoding = end + end = this.length + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + if (val.length === 1) { + const code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } + } else if (typeof val === 'number') { + val = val & 255 + } else if (typeof val === 'boolean') { + val = Number(val) + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } + + if (end <= start) { + return this + } + + start = start >>> 0 + end = end === undefined ? this.length : end >>> 0 + + if (!val) val = 0 + + let i + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val + } + } else { + const bytes = Buffer.isBuffer(val) + ? val + : Buffer.from(val, encoding) + const len = bytes.length + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len] + } + } + + return this +} + +// CUSTOM ERRORS +// ============= + +// Simplified versions from Node, changed for Buffer-only usage +const errors = {} +function E (sym, getMessage, Base) { + errors[sym] = class NodeError extends Base { + constructor () { + super() + + Object.defineProperty(this, 'message', { + value: getMessage.apply(this, arguments), + writable: true, + configurable: true + }) + + // Add the error code to the name to include it in the stack trace. + this.name = `${this.name} [${sym}]` + // Access the stack to generate the error message including the error code + // from the name. + this.stack // eslint-disable-line no-unused-expressions + // Reset the name to the actual name. + delete this.name + } + + get code () { + return sym + } + + set code (value) { + Object.defineProperty(this, 'code', { + configurable: true, + enumerable: true, + value, + writable: true + }) + } + + toString () { + return `${this.name} [${sym}]: ${this.message}` + } + } +} + +E('ERR_BUFFER_OUT_OF_BOUNDS', + function (name) { + if (name) { + return `${name} is outside of buffer bounds` + } + + return 'Attempt to access memory outside buffer bounds' + }, RangeError) +E('ERR_INVALID_ARG_TYPE', + function (name, actual) { + return `The "${name}" argument must be of type number. Received type ${typeof actual}` + }, TypeError) +E('ERR_OUT_OF_RANGE', + function (str, range, input) { + let msg = `The value of "${str}" is out of range.` + let received = input + if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) { + received = addNumericalSeparator(String(input)) + } else if (typeof input === 'bigint') { + received = String(input) + if (input > BigInt(2) ** BigInt(32) || input < -(BigInt(2) ** BigInt(32))) { + received = addNumericalSeparator(received) + } + received += 'n' + } + msg += ` It must be ${range}. Received ${received}` + return msg + }, RangeError) + +function addNumericalSeparator (val) { + let res = '' + let i = val.length + const start = val[0] === '-' ? 1 : 0 + for (; i >= start + 4; i -= 3) { + res = `_${val.slice(i - 3, i)}${res}` + } + return `${val.slice(0, i)}${res}` +} + +// CHECK FUNCTIONS +// =============== + +function checkBounds (buf, offset, byteLength) { + validateNumber(offset, 'offset') + if (buf[offset] === undefined || buf[offset + byteLength] === undefined) { + boundsError(offset, buf.length - (byteLength + 1)) + } +} + +function checkIntBI (value, min, max, buf, offset, byteLength) { + if (value > max || value < min) { + const n = typeof min === 'bigint' ? 'n' : '' + let range + if (byteLength > 3) { + if (min === 0 || min === BigInt(0)) { + range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}` + } else { + range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` + + `${(byteLength + 1) * 8 - 1}${n}` + } + } else { + range = `>= ${min}${n} and <= ${max}${n}` + } + throw new errors.ERR_OUT_OF_RANGE('value', range, value) + } + checkBounds(buf, offset, byteLength) +} + +function validateNumber (value, name) { + if (typeof value !== 'number') { + throw new errors.ERR_INVALID_ARG_TYPE(name, 'number', value) + } +} + +function boundsError (value, length, type) { + if (Math.floor(value) !== value) { + validateNumber(value, type) + throw new errors.ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value) + } + + if (length < 0) { + throw new errors.ERR_BUFFER_OUT_OF_BOUNDS() + } + + throw new errors.ERR_OUT_OF_RANGE(type || 'offset', + `>= ${type ? 1 : 0} and <= ${length}`, + value) +} + +// HELPER FUNCTIONS +// ================ + +const INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g + +function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, '') + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '=' + } + return str +} + +function utf8ToBytes (string, units) { + units = units || Infinity + let codePoint + const length = string.length + let leadSurrogate = null + const bytes = [] + + for (let i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i) + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + continue + } + + // valid lead + leadSurrogate = codePoint + + continue + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + leadSurrogate = codePoint + continue + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) + } + + leadSurrogate = null + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint) + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ) + } else { + throw new Error('Invalid code point') + } + } + + return bytes +} + +function asciiToBytes (str) { + const byteArray = [] + for (let i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF) + } + return byteArray +} + +function utf16leToBytes (str, units) { + let c, hi, lo + const byteArray = [] + for (let i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i) + hi = c >> 8 + lo = c % 256 + byteArray.push(lo) + byteArray.push(hi) + } + + return byteArray +} + +function base64ToBytes (str) { + return base64.toByteArray(base64clean(str)) +} + +function blitBuffer (src, dst, offset, length) { + let i + for (i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i] + } + return i +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare +} + +// Create lookup table for `toString('hex')` +// See: https://github.com/feross/buffer/issues/219 +const hexSliceLookupTable = (function () { + const alphabet = '0123456789abcdef' + const table = new Array(256) + for (let i = 0; i < 16; ++i) { + const i16 = i * 16 + for (let j = 0; j < 16; ++j) { + table[i16 + j] = alphabet[i] + alphabet[j] + } + } + return table +})() + +// Return not function with Error if BigInt not supported +function defineBigIntMethod (fn) { + return typeof BigInt === 'undefined' ? BufferBigIntNotDefined : fn +} + +function BufferBigIntNotDefined () { + throw new Error('BigInt not supported') +} + + +/***/ }), + +/***/ 7811: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +/*! + * content-type + * Copyright(c) 2015 Douglas Christopher Wilson + * MIT Licensed + */ + + + +/** + * RegExp to match *( ";" parameter ) in RFC 7231 sec 3.1.1.1 + * + * parameter = token "=" ( token / quoted-string ) + * token = 1*tchar + * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" + * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" + * / DIGIT / ALPHA + * ; any VCHAR, except delimiters + * quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + * qdtext = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text + * obs-text = %x80-FF + * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + */ +var PARAM_REGEXP = /; *([!#$%&'*+.^_`|~0-9A-Za-z-]+) *= *("(?:[\u000b\u0020\u0021\u0023-\u005b\u005d-\u007e\u0080-\u00ff]|\\[\u000b\u0020-\u00ff])*"|[!#$%&'*+.^_`|~0-9A-Za-z-]+) */g +var TEXT_REGEXP = /^[\u000b\u0020-\u007e\u0080-\u00ff]+$/ +var TOKEN_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/ + +/** + * RegExp to match quoted-pair in RFC 7230 sec 3.2.6 + * + * quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + * obs-text = %x80-FF + */ +var QESC_REGEXP = /\\([\u000b\u0020-\u00ff])/g + +/** + * RegExp to match chars that must be quoted-pair in RFC 7230 sec 3.2.6 + */ +var QUOTE_REGEXP = /([\\"])/g + +/** + * RegExp to match type in RFC 7231 sec 3.1.1.1 + * + * media-type = type "/" subtype + * type = token + * subtype = token + */ +var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/ + +/** + * Module exports. + * @public + */ + +exports.format = format +exports.parse = parse + +/** + * Format object to media type. + * + * @param {object} obj + * @return {string} + * @public + */ + +function format (obj) { + if (!obj || typeof obj !== 'object') { + throw new TypeError('argument obj is required') + } + + var parameters = obj.parameters + var type = obj.type + + if (!type || !TYPE_REGEXP.test(type)) { + throw new TypeError('invalid type') + } + + var string = type + + // append parameters + if (parameters && typeof parameters === 'object') { + var param + var params = Object.keys(parameters).sort() + + for (var i = 0; i < params.length; i++) { + param = params[i] + + if (!TOKEN_REGEXP.test(param)) { + throw new TypeError('invalid parameter name') + } + + string += '; ' + param + '=' + qstring(parameters[param]) + } + } + + return string +} + +/** + * Parse media type to object. + * + * @param {string|object} string + * @return {Object} + * @public + */ + +function parse (string) { + if (!string) { + throw new TypeError('argument string is required') + } + + // support req/res-like objects as argument + var header = typeof string === 'object' + ? getcontenttype(string) + : string + + if (typeof header !== 'string') { + throw new TypeError('argument string is required to be a string') + } + + var index = header.indexOf(';') + var type = index !== -1 + ? header.substr(0, index).trim() + : header.trim() + + if (!TYPE_REGEXP.test(type)) { + throw new TypeError('invalid media type') + } + + var obj = new ContentType(type.toLowerCase()) + + // parse parameters + if (index !== -1) { + var key + var match + var value + + PARAM_REGEXP.lastIndex = index + + while ((match = PARAM_REGEXP.exec(header))) { + if (match.index !== index) { + throw new TypeError('invalid parameter format') + } + + index += match[0].length + key = match[1].toLowerCase() + value = match[2] + + if (value[0] === '"') { + // remove quotes and escapes + value = value + .substr(1, value.length - 2) + .replace(QESC_REGEXP, '$1') + } + + obj.parameters[key] = value + } + + if (index !== header.length) { + throw new TypeError('invalid parameter format') + } + } + + return obj +} + +/** + * Get content-type from req/res objects. + * + * @param {object} + * @return {Object} + * @private + */ + +function getcontenttype (obj) { + var header + + if (typeof obj.getHeader === 'function') { + // res-like + header = obj.getHeader('content-type') + } else if (typeof obj.headers === 'object') { + // req-like + header = obj.headers && obj.headers['content-type'] + } + + if (typeof header !== 'string') { + throw new TypeError('content-type header is missing from object') + } + + return header +} + +/** + * Quote a string if necessary. + * + * @param {string} val + * @return {string} + * @private + */ + +function qstring (val) { + var str = String(val) + + // no need to quote tokens + if (TOKEN_REGEXP.test(str)) { + return str + } + + if (str.length > 0 && !TEXT_REGEXP.test(str)) { + throw new TypeError('invalid parameter value') + } + + return '"' + str.replace(QUOTE_REGEXP, '\\$1') + '"' +} + +/** + * Class to represent a content type. + * @private + */ +function ContentType (type) { + this.parameters = Object.create(null) + this.type = type +} + + +/***/ }), + +/***/ 1227: +/***/ ((module, exports, __webpack_require__) => { + +/* provided dependency */ var process = __webpack_require__(4155); +/* eslint-env browser */ + +/** + * This is the web browser implementation of `debug()`. + */ + +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = localstorage(); +exports.destroy = (() => { + let warned = false; + + return () => { + if (!warned) { + warned = true; + console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); + } + }; +})(); + +/** + * Colors. + */ + +exports.colors = [ + '#0000CC', + '#0000FF', + '#0033CC', + '#0033FF', + '#0066CC', + '#0066FF', + '#0099CC', + '#0099FF', + '#00CC00', + '#00CC33', + '#00CC66', + '#00CC99', + '#00CCCC', + '#00CCFF', + '#3300CC', + '#3300FF', + '#3333CC', + '#3333FF', + '#3366CC', + '#3366FF', + '#3399CC', + '#3399FF', + '#33CC00', + '#33CC33', + '#33CC66', + '#33CC99', + '#33CCCC', + '#33CCFF', + '#6600CC', + '#6600FF', + '#6633CC', + '#6633FF', + '#66CC00', + '#66CC33', + '#9900CC', + '#9900FF', + '#9933CC', + '#9933FF', + '#99CC00', + '#99CC33', + '#CC0000', + '#CC0033', + '#CC0066', + '#CC0099', + '#CC00CC', + '#CC00FF', + '#CC3300', + '#CC3333', + '#CC3366', + '#CC3399', + '#CC33CC', + '#CC33FF', + '#CC6600', + '#CC6633', + '#CC9900', + '#CC9933', + '#CCCC00', + '#CCCC33', + '#FF0000', + '#FF0033', + '#FF0066', + '#FF0099', + '#FF00CC', + '#FF00FF', + '#FF3300', + '#FF3333', + '#FF3366', + '#FF3399', + '#FF33CC', + '#FF33FF', + '#FF6600', + '#FF6633', + '#FF9900', + '#FF9933', + '#FFCC00', + '#FFCC33' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ + +// eslint-disable-next-line complexity +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { + return true; + } + + // Internet Explorer and Edge do not support colors. + if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { + return false; + } + + // Is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // Is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // Is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // Double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} + +/** + * Colorize log arguments if enabled. + * + * @api public + */ + +function formatArgs(args) { + args[0] = (this.useColors ? '%c' : '') + + this.namespace + + (this.useColors ? ' %c' : ' ') + + args[0] + + (this.useColors ? '%c ' : ' ') + + '+' + module.exports.humanize(this.diff); + + if (!this.useColors) { + return; + } + + const c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit'); + + // The final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + let index = 0; + let lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, match => { + if (match === '%%') { + return; + } + index++; + if (match === '%c') { + // We only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); + + args.splice(lastC, 0, c); +} + +/** + * Invokes `console.debug()` when available. + * No-op when `console.debug` is not a "function". + * If `console.debug` is not available, falls back + * to `console.log`. + * + * @api public + */ +exports.log = console.debug || console.log || (() => {}); + +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ +function save(namespaces) { + try { + if (namespaces) { + exports.storage.setItem('debug', namespaces); + } else { + exports.storage.removeItem('debug'); + } + } catch (error) { + // Swallow + // XXX (@Qix-) should we be logging these? + } +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ +function load() { + let r; + try { + r = exports.storage.getItem('debug'); + } catch (error) { + // Swallow + // XXX (@Qix-) should we be logging these? + } + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + + return r; +} + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context + // The Browser also has localStorage in the global context. + return localStorage; + } catch (error) { + // Swallow + // XXX (@Qix-) should we be logging these? + } +} + +module.exports = __webpack_require__(2447)(exports); + +const {formatters} = module.exports; + +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +formatters.j = function (v) { + try { + return JSON.stringify(v); + } catch (error) { + return '[UnexpectedJSONParseError]: ' + error.message; + } +}; + + +/***/ }), + +/***/ 2447: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + */ + +function setup(env) { + createDebug.debug = createDebug; + createDebug.default = createDebug; + createDebug.coerce = coerce; + createDebug.disable = disable; + createDebug.enable = enable; + createDebug.enabled = enabled; + createDebug.humanize = __webpack_require__(7824); + createDebug.destroy = destroy; + + Object.keys(env).forEach(key => { + createDebug[key] = env[key]; + }); + + /** + * The currently active debug mode names, and names to skip. + */ + + createDebug.names = []; + createDebug.skips = []; + + /** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + createDebug.formatters = {}; + + /** + * Selects a color for a debug namespace + * @param {String} namespace The namespace string for the debug instance to be colored + * @return {Number|String} An ANSI color code for the given namespace + * @api private + */ + function selectColor(namespace) { + let hash = 0; + + for (let i = 0; i < namespace.length; i++) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; + } + createDebug.selectColor = selectColor; + + /** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + function createDebug(namespace) { + let prevTime; + let enableOverride = null; + let namespacesCache; + let enabledCache; + + function debug(...args) { + // Disabled? + if (!debug.enabled) { + return; + } + + const self = debug; + + // Set `diff` timestamp + const curr = Number(new Date()); + const ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + args[0] = createDebug.coerce(args[0]); + + if (typeof args[0] !== 'string') { + // Anything else let's inspect with %O + args.unshift('%O'); + } + + // Apply any `formatters` transformations + let index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => { + // If we encounter an escaped % then don't increase the array index + if (match === '%%') { + return '%'; + } + index++; + const formatter = createDebug.formatters[format]; + if (typeof formatter === 'function') { + const val = args[index]; + match = formatter.call(self, val); + + // Now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // Apply env-specific formatting (colors, etc.) + createDebug.formatArgs.call(self, args); + + const logFn = self.log || createDebug.log; + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.useColors = createDebug.useColors(); + debug.color = createDebug.selectColor(namespace); + debug.extend = extend; + debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release. + + Object.defineProperty(debug, 'enabled', { + enumerable: true, + configurable: false, + get: () => { + if (enableOverride !== null) { + return enableOverride; + } + if (namespacesCache !== createDebug.namespaces) { + namespacesCache = createDebug.namespaces; + enabledCache = createDebug.enabled(namespace); + } + + return enabledCache; + }, + set: v => { + enableOverride = v; + } + }); + + // Env-specific initialization logic for debug instances + if (typeof createDebug.init === 'function') { + createDebug.init(debug); + } + + return debug; + } + + function extend(namespace, delimiter) { + const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); + newDebug.log = this.log; + return newDebug; + } + + /** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + function enable(namespaces) { + createDebug.save(namespaces); + createDebug.namespaces = namespaces; + + createDebug.names = []; + createDebug.skips = []; + + let i; + const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + const len = split.length; + + for (i = 0; i < len; i++) { + if (!split[i]) { + // ignore empty strings + continue; + } + + namespaces = split[i].replace(/\*/g, '.*?'); + + if (namespaces[0] === '-') { + createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); + } else { + createDebug.names.push(new RegExp('^' + namespaces + '$')); + } + } + } + + /** + * Disable debug output. + * + * @return {String} namespaces + * @api public + */ + function disable() { + const namespaces = [ + ...createDebug.names.map(toNamespace), + ...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) + ].join(','); + createDebug.enable(''); + return namespaces; + } + + /** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + function enabled(name) { + if (name[name.length - 1] === '*') { + return true; + } + + let i; + let len; + + for (i = 0, len = createDebug.skips.length; i < len; i++) { + if (createDebug.skips[i].test(name)) { + return false; + } + } + + for (i = 0, len = createDebug.names.length; i < len; i++) { + if (createDebug.names[i].test(name)) { + return true; + } + } + + return false; + } + + /** + * Convert regexp to namespace + * + * @param {RegExp} regxep + * @return {String} namespace + * @api private + */ + function toNamespace(regexp) { + return regexp.toString() + .substring(2, regexp.toString().length - 2) + .replace(/\.\*\?$/, '*'); + } + + /** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + function coerce(val) { + if (val instanceof Error) { + return val.stack || val.message; + } + return val; + } + + /** + * XXX DO NOT USE. This is a temporary stub function. + * XXX It WILL be removed in the next major release. + */ + function destroy() { + console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); + } + + createDebug.enable(createDebug.load()); + + return createDebug; +} + +module.exports = setup; + + +/***/ }), + +/***/ 7187: +/***/ ((module) => { + +"use strict"; +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +var R = typeof Reflect === 'object' ? Reflect : null +var ReflectApply = R && typeof R.apply === 'function' + ? R.apply + : function ReflectApply(target, receiver, args) { + return Function.prototype.apply.call(target, receiver, args); + } + +var ReflectOwnKeys +if (R && typeof R.ownKeys === 'function') { + ReflectOwnKeys = R.ownKeys +} else if (Object.getOwnPropertySymbols) { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target) + .concat(Object.getOwnPropertySymbols(target)); + }; +} else { + ReflectOwnKeys = function ReflectOwnKeys(target) { + return Object.getOwnPropertyNames(target); + }; +} + +function ProcessEmitWarning(warning) { + if (console && console.warn) console.warn(warning); +} + +var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) { + return value !== value; +} + +function EventEmitter() { + EventEmitter.init.call(this); +} +module.exports = EventEmitter; +module.exports.once = once; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._eventsCount = 0; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +var defaultMaxListeners = 10; + +function checkListener(listener) { + if (typeof listener !== 'function') { + throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener); + } +} + +Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { + throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.'); + } + defaultMaxListeners = arg; + } +}); + +EventEmitter.init = function() { + + if (this._events === undefined || + this._events === Object.getPrototypeOf(this)._events) { + this._events = Object.create(null); + this._eventsCount = 0; + } + + this._maxListeners = this._maxListeners || undefined; +}; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { + throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.'); + } + this._maxListeners = n; + return this; +}; + +function _getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} + +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return _getMaxListeners(this); +}; + +EventEmitter.prototype.emit = function emit(type) { + var args = []; + for (var i = 1; i < arguments.length; i++) args.push(arguments[i]); + var doError = (type === 'error'); + + var events = this._events; + if (events !== undefined) + doError = (doError && events.error === undefined); + else if (!doError) + return false; + + // If there is no 'error' event listener then throw. + if (doError) { + var er; + if (args.length > 0) + er = args[0]; + if (er instanceof Error) { + // Note: The comments on the `throw` lines are intentional, they show + // up in Node's output if this results in an unhandled exception. + throw er; // Unhandled 'error' event + } + // At least give some kind of context to the user + var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : '')); + err.context = er; + throw err; // Unhandled 'error' event + } + + var handler = events[type]; + + if (handler === undefined) + return false; + + if (typeof handler === 'function') { + ReflectApply(handler, this, args); + } else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + ReflectApply(listeners[i], this, args); + } + + return true; +}; + +function _addListener(target, type, listener, prepend) { + var m; + var events; + var existing; + + checkListener(listener); + + events = target._events; + if (events === undefined) { + events = target._events = Object.create(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener !== undefined) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); + + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } + + if (existing === undefined) { + // Optimize the case of one listener. Don't need the extra array object. + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; + // If we've already got an array, just append. + } else if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } + + // Check for listener leak + m = _getMaxListeners(target); + if (m > 0 && existing.length > m && !existing.warned) { + existing.warned = true; + // No error code for this since it is a Warning + // eslint-disable-next-line no-restricted-syntax + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' ' + String(type) + ' listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + ProcessEmitWarning(w); + } + } + + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; + +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + if (arguments.length === 0) + return this.listener.call(this.target); + return this.listener.apply(this.target, arguments); + } +} + +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = onceWrapper.bind(state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} + +EventEmitter.prototype.once = function once(type, listener) { + checkListener(listener); + this.on(type, _onceWrap(this, type, listener)); + return this; +}; + +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + checkListener(listener); + this.prependListener(type, _onceWrap(this, type, listener)); + return this; + }; + +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; + + checkListener(listener); + + events = this._events; + if (events === undefined) + return this; + + list = events[type]; + if (list === undefined) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else { + spliceOne(list, position); + } + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener !== undefined) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (events === undefined) + return this; + + // not listening for removeListener, no need to emit + if (events.removeListener === undefined) { + if (arguments.length === 0) { + this._events = Object.create(null); + this._eventsCount = 0; + } else if (events[type] !== undefined) { + if (--this._eventsCount === 0) + this._events = Object.create(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = Object.keys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = Object.create(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners !== undefined) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (events === undefined) + return []; + + var evlistener = events[type]; + if (evlistener === undefined) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? + unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); +}; + +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); +}; + +EventEmitter.listenerCount = function(emitter, type) { + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } +}; + +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events !== undefined) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener !== undefined) { + return evlistener.length; + } + } + + return 0; +} + +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; +}; + +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; +} + +function spliceOne(list, index) { + for (; index + 1 < list.length; index++) + list[index] = list[index + 1]; + list.pop(); +} + +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function once(emitter, name) { + return new Promise(function (resolve, reject) { + function errorListener(err) { + emitter.removeListener(name, resolver); + reject(err); + } + + function resolver() { + if (typeof emitter.removeListener === 'function') { + emitter.removeListener('error', errorListener); + } + resolve([].slice.call(arguments)); + }; + + eventTargetAgnosticAddListener(emitter, name, resolver, { once: true }); + if (name !== 'error') { + addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true }); + } + }); +} + +function addErrorHandlerIfEventEmitter(emitter, handler, flags) { + if (typeof emitter.on === 'function') { + eventTargetAgnosticAddListener(emitter, 'error', handler, flags); + } +} + +function eventTargetAgnosticAddListener(emitter, name, listener, flags) { + if (typeof emitter.on === 'function') { + if (flags.once) { + emitter.once(name, listener); + } else { + emitter.on(name, listener); + } + } else if (typeof emitter.addEventListener === 'function') { + // EventTarget does not have `error` event semantics like Node + // EventEmitters, we do not listen for `error` events here. + emitter.addEventListener(name, function wrapListener(arg) { + // IE does not have builtin `{ once: true }` support so we + // have to do it manually. + if (flags.once) { + emitter.removeEventListener(name, wrapListener); + } + listener(arg); + }); + } else { + throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type ' + typeof emitter); + } +} + + +/***/ }), + +/***/ 1: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +const Token = __webpack_require__(3416); +const strtok3 = __webpack_require__(5849); +const { + stringToBytes, + tarHeaderChecksumMatches, + uint32SyncSafeToken +} = __webpack_require__(6188); +const supported = __webpack_require__(9898); + +const minimumBytes = 4100; // A fair amount of file-types are detectable within this range + +async function fromStream(stream) { + const tokenizer = await strtok3.fromStream(stream); + try { + return await fromTokenizer(tokenizer); + } finally { + await tokenizer.close(); + } +} + +async function fromBuffer(input) { + if (!(input instanceof Uint8Array || input instanceof ArrayBuffer || Buffer.isBuffer(input))) { + throw new TypeError(`Expected the \`input\` argument to be of type \`Uint8Array\` or \`Buffer\` or \`ArrayBuffer\`, got \`${typeof input}\``); + } + + const buffer = input instanceof Buffer ? input : Buffer.from(input); + + if (!(buffer && buffer.length > 1)) { + return; + } + + const tokenizer = strtok3.fromBuffer(buffer); + return fromTokenizer(tokenizer); +} + +function _check(buffer, headers, options) { + options = { + offset: 0, + ...options + }; + + for (const [index, header] of headers.entries()) { + // If a bitmask is set + if (options.mask) { + // If header doesn't equal `buf` with bits masked off + if (header !== (options.mask[index] & buffer[index + options.offset])) { + return false; + } + } else if (header !== buffer[index + options.offset]) { + return false; + } + } + + return true; +} + +async function fromTokenizer(tokenizer) { + try { + return _fromTokenizer(tokenizer); + } catch (error) { + if (!(error instanceof strtok3.EndOfStreamError)) { + throw error; + } + } +} + +async function _fromTokenizer(tokenizer) { + let buffer = Buffer.alloc(minimumBytes); + const bytesRead = 12; + const check = (header, options) => _check(buffer, header, options); + const checkString = (header, options) => check(stringToBytes(header), options); + + // Keep reading until EOF if the file size is unknown. + if (!tokenizer.fileInfo.size) { + tokenizer.fileInfo.size = Number.MAX_SAFE_INTEGER; + } + + await tokenizer.peekBuffer(buffer, {length: bytesRead, mayBeLess: true}); + + // -- 2-byte signatures -- + + if (check([0x42, 0x4D])) { + return { + ext: 'bmp', + mime: 'image/bmp' + }; + } + + if (check([0x0B, 0x77])) { + return { + ext: 'ac3', + mime: 'audio/vnd.dolby.dd-raw' + }; + } + + if (check([0x78, 0x01])) { + return { + ext: 'dmg', + mime: 'application/x-apple-diskimage' + }; + } + + if (check([0x4D, 0x5A])) { + return { + ext: 'exe', + mime: 'application/x-msdownload' + }; + } + + if (check([0x25, 0x21])) { + await tokenizer.peekBuffer(buffer, {length: 24, mayBeLess: true}); + + if (checkString('PS-Adobe-', {offset: 2}) && + checkString(' EPSF-', {offset: 14})) { + return { + ext: 'eps', + mime: 'application/eps' + }; + } + + return { + ext: 'ps', + mime: 'application/postscript' + }; + } + + if ( + check([0x1F, 0xA0]) || + check([0x1F, 0x9D]) + ) { + return { + ext: 'Z', + mime: 'application/x-compress' + }; + } + + // -- 3-byte signatures -- + + if (check([0xFF, 0xD8, 0xFF])) { + return { + ext: 'jpg', + mime: 'image/jpeg' + }; + } + + if (check([0x49, 0x49, 0xBC])) { + return { + ext: 'jxr', + mime: 'image/vnd.ms-photo' + }; + } + + if (check([0x1F, 0x8B, 0x8])) { + return { + ext: 'gz', + mime: 'application/gzip' + }; + } + + if (check([0x42, 0x5A, 0x68])) { + return { + ext: 'bz2', + mime: 'application/x-bzip2' + }; + } + + if (checkString('ID3')) { + await tokenizer.ignore(6); // Skip ID3 header until the header size + const id3HeaderLen = await tokenizer.readToken(uint32SyncSafeToken); + if (tokenizer.position + id3HeaderLen > tokenizer.fileInfo.size) { + // Guess file type based on ID3 header for backward compatibility + return { + ext: 'mp3', + mime: 'audio/mpeg' + }; + } + + await tokenizer.ignore(id3HeaderLen); + return fromTokenizer(tokenizer); // Skip ID3 header, recursion + } + + // Musepack, SV7 + if (checkString('MP+')) { + return { + ext: 'mpc', + mime: 'audio/x-musepack' + }; + } + + if ( + (buffer[0] === 0x43 || buffer[0] === 0x46) && + check([0x57, 0x53], {offset: 1}) + ) { + return { + ext: 'swf', + mime: 'application/x-shockwave-flash' + }; + } + + // -- 4-byte signatures -- + + if (check([0x47, 0x49, 0x46])) { + return { + ext: 'gif', + mime: 'image/gif' + }; + } + + if (checkString('FLIF')) { + return { + ext: 'flif', + mime: 'image/flif' + }; + } + + if (checkString('8BPS')) { + return { + ext: 'psd', + mime: 'image/vnd.adobe.photoshop' + }; + } + + if (checkString('WEBP', {offset: 8})) { + return { + ext: 'webp', + mime: 'image/webp' + }; + } + + // Musepack, SV8 + if (checkString('MPCK')) { + return { + ext: 'mpc', + mime: 'audio/x-musepack' + }; + } + + if (checkString('FORM')) { + return { + ext: 'aif', + mime: 'audio/aiff' + }; + } + + if (checkString('icns', {offset: 0})) { + return { + ext: 'icns', + mime: 'image/icns' + }; + } + + // Zip-based file formats + // Need to be before the `zip` check + if (check([0x50, 0x4B, 0x3, 0x4])) { // Local file header signature + try { + while (tokenizer.position + 30 < tokenizer.fileInfo.size) { + await tokenizer.readBuffer(buffer, {length: 30}); + + // https://en.wikipedia.org/wiki/Zip_(file_format)#File_headers + const zipHeader = { + compressedSize: buffer.readUInt32LE(18), + uncompressedSize: buffer.readUInt32LE(22), + filenameLength: buffer.readUInt16LE(26), + extraFieldLength: buffer.readUInt16LE(28) + }; + + zipHeader.filename = await tokenizer.readToken(new Token.StringType(zipHeader.filenameLength, 'utf-8')); + await tokenizer.ignore(zipHeader.extraFieldLength); + + // Assumes signed `.xpi` from addons.mozilla.org + if (zipHeader.filename === 'META-INF/mozilla.rsa') { + return { + ext: 'xpi', + mime: 'application/x-xpinstall' + }; + } + + if (zipHeader.filename.endsWith('.rels') || zipHeader.filename.endsWith('.xml')) { + const type = zipHeader.filename.split('/')[0]; + switch (type) { + case '_rels': + break; + case 'word': + return { + ext: 'docx', + mime: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' + }; + case 'ppt': + return { + ext: 'pptx', + mime: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' + }; + case 'xl': + return { + ext: 'xlsx', + mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }; + default: + break; + } + } + + if (zipHeader.filename.startsWith('xl/')) { + return { + ext: 'xlsx', + mime: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + }; + } + + if (zipHeader.filename.startsWith('3D/') && zipHeader.filename.endsWith('.model')) { + return { + ext: '3mf', + mime: 'model/3mf' + }; + } + + // The docx, xlsx and pptx file types extend the Office Open XML file format: + // https://en.wikipedia.org/wiki/Office_Open_XML_file_formats + // We look for: + // - one entry named '[Content_Types].xml' or '_rels/.rels', + // - one entry indicating specific type of file. + // MS Office, OpenOffice and LibreOffice may put the parts in different order, so the check should not rely on it. + if (zipHeader.filename === 'mimetype' && zipHeader.compressedSize === zipHeader.uncompressedSize) { + const mimeType = await tokenizer.readToken(new Token.StringType(zipHeader.compressedSize, 'utf-8')); + + switch (mimeType) { + case 'application/epub+zip': + return { + ext: 'epub', + mime: 'application/epub+zip' + }; + case 'application/vnd.oasis.opendocument.text': + return { + ext: 'odt', + mime: 'application/vnd.oasis.opendocument.text' + }; + case 'application/vnd.oasis.opendocument.spreadsheet': + return { + ext: 'ods', + mime: 'application/vnd.oasis.opendocument.spreadsheet' + }; + case 'application/vnd.oasis.opendocument.presentation': + return { + ext: 'odp', + mime: 'application/vnd.oasis.opendocument.presentation' + }; + default: + } + } + + // Try to find next header manually when current one is corrupted + if (zipHeader.compressedSize === 0) { + let nextHeaderIndex = -1; + + while (nextHeaderIndex < 0 && (tokenizer.position < tokenizer.fileInfo.size)) { + await tokenizer.peekBuffer(buffer, {mayBeLess: true}); + + nextHeaderIndex = buffer.indexOf('504B0304', 0, 'hex'); + // Move position to the next header if found, skip the whole buffer otherwise + await tokenizer.ignore(nextHeaderIndex >= 0 ? nextHeaderIndex : buffer.length); + } + } else { + await tokenizer.ignore(zipHeader.compressedSize); + } + } + } catch (error) { + if (!(error instanceof strtok3.EndOfStreamError)) { + throw error; + } + } + + return { + ext: 'zip', + mime: 'application/zip' + }; + } + + if (checkString('OggS')) { + // This is an OGG container + await tokenizer.ignore(28); + const type = Buffer.alloc(8); + await tokenizer.readBuffer(type); + + // Needs to be before `ogg` check + if (_check(type, [0x4F, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64])) { + return { + ext: 'opus', + mime: 'audio/opus' + }; + } + + // If ' theora' in header. + if (_check(type, [0x80, 0x74, 0x68, 0x65, 0x6F, 0x72, 0x61])) { + return { + ext: 'ogv', + mime: 'video/ogg' + }; + } + + // If '\x01video' in header. + if (_check(type, [0x01, 0x76, 0x69, 0x64, 0x65, 0x6F, 0x00])) { + return { + ext: 'ogm', + mime: 'video/ogg' + }; + } + + // If ' FLAC' in header https://xiph.org/flac/faq.html + if (_check(type, [0x7F, 0x46, 0x4C, 0x41, 0x43])) { + return { + ext: 'oga', + mime: 'audio/ogg' + }; + } + + // 'Speex ' in header https://en.wikipedia.org/wiki/Speex + if (_check(type, [0x53, 0x70, 0x65, 0x65, 0x78, 0x20, 0x20])) { + return { + ext: 'spx', + mime: 'audio/ogg' + }; + } + + // If '\x01vorbis' in header + if (_check(type, [0x01, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73])) { + return { + ext: 'ogg', + mime: 'audio/ogg' + }; + } + + // Default OGG container https://www.iana.org/assignments/media-types/application/ogg + return { + ext: 'ogx', + mime: 'application/ogg' + }; + } + + if ( + check([0x50, 0x4B]) && + (buffer[2] === 0x3 || buffer[2] === 0x5 || buffer[2] === 0x7) && + (buffer[3] === 0x4 || buffer[3] === 0x6 || buffer[3] === 0x8) + ) { + return { + ext: 'zip', + mime: 'application/zip' + }; + } + + // + + // File Type Box (https://en.wikipedia.org/wiki/ISO_base_media_file_format) + // It's not required to be first, but it's recommended to be. Almost all ISO base media files start with `ftyp` box. + // `ftyp` box must contain a brand major identifier, which must consist of ISO 8859-1 printable characters. + // Here we check for 8859-1 printable characters (for simplicity, it's a mask which also catches one non-printable character). + if ( + checkString('ftyp', {offset: 4}) && + (buffer[8] & 0x60) !== 0x00 // Brand major, first character ASCII? + ) { + // They all can have MIME `video/mp4` except `application/mp4` special-case which is hard to detect. + // For some cases, we're specific, everything else falls to `video/mp4` with `mp4` extension. + const brandMajor = buffer.toString('binary', 8, 12).replace('\0', ' ').trim(); + switch (brandMajor) { + case 'avif': + return {ext: 'avif', mime: 'image/avif'}; + case 'mif1': + return {ext: 'heic', mime: 'image/heif'}; + case 'msf1': + return {ext: 'heic', mime: 'image/heif-sequence'}; + case 'heic': + case 'heix': + return {ext: 'heic', mime: 'image/heic'}; + case 'hevc': + case 'hevx': + return {ext: 'heic', mime: 'image/heic-sequence'}; + case 'qt': + return {ext: 'mov', mime: 'video/quicktime'}; + case 'M4V': + case 'M4VH': + case 'M4VP': + return {ext: 'm4v', mime: 'video/x-m4v'}; + case 'M4P': + return {ext: 'm4p', mime: 'video/mp4'}; + case 'M4B': + return {ext: 'm4b', mime: 'audio/mp4'}; + case 'M4A': + return {ext: 'm4a', mime: 'audio/x-m4a'}; + case 'F4V': + return {ext: 'f4v', mime: 'video/mp4'}; + case 'F4P': + return {ext: 'f4p', mime: 'video/mp4'}; + case 'F4A': + return {ext: 'f4a', mime: 'audio/mp4'}; + case 'F4B': + return {ext: 'f4b', mime: 'audio/mp4'}; + case 'crx': + return {ext: 'cr3', mime: 'image/x-canon-cr3'}; + default: + if (brandMajor.startsWith('3g')) { + if (brandMajor.startsWith('3g2')) { + return {ext: '3g2', mime: 'video/3gpp2'}; + } + + return {ext: '3gp', mime: 'video/3gpp'}; + } + + return {ext: 'mp4', mime: 'video/mp4'}; + } + } + + if (checkString('MThd')) { + return { + ext: 'mid', + mime: 'audio/midi' + }; + } + + if ( + checkString('wOFF') && + ( + check([0x00, 0x01, 0x00, 0x00], {offset: 4}) || + checkString('OTTO', {offset: 4}) + ) + ) { + return { + ext: 'woff', + mime: 'font/woff' + }; + } + + if ( + checkString('wOF2') && + ( + check([0x00, 0x01, 0x00, 0x00], {offset: 4}) || + checkString('OTTO', {offset: 4}) + ) + ) { + return { + ext: 'woff2', + mime: 'font/woff2' + }; + } + + if (check([0xD4, 0xC3, 0xB2, 0xA1]) || check([0xA1, 0xB2, 0xC3, 0xD4])) { + return { + ext: 'pcap', + mime: 'application/vnd.tcpdump.pcap' + }; + } + + // Sony DSD Stream File (DSF) + if (checkString('DSD ')) { + return { + ext: 'dsf', + mime: 'audio/x-dsf' // Non-standard + }; + } + + if (checkString('LZIP')) { + return { + ext: 'lz', + mime: 'application/x-lzip' + }; + } + + if (checkString('fLaC')) { + return { + ext: 'flac', + mime: 'audio/x-flac' + }; + } + + if (check([0x42, 0x50, 0x47, 0xFB])) { + return { + ext: 'bpg', + mime: 'image/bpg' + }; + } + + if (checkString('wvpk')) { + return { + ext: 'wv', + mime: 'audio/wavpack' + }; + } + + if (checkString('%PDF')) { + await tokenizer.ignore(1350); + const maxBufferSize = 10 * 1024 * 1024; + const buffer = Buffer.alloc(Math.min(maxBufferSize, tokenizer.fileInfo.size)); + await tokenizer.readBuffer(buffer, {mayBeLess: true}); + + // Check if this is an Adobe Illustrator file + if (buffer.includes(Buffer.from('AIPrivateData'))) { + return { + ext: 'ai', + mime: 'application/postscript' + }; + } + + // Assume this is just a normal PDF + return { + ext: 'pdf', + mime: 'application/pdf' + }; + } + + if (check([0x00, 0x61, 0x73, 0x6D])) { + return { + ext: 'wasm', + mime: 'application/wasm' + }; + } + + // TIFF, little-endian type + if (check([0x49, 0x49, 0x2A, 0x0])) { + if (checkString('CR', {offset: 8})) { + return { + ext: 'cr2', + mime: 'image/x-canon-cr2' + }; + } + + if (check([0x1C, 0x00, 0xFE, 0x00], {offset: 8}) || check([0x1F, 0x00, 0x0B, 0x00], {offset: 8})) { + return { + ext: 'nef', + mime: 'image/x-nikon-nef' + }; + } + + if ( + check([0x08, 0x00, 0x00, 0x00], {offset: 4}) && + (check([0x2D, 0x00, 0xFE, 0x00], {offset: 8}) || + check([0x27, 0x00, 0xFE, 0x00], {offset: 8})) + ) { + return { + ext: 'dng', + mime: 'image/x-adobe-dng' + }; + } + + buffer = Buffer.alloc(24); + await tokenizer.peekBuffer(buffer); + if ( + (check([0x10, 0xFB, 0x86, 0x01], {offset: 4}) || check([0x08, 0x00, 0x00, 0x00], {offset: 4})) && + // This pattern differentiates ARW from other TIFF-ish file types: + check([0x00, 0xFE, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x01], {offset: 9}) + ) { + return { + ext: 'arw', + mime: 'image/x-sony-arw' + }; + } + + return { + ext: 'tif', + mime: 'image/tiff' + }; + } + + // TIFF, big-endian type + if (check([0x4D, 0x4D, 0x0, 0x2A])) { + return { + ext: 'tif', + mime: 'image/tiff' + }; + } + + if (checkString('MAC ')) { + return { + ext: 'ape', + mime: 'audio/ape' + }; + } + + // https://github.com/threatstack/libmagic/blob/master/magic/Magdir/matroska + if (check([0x1A, 0x45, 0xDF, 0xA3])) { // Root element: EBML + async function readField() { + const msb = await tokenizer.peekNumber(Token.UINT8); + let mask = 0x80; + let ic = 0; // 0 = A, 1 = B, 2 = C, 3 = D + + while ((msb & mask) === 0) { + ++ic; + mask >>= 1; + } + + const id = Buffer.alloc(ic + 1); + await tokenizer.readBuffer(id); + return id; + } + + async function readElement() { + const id = await readField(); + const lenField = await readField(); + lenField[0] ^= 0x80 >> (lenField.length - 1); + const nrLen = Math.min(6, lenField.length); // JavaScript can max read 6 bytes integer + return { + id: id.readUIntBE(0, id.length), + len: lenField.readUIntBE(lenField.length - nrLen, nrLen) + }; + } + + async function readChildren(level, children) { + while (children > 0) { + const e = await readElement(); + if (e.id === 0x4282) { + return tokenizer.readToken(new Token.StringType(e.len, 'utf-8')); // Return DocType + } + + await tokenizer.ignore(e.len); // ignore payload + --children; + } + } + + const re = await readElement(); + const docType = await readChildren(1, re.len); + + switch (docType) { + case 'webm': + return { + ext: 'webm', + mime: 'video/webm' + }; + + case 'matroska': + return { + ext: 'mkv', + mime: 'video/x-matroska' + }; + + default: + return; + } + } + + // RIFF file format which might be AVI, WAV, QCP, etc + if (check([0x52, 0x49, 0x46, 0x46])) { + if (check([0x41, 0x56, 0x49], {offset: 8})) { + return { + ext: 'avi', + mime: 'video/vnd.avi' + }; + } + + if (check([0x57, 0x41, 0x56, 0x45], {offset: 8})) { + return { + ext: 'wav', + mime: 'audio/vnd.wave' + }; + } + + // QLCM, QCP file + if (check([0x51, 0x4C, 0x43, 0x4D], {offset: 8})) { + return { + ext: 'qcp', + mime: 'audio/qcelp' + }; + } + } + + if (checkString('SQLi')) { + return { + ext: 'sqlite', + mime: 'application/x-sqlite3' + }; + } + + if (check([0x4E, 0x45, 0x53, 0x1A])) { + return { + ext: 'nes', + mime: 'application/x-nintendo-nes-rom' + }; + } + + if (checkString('Cr24')) { + return { + ext: 'crx', + mime: 'application/x-google-chrome-extension' + }; + } + + if ( + checkString('MSCF') || + checkString('ISc(') + ) { + return { + ext: 'cab', + mime: 'application/vnd.ms-cab-compressed' + }; + } + + if (check([0xED, 0xAB, 0xEE, 0xDB])) { + return { + ext: 'rpm', + mime: 'application/x-rpm' + }; + } + + if (check([0xC5, 0xD0, 0xD3, 0xC6])) { + return { + ext: 'eps', + mime: 'application/eps' + }; + } + + if (check([0x28, 0xB5, 0x2F, 0xFD])) { + return { + ext: 'zst', + mime: 'application/zstd' + }; + } + + // -- 5-byte signatures -- + + if (check([0x4F, 0x54, 0x54, 0x4F, 0x00])) { + return { + ext: 'otf', + mime: 'font/otf' + }; + } + + if (checkString('#!AMR')) { + return { + ext: 'amr', + mime: 'audio/amr' + }; + } + + if (checkString('{\\rtf')) { + return { + ext: 'rtf', + mime: 'application/rtf' + }; + } + + if (check([0x46, 0x4C, 0x56, 0x01])) { + return { + ext: 'flv', + mime: 'video/x-flv' + }; + } + + if (checkString('IMPM')) { + return { + ext: 'it', + mime: 'audio/x-it' + }; + } + + if ( + checkString('-lh0-', {offset: 2}) || + checkString('-lh1-', {offset: 2}) || + checkString('-lh2-', {offset: 2}) || + checkString('-lh3-', {offset: 2}) || + checkString('-lh4-', {offset: 2}) || + checkString('-lh5-', {offset: 2}) || + checkString('-lh6-', {offset: 2}) || + checkString('-lh7-', {offset: 2}) || + checkString('-lzs-', {offset: 2}) || + checkString('-lz4-', {offset: 2}) || + checkString('-lz5-', {offset: 2}) || + checkString('-lhd-', {offset: 2}) + ) { + return { + ext: 'lzh', + mime: 'application/x-lzh-compressed' + }; + } + + // MPEG program stream (PS or MPEG-PS) + if (check([0x00, 0x00, 0x01, 0xBA])) { + // MPEG-PS, MPEG-1 Part 1 + if (check([0x21], {offset: 4, mask: [0xF1]})) { + return { + ext: 'mpg', // May also be .ps, .mpeg + mime: 'video/MP1S' + }; + } + + // MPEG-PS, MPEG-2 Part 1 + if (check([0x44], {offset: 4, mask: [0xC4]})) { + return { + ext: 'mpg', // May also be .mpg, .m2p, .vob or .sub + mime: 'video/MP2P' + }; + } + } + + if (checkString('ITSF')) { + return { + ext: 'chm', + mime: 'application/vnd.ms-htmlhelp' + }; + } + + // -- 6-byte signatures -- + + if (check([0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00])) { + return { + ext: 'xz', + mime: 'application/x-xz' + }; + } + + if (checkString('')) { + await tokenizer.ignore(8); + const str = await tokenizer.readToken(new Token.StringType(13, 'ascii')); + if (str === 'debian-binary') { + return { + ext: 'deb', + mime: 'application/x-deb' + }; + } + + return { + ext: 'ar', + mime: 'application/x-unix-archive' + }; + } + + // -- 8-byte signatures -- + + if (check([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])) { + // APNG format (https://wiki.mozilla.org/APNG_Specification) + // 1. Find the first IDAT (image data) chunk (49 44 41 54) + // 2. Check if there is an "acTL" chunk before the IDAT one (61 63 54 4C) + + // Offset calculated as follows: + // - 8 bytes: PNG signature + // - 4 (length) + 4 (chunk type) + 13 (chunk data) + 4 (CRC): IHDR chunk + + await tokenizer.ignore(8); // ignore PNG signature + + async function readChunkHeader() { + return { + length: await tokenizer.readToken(Token.INT32_BE), + type: await tokenizer.readToken(new Token.StringType(4, 'binary')) + }; + } + + do { + const chunk = await readChunkHeader(); + if (chunk.length < 0) { + return; // Invalid chunk length + } + + switch (chunk.type) { + case 'IDAT': + return { + ext: 'png', + mime: 'image/png' + }; + case 'acTL': + return { + ext: 'apng', + mime: 'image/apng' + }; + default: + await tokenizer.ignore(chunk.length + 4); // Ignore chunk-data + CRC + } + } while (tokenizer.position + 8 < tokenizer.fileInfo.size); + + return { + ext: 'png', + mime: 'image/png' + }; + } + + if (check([0x41, 0x52, 0x52, 0x4F, 0x57, 0x31, 0x00, 0x00])) { + return { + ext: 'arrow', + mime: 'application/x-apache-arrow' + }; + } + + if (check([0x67, 0x6C, 0x54, 0x46, 0x02, 0x00, 0x00, 0x00])) { + return { + ext: 'glb', + mime: 'model/gltf-binary' + }; + } + + // `mov` format variants + if ( + check([0x66, 0x72, 0x65, 0x65], {offset: 4}) || // `free` + check([0x6D, 0x64, 0x61, 0x74], {offset: 4}) || // `mdat` MJPEG + check([0x6D, 0x6F, 0x6F, 0x76], {offset: 4}) || // `moov` + check([0x77, 0x69, 0x64, 0x65], {offset: 4}) // `wide` + ) { + return { + ext: 'mov', + mime: 'video/quicktime' + }; + } + + // -- 9-byte signatures -- + + if (check([0x49, 0x49, 0x52, 0x4F, 0x08, 0x00, 0x00, 0x00, 0x18])) { + return { + ext: 'orf', + mime: 'image/x-olympus-orf' + }; + } + + if (checkString('gimp xcf ')) { + return { + ext: 'xcf', + mime: 'image/x-xcf' + }; + } + + // -- 12-byte signatures -- + + if (check([0x49, 0x49, 0x55, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0xE7, 0x74, 0xD8])) { + return { + ext: 'rw2', + mime: 'image/x-panasonic-rw2' + }; + } + + // ASF_Header_Object first 80 bytes + if (check([0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9])) { + async function readHeader() { + const guid = Buffer.alloc(16); + await tokenizer.readBuffer(guid); + return { + id: guid, + size: Number(await tokenizer.readToken(Token.UINT64_LE)) + }; + } + + await tokenizer.ignore(30); + // Search for header should be in first 1KB of file. + while (tokenizer.position + 24 < tokenizer.fileInfo.size) { + const header = await readHeader(); + let payload = header.size - 24; + if (_check(header.id, [0x91, 0x07, 0xDC, 0xB7, 0xB7, 0xA9, 0xCF, 0x11, 0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65])) { + // Sync on Stream-Properties-Object (B7DC0791-A9B7-11CF-8EE6-00C00C205365) + const typeId = Buffer.alloc(16); + payload -= await tokenizer.readBuffer(typeId); + + if (_check(typeId, [0x40, 0x9E, 0x69, 0xF8, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B])) { + // Found audio: + return { + ext: 'asf', + mime: 'audio/x-ms-asf' + }; + } + + if (_check(typeId, [0xC0, 0xEF, 0x19, 0xBC, 0x4D, 0x5B, 0xCF, 0x11, 0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B])) { + // Found video: + return { + ext: 'asf', + mime: 'video/x-ms-asf' + }; + } + + break; + } + + await tokenizer.ignore(payload); + } + + // Default to ASF generic extension + return { + ext: 'asf', + mime: 'application/vnd.ms-asf' + }; + } + + if (check([0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A])) { + return { + ext: 'ktx', + mime: 'image/ktx' + }; + } + + if ((check([0x7E, 0x10, 0x04]) || check([0x7E, 0x18, 0x04])) && check([0x30, 0x4D, 0x49, 0x45], {offset: 4})) { + return { + ext: 'mie', + mime: 'application/x-mie' + }; + } + + if (check([0x27, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], {offset: 2})) { + return { + ext: 'shp', + mime: 'application/x-esri-shape' + }; + } + + if (check([0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A])) { + // JPEG-2000 family + + await tokenizer.ignore(20); + const type = await tokenizer.readToken(new Token.StringType(4, 'ascii')); + switch (type) { + case 'jp2 ': + return { + ext: 'jp2', + mime: 'image/jp2' + }; + case 'jpx ': + return { + ext: 'jpx', + mime: 'image/jpx' + }; + case 'jpm ': + return { + ext: 'jpm', + mime: 'image/jpm' + }; + case 'mjp2': + return { + ext: 'mj2', + mime: 'image/mj2' + }; + default: + return; + } + } + + if ( + check([0xFF, 0x0A]) || + check([0x00, 0x00, 0x00, 0x0C, 0x4A, 0x58, 0x4C, 0x20, 0x0D, 0x0A, 0x87, 0x0A]) + ) { + return { + ext: 'jxl', + mime: 'image/jxl' + }; + } + + // -- Unsafe signatures -- + + if ( + check([0x0, 0x0, 0x1, 0xBA]) || + check([0x0, 0x0, 0x1, 0xB3]) + ) { + return { + ext: 'mpg', + mime: 'video/mpeg' + }; + } + + if (check([0x00, 0x01, 0x00, 0x00, 0x00])) { + return { + ext: 'ttf', + mime: 'font/ttf' + }; + } + + if (check([0x00, 0x00, 0x01, 0x00])) { + return { + ext: 'ico', + mime: 'image/x-icon' + }; + } + + if (check([0x00, 0x00, 0x02, 0x00])) { + return { + ext: 'cur', + mime: 'image/x-icon' + }; + } + + if (check([0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1])) { + // Detected Microsoft Compound File Binary File (MS-CFB) Format. + return { + ext: 'cfb', + mime: 'application/x-cfb' + }; + } + + // Increase sample size from 12 to 256. + await tokenizer.peekBuffer(buffer, {length: Math.min(256, tokenizer.fileInfo.size), mayBeLess: true}); + + // -- 15-byte signatures -- + + if (checkString('BEGIN:')) { + if (checkString('VCARD', {offset: 6})) { + return { + ext: 'vcf', + mime: 'text/vcard' + }; + } + + if (checkString('VCALENDAR', {offset: 6})) { + return { + ext: 'ics', + mime: 'text/calendar' + }; + } + } + + // `raf` is here just to keep all the raw image detectors together. + if (checkString('FUJIFILMCCD-RAW')) { + return { + ext: 'raf', + mime: 'image/x-fujifilm-raf' + }; + } + + if (checkString('Extended Module:')) { + return { + ext: 'xm', + mime: 'audio/x-xm' + }; + } + + if (checkString('Creative Voice File')) { + return { + ext: 'voc', + mime: 'audio/x-voc' + }; + } + + if (check([0x04, 0x00, 0x00, 0x00]) && buffer.length >= 16) { // Rough & quick check Pickle/ASAR + const jsonSize = buffer.readUInt32LE(12); + if (jsonSize > 12 && buffer.length >= jsonSize + 16) { + try { + const header = buffer.slice(16, jsonSize + 16).toString(); + const json = JSON.parse(header); + // Check if Pickle is ASAR + if (json.files) { // Final check, assuring Pickle/ASAR format + return { + ext: 'asar', + mime: 'application/x-asar' + }; + } + } catch (_) { + } + } + } + + if (check([0x06, 0x0E, 0x2B, 0x34, 0x02, 0x05, 0x01, 0x01, 0x0D, 0x01, 0x02, 0x01, 0x01, 0x02])) { + return { + ext: 'mxf', + mime: 'application/mxf' + }; + } + + if (checkString('SCRM', {offset: 44})) { + return { + ext: 's3m', + mime: 'audio/x-s3m' + }; + } + + if (check([0x47], {offset: 4}) && (check([0x47], {offset: 192}) || check([0x47], {offset: 196}))) { + return { + ext: 'mts', + mime: 'video/mp2t' + }; + } + + if (check([0x42, 0x4F, 0x4F, 0x4B, 0x4D, 0x4F, 0x42, 0x49], {offset: 60})) { + return { + ext: 'mobi', + mime: 'application/x-mobipocket-ebook' + }; + } + + if (check([0x44, 0x49, 0x43, 0x4D], {offset: 128})) { + return { + ext: 'dcm', + mime: 'application/dicom' + }; + } + + if (check([0x4C, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46])) { + return { + ext: 'lnk', + mime: 'application/x.ms.shortcut' // Invented by us + }; + } + + if (check([0x62, 0x6F, 0x6F, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x6D, 0x61, 0x72, 0x6B, 0x00, 0x00, 0x00, 0x00])) { + return { + ext: 'alias', + mime: 'application/x.apple.alias' // Invented by us + }; + } + + if ( + check([0x4C, 0x50], {offset: 34}) && + ( + check([0x00, 0x00, 0x01], {offset: 8}) || + check([0x01, 0x00, 0x02], {offset: 8}) || + check([0x02, 0x00, 0x02], {offset: 8}) + ) + ) { + return { + ext: 'eot', + mime: 'application/vnd.ms-fontobject' + }; + } + + if (check([0x06, 0x06, 0xED, 0xF5, 0xD8, 0x1D, 0x46, 0xE5, 0xBD, 0x31, 0xEF, 0xE7, 0xFE, 0x74, 0xB7, 0x1D])) { + return { + ext: 'indd', + mime: 'application/x-indesign' + }; + } + + // Increase sample size from 256 to 512 + await tokenizer.peekBuffer(buffer, {length: Math.min(512, tokenizer.fileInfo.size), mayBeLess: true}); + + // Requires a buffer size of 512 bytes + if (tarHeaderChecksumMatches(buffer)) { + return { + ext: 'tar', + mime: 'application/x-tar' + }; + } + + if (check([0xFF, 0xFE, 0xFF, 0x0E, 0x53, 0x00, 0x6B, 0x00, 0x65, 0x00, 0x74, 0x00, 0x63, 0x00, 0x68, 0x00, 0x55, 0x00, 0x70, 0x00, 0x20, 0x00, 0x4D, 0x00, 0x6F, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6C, 0x00])) { + return { + ext: 'skp', + mime: 'application/vnd.sketchup.skp' + }; + } + + if (checkString('-----BEGIN PGP MESSAGE-----')) { + return { + ext: 'pgp', + mime: 'application/pgp-encrypted' + }; + } + + // Check MPEG 1 or 2 Layer 3 header, or 'layer 0' for ADTS (MPEG sync-word 0xFFE) + if (buffer.length >= 2 && check([0xFF, 0xE0], {offset: 0, mask: [0xFF, 0xE0]})) { + if (check([0x10], {offset: 1, mask: [0x16]})) { + // Check for (ADTS) MPEG-2 + if (check([0x08], {offset: 1, mask: [0x08]})) { + return { + ext: 'aac', + mime: 'audio/aac' + }; + } + + // Must be (ADTS) MPEG-4 + return { + ext: 'aac', + mime: 'audio/aac' + }; + } + + // MPEG 1 or 2 Layer 3 header + // Check for MPEG layer 3 + if (check([0x02], {offset: 1, mask: [0x06]})) { + return { + ext: 'mp3', + mime: 'audio/mpeg' + }; + } + + // Check for MPEG layer 2 + if (check([0x04], {offset: 1, mask: [0x06]})) { + return { + ext: 'mp2', + mime: 'audio/mpeg' + }; + } + + // Check for MPEG layer 1 + if (check([0x06], {offset: 1, mask: [0x06]})) { + return { + ext: 'mp1', + mime: 'audio/mpeg' + }; + } + } +} + +const stream = readableStream => new Promise((resolve, reject) => { + // Using `eval` to work around issues when bundling with Webpack + const stream = eval('require')('stream'); // eslint-disable-line no-eval + + readableStream.on('error', reject); + readableStream.once('readable', async () => { + // Set up output stream + const pass = new stream.PassThrough(); + let outputStream; + if (stream.pipeline) { + outputStream = stream.pipeline(readableStream, pass, () => { + }); + } else { + outputStream = readableStream.pipe(pass); + } + + // Read the input stream and detect the filetype + const chunk = readableStream.read(minimumBytes) || readableStream.read() || Buffer.alloc(0); + try { + const fileType = await fromBuffer(chunk); + pass.fileType = fileType; + } catch (error) { + reject(error); + } + + resolve(outputStream); + }); +}); + +const fileType = { + fromStream, + fromTokenizer, + fromBuffer, + stream +}; + +Object.defineProperty(fileType, 'extensions', { + get() { + return new Set(supported.extensions); + } +}); + +Object.defineProperty(fileType, 'mimeTypes', { + get() { + return new Set(supported.mimeTypes); + } +}); + +module.exports = fileType; + + +/***/ }), + +/***/ 9898: +/***/ ((module) => { + +"use strict"; + + +module.exports = { + extensions: [ + 'jpg', + 'png', + 'apng', + 'gif', + 'webp', + 'flif', + 'xcf', + 'cr2', + 'cr3', + 'orf', + 'arw', + 'dng', + 'nef', + 'rw2', + 'raf', + 'tif', + 'bmp', + 'icns', + 'jxr', + 'psd', + 'indd', + 'zip', + 'tar', + 'rar', + 'gz', + 'bz2', + '7z', + 'dmg', + 'mp4', + 'mid', + 'mkv', + 'webm', + 'mov', + 'avi', + 'mpg', + 'mp2', + 'mp3', + 'm4a', + 'oga', + 'ogg', + 'ogv', + 'opus', + 'flac', + 'wav', + 'spx', + 'amr', + 'pdf', + 'epub', + 'exe', + 'swf', + 'rtf', + 'wasm', + 'woff', + 'woff2', + 'eot', + 'ttf', + 'otf', + 'ico', + 'flv', + 'ps', + 'xz', + 'sqlite', + 'nes', + 'crx', + 'xpi', + 'cab', + 'deb', + 'ar', + 'rpm', + 'Z', + 'lz', + 'cfb', + 'mxf', + 'mts', + 'blend', + 'bpg', + 'docx', + 'pptx', + 'xlsx', + '3gp', + '3g2', + 'jp2', + 'jpm', + 'jpx', + 'mj2', + 'aif', + 'qcp', + 'odt', + 'ods', + 'odp', + 'xml', + 'mobi', + 'heic', + 'cur', + 'ktx', + 'ape', + 'wv', + 'dcm', + 'ics', + 'glb', + 'pcap', + 'dsf', + 'lnk', + 'alias', + 'voc', + 'ac3', + 'm4v', + 'm4p', + 'm4b', + 'f4v', + 'f4p', + 'f4b', + 'f4a', + 'mie', + 'asf', + 'ogm', + 'ogx', + 'mpc', + 'arrow', + 'shp', + 'aac', + 'mp1', + 'it', + 's3m', + 'xm', + 'ai', + 'skp', + 'avif', + 'eps', + 'lzh', + 'pgp', + 'asar', + 'stl', + 'chm', + '3mf', + 'zst', + 'jxl', + 'vcf' + ], + mimeTypes: [ + 'image/jpeg', + 'image/png', + 'image/gif', + 'image/webp', + 'image/flif', + 'image/x-xcf', + 'image/x-canon-cr2', + 'image/x-canon-cr3', + 'image/tiff', + 'image/bmp', + 'image/vnd.ms-photo', + 'image/vnd.adobe.photoshop', + 'application/x-indesign', + 'application/epub+zip', + 'application/x-xpinstall', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/zip', + 'application/x-tar', + 'application/x-rar-compressed', + 'application/gzip', + 'application/x-bzip2', + 'application/x-7z-compressed', + 'application/x-apple-diskimage', + 'application/x-apache-arrow', + 'video/mp4', + 'audio/midi', + 'video/x-matroska', + 'video/webm', + 'video/quicktime', + 'video/vnd.avi', + 'audio/vnd.wave', + 'audio/qcelp', + 'audio/x-ms-asf', + 'video/x-ms-asf', + 'application/vnd.ms-asf', + 'video/mpeg', + 'video/3gpp', + 'audio/mpeg', + 'audio/mp4', // RFC 4337 + 'audio/opus', + 'video/ogg', + 'audio/ogg', + 'application/ogg', + 'audio/x-flac', + 'audio/ape', + 'audio/wavpack', + 'audio/amr', + 'application/pdf', + 'application/x-msdownload', + 'application/x-shockwave-flash', + 'application/rtf', + 'application/wasm', + 'font/woff', + 'font/woff2', + 'application/vnd.ms-fontobject', + 'font/ttf', + 'font/otf', + 'image/x-icon', + 'video/x-flv', + 'application/postscript', + 'application/eps', + 'application/x-xz', + 'application/x-sqlite3', + 'application/x-nintendo-nes-rom', + 'application/x-google-chrome-extension', + 'application/vnd.ms-cab-compressed', + 'application/x-deb', + 'application/x-unix-archive', + 'application/x-rpm', + 'application/x-compress', + 'application/x-lzip', + 'application/x-cfb', + 'application/x-mie', + 'application/mxf', + 'video/mp2t', + 'application/x-blender', + 'image/bpg', + 'image/jp2', + 'image/jpx', + 'image/jpm', + 'image/mj2', + 'audio/aiff', + 'application/xml', + 'application/x-mobipocket-ebook', + 'image/heif', + 'image/heif-sequence', + 'image/heic', + 'image/heic-sequence', + 'image/icns', + 'image/ktx', + 'application/dicom', + 'audio/x-musepack', + 'text/calendar', + 'text/vcard', + 'model/gltf-binary', + 'application/vnd.tcpdump.pcap', + 'audio/x-dsf', // Non-standard + 'application/x.ms.shortcut', // Invented by us + 'application/x.apple.alias', // Invented by us + 'audio/x-voc', + 'audio/vnd.dolby.dd-raw', + 'audio/x-m4a', + 'image/apng', + 'image/x-olympus-orf', + 'image/x-sony-arw', + 'image/x-adobe-dng', + 'image/x-nikon-nef', + 'image/x-panasonic-rw2', + 'image/x-fujifilm-raf', + 'video/x-m4v', + 'video/3gpp2', + 'application/x-esri-shape', + 'audio/aac', + 'audio/x-it', + 'audio/x-s3m', + 'audio/x-xm', + 'video/MP1S', + 'video/MP2P', + 'application/vnd.sketchup.skp', + 'image/avif', + 'application/x-lzh-compressed', + 'application/pgp-encrypted', + 'application/x-asar', + 'model/stl', + 'application/vnd.ms-htmlhelp', + 'model/3mf', + 'image/jxl', + 'application/zstd' + ] +}; + + +/***/ }), + +/***/ 6188: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +exports.stringToBytes = string => [...string].map(character => character.charCodeAt(0)); + +/** +Checks whether the TAR checksum is valid. + +@param {Buffer} buffer - The TAR header `[offset ... offset + 512]`. +@param {number} offset - TAR header offset. +@returns {boolean} `true` if the TAR checksum is valid, otherwise `false`. +*/ +exports.tarHeaderChecksumMatches = (buffer, offset = 0) => { + const readSum = parseInt(buffer.toString('utf8', 148, 154).replace(/\0.*$/, '').trim(), 8); // Read sum in header + if (isNaN(readSum)) { + return false; + } + + let sum = 8 * 0x20; // Initialize signed bit sum + + for (let i = offset; i < offset + 148; i++) { + sum += buffer[i]; + } + + for (let i = offset + 156; i < offset + 512; i++) { + sum += buffer[i]; + } + + return readSum === sum; +}; + +/** +ID3 UINT32 sync-safe tokenizer token. +28 bits (representing up to 256MB) integer, the msb is 0 to avoid "false syncsignals". +*/ +exports.uint32SyncSafeToken = { + get: (buffer, offset) => { + return (buffer[offset + 3] & 0x7F) | ((buffer[offset + 2]) << 7) | ((buffer[offset + 1]) << 14) | ((buffer[offset]) << 21); + }, + len: 4 +}; + + +/***/ }), + +/***/ 645: +/***/ ((__unused_webpack_module, exports) => { + +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var nBits = -7 + var i = isLE ? (nBytes - 1) : 0 + var d = isLE ? -1 : 1 + var s = buffer[offset + i] + + i += d + + e = s & ((1 << (-nBits)) - 1) + s >>= (-nBits) + nBits += eLen + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + m = e & ((1 << (-nBits)) - 1) + e >>= (-nBits) + nBits += mLen + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} + + if (e === 0) { + e = 1 - eBias + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) + } else { + m = m + Math.pow(2, mLen) + e = e - eBias + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) +} + +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c + var eLen = (nBytes * 8) - mLen - 1 + var eMax = (1 << eLen) - 1 + var eBias = eMax >> 1 + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) + var i = isLE ? 0 : (nBytes - 1) + var d = isLE ? 1 : -1 + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 + + value = Math.abs(value) + + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0 + e = eMax + } else { + e = Math.floor(Math.log(value) / Math.LN2) + if (value * (c = Math.pow(2, -e)) < 1) { + e-- + c *= 2 + } + if (e + eBias >= 1) { + value += rt / c + } else { + value += rt * Math.pow(2, 1 - eBias) + } + if (value * c >= 2) { + e++ + c /= 2 + } + + if (e + eBias >= eMax) { + m = 0 + e = eMax + } else if (e + eBias >= 1) { + m = ((value * c) - 1) * Math.pow(2, mLen) + e = e + eBias + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) + e = 0 + } + } + + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + + e = (e << mLen) | m + eLen += mLen + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + + buffer[offset + i - d] |= s * 128 +} + + +/***/ }), + +/***/ 5717: +/***/ ((module) => { + +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }) + } + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + if (superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } + } +} + + +/***/ }), + +/***/ 2577: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; +/*! + * media-typer + * Copyright(c) 2014-2017 Douglas Christopher Wilson + * MIT Licensed + */ + + + +/** + * RegExp to match type in RFC 6838 + * + * type-name = restricted-name + * subtype-name = restricted-name + * restricted-name = restricted-name-first *126restricted-name-chars + * restricted-name-first = ALPHA / DIGIT + * restricted-name-chars = ALPHA / DIGIT / "!" / "#" / + * "$" / "&" / "-" / "^" / "_" + * restricted-name-chars =/ "." ; Characters before first dot always + * ; specify a facet name + * restricted-name-chars =/ "+" ; Characters after last plus always + * ; specify a structured syntax suffix + * ALPHA = %x41-5A / %x61-7A ; A-Z / a-z + * DIGIT = %x30-39 ; 0-9 + */ +var SUBTYPE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.-]{0,126}$/ +var TYPE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/ +var TYPE_REGEXP = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/ + +/** + * Module exports. + */ + +exports.format = format +exports.parse = parse +exports.test = test + +/** + * Format object to media type. + * + * @param {object} obj + * @return {string} + * @public + */ + +function format (obj) { + if (!obj || typeof obj !== 'object') { + throw new TypeError('argument obj is required') + } + + var subtype = obj.subtype + var suffix = obj.suffix + var type = obj.type + + if (!type || !TYPE_NAME_REGEXP.test(type)) { + throw new TypeError('invalid type') + } + + if (!subtype || !SUBTYPE_NAME_REGEXP.test(subtype)) { + throw new TypeError('invalid subtype') + } + + // format as type/subtype + var string = type + '/' + subtype + + // append +suffix + if (suffix) { + if (!TYPE_NAME_REGEXP.test(suffix)) { + throw new TypeError('invalid suffix') + } + + string += '+' + suffix + } + + return string +} + +/** + * Test media type. + * + * @param {string} string + * @return {object} + * @public + */ + +function test (string) { + if (!string) { + throw new TypeError('argument string is required') + } + + if (typeof string !== 'string') { + throw new TypeError('argument string is required to be a string') + } + + return TYPE_REGEXP.test(string.toLowerCase()) +} + +/** + * Parse media type to object. + * + * @param {string} string + * @return {object} + * @public + */ + +function parse (string) { + if (!string) { + throw new TypeError('argument string is required') + } + + if (typeof string !== 'string') { + throw new TypeError('argument string is required to be a string') + } + + var match = TYPE_REGEXP.exec(string.toLowerCase()) + + if (!match) { + throw new TypeError('invalid media type') + } + + var type = match[1] + var subtype = match[2] + var suffix + + // suffix after last + + var index = subtype.lastIndexOf('+') + if (index !== -1) { + suffix = subtype.substr(index + 1) + subtype = subtype.substr(0, index) + } + + return new MediaType(type, subtype, suffix) +} + +/** + * Class for MediaType object. + * @public + */ + +function MediaType (type, subtype, suffix) { + this.type = type + this.subtype = subtype + this.suffix = suffix +} + + +/***/ }), + +/***/ 7824: +/***/ ((module) => { + +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var w = d * 7; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isFinite(val)) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'weeks': + case 'week': + case 'w': + return n * w; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return Math.round(ms / d) + 'd'; + } + if (msAbs >= h) { + return Math.round(ms / h) + 'h'; + } + if (msAbs >= m) { + return Math.round(ms / m) + 'm'; + } + if (msAbs >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return plural(ms, msAbs, d, 'day'); + } + if (msAbs >= h) { + return plural(ms, msAbs, h, 'hour'); + } + if (msAbs >= m) { + return plural(ms, msAbs, m, 'minute'); + } + if (msAbs >= s) { + return plural(ms, msAbs, s, 'second'); + } + return ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, msAbs, n, name) { + var isPlural = msAbs >= n * 1.5; + return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); +} + + +/***/ }), + +/***/ 3275: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ParserFactory = exports.parseHttpContentType = void 0; +const FileType = __webpack_require__(1); +const ContentType = __webpack_require__(7811); +const MimeType = __webpack_require__(2577); +const debug_1 = __webpack_require__(1227); +const MetadataCollector_1 = __webpack_require__(7584); +const AiffParser_1 = __webpack_require__(5410); +const APEv2Parser_1 = __webpack_require__(6742); +const AsfParser_1 = __webpack_require__(1004); +const FlacParser_1 = __webpack_require__(498); +const MP4Parser_1 = __webpack_require__(8841); +const MpegParser_1 = __webpack_require__(60); +const musepack_1 = __webpack_require__(9606); +const OggParser_1 = __webpack_require__(1915); +const WaveParser_1 = __webpack_require__(2682); +const WavPackParser_1 = __webpack_require__(5870); +const DsfParser_1 = __webpack_require__(1533); +const DsdiffParser_1 = __webpack_require__(6789); +const MatroskaParser_1 = __webpack_require__(78); +const debug = (0, debug_1.default)('music-metadata:parser:factory'); +function parseHttpContentType(contentType) { + const type = ContentType.parse(contentType); + const mime = MimeType.parse(type.type); + return { + type: mime.type, + subtype: mime.subtype, + suffix: mime.suffix, + parameters: type.parameters + }; +} +exports.parseHttpContentType = parseHttpContentType; +async function parse(tokenizer, parserId, opts = {}) { + // Parser found, execute parser + const parser = await ParserFactory.loadParser(parserId); + const metadata = new MetadataCollector_1.MetadataCollector(opts); + await parser.init(metadata, tokenizer, opts).parse(); + return metadata.toCommonMetadata(); +} +class ParserFactory { + /** + * Parse metadata from tokenizer + * @param tokenizer - Tokenizer + * @param opts - Options + * @returns Native metadata + */ + static async parseOnContentType(tokenizer, opts) { + const { mimeType, path, url } = await tokenizer.fileInfo; + // Resolve parser based on MIME-type or file extension + const parserId = ParserFactory.getParserIdForMimeType(mimeType) || ParserFactory.getParserIdForExtension(path) || ParserFactory.getParserIdForExtension(url); + if (!parserId) { + debug('No parser found for MIME-type / extension: ' + mimeType); + } + return this.parse(tokenizer, parserId, opts); + } + static async parse(tokenizer, parserId, opts) { + if (!parserId) { + // Parser could not be determined on MIME-type or extension + debug('Guess parser on content...'); + const buf = Buffer.alloc(4100); + await tokenizer.peekBuffer(buf, { mayBeLess: true }); + if (tokenizer.fileInfo.path) { + parserId = this.getParserIdForExtension(tokenizer.fileInfo.path); + } + if (!parserId) { + const guessedType = await FileType.fromBuffer(buf); + if (!guessedType) { + throw new Error('Failed to determine audio format'); + } + debug(`Guessed file type is mime=${guessedType.mime}, extension=${guessedType.ext}`); + parserId = ParserFactory.getParserIdForMimeType(guessedType.mime); + if (!parserId) { + throw new Error('Guessed MIME-type not supported: ' + guessedType.mime); + } + } + } + // Parser found, execute parser + return parse(tokenizer, parserId, opts); + } + /** + * @param filePath - Path, filename or extension to audio file + * @return Parser sub-module name + */ + static getParserIdForExtension(filePath) { + if (!filePath) + return; + const extension = this.getExtension(filePath).toLocaleLowerCase() || filePath; + switch (extension) { + case '.mp2': + case '.mp3': + case '.m2a': + case '.aac': // Assume it is ADTS-container + return 'mpeg'; + case '.ape': + return 'apev2'; + case '.mp4': + case '.m4a': + case '.m4b': + case '.m4pa': + case '.m4v': + case '.m4r': + case '.3gp': + return 'mp4'; + case '.wma': + case '.wmv': + case '.asf': + return 'asf'; + case '.flac': + return 'flac'; + case '.ogg': + case '.ogv': + case '.oga': + case '.ogm': + case '.ogx': + case '.opus': // recommended filename extension for Ogg Opus + case '.spx': // recommended filename extension for Ogg Speex + return 'ogg'; + case '.aif': + case '.aiff': + case '.aifc': + return 'aiff'; + case '.wav': + case '.bwf': // Broadcast Wave Format + return 'riff'; + case '.wv': + case '.wvp': + return 'wavpack'; + case '.mpc': + return 'musepack'; + case '.dsf': + return 'dsf'; + case '.dff': + return 'dsdiff'; + case '.mka': + case '.mkv': + case '.mk3d': + case '.mks': + case '.webm': + return 'matroska'; + } + } + static async loadParser(moduleName) { + switch (moduleName) { + case 'aiff': return new AiffParser_1.AIFFParser(); + case 'adts': + case 'mpeg': + return new MpegParser_1.MpegParser(); + case 'apev2': return new APEv2Parser_1.APEv2Parser(); + case 'asf': return new AsfParser_1.AsfParser(); + case 'dsf': return new DsfParser_1.DsfParser(); + case 'dsdiff': return new DsdiffParser_1.DsdiffParser(); + case 'flac': return new FlacParser_1.FlacParser(); + case 'mp4': return new MP4Parser_1.MP4Parser(); + case 'musepack': return new musepack_1.default(); + case 'ogg': return new OggParser_1.OggParser(); + case 'riff': return new WaveParser_1.WaveParser(); + case 'wavpack': return new WavPackParser_1.WavPackParser(); + case 'matroska': return new MatroskaParser_1.MatroskaParser(); + default: + throw new Error(`Unknown parser type: ${moduleName}`); + } + } + static getExtension(fname) { + const i = fname.lastIndexOf('.'); + return i === -1 ? '' : fname.slice(i); + } + /** + * @param httpContentType - HTTP Content-Type, extension, path or filename + * @returns Parser sub-module name + */ + static getParserIdForMimeType(httpContentType) { + let mime; + try { + mime = parseHttpContentType(httpContentType); + } + catch (err) { + debug(`Invalid HTTP Content-Type header value: ${httpContentType}`); + return; + } + const subType = mime.subtype.indexOf('x-') === 0 ? mime.subtype.substring(2) : mime.subtype; + switch (mime.type) { + case 'audio': + switch (subType) { + case 'mp3': // Incorrect MIME-type, Chrome, in Web API File object + case 'mpeg': + return 'mpeg'; + case 'aac': + case 'aacp': + return 'adts'; + case 'flac': + return 'flac'; + case 'ape': + case 'monkeys-audio': + return 'apev2'; + case 'mp4': + case 'm4a': + return 'mp4'; + case 'ogg': // RFC 7845 + case 'opus': // RFC 6716 + case 'speex': // RFC 5574 + return 'ogg'; + case 'ms-wma': + case 'ms-wmv': + case 'ms-asf': + return 'asf'; + case 'aiff': + case 'aif': + case 'aifc': + return 'aiff'; + case 'vnd.wave': + case 'wav': + case 'wave': + return 'riff'; + case 'wavpack': + return 'wavpack'; + case 'musepack': + return 'musepack'; + case 'matroska': + case 'webm': + return 'matroska'; + case 'dsf': + return 'dsf'; + } + break; + case 'video': + switch (subType) { + case 'ms-asf': + case 'ms-wmv': + return 'asf'; + case 'm4v': + case 'mp4': + return 'mp4'; + case 'ogg': + return 'ogg'; + case 'matroska': + case 'webm': + return 'matroska'; + } + break; + case 'application': + switch (subType) { + case 'vnd.ms-asf': + return 'asf'; + case 'ogg': + return 'ogg'; + } + break; + } + } +} +exports.ParserFactory = ParserFactory; + + +/***/ }), + +/***/ 5410: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AIFFParser = void 0; +const Token = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const strtok3 = __webpack_require__(5849); +const ID3v2Parser_1 = __webpack_require__(8928); +const FourCC_1 = __webpack_require__(8049); +const BasicParser_1 = __webpack_require__(7805); +const AiffToken = __webpack_require__(1162); +const iff = __webpack_require__(4633); +const debug = (0, debug_1.default)('music-metadata:parser:aiff'); +/** + * AIFF - Audio Interchange File Format + * + * Ref: + * - http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/AIFF.html + * - http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/AIFF-1.3.pdf + */ +class AIFFParser extends BasicParser_1.BasicParser { + async parse() { + const header = await this.tokenizer.readToken(iff.Header); + if (header.chunkID !== 'FORM') + throw new Error('Invalid Chunk-ID, expected \'FORM\''); // Not AIFF format + const type = await this.tokenizer.readToken(FourCC_1.FourCcToken); + switch (type) { + case 'AIFF': + this.metadata.setFormat('container', type); + this.isCompressed = false; + break; + case 'AIFC': + this.metadata.setFormat('container', 'AIFF-C'); + this.isCompressed = true; + break; + default: + throw Error('Unsupported AIFF type: ' + type); + } + this.metadata.setFormat('lossless', !this.isCompressed); + try { + while (!this.tokenizer.fileInfo.size || this.tokenizer.fileInfo.size - this.tokenizer.position >= iff.Header.len) { + debug('Reading AIFF chunk at offset=' + this.tokenizer.position); + const chunkHeader = await this.tokenizer.readToken(iff.Header); + debug(`Chunk id=${chunkHeader.chunkID}`); + const nextChunk = 2 * Math.round(chunkHeader.chunkSize / 2); + const bytesRead = await this.readData(chunkHeader); + await this.tokenizer.ignore(nextChunk - bytesRead); + } + } + catch (err) { + if (err instanceof strtok3.EndOfStreamError) { + debug(`End-of-stream`); + } + else { + throw err; + } + } + } + async readData(header) { + switch (header.chunkID) { + case 'COMM': // The Common Chunk + const common = await this.tokenizer.readToken(new AiffToken.Common(header, this.isCompressed)); + this.metadata.setFormat('bitsPerSample', common.sampleSize); + this.metadata.setFormat('sampleRate', common.sampleRate); + this.metadata.setFormat('numberOfChannels', common.numChannels); + this.metadata.setFormat('numberOfSamples', common.numSampleFrames); + this.metadata.setFormat('duration', common.numSampleFrames / common.sampleRate); + this.metadata.setFormat('codec', common.compressionName); + return header.chunkSize; + case 'ID3 ': // ID3-meta-data + const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(header.chunkSize)); + const rst = strtok3.fromBuffer(id3_data); + await new ID3v2Parser_1.ID3v2Parser().parse(this.metadata, rst, this.options); + return header.chunkSize; + case 'SSND': // Sound Data Chunk + if (this.metadata.format.duration) { + this.metadata.setFormat('bitrate', 8 * header.chunkSize / this.metadata.format.duration); + } + return 0; + default: + return 0; + } + } +} +exports.AIFFParser = AIFFParser; + + +/***/ }), + +/***/ 1162: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Common = void 0; +const Token = __webpack_require__(3416); +const FourCC_1 = __webpack_require__(8049); +class Common { + constructor(header, isAifc) { + this.isAifc = isAifc; + const minimumChunkSize = isAifc ? 22 : 18; + if (header.chunkSize < minimumChunkSize) + throw new Error(`COMMON CHUNK size should always be at least ${minimumChunkSize}`); + this.len = header.chunkSize; + } + get(buf, off) { + // see: https://cycling74.com/forums/aiffs-80-bit-sample-rate-value + const shift = buf.readUInt16BE(off + 8) - 16398; + const baseSampleRate = buf.readUInt16BE(off + 8 + 2); + const res = { + numChannels: buf.readUInt16BE(off), + numSampleFrames: buf.readUInt32BE(off + 2), + sampleSize: buf.readUInt16BE(off + 6), + sampleRate: shift < 0 ? baseSampleRate >> Math.abs(shift) : baseSampleRate << shift + }; + if (this.isAifc) { + res.compressionType = FourCC_1.FourCcToken.get(buf, off + 18); + if (this.len > 22) { + const strLen = buf.readInt8(off + 22); + const padding = (strLen + 1) % 2; + if (23 + strLen + padding === this.len) { + res.compressionName = new Token.StringType(strLen, 'binary').get(buf, off + 23); + } + else { + throw new Error('Illegal pstring length'); + } + } + } + else { + res.compressionName = 'PCM'; + } + return res; + } +} +exports.Common = Common; + + +/***/ }), + +/***/ 6742: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.APEv2Parser = void 0; +const debug_1 = __webpack_require__(1227); +const strtok3 = __webpack_require__(5849); +const token_types_1 = __webpack_require__(3416); +const util = __webpack_require__(3769); +const BasicParser_1 = __webpack_require__(7805); +const APEv2Token_1 = __webpack_require__(876); +const debug = (0, debug_1.default)('music-metadata:parser:APEv2'); +const tagFormat = 'APEv2'; +const preamble = 'APETAGEX'; +class APEv2Parser extends BasicParser_1.BasicParser { + constructor() { + super(...arguments); + this.ape = {}; + } + static tryParseApeHeader(metadata, tokenizer, options) { + const apeParser = new APEv2Parser(); + apeParser.init(metadata, tokenizer, options); + return apeParser.tryParseApeHeader(); + } + /** + * Calculate the media file duration + * @param ah ApeHeader + * @return {number} duration in seconds + */ + static calculateDuration(ah) { + let duration = ah.totalFrames > 1 ? ah.blocksPerFrame * (ah.totalFrames - 1) : 0; + duration += ah.finalFrameBlocks; + return duration / ah.sampleRate; + } + /** + * Calculates the APEv1 / APEv2 first field offset + * @param reader + * @param offset + */ + static async findApeFooterOffset(reader, offset) { + // Search for APE footer header at the end of the file + const apeBuf = Buffer.alloc(APEv2Token_1.TagFooter.len); + await reader.randomRead(apeBuf, 0, APEv2Token_1.TagFooter.len, offset - APEv2Token_1.TagFooter.len); + const tagFooter = APEv2Token_1.TagFooter.get(apeBuf, 0); + if (tagFooter.ID === 'APETAGEX') { + debug(`APE footer header at offset=${offset}`); + return { footer: tagFooter, offset: offset - tagFooter.size }; + } + } + static parseTagFooter(metadata, buffer, options) { + const footer = APEv2Token_1.TagFooter.get(buffer, buffer.length - APEv2Token_1.TagFooter.len); + if (footer.ID !== preamble) + throw new Error('Unexpected APEv2 Footer ID preamble value.'); + strtok3.fromBuffer(buffer); + const apeParser = new APEv2Parser(); + apeParser.init(metadata, strtok3.fromBuffer(buffer), options); + return apeParser.parseTags(footer); + } + /** + * Parse APEv1 / APEv2 header if header signature found + */ + async tryParseApeHeader() { + if (this.tokenizer.fileInfo.size && this.tokenizer.fileInfo.size - this.tokenizer.position < APEv2Token_1.TagFooter.len) { + debug(`No APEv2 header found, end-of-file reached`); + return; + } + const footer = await this.tokenizer.peekToken(APEv2Token_1.TagFooter); + if (footer.ID === preamble) { + await this.tokenizer.ignore(APEv2Token_1.TagFooter.len); + return this.parseTags(footer); + } + else { + debug(`APEv2 header not found at offset=${this.tokenizer.position}`); + if (this.tokenizer.fileInfo.size) { + // Try to read the APEv2 header using just the footer-header + const remaining = this.tokenizer.fileInfo.size - this.tokenizer.position; // ToDo: take ID3v1 into account + const buffer = Buffer.alloc(remaining); + await this.tokenizer.readBuffer(buffer); + return APEv2Parser.parseTagFooter(this.metadata, buffer, this.options); + } + } + } + async parse() { + const descriptor = await this.tokenizer.readToken(APEv2Token_1.DescriptorParser); + if (descriptor.ID !== 'MAC ') + throw new Error('Unexpected descriptor ID'); + this.ape.descriptor = descriptor; + const lenExp = descriptor.descriptorBytes - APEv2Token_1.DescriptorParser.len; + const header = await (lenExp > 0 ? this.parseDescriptorExpansion(lenExp) : this.parseHeader()); + await this.tokenizer.ignore(header.forwardBytes); + return this.tryParseApeHeader(); + } + async parseTags(footer) { + const keyBuffer = Buffer.alloc(256); // maximum tag key length + let bytesRemaining = footer.size - APEv2Token_1.TagFooter.len; + debug(`Parse APE tags at offset=${this.tokenizer.position}, size=${bytesRemaining}`); + for (let i = 0; i < footer.fields; i++) { + if (bytesRemaining < APEv2Token_1.TagItemHeader.len) { + this.metadata.addWarning(`APEv2 Tag-header: ${footer.fields - i} items remaining, but no more tag data to read.`); + break; + } + // Only APEv2 tag has tag item headers + const tagItemHeader = await this.tokenizer.readToken(APEv2Token_1.TagItemHeader); + bytesRemaining -= APEv2Token_1.TagItemHeader.len + tagItemHeader.size; + await this.tokenizer.peekBuffer(keyBuffer, { length: Math.min(keyBuffer.length, bytesRemaining) }); + let zero = util.findZero(keyBuffer, 0, keyBuffer.length); + const key = await this.tokenizer.readToken(new token_types_1.StringType(zero, 'ascii')); + await this.tokenizer.ignore(1); + bytesRemaining -= key.length + 1; + switch (tagItemHeader.flags.dataType) { + case APEv2Token_1.DataType.text_utf8: { // utf-8 text-string + const value = await this.tokenizer.readToken(new token_types_1.StringType(tagItemHeader.size, 'utf8')); + const values = value.split(/\x00/g); + for (const val of values) { + this.metadata.addTag(tagFormat, key, val); + } + break; + } + case APEv2Token_1.DataType.binary: // binary (probably artwork) + if (this.options.skipCovers) { + await this.tokenizer.ignore(tagItemHeader.size); + } + else { + const picData = Buffer.alloc(tagItemHeader.size); + await this.tokenizer.readBuffer(picData); + zero = util.findZero(picData, 0, picData.length); + const description = picData.toString('utf8', 0, zero); + const data = Buffer.from(picData.slice(zero + 1)); + this.metadata.addTag(tagFormat, key, { + description, + data + }); + } + break; + case APEv2Token_1.DataType.external_info: + debug(`Ignore external info ${key}`); + await this.tokenizer.ignore(tagItemHeader.size); + break; + case APEv2Token_1.DataType.reserved: + debug(`Ignore external info ${key}`); + this.metadata.addWarning(`APEv2 header declares a reserved datatype for "${key}"`); + await this.tokenizer.ignore(tagItemHeader.size); + break; + } + } + } + async parseDescriptorExpansion(lenExp) { + await this.tokenizer.ignore(lenExp); + return this.parseHeader(); + } + async parseHeader() { + const header = await this.tokenizer.readToken(APEv2Token_1.Header); + // ToDo before + this.metadata.setFormat('lossless', true); + this.metadata.setFormat('container', 'Monkey\'s Audio'); + this.metadata.setFormat('bitsPerSample', header.bitsPerSample); + this.metadata.setFormat('sampleRate', header.sampleRate); + this.metadata.setFormat('numberOfChannels', header.channel); + this.metadata.setFormat('duration', APEv2Parser.calculateDuration(header)); + return { + forwardBytes: this.ape.descriptor.seekTableBytes + this.ape.descriptor.headerDataBytes + + this.ape.descriptor.apeFrameDataBytes + this.ape.descriptor.terminatingDataBytes + }; + } +} +exports.APEv2Parser = APEv2Parser; + + +/***/ }), + +/***/ 8414: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.APEv2TagMapper = void 0; +const CaseInsensitiveTagMap_1 = __webpack_require__(4132); +/** + * ID3v2.2 tag mappings + */ +const apev2TagMap = { + Title: 'title', + Artist: 'artist', + Artists: 'artists', + 'Album Artist': 'albumartist', + Album: 'album', + Year: 'date', + Originalyear: 'originalyear', + Originaldate: 'originaldate', + Comment: 'comment', + Track: 'track', + Disc: 'disk', + DISCNUMBER: 'disk', + Genre: 'genre', + 'Cover Art (Front)': 'picture', + 'Cover Art (Back)': 'picture', + Composer: 'composer', + Lyrics: 'lyrics', + ALBUMSORT: 'albumsort', + TITLESORT: 'titlesort', + WORK: 'work', + ARTISTSORT: 'artistsort', + ALBUMARTISTSORT: 'albumartistsort', + COMPOSERSORT: 'composersort', + Lyricist: 'lyricist', + Writer: 'writer', + Conductor: 'conductor', + // 'Performer=artist (instrument)': 'performer:instrument', + MixArtist: 'remixer', + Arranger: 'arranger', + Engineer: 'engineer', + Producer: 'producer', + DJMixer: 'djmixer', + Mixer: 'mixer', + Label: 'label', + Grouping: 'grouping', + Subtitle: 'subtitle', + DiscSubtitle: 'discsubtitle', + Compilation: 'compilation', + BPM: 'bpm', + Mood: 'mood', + Media: 'media', + CatalogNumber: 'catalognumber', + MUSICBRAINZ_ALBUMSTATUS: 'releasestatus', + MUSICBRAINZ_ALBUMTYPE: 'releasetype', + RELEASECOUNTRY: 'releasecountry', + Script: 'script', + Language: 'language', + Copyright: 'copyright', + LICENSE: 'license', + EncodedBy: 'encodedby', + EncoderSettings: 'encodersettings', + Barcode: 'barcode', + ISRC: 'isrc', + ASIN: 'asin', + musicbrainz_trackid: 'musicbrainz_recordingid', + musicbrainz_releasetrackid: 'musicbrainz_trackid', + MUSICBRAINZ_ALBUMID: 'musicbrainz_albumid', + MUSICBRAINZ_ARTISTID: 'musicbrainz_artistid', + MUSICBRAINZ_ALBUMARTISTID: 'musicbrainz_albumartistid', + MUSICBRAINZ_RELEASEGROUPID: 'musicbrainz_releasegroupid', + MUSICBRAINZ_WORKID: 'musicbrainz_workid', + MUSICBRAINZ_TRMID: 'musicbrainz_trmid', + MUSICBRAINZ_DISCID: 'musicbrainz_discid', + Acoustid_Id: 'acoustid_id', + ACOUSTID_FINGERPRINT: 'acoustid_fingerprint', + MUSICIP_PUID: 'musicip_puid', + Weblink: 'website', + REPLAYGAIN_TRACK_GAIN: 'replaygain_track_gain', + REPLAYGAIN_TRACK_PEAK: 'replaygain_track_peak', + MP3GAIN_MINMAX: 'replaygain_track_minmax', + MP3GAIN_UNDO: 'replaygain_undo' +}; +class APEv2TagMapper extends CaseInsensitiveTagMap_1.CaseInsensitiveTagMap { + constructor() { + super(['APEv2'], apev2TagMap); + } +} +exports.APEv2TagMapper = APEv2TagMapper; +//# sourceMappingURL=APEv2TagMapper.js.map + +/***/ }), + +/***/ 876: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isBitSet = exports.parseTagFlags = exports.TagField = exports.TagItemHeader = exports.TagFooter = exports.Header = exports.DescriptorParser = exports.DataType = void 0; +const Token = __webpack_require__(3416); +const FourCC_1 = __webpack_require__(8049); +var DataType; +(function (DataType) { + DataType[DataType["text_utf8"] = 0] = "text_utf8"; + DataType[DataType["binary"] = 1] = "binary"; + DataType[DataType["external_info"] = 2] = "external_info"; + DataType[DataType["reserved"] = 3] = "reserved"; +})(DataType = exports.DataType || (exports.DataType = {})); +/** + * APE_DESCRIPTOR: defines the sizes (and offsets) of all the pieces, as well as the MD5 checksum + */ +exports.DescriptorParser = { + len: 52, + get: (buf, off) => { + return { + // should equal 'MAC ' + ID: FourCC_1.FourCcToken.get(buf, off), + // versionIndex number * 1000 (3.81 = 3810) (remember that 4-byte alignment causes this to take 4-bytes) + version: Token.UINT32_LE.get(buf, off + 4) / 1000, + // the number of descriptor bytes (allows later expansion of this header) + descriptorBytes: Token.UINT32_LE.get(buf, off + 8), + // the number of header APE_HEADER bytes + headerBytes: Token.UINT32_LE.get(buf, off + 12), + // the number of header APE_HEADER bytes + seekTableBytes: Token.UINT32_LE.get(buf, off + 16), + // the number of header data bytes (from original file) + headerDataBytes: Token.UINT32_LE.get(buf, off + 20), + // the number of bytes of APE frame data + apeFrameDataBytes: Token.UINT32_LE.get(buf, off + 24), + // the high order number of APE frame data bytes + apeFrameDataBytesHigh: Token.UINT32_LE.get(buf, off + 28), + // the terminating data of the file (not including tag data) + terminatingDataBytes: Token.UINT32_LE.get(buf, off + 32), + // the MD5 hash of the file (see notes for usage... it's a little tricky) + fileMD5: new Token.Uint8ArrayType(16).get(buf, off + 36) + }; + } +}; +/** + * APE_HEADER: describes all of the necessary information about the APE file + */ +exports.Header = { + len: 24, + get: (buf, off) => { + return { + // the compression level (see defines I.E. COMPRESSION_LEVEL_FAST) + compressionLevel: Token.UINT16_LE.get(buf, off), + // any format flags (for future use) + formatFlags: Token.UINT16_LE.get(buf, off + 2), + // the number of audio blocks in one frame + blocksPerFrame: Token.UINT32_LE.get(buf, off + 4), + // the number of audio blocks in the final frame + finalFrameBlocks: Token.UINT32_LE.get(buf, off + 8), + // the total number of frames + totalFrames: Token.UINT32_LE.get(buf, off + 12), + // the bits per sample (typically 16) + bitsPerSample: Token.UINT16_LE.get(buf, off + 16), + // the number of channels (1 or 2) + channel: Token.UINT16_LE.get(buf, off + 18), + // the sample rate (typically 44100) + sampleRate: Token.UINT32_LE.get(buf, off + 20) + }; + } +}; +/** + * APE Tag Header/Footer Version 2.0 + * TAG: describes all the properties of the file [optional] + */ +exports.TagFooter = { + len: 32, + get: (buf, off) => { + return { + // should equal 'APETAGEX' + ID: new Token.StringType(8, 'ascii').get(buf, off), + // equals CURRENT_APE_TAG_VERSION + version: Token.UINT32_LE.get(buf, off + 8), + // the complete size of the tag, including this footer (excludes header) + size: Token.UINT32_LE.get(buf, off + 12), + // the number of fields in the tag + fields: Token.UINT32_LE.get(buf, off + 16), + // reserved for later use (must be zero), + flags: parseTagFlags(Token.UINT32_LE.get(buf, off + 20)) + }; + } +}; +/** + * APE Tag v2.0 Item Header + */ +exports.TagItemHeader = { + len: 8, + get: (buf, off) => { + return { + // Length of assigned value in bytes + size: Token.UINT32_LE.get(buf, off), + // reserved for later use (must be zero), + flags: parseTagFlags(Token.UINT32_LE.get(buf, off + 4)) + }; + } +}; +const TagField = footer => { + return new Token.Uint8ArrayType(footer.size - exports.TagFooter.len); +}; +exports.TagField = TagField; +function parseTagFlags(flags) { + return { + containsHeader: isBitSet(flags, 31), + containsFooter: isBitSet(flags, 30), + isHeader: isBitSet(flags, 31), + readOnly: isBitSet(flags, 0), + dataType: (flags & 6) >> 1 + }; +} +exports.parseTagFlags = parseTagFlags; +/** + * @param num {number} + * @param bit 0 is least significant bit (LSB) + * @return {boolean} true if bit is 1; otherwise false + */ +function isBitSet(num, bit) { + return (num & 1 << bit) !== 0; +} +exports.isBitSet = isBitSet; +//# sourceMappingURL=APEv2Token.js.map + +/***/ }), + +/***/ 5174: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +// ASF Objects +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.WmPictureToken = exports.MetadataLibraryObjectState = exports.MetadataObjectState = exports.ExtendedStreamPropertiesObjectState = exports.ExtendedContentDescriptionObjectState = exports.ContentDescriptionObjectState = exports.readCodecEntries = exports.HeaderExtensionObject = exports.StreamPropertiesObject = exports.FilePropertiesObject = exports.IgnoreObjectState = exports.State = exports.HeaderObjectToken = exports.TopLevelHeaderObjectToken = exports.DataType = void 0; +const util = __webpack_require__(3769); +const Token = __webpack_require__(3416); +const GUID_1 = __webpack_require__(8054); +const AsfUtil_1 = __webpack_require__(2252); +const ID3v2Token_1 = __webpack_require__(8281); +/** + * Data Type: Specifies the type of information being stored. The following values are recognized. + */ +var DataType; +(function (DataType) { + /** + * Unicode string. The data consists of a sequence of Unicode characters. + */ + DataType[DataType["UnicodeString"] = 0] = "UnicodeString"; + /** + * BYTE array. The type of data is implementation-specific. + */ + DataType[DataType["ByteArray"] = 1] = "ByteArray"; + /** + * BOOL. The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values. + */ + DataType[DataType["Bool"] = 2] = "Bool"; + /** + * DWORD. The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer. + */ + DataType[DataType["DWord"] = 3] = "DWord"; + /** + * QWORD. The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer. + */ + DataType[DataType["QWord"] = 4] = "QWord"; + /** + * WORD. The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. + */ + DataType[DataType["Word"] = 5] = "Word"; +})(DataType = exports.DataType || (exports.DataType = {})); +/** + * Token for: 3. ASF top-level Header Object + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3 + */ +exports.TopLevelHeaderObjectToken = { + len: 30, + get: (buf, off) => { + return { + objectId: GUID_1.default.fromBin(new Token.BufferType(16).get(buf, off)), + objectSize: Number(Token.UINT64_LE.get(buf, off + 16)), + numberOfHeaderObjects: Token.UINT32_LE.get(buf, off + 24) + // Reserved: 2 bytes + }; + } +}; +/** + * Token for: 3.1 Header Object (mandatory, one only) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_1 + */ +exports.HeaderObjectToken = { + len: 24, + get: (buf, off) => { + return { + objectId: GUID_1.default.fromBin(new Token.BufferType(16).get(buf, off)), + objectSize: Number(Token.UINT64_LE.get(buf, off + 16)) + }; + } +}; +class State { + constructor(header) { + this.len = Number(header.objectSize) - exports.HeaderObjectToken.len; + } + postProcessTag(tags, name, valueType, data) { + if (name === 'WM/Picture') { + tags.push({ id: name, value: WmPictureToken.fromBuffer(data) }); + } + else { + const parseAttr = AsfUtil_1.AsfUtil.getParserForAttr(valueType); + if (!parseAttr) { + throw new Error('unexpected value headerType: ' + valueType); + } + tags.push({ id: name, value: parseAttr(data) }); + } + } +} +exports.State = State; +// ToDo: use ignore type +class IgnoreObjectState extends State { + constructor(header) { + super(header); + } + get(buf, off) { + return null; + } +} +exports.IgnoreObjectState = IgnoreObjectState; +/** + * Token for: 3.2: File Properties Object (mandatory, one only) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_2 + */ +class FilePropertiesObject extends State { + constructor(header) { + super(header); + } + get(buf, off) { + return { + fileId: GUID_1.default.fromBin(buf, off), + fileSize: Token.UINT64_LE.get(buf, off + 16), + creationDate: Token.UINT64_LE.get(buf, off + 24), + dataPacketsCount: Token.UINT64_LE.get(buf, off + 32), + playDuration: Token.UINT64_LE.get(buf, off + 40), + sendDuration: Token.UINT64_LE.get(buf, off + 48), + preroll: Token.UINT64_LE.get(buf, off + 56), + flags: { + broadcast: util.getBit(buf, off + 64, 24), + seekable: util.getBit(buf, off + 64, 25) + }, + // flagsNumeric: Token.UINT32_LE.get(buf, off + 64), + minimumDataPacketSize: Token.UINT32_LE.get(buf, off + 68), + maximumDataPacketSize: Token.UINT32_LE.get(buf, off + 72), + maximumBitrate: Token.UINT32_LE.get(buf, off + 76) + }; + } +} +exports.FilePropertiesObject = FilePropertiesObject; +FilePropertiesObject.guid = GUID_1.default.FilePropertiesObject; +/** + * Token for: 3.3 Stream Properties Object (mandatory, one per stream) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_3 + */ +class StreamPropertiesObject extends State { + constructor(header) { + super(header); + } + get(buf, off) { + return { + streamType: GUID_1.default.decodeMediaType(GUID_1.default.fromBin(buf, off)), + errorCorrectionType: GUID_1.default.fromBin(buf, off + 8) + // ToDo + }; + } +} +exports.StreamPropertiesObject = StreamPropertiesObject; +StreamPropertiesObject.guid = GUID_1.default.StreamPropertiesObject; +/** + * 3.4: Header Extension Object (mandatory, one only) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_4 + */ +class HeaderExtensionObject { + constructor() { + this.len = 22; + } + get(buf, off) { + return { + reserved1: GUID_1.default.fromBin(buf, off), + reserved2: buf.readUInt16LE(off + 16), + extensionDataSize: buf.readUInt32LE(off + 18) + }; + } +} +exports.HeaderExtensionObject = HeaderExtensionObject; +HeaderExtensionObject.guid = GUID_1.default.HeaderExtensionObject; +/** + * 3.5: The Codec List Object provides user-friendly information about the codecs and formats used to encode the content found in the ASF file. + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_5 + */ +const CodecListObjectHeader = { + len: 20, + get: (buf, off) => { + return { + entryCount: buf.readUInt16LE(off + 16) + }; + } +}; +async function readString(tokenizer) { + const length = await tokenizer.readNumber(Token.UINT16_LE); + return (await tokenizer.readToken(new Token.StringType(length * 2, 'utf16le'))).replace('\0', ''); +} +/** + * 3.5: Read the Codec-List-Object, which provides user-friendly information about the codecs and formats used to encode the content found in the ASF file. + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_5 + */ +async function readCodecEntries(tokenizer) { + const codecHeader = await tokenizer.readToken(CodecListObjectHeader); + const entries = []; + for (let i = 0; i < codecHeader.entryCount; ++i) { + entries.push(await readCodecEntry(tokenizer)); + } + return entries; +} +exports.readCodecEntries = readCodecEntries; +async function readInformation(tokenizer) { + const length = await tokenizer.readNumber(Token.UINT16_LE); + const buf = Buffer.alloc(length); + await tokenizer.readBuffer(buf); + return buf; +} +/** + * Read Codec-Entries + * @param tokenizer + */ +async function readCodecEntry(tokenizer) { + const type = await tokenizer.readNumber(Token.UINT16_LE); + return { + type: { + videoCodec: (type & 0x0001) === 0x0001, + audioCodec: (type & 0x0002) === 0x0002 + }, + codecName: await readString(tokenizer), + description: await readString(tokenizer), + information: await readInformation(tokenizer) + }; +} +/** + * 3.10 Content Description Object (optional, one only) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_10 + */ +class ContentDescriptionObjectState extends State { + constructor(header) { + super(header); + } + get(buf, off) { + const tags = []; + let pos = off + 10; + for (let i = 0; i < ContentDescriptionObjectState.contentDescTags.length; ++i) { + const length = buf.readUInt16LE(off + i * 2); + if (length > 0) { + const tagName = ContentDescriptionObjectState.contentDescTags[i]; + const end = pos + length; + tags.push({ id: tagName, value: AsfUtil_1.AsfUtil.parseUnicodeAttr(buf.slice(pos, end)) }); + pos = end; + } + } + return tags; + } +} +exports.ContentDescriptionObjectState = ContentDescriptionObjectState; +ContentDescriptionObjectState.guid = GUID_1.default.ContentDescriptionObject; +ContentDescriptionObjectState.contentDescTags = ['Title', 'Author', 'Copyright', 'Description', 'Rating']; +/** + * 3.11 Extended Content Description Object (optional, one only) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/03_asf_top_level_header_object.html#3_11 + */ +class ExtendedContentDescriptionObjectState extends State { + constructor(header) { + super(header); + } + get(buf, off) { + const tags = []; + const attrCount = buf.readUInt16LE(off); + let pos = off + 2; + for (let i = 0; i < attrCount; i += 1) { + const nameLen = buf.readUInt16LE(pos); + pos += 2; + const name = AsfUtil_1.AsfUtil.parseUnicodeAttr(buf.slice(pos, pos + nameLen)); + pos += nameLen; + const valueType = buf.readUInt16LE(pos); + pos += 2; + const valueLen = buf.readUInt16LE(pos); + pos += 2; + const value = buf.slice(pos, pos + valueLen); + pos += valueLen; + this.postProcessTag(tags, name, valueType, value); + } + return tags; + } +} +exports.ExtendedContentDescriptionObjectState = ExtendedContentDescriptionObjectState; +ExtendedContentDescriptionObjectState.guid = GUID_1.default.ExtendedContentDescriptionObject; +/** + * 4.1 Extended Stream Properties Object (optional, 1 per media stream) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/04_objects_in_the_asf_header_extension_object.html#4_1 + */ +class ExtendedStreamPropertiesObjectState extends State { + constructor(header) { + super(header); + } + get(buf, off) { + return { + startTime: Token.UINT64_LE.get(buf, off), + endTime: Token.UINT64_LE.get(buf, off + 8), + dataBitrate: buf.readInt32LE(off + 12), + bufferSize: buf.readInt32LE(off + 16), + initialBufferFullness: buf.readInt32LE(off + 20), + alternateDataBitrate: buf.readInt32LE(off + 24), + alternateBufferSize: buf.readInt32LE(off + 28), + alternateInitialBufferFullness: buf.readInt32LE(off + 32), + maximumObjectSize: buf.readInt32LE(off + 36), + flags: { + reliableFlag: util.getBit(buf, off + 40, 0), + seekableFlag: util.getBit(buf, off + 40, 1), + resendLiveCleanpointsFlag: util.getBit(buf, off + 40, 2) + }, + // flagsNumeric: Token.UINT32_LE.get(buf, off + 64), + streamNumber: buf.readInt16LE(off + 42), + streamLanguageId: buf.readInt16LE(off + 44), + averageTimePerFrame: buf.readInt32LE(off + 52), + streamNameCount: buf.readInt32LE(off + 54), + payloadExtensionSystems: buf.readInt32LE(off + 56), + streamNames: [], + streamPropertiesObject: null + }; + } +} +exports.ExtendedStreamPropertiesObjectState = ExtendedStreamPropertiesObjectState; +ExtendedStreamPropertiesObjectState.guid = GUID_1.default.ExtendedStreamPropertiesObject; +/** + * 4.7 Metadata Object (optional, 0 or 1) + * Ref: http://drang.s4.xrea.com/program/tips/id3tag/wmp/04_objects_in_the_asf_header_extension_object.html#4_7 + */ +class MetadataObjectState extends State { + constructor(header) { + super(header); + } + get(uint8Array, off) { + const tags = []; + const buf = Buffer.from(uint8Array); + const descriptionRecordsCount = buf.readUInt16LE(off); + let pos = off + 2; + for (let i = 0; i < descriptionRecordsCount; i += 1) { + pos += 4; + const nameLen = buf.readUInt16LE(pos); + pos += 2; + const dataType = buf.readUInt16LE(pos); + pos += 2; + const dataLen = buf.readUInt32LE(pos); + pos += 4; + const name = AsfUtil_1.AsfUtil.parseUnicodeAttr(buf.slice(pos, pos + nameLen)); + pos += nameLen; + const data = buf.slice(pos, pos + dataLen); + pos += dataLen; + this.postProcessTag(tags, name, dataType, data); + } + return tags; + } +} +exports.MetadataObjectState = MetadataObjectState; +MetadataObjectState.guid = GUID_1.default.MetadataObject; +// 4.8 Metadata Library Object (optional, 0 or 1) +class MetadataLibraryObjectState extends MetadataObjectState { + constructor(header) { + super(header); + } +} +exports.MetadataLibraryObjectState = MetadataLibraryObjectState; +MetadataLibraryObjectState.guid = GUID_1.default.MetadataLibraryObject; +/** + * Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd757977(v=vs.85).aspx + */ +class WmPictureToken { + constructor(len) { + this.len = len; + } + static fromBase64(base64str) { + return this.fromBuffer(Buffer.from(base64str, 'base64')); + } + static fromBuffer(buffer) { + const pic = new WmPictureToken(buffer.length); + return pic.get(buffer, 0); + } + get(buffer, offset) { + const typeId = buffer.readUInt8(offset++); + const size = buffer.readInt32LE(offset); + let index = 5; + while (buffer.readUInt16BE(index) !== 0) { + index += 2; + } + const format = buffer.slice(5, index).toString('utf16le'); + while (buffer.readUInt16BE(index) !== 0) { + index += 2; + } + const description = buffer.slice(5, index).toString('utf16le'); + return { + type: ID3v2Token_1.AttachedPictureType[typeId], + format, + description, + size, + data: buffer.slice(index + 4) + }; + } +} +exports.WmPictureToken = WmPictureToken; + + +/***/ }), + +/***/ 1004: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AsfParser = void 0; +const debug_1 = __webpack_require__(1227); +const type_1 = __webpack_require__(6032); +const GUID_1 = __webpack_require__(8054); +const AsfObject = __webpack_require__(5174); +const BasicParser_1 = __webpack_require__(7805); +const debug = (0, debug_1.default)('music-metadata:parser:ASF'); +const headerType = 'asf'; +/** + * Windows Media Metadata Usage Guidelines + * - Ref: https://msdn.microsoft.com/en-us/library/ms867702.aspx + * + * Ref: + * - https://tools.ietf.org/html/draft-fleischman-asf-01 + * - https://hwiegman.home.xs4all.nl/fileformats/asf/ASF_Specification.pdf + * - http://drang.s4.xrea.com/program/tips/id3tag/wmp/index.html + * - https://msdn.microsoft.com/en-us/library/windows/desktop/ee663575(v=vs.85).aspx + */ +class AsfParser extends BasicParser_1.BasicParser { + async parse() { + const header = await this.tokenizer.readToken(AsfObject.TopLevelHeaderObjectToken); + if (!header.objectId.equals(GUID_1.default.HeaderObject)) { + throw new Error('expected asf header; but was not found; got: ' + header.objectId.str); + } + try { + await this.parseObjectHeader(header.numberOfHeaderObjects); + } + catch (err) { + debug('Error while parsing ASF: %s', err); + } + } + async parseObjectHeader(numberOfObjectHeaders) { + let tags; + do { + // Parse common header of the ASF Object (3.1) + const header = await this.tokenizer.readToken(AsfObject.HeaderObjectToken); + // Parse data part of the ASF Object + debug('header GUID=%s', header.objectId.str); + switch (header.objectId.str) { + case AsfObject.FilePropertiesObject.guid.str: // 3.2 + const fpo = await this.tokenizer.readToken(new AsfObject.FilePropertiesObject(header)); + this.metadata.setFormat('duration', Number(fpo.playDuration / BigInt(1000)) / 10000 - Number(fpo.preroll) / 1000); + this.metadata.setFormat('bitrate', fpo.maximumBitrate); + break; + case AsfObject.StreamPropertiesObject.guid.str: // 3.3 + const spo = await this.tokenizer.readToken(new AsfObject.StreamPropertiesObject(header)); + this.metadata.setFormat('container', 'ASF/' + spo.streamType); + break; + case AsfObject.HeaderExtensionObject.guid.str: // 3.4 + const extHeader = await this.tokenizer.readToken(new AsfObject.HeaderExtensionObject()); + await this.parseExtensionObject(extHeader.extensionDataSize); + break; + case AsfObject.ContentDescriptionObjectState.guid.str: // 3.10 + tags = await this.tokenizer.readToken(new AsfObject.ContentDescriptionObjectState(header)); + this.addTags(tags); + break; + case AsfObject.ExtendedContentDescriptionObjectState.guid.str: // 3.11 + tags = await this.tokenizer.readToken(new AsfObject.ExtendedContentDescriptionObjectState(header)); + this.addTags(tags); + break; + case GUID_1.default.CodecListObject.str: + const codecs = await AsfObject.readCodecEntries(this.tokenizer); + codecs.forEach(codec => { + this.metadata.addStreamInfo({ + type: codec.type.videoCodec ? type_1.TrackType.video : type_1.TrackType.audio, + codecName: codec.codecName + }); + }); + const audioCodecs = codecs.filter(codec => codec.type.audioCodec).map(codec => codec.codecName).join('/'); + this.metadata.setFormat('codec', audioCodecs); + break; + case GUID_1.default.StreamBitratePropertiesObject.str: + // ToDo? + await this.tokenizer.ignore(header.objectSize - AsfObject.HeaderObjectToken.len); + break; + case GUID_1.default.PaddingObject.str: + // ToDo: register bytes pad + debug('Padding: %s bytes', header.objectSize - AsfObject.HeaderObjectToken.len); + await this.tokenizer.ignore(header.objectSize - AsfObject.HeaderObjectToken.len); + break; + default: + this.metadata.addWarning('Ignore ASF-Object-GUID: ' + header.objectId.str); + debug('Ignore ASF-Object-GUID: %s', header.objectId.str); + await this.tokenizer.readToken(new AsfObject.IgnoreObjectState(header)); + } + } while (--numberOfObjectHeaders); + // done + } + addTags(tags) { + tags.forEach(tag => { + this.metadata.addTag(headerType, tag.id, tag.value); + }); + } + async parseExtensionObject(extensionSize) { + do { + // Parse common header of the ASF Object (3.1) + const header = await this.tokenizer.readToken(AsfObject.HeaderObjectToken); + const remaining = header.objectSize - AsfObject.HeaderObjectToken.len; + // Parse data part of the ASF Object + switch (header.objectId.str) { + case AsfObject.ExtendedStreamPropertiesObjectState.guid.str: // 4.1 + // ToDo: extended stream header properties are ignored + await this.tokenizer.readToken(new AsfObject.ExtendedStreamPropertiesObjectState(header)); + break; + case AsfObject.MetadataObjectState.guid.str: // 4.7 + const moTags = await this.tokenizer.readToken(new AsfObject.MetadataObjectState(header)); + this.addTags(moTags); + break; + case AsfObject.MetadataLibraryObjectState.guid.str: // 4.8 + const mlTags = await this.tokenizer.readToken(new AsfObject.MetadataLibraryObjectState(header)); + this.addTags(mlTags); + break; + case GUID_1.default.PaddingObject.str: + // ToDo: register bytes pad + await this.tokenizer.ignore(remaining); + break; + case GUID_1.default.CompatibilityObject.str: + this.tokenizer.ignore(remaining); + break; + case GUID_1.default.ASF_Index_Placeholder_Object.str: + await this.tokenizer.ignore(remaining); + break; + default: + this.metadata.addWarning('Ignore ASF-Object-GUID: ' + header.objectId.str); + // console.log("Ignore ASF-Object-GUID: %s", header.objectId.str); + await this.tokenizer.readToken(new AsfObject.IgnoreObjectState(header)); + break; + } + extensionSize -= header.objectSize; + } while (extensionSize > 0); + } +} +exports.AsfParser = AsfParser; + + +/***/ }), + +/***/ 9004: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AsfTagMapper = void 0; +const GenericTagMapper_1 = __webpack_require__(9918); +/** + * ASF Metadata tag mappings. + * See http://msdn.microsoft.com/en-us/library/ms867702.aspx + */ +const asfTagMap = { + Title: 'title', + Author: 'artist', + 'WM/AlbumArtist': 'albumartist', + 'WM/AlbumTitle': 'album', + 'WM/Year': 'date', + 'WM/OriginalReleaseTime': 'originaldate', + 'WM/OriginalReleaseYear': 'originalyear', + Description: 'comment', + 'WM/TrackNumber': 'track', + 'WM/PartOfSet': 'disk', + 'WM/Genre': 'genre', + 'WM/Composer': 'composer', + 'WM/Lyrics': 'lyrics', + 'WM/AlbumSortOrder': 'albumsort', + 'WM/TitleSortOrder': 'titlesort', + 'WM/ArtistSortOrder': 'artistsort', + 'WM/AlbumArtistSortOrder': 'albumartistsort', + 'WM/ComposerSortOrder': 'composersort', + 'WM/Writer': 'lyricist', + 'WM/Conductor': 'conductor', + 'WM/ModifiedBy': 'remixer', + 'WM/Engineer': 'engineer', + 'WM/Producer': 'producer', + 'WM/DJMixer': 'djmixer', + 'WM/Mixer': 'mixer', + 'WM/Publisher': 'label', + 'WM/ContentGroupDescription': 'grouping', + 'WM/SubTitle': 'subtitle', + 'WM/SetSubTitle': 'discsubtitle', + // 'WM/PartOfSet': 'totaldiscs', + 'WM/IsCompilation': 'compilation', + 'WM/SharedUserRating': 'rating', + 'WM/BeatsPerMinute': 'bpm', + 'WM/Mood': 'mood', + 'WM/Media': 'media', + 'WM/CatalogNo': 'catalognumber', + 'MusicBrainz/Album Status': 'releasestatus', + 'MusicBrainz/Album Type': 'releasetype', + 'MusicBrainz/Album Release Country': 'releasecountry', + 'WM/Script': 'script', + 'WM/Language': 'language', + Copyright: 'copyright', + LICENSE: 'license', + 'WM/EncodedBy': 'encodedby', + 'WM/EncodingSettings': 'encodersettings', + 'WM/Barcode': 'barcode', + 'WM/ISRC': 'isrc', + 'MusicBrainz/Track Id': 'musicbrainz_recordingid', + 'MusicBrainz/Release Track Id': 'musicbrainz_trackid', + 'MusicBrainz/Album Id': 'musicbrainz_albumid', + 'MusicBrainz/Artist Id': 'musicbrainz_artistid', + 'MusicBrainz/Album Artist Id': 'musicbrainz_albumartistid', + 'MusicBrainz/Release Group Id': 'musicbrainz_releasegroupid', + 'MusicBrainz/Work Id': 'musicbrainz_workid', + 'MusicBrainz/TRM Id': 'musicbrainz_trmid', + 'MusicBrainz/Disc Id': 'musicbrainz_discid', + 'Acoustid/Id': 'acoustid_id', + 'Acoustid/Fingerprint': 'acoustid_fingerprint', + 'MusicIP/PUID': 'musicip_puid', + 'WM/ARTISTS': 'artists', + 'WM/InitialKey': 'key', + ASIN: 'asin', + 'WM/Work': 'work', + 'WM/AuthorURL': 'website', + 'WM/Picture': 'picture' +}; +class AsfTagMapper extends GenericTagMapper_1.CommonTagMapper { + static toRating(rating) { + return { + rating: parseFloat(rating + 1) / 5 + }; + } + constructor() { + super(['asf'], asfTagMap); + } + postMap(tag) { + switch (tag.id) { + case 'WM/SharedUserRating': + const keys = tag.id.split(':'); + tag.value = AsfTagMapper.toRating(tag.value); + tag.id = keys[0]; + break; + } + } +} +exports.AsfTagMapper = AsfTagMapper; +//# sourceMappingURL=AsfTagMapper.js.map + +/***/ }), + +/***/ 2252: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AsfUtil = void 0; +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +class AsfUtil { + static getParserForAttr(i) { + return AsfUtil.attributeParsers[i]; + } + static parseUnicodeAttr(uint8Array) { + return util.stripNulls(util.decodeString(uint8Array, 'utf16le')); + } + static parseByteArrayAttr(buf) { + return Buffer.from(buf); + } + static parseBoolAttr(buf, offset = 0) { + return AsfUtil.parseWordAttr(buf, offset) === 1; + } + static parseDWordAttr(buf, offset = 0) { + return buf.readUInt32LE(offset); + } + static parseQWordAttr(buf, offset = 0) { + return Token.UINT64_LE.get(buf, offset); + } + static parseWordAttr(buf, offset = 0) { + return buf.readUInt16LE(offset); + } +} +exports.AsfUtil = AsfUtil; +AsfUtil.attributeParsers = [ + AsfUtil.parseUnicodeAttr, + AsfUtil.parseByteArrayAttr, + AsfUtil.parseBoolAttr, + AsfUtil.parseDWordAttr, + AsfUtil.parseQWordAttr, + AsfUtil.parseWordAttr, + AsfUtil.parseByteArrayAttr +]; + + +/***/ }), + +/***/ 8054: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +/** + * Ref: + * - https://tools.ietf.org/html/draft-fleischman-asf-01, Appendix A: ASF GUIDs + * - http://drang.s4.xrea.com/program/tips/id3tag/wmp/10_asf_guids.html + * - http://drang.s4.xrea.com/program/tips/id3tag/wmp/index.html + * - http://drang.s4.xrea.com/program/tips/id3tag/wmp/10_asf_guids.html + * + * ASF File Structure: + * - https://msdn.microsoft.com/en-us/library/windows/desktop/ee663575(v=vs.85).aspx + * + * ASF GUIDs: + * - http://drang.s4.xrea.com/program/tips/id3tag/wmp/10_asf_guids.html + * - https://github.com/dji-sdk/FFmpeg/blob/master/libavformat/asf.c + */ +class GUID { + constructor(str) { + this.str = str; + } + static fromBin(bin, offset = 0) { + return new GUID(this.decode(bin, offset)); + } + /** + * Decode GUID in format like "B503BF5F-2EA9-CF11-8EE3-00C00C205365" + * @param objectId Binary GUID + * @param offset Read offset in bytes, default 0 + * @returns GUID as dashed hexadecimal representation + */ + static decode(objectId, offset = 0) { + const guid = objectId.readUInt32LE(offset).toString(16) + "-" + + objectId.readUInt16LE(offset + 4).toString(16) + "-" + + objectId.readUInt16LE(offset + 6).toString(16) + "-" + + objectId.readUInt16BE(offset + 8).toString(16) + "-" + + objectId.slice(offset + 10, offset + 16).toString('hex'); + return guid.toUpperCase(); + } + /** + * Decode stream type + * @param mediaType Media type GUID + * @returns Media type + */ + static decodeMediaType(mediaType) { + switch (mediaType.str) { + case GUID.AudioMedia.str: return 'audio'; + case GUID.VideoMedia.str: return 'video'; + case GUID.CommandMedia.str: return 'command'; + case GUID.Degradable_JPEG_Media.str: return 'degradable-jpeg'; + case GUID.FileTransferMedia.str: return 'file-transfer'; + case GUID.BinaryMedia.str: return 'binary'; + } + } + /** + * Encode GUID + * @param guid GUID like: "B503BF5F-2EA9-CF11-8EE3-00C00C205365" + * @returns Encoded Binary GUID + */ + static encode(str) { + const bin = Buffer.alloc(16); + bin.writeUInt32LE(parseInt(str.slice(0, 8), 16), 0); + bin.writeUInt16LE(parseInt(str.slice(9, 13), 16), 4); + bin.writeUInt16LE(parseInt(str.slice(14, 18), 16), 6); + Buffer.from(str.slice(19, 23), "hex").copy(bin, 8); + Buffer.from(str.slice(24), "hex").copy(bin, 10); + return bin; + } + equals(guid) { + return this.str === guid.str; + } + toBin() { + return GUID.encode(this.str); + } +} +exports["default"] = GUID; +// 10.1 Top-level ASF object GUIDs +GUID.HeaderObject = new GUID("75B22630-668E-11CF-A6D9-00AA0062CE6C"); +GUID.DataObject = new GUID("75B22636-668E-11CF-A6D9-00AA0062CE6C"); +GUID.SimpleIndexObject = new GUID("33000890-E5B1-11CF-89F4-00A0C90349CB"); +GUID.IndexObject = new GUID("D6E229D3-35DA-11D1-9034-00A0C90349BE"); +GUID.MediaObjectIndexObject = new GUID("FEB103F8-12AD-4C64-840F-2A1D2F7AD48C"); +GUID.TimecodeIndexObject = new GUID("3CB73FD0-0C4A-4803-953D-EDF7B6228F0C"); +// 10.2 Header Object GUIDs +GUID.FilePropertiesObject = new GUID("8CABDCA1-A947-11CF-8EE4-00C00C205365"); +GUID.StreamPropertiesObject = new GUID("B7DC0791-A9B7-11CF-8EE6-00C00C205365"); +GUID.HeaderExtensionObject = new GUID("5FBF03B5-A92E-11CF-8EE3-00C00C205365"); +GUID.CodecListObject = new GUID("86D15240-311D-11D0-A3A4-00A0C90348F6"); +GUID.ScriptCommandObject = new GUID("1EFB1A30-0B62-11D0-A39B-00A0C90348F6"); +GUID.MarkerObject = new GUID("F487CD01-A951-11CF-8EE6-00C00C205365"); +GUID.BitrateMutualExclusionObject = new GUID("D6E229DC-35DA-11D1-9034-00A0C90349BE"); +GUID.ErrorCorrectionObject = new GUID("75B22635-668E-11CF-A6D9-00AA0062CE6C"); +GUID.ContentDescriptionObject = new GUID("75B22633-668E-11CF-A6D9-00AA0062CE6C"); +GUID.ExtendedContentDescriptionObject = new GUID("D2D0A440-E307-11D2-97F0-00A0C95EA850"); +GUID.ContentBrandingObject = new GUID("2211B3FA-BD23-11D2-B4B7-00A0C955FC6E"); +GUID.StreamBitratePropertiesObject = new GUID("7BF875CE-468D-11D1-8D82-006097C9A2B2"); +GUID.ContentEncryptionObject = new GUID("2211B3FB-BD23-11D2-B4B7-00A0C955FC6E"); +GUID.ExtendedContentEncryptionObject = new GUID("298AE614-2622-4C17-B935-DAE07EE9289C"); +GUID.DigitalSignatureObject = new GUID("2211B3FC-BD23-11D2-B4B7-00A0C955FC6E"); +GUID.PaddingObject = new GUID("1806D474-CADF-4509-A4BA-9AABCB96AAE8"); +// 10.3 Header Extension Object GUIDs +GUID.ExtendedStreamPropertiesObject = new GUID("14E6A5CB-C672-4332-8399-A96952065B5A"); +GUID.AdvancedMutualExclusionObject = new GUID("A08649CF-4775-4670-8A16-6E35357566CD"); +GUID.GroupMutualExclusionObject = new GUID("D1465A40-5A79-4338-B71B-E36B8FD6C249"); +GUID.StreamPrioritizationObject = new GUID("D4FED15B-88D3-454F-81F0-ED5C45999E24"); +GUID.BandwidthSharingObject = new GUID("A69609E6-517B-11D2-B6AF-00C04FD908E9"); +GUID.LanguageListObject = new GUID("7C4346A9-EFE0-4BFC-B229-393EDE415C85"); +GUID.MetadataObject = new GUID("C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA"); +GUID.MetadataLibraryObject = new GUID("44231C94-9498-49D1-A141-1D134E457054"); +GUID.IndexParametersObject = new GUID("D6E229DF-35DA-11D1-9034-00A0C90349BE"); +GUID.MediaObjectIndexParametersObject = new GUID("6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7"); +GUID.TimecodeIndexParametersObject = new GUID("F55E496D-9797-4B5D-8C8B-604DFE9BFB24"); +GUID.CompatibilityObject = new GUID("26F18B5D-4584-47EC-9F5F-0E651F0452C9"); +GUID.AdvancedContentEncryptionObject = new GUID("43058533-6981-49E6-9B74-AD12CB86D58C"); +// 10.4 Stream Properties Object Stream Type GUIDs +GUID.AudioMedia = new GUID("F8699E40-5B4D-11CF-A8FD-00805F5C442B"); +GUID.VideoMedia = new GUID("BC19EFC0-5B4D-11CF-A8FD-00805F5C442B"); +GUID.CommandMedia = new GUID("59DACFC0-59E6-11D0-A3AC-00A0C90348F6"); +GUID.JFIF_Media = new GUID("B61BE100-5B4E-11CF-A8FD-00805F5C442B"); +GUID.Degradable_JPEG_Media = new GUID("35907DE0-E415-11CF-A917-00805F5C442B"); +GUID.FileTransferMedia = new GUID("91BD222C-F21C-497A-8B6D-5AA86BFC0185"); +GUID.BinaryMedia = new GUID("3AFB65E2-47EF-40F2-AC2C-70A90D71D343"); +GUID.ASF_Index_Placeholder_Object = new GUID("D9AADE20-7C17-4F9C-BC28-8555DD98E2A2"); + + +/***/ }), + +/***/ 7805: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BasicParser = void 0; +class BasicParser { + /** + * Initialize parser with output (metadata), input (tokenizer) & parsing options (options). + * @param {INativeMetadataCollector} metadata Output + * @param {ITokenizer} tokenizer Input + * @param {IOptions} options Parsing options + */ + init(metadata, tokenizer, options) { + this.metadata = metadata; + this.tokenizer = tokenizer; + this.options = options; + return this; + } +} +exports.BasicParser = BasicParser; + + +/***/ }), + +/***/ 4132: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.CaseInsensitiveTagMap = void 0; +const GenericTagMapper_1 = __webpack_require__(9918); +class CaseInsensitiveTagMap extends GenericTagMapper_1.CommonTagMapper { + constructor(tagTypes, tagMap) { + const upperCaseMap = {}; + for (const tag of Object.keys(tagMap)) { + upperCaseMap[tag.toUpperCase()] = tagMap[tag]; + } + super(tagTypes, upperCaseMap); + } + /** + * @tag Native header tag + * @return common tag name (alias) + */ + getCommonName(tag) { + return this.tagMap[tag.toUpperCase()]; + } +} +exports.CaseInsensitiveTagMap = CaseInsensitiveTagMap; +//# sourceMappingURL=CaseInsensitiveTagMap.js.map + +/***/ }), + +/***/ 6592: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.CombinedTagMapper = void 0; +const ID3v1TagMap_1 = __webpack_require__(2939); +const ID3v24TagMapper_1 = __webpack_require__(4005); +const AsfTagMapper_1 = __webpack_require__(9004); +const ID3v22TagMapper_1 = __webpack_require__(7183); +const APEv2TagMapper_1 = __webpack_require__(8414); +const MP4TagMapper_1 = __webpack_require__(7852); +const VorbisTagMapper_1 = __webpack_require__(9860); +const RiffInfoTagMap_1 = __webpack_require__(5756); +const MatroskaTagMapper_1 = __webpack_require__(5481); +class CombinedTagMapper { + constructor() { + this.tagMappers = {}; + [ + new ID3v1TagMap_1.ID3v1TagMapper(), + new ID3v22TagMapper_1.ID3v22TagMapper(), + new ID3v24TagMapper_1.ID3v24TagMapper(), + new MP4TagMapper_1.MP4TagMapper(), + new MP4TagMapper_1.MP4TagMapper(), + new VorbisTagMapper_1.VorbisTagMapper(), + new APEv2TagMapper_1.APEv2TagMapper(), + new AsfTagMapper_1.AsfTagMapper(), + new RiffInfoTagMap_1.RiffInfoTagMapper(), + new MatroskaTagMapper_1.MatroskaTagMapper() + ].forEach(mapper => { + this.registerTagMapper(mapper); + }); + } + /** + * Convert native to generic (common) tags + * @param tagType Originating tag format + * @param tag Native tag to map to a generic tag id + * @param warnings + * @return Generic tag result (output of this function) + */ + mapTag(tagType, tag, warnings) { + const tagMapper = this.tagMappers[tagType]; + if (tagMapper) { + return this.tagMappers[tagType].mapGenericTag(tag, warnings); + } + throw new Error('No generic tag mapper defined for tag-format: ' + tagType); + } + registerTagMapper(genericTagMapper) { + for (const tagType of genericTagMapper.tagTypes) { + this.tagMappers[tagType] = genericTagMapper; + } + } +} +exports.CombinedTagMapper = CombinedTagMapper; +//# sourceMappingURL=CombinedTagMapper.js.map + +/***/ }), + +/***/ 8049: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.FourCcToken = void 0; +const util = __webpack_require__(3769); +const validFourCC = /^[\x21-\x7e©][\x20-\x7e\x00()]{3}/; +/** + * Token for read FourCC + * Ref: https://en.wikipedia.org/wiki/FourCC + */ +exports.FourCcToken = { + len: 4, + get: (buf, off) => { + const id = buf.toString('binary', off, off + exports.FourCcToken.len); + switch (id) { + default: + if (!id.match(validFourCC)) { + throw new Error(`FourCC contains invalid characters: ${util.a2hex(id)} "${id}"`); + } + } + return id; + }, + put: (buffer, offset, id) => { + const str = Buffer.from(id, 'binary'); + if (str.length !== 4) + throw new Error('Invalid length'); + return str.copy(buffer, offset); + } +}; +//# sourceMappingURL=FourCC.js.map + +/***/ }), + +/***/ 9918: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.CommonTagMapper = void 0; +class CommonTagMapper { + constructor(tagTypes, tagMap) { + this.tagTypes = tagTypes; + this.tagMap = tagMap; + } + static toIntOrNull(str) { + const cleaned = parseInt(str, 10); + return isNaN(cleaned) ? null : cleaned; + } + // TODO: a string of 1of1 would fail to be converted + // converts 1/10 to no : 1, of : 10 + // or 1 to no : 1, of : 0 + static normalizeTrack(origVal) { + const split = origVal.toString().split('/'); + return { + no: parseInt(split[0], 10) || null, + of: parseInt(split[1], 10) || null + }; + } + /** + * Process and set common tags + * write common tags to + * @param tag Native tag + * @param warnings Register warnings + * @return common name + */ + mapGenericTag(tag, warnings) { + tag = { id: tag.id, value: tag.value }; // clone object + this.postMap(tag, warnings); + // Convert native tag event to generic 'alias' tag + const id = this.getCommonName(tag.id); + return id ? { id, value: tag.value } : null; + } + /** + * Convert native tag key to common tag key + * @tag Native header tag + * @return common tag name (alias) + */ + getCommonName(tag) { + return this.tagMap[tag]; + } + /** + * Handle post mapping exceptions / correction + * @param tag Tag e.g. {"©alb", "Buena Vista Social Club") + * @param warnings Used to register warnings + */ + postMap(tag, warnings) { + return; + } +} +exports.CommonTagMapper = CommonTagMapper; +CommonTagMapper.maxRatingScore = 1; +//# sourceMappingURL=GenericTagMapper.js.map + +/***/ }), + +/***/ 103: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.isUnique = exports.isSingleton = exports.commonTags = void 0; +exports.commonTags = { + year: { multiple: false }, + track: { multiple: false }, + disk: { multiple: false }, + title: { multiple: false }, + artist: { multiple: false }, + artists: { multiple: true, unique: true }, + albumartist: { multiple: false }, + album: { multiple: false }, + date: { multiple: false }, + originaldate: { multiple: false }, + originalyear: { multiple: false }, + comment: { multiple: true, unique: false }, + genre: { multiple: true, unique: true }, + picture: { multiple: true, unique: true }, + composer: { multiple: true, unique: true }, + lyrics: { multiple: true, unique: false }, + albumsort: { multiple: false, unique: true }, + titlesort: { multiple: false, unique: true }, + work: { multiple: false, unique: true }, + artistsort: { multiple: false, unique: true }, + albumartistsort: { multiple: false, unique: true }, + composersort: { multiple: false, unique: true }, + lyricist: { multiple: true, unique: true }, + writer: { multiple: true, unique: true }, + conductor: { multiple: true, unique: true }, + remixer: { multiple: true, unique: true }, + arranger: { multiple: true, unique: true }, + engineer: { multiple: true, unique: true }, + producer: { multiple: true, unique: true }, + technician: { multiple: true, unique: true }, + djmixer: { multiple: true, unique: true }, + mixer: { multiple: true, unique: true }, + label: { multiple: true, unique: true }, + grouping: { multiple: false }, + subtitle: { multiple: true }, + discsubtitle: { multiple: false }, + totaltracks: { multiple: false }, + totaldiscs: { multiple: false }, + compilation: { multiple: false }, + rating: { multiple: true }, + bpm: { multiple: false }, + mood: { multiple: false }, + media: { multiple: false }, + catalognumber: { multiple: true, unique: true }, + tvShow: { multiple: false }, + tvShowSort: { multiple: false }, + tvSeason: { multiple: false }, + tvEpisode: { multiple: false }, + tvEpisodeId: { multiple: false }, + tvNetwork: { multiple: false }, + podcast: { multiple: false }, + podcasturl: { multiple: false }, + releasestatus: { multiple: false }, + releasetype: { multiple: true }, + releasecountry: { multiple: false }, + script: { multiple: false }, + language: { multiple: false }, + copyright: { multiple: false }, + license: { multiple: false }, + encodedby: { multiple: false }, + encodersettings: { multiple: false }, + gapless: { multiple: false }, + barcode: { multiple: false }, + isrc: { multiple: true }, + asin: { multiple: false }, + musicbrainz_recordingid: { multiple: false }, + musicbrainz_trackid: { multiple: false }, + musicbrainz_albumid: { multiple: false }, + musicbrainz_artistid: { multiple: true }, + musicbrainz_albumartistid: { multiple: true }, + musicbrainz_releasegroupid: { multiple: false }, + musicbrainz_workid: { multiple: false }, + musicbrainz_trmid: { multiple: false }, + musicbrainz_discid: { multiple: false }, + acoustid_id: { multiple: false }, + acoustid_fingerprint: { multiple: false }, + musicip_puid: { multiple: false }, + musicip_fingerprint: { multiple: false }, + website: { multiple: false }, + 'performer:instrument': { multiple: true, unique: true }, + averageLevel: { multiple: false }, + peakLevel: { multiple: false }, + notes: { multiple: true, unique: false }, + key: { multiple: false }, + originalalbum: { multiple: false }, + originalartist: { multiple: false }, + discogs_artist_id: { multiple: true, unique: true }, + discogs_release_id: { multiple: false }, + discogs_label_id: { multiple: false }, + discogs_master_release_id: { multiple: false }, + discogs_votes: { multiple: false }, + discogs_rating: { multiple: false }, + replaygain_track_peak: { multiple: false }, + replaygain_track_gain: { multiple: false }, + replaygain_album_peak: { multiple: false }, + replaygain_album_gain: { multiple: false }, + replaygain_track_minmax: { multiple: false }, + replaygain_album_minmax: { multiple: false }, + replaygain_undo: { multiple: false }, + description: { multiple: true }, + longDescription: { multiple: false }, + category: { multiple: true }, + hdVideo: { multiple: false }, + keywords: { multiple: true }, + movement: { multiple: false }, + movementIndex: { multiple: false }, + movementTotal: { multiple: false }, + podcastId: { multiple: false }, + showMovement: { multiple: false }, + stik: { multiple: false } +}; +/** + * @param alias Name of common tag + * @returns {boolean|*} true if given alias is mapped as a singleton', otherwise false + */ +function isSingleton(alias) { + return exports.commonTags.hasOwnProperty(alias) && !exports.commonTags[alias].multiple; +} +exports.isSingleton = isSingleton; +/** + * @param alias Common (generic) tag + * @returns {boolean|*} true if given alias is a singleton or explicitly marked as unique + */ +function isUnique(alias) { + return !exports.commonTags[alias].multiple || exports.commonTags[alias].unique; +} +exports.isUnique = isUnique; +//# sourceMappingURL=GenericTagTypes.js.map + +/***/ }), + +/***/ 7584: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.joinArtists = exports.MetadataCollector = void 0; +const type_1 = __webpack_require__(6032); +const debug_1 = __webpack_require__(1227); +const GenericTagTypes_1 = __webpack_require__(103); +const CombinedTagMapper_1 = __webpack_require__(6592); +const GenericTagMapper_1 = __webpack_require__(9918); +const Util_1 = __webpack_require__(3769); +const FileType = __webpack_require__(1); +const debug = (0, debug_1.default)('music-metadata:collector'); +const TagPriority = ['matroska', 'APEv2', 'vorbis', 'ID3v2.4', 'ID3v2.3', 'ID3v2.2', 'exif', 'asf', 'iTunes', 'ID3v1']; +/** + * Provided to the parser to uodate the metadata result. + * Responsible for triggering async updates + */ +class MetadataCollector { + constructor(opts) { + this.opts = opts; + this.format = { + tagTypes: [], + trackInfo: [] + }; + this.native = {}; + this.common = { + track: { no: null, of: null }, + disk: { no: null, of: null }, + movementIndex: {} + }; + this.quality = { + warnings: [] + }; + /** + * Keeps track of origin priority for each mapped id + */ + this.commonOrigin = {}; + /** + * Maps a tag type to a priority + */ + this.originPriority = {}; + this.tagMapper = new CombinedTagMapper_1.CombinedTagMapper(); + let priority = 1; + for (const tagType of TagPriority) { + this.originPriority[tagType] = priority++; + } + this.originPriority.artificial = 500; // Filled using alternative tags + this.originPriority.id3v1 = 600; // Consider worst due to field length limit + } + /** + * @returns {boolean} true if one or more tags have been found + */ + hasAny() { + return Object.keys(this.native).length > 0; + } + addStreamInfo(streamInfo) { + debug(`streamInfo: type=${type_1.TrackType[streamInfo.type]}, codec=${streamInfo.codecName}`); + this.format.trackInfo.push(streamInfo); + } + setFormat(key, value) { + debug(`format: ${key} = ${value}`); + this.format[key] = value; // as any to override readonly + if (this.opts.observer) { + this.opts.observer({ metadata: this, tag: { type: 'format', id: key, value } }); + } + } + addTag(tagType, tagId, value) { + debug(`tag ${tagType}.${tagId} = ${value}`); + if (!this.native[tagType]) { + this.format.tagTypes.push(tagType); + this.native[tagType] = []; + } + this.native[tagType].push({ id: tagId, value }); + this.toCommon(tagType, tagId, value); + } + addWarning(warning) { + this.quality.warnings.push({ message: warning }); + } + postMap(tagType, tag) { + // Common tag (alias) found + // check if we need to do something special with common tag + // if the event has been aliased then we need to clean it before + // it is emitted to the user. e.g. genre (20) -> Electronic + switch (tag.id) { + case 'artist': + if (this.commonOrigin.artist === this.originPriority[tagType]) { + // Assume the artist field is used as artists + return this.postMap('artificial', { id: 'artists', value: tag.value }); + } + if (!this.common.artists) { + // Fill artists using artist source + this.setGenericTag('artificial', { id: 'artists', value: tag.value }); + } + break; + case 'artists': + if (!this.common.artist || this.commonOrigin.artist === this.originPriority.artificial) { + if (!this.common.artists || this.common.artists.indexOf(tag.value) === -1) { + // Fill artist using artists source + const artists = (this.common.artists || []).concat([tag.value]); + const value = joinArtists(artists); + const artistTag = { id: 'artist', value }; + this.setGenericTag('artificial', artistTag); + } + } + break; + case 'picture': + this.postFixPicture(tag.value).then(picture => { + if (picture !== null) { + tag.value = picture; + this.setGenericTag(tagType, tag); + } + }); + return; + case 'totaltracks': + this.common.track.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value); + return; + case 'totaldiscs': + this.common.disk.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value); + return; + case 'movementTotal': + this.common.movementIndex.of = GenericTagMapper_1.CommonTagMapper.toIntOrNull(tag.value); + return; + case 'track': + case 'disk': + case 'movementIndex': + const of = this.common[tag.id].of; // store of value, maybe maybe overwritten + this.common[tag.id] = GenericTagMapper_1.CommonTagMapper.normalizeTrack(tag.value); + this.common[tag.id].of = of != null ? of : this.common[tag.id].of; + return; + case 'bpm': + case 'year': + case 'originalyear': + tag.value = parseInt(tag.value, 10); + break; + case 'date': + // ToDo: be more strict on 'YYYY...' + const year = parseInt(tag.value.substr(0, 4), 10); + if (!isNaN(year)) { + this.common.year = year; + } + break; + case 'discogs_label_id': + case 'discogs_release_id': + case 'discogs_master_release_id': + case 'discogs_artist_id': + case 'discogs_votes': + tag.value = typeof tag.value === 'string' ? parseInt(tag.value, 10) : tag.value; + break; + case 'replaygain_track_gain': + case 'replaygain_track_peak': + case 'replaygain_album_gain': + case 'replaygain_album_peak': + tag.value = (0, Util_1.toRatio)(tag.value); + break; + case 'replaygain_track_minmax': + tag.value = tag.value.split(',').map(v => parseInt(v, 10)); + break; + case 'replaygain_undo': + const minMix = tag.value.split(',').map(v => parseInt(v, 10)); + tag.value = { + leftChannel: minMix[0], + rightChannel: minMix[1] + }; + break; + case 'gapless': // iTunes gap-less flag + case 'compilation': + case 'podcast': + case 'showMovement': + tag.value = tag.value === '1' || tag.value === 1; // boolean + break; + case 'isrc': // Only keep unique values + if (this.common[tag.id] && this.common[tag.id].indexOf(tag.value) !== -1) + return; + break; + default: + // nothing to do + } + if (tag.value !== null) { + this.setGenericTag(tagType, tag); + } + } + /** + * Convert native tags to common tags + * @returns {IAudioMetadata} Native + common tags + */ + toCommonMetadata() { + return { + format: this.format, + native: this.native, + quality: this.quality, + common: this.common + }; + } + /** + * Fix some common issues with picture object + * @param picture Picture + */ + async postFixPicture(picture) { + if (picture.data && picture.data.length > 0) { + if (!picture.format) { + const fileType = await FileType.fromBuffer(picture.data); + if (fileType) { + picture.format = fileType.mime; + } + else { + return null; + } + } + picture.format = picture.format.toLocaleLowerCase(); + switch (picture.format) { + case 'image/jpg': + picture.format = 'image/jpeg'; // ToDo: register warning + } + return picture; + } + this.addWarning(`Empty picture tag found`); + return null; + } + /** + * Convert native tag to common tags + */ + toCommon(tagType, tagId, value) { + const tag = { id: tagId, value }; + const genericTag = this.tagMapper.mapTag(tagType, tag, this); + if (genericTag) { + this.postMap(tagType, genericTag); + } + } + /** + * Set generic tag + */ + setGenericTag(tagType, tag) { + debug(`common.${tag.id} = ${tag.value}`); + const prio0 = this.commonOrigin[tag.id] || 1000; + const prio1 = this.originPriority[tagType]; + if ((0, GenericTagTypes_1.isSingleton)(tag.id)) { + if (prio1 <= prio0) { + this.common[tag.id] = tag.value; + this.commonOrigin[tag.id] = prio1; + } + else { + return debug(`Ignore native tag (singleton): ${tagType}.${tag.id} = ${tag.value}`); + } + } + else { + if (prio1 === prio0) { + if (!(0, GenericTagTypes_1.isUnique)(tag.id) || this.common[tag.id].indexOf(tag.value) === -1) { + this.common[tag.id].push(tag.value); + } + else { + debug(`Ignore duplicate value: ${tagType}.${tag.id} = ${tag.value}`); + } + // no effect? this.commonOrigin[tag.id] = prio1; + } + else if (prio1 < prio0) { + this.common[tag.id] = [tag.value]; + this.commonOrigin[tag.id] = prio1; + } + else { + return debug(`Ignore native tag (list): ${tagType}.${tag.id} = ${tag.value}`); + } + } + if (this.opts.observer) { + this.opts.observer({ metadata: this, tag: { type: 'common', id: tag.id, value: tag.value } }); + } + // ToDo: trigger metadata event + } +} +exports.MetadataCollector = MetadataCollector; +function joinArtists(artists) { + if (artists.length > 2) { + return artists.slice(0, artists.length - 1).join(', ') + ' & ' + artists[artists.length - 1]; + } + return artists.join(' & '); +} +exports.joinArtists = joinArtists; +//# sourceMappingURL=MetadataCollector.js.map + +/***/ }), + +/***/ 9461: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.RandomUint8ArrayReader = void 0; +/** + * Provides abstract Uint8Array access via the IRandomRead interface + */ +class RandomUint8ArrayReader { + constructor(uint8Array) { + this.uint8Array = uint8Array; + this.fileSize = uint8Array.length; + } + /** + * Read from a given position of an abstracted file or buffer. + * @param uint8Array - Uint8Array that the data will be written to. + * @param offset - Offset in the buffer to start writing at. + * @param length - Integer specifying the number of bytes to read. + * @param position - Specifies where to begin reading from in the file. + * @return Promise providing bytes read + */ + async randomRead(uint8Array, offset, length, position) { + uint8Array.set(this.uint8Array.subarray(position, position + length), offset); + return length; + } +} +exports.RandomUint8ArrayReader = RandomUint8ArrayReader; + + +/***/ }), + +/***/ 3769: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.toRatio = exports.dbToRatio = exports.ratioToDb = exports.a2hex = exports.isBitSet = exports.getBitAllignedNumber = exports.stripNulls = exports.decodeString = exports.trimRightNull = exports.findZero = exports.getBit = void 0; +function getBit(buf, off, bit) { + return (buf[off] & (1 << bit)) !== 0; +} +exports.getBit = getBit; +/** + * Found delimiting zero in uint8Array + * @param uint8Array Uint8Array to find the zero delimiter in + * @param start Offset in uint8Array + * @param end Last position to parse in uint8Array + * @param encoding The string encoding used + * @return Absolute position on uint8Array where zero found + */ +function findZero(uint8Array, start, end, encoding) { + let i = start; + if (encoding === 'utf16le') { + while (uint8Array[i] !== 0 || uint8Array[i + 1] !== 0) { + if (i >= end) + return end; + i += 2; + } + return i; + } + else { + while (uint8Array[i] !== 0) { + if (i >= end) + return end; + i++; + } + return i; + } +} +exports.findZero = findZero; +function trimRightNull(x) { + const pos0 = x.indexOf('\0'); + return pos0 === -1 ? x : x.substr(0, pos0); +} +exports.trimRightNull = trimRightNull; +function swapBytes(uint8Array) { + const l = uint8Array.length; + if ((l & 1) !== 0) + throw new Error('Buffer length must be even'); + for (let i = 0; i < l; i += 2) { + const a = uint8Array[i]; + uint8Array[i] = uint8Array[i + 1]; + uint8Array[i + 1] = a; + } + return uint8Array; +} +/** + * Decode string + */ +function decodeString(uint8Array, encoding) { + // annoying workaround for a double BOM issue + // https://github.com/leetreveil/musicmetadata/issues/84 + if (uint8Array[0] === 0xFF && uint8Array[1] === 0xFE) { // little endian + return decodeString(uint8Array.subarray(2), encoding); + } + else if (encoding === 'utf16le' && uint8Array[0] === 0xFE && uint8Array[1] === 0xFF) { + // BOM, indicating big endian decoding + if ((uint8Array.length & 1) !== 0) + throw new Error('Expected even number of octets for 16-bit unicode string'); + return decodeString(swapBytes(uint8Array), encoding); + } + return Buffer.from(uint8Array).toString(encoding); +} +exports.decodeString = decodeString; +function stripNulls(str) { + str = str.replace(/^\x00+/g, ''); + str = str.replace(/\x00+$/g, ''); + return str; +} +exports.stripNulls = stripNulls; +/** + * Read bit-aligned number start from buffer + * Total offset in bits = byteOffset * 8 + bitOffset + * @param source Byte buffer + * @param byteOffset Starting offset in bytes + * @param bitOffset Starting offset in bits: 0 = lsb + * @param len Length of number in bits + * @return Decoded bit aligned number + */ +function getBitAllignedNumber(source, byteOffset, bitOffset, len) { + const byteOff = byteOffset + ~~(bitOffset / 8); + const bitOff = bitOffset % 8; + let value = source[byteOff]; + value &= 0xff >> bitOff; + const bitsRead = 8 - bitOff; + const bitsLeft = len - bitsRead; + if (bitsLeft < 0) { + value >>= (8 - bitOff - len); + } + else if (bitsLeft > 0) { + value <<= bitsLeft; + value |= getBitAllignedNumber(source, byteOffset, bitOffset + bitsRead, bitsLeft); + } + return value; +} +exports.getBitAllignedNumber = getBitAllignedNumber; +/** + * Read bit-aligned number start from buffer + * Total offset in bits = byteOffset * 8 + bitOffset + * @param source Byte Uint8Array + * @param byteOffset Starting offset in bytes + * @param bitOffset Starting offset in bits: 0 = most significant bit, 7 is the least significant bit + * @return True if bit is set + */ +function isBitSet(source, byteOffset, bitOffset) { + return getBitAllignedNumber(source, byteOffset, bitOffset, 1) === 1; +} +exports.isBitSet = isBitSet; +function a2hex(str) { + const arr = []; + for (let i = 0, l = str.length; i < l; i++) { + const hex = Number(str.charCodeAt(i)).toString(16); + arr.push(hex.length === 1 ? '0' + hex : hex); + } + return arr.join(' '); +} +exports.a2hex = a2hex; +/** + * Convert power ratio to DB + * ratio: [0..1] + */ +function ratioToDb(ratio) { + return 10 * Math.log10(ratio); +} +exports.ratioToDb = ratioToDb; +/** + * Convert dB to ratio + * db Decibels + */ +function dbToRatio(dB) { + return Math.pow(10, dB / 10); +} +exports.dbToRatio = dbToRatio; +/** + * Convert replay gain to ratio and Decibel + * @param value string holding a ratio like '0.034' or '-7.54 dB' + */ +function toRatio(value) { + const ps = value.split(' ').map(p => p.trim().toLowerCase()); + // @ts-ignore + if (ps.length >= 1) { + const v = parseFloat(ps[0]); + return ps.length === 2 && ps[1] === 'db' ? { + dB: v, + ratio: dbToRatio(v) + } : { + dB: ratioToDb(v), + ratio: v + }; + } +} +exports.toRatio = toRatio; +//# sourceMappingURL=Util.js.map + +/***/ }), + +/***/ 523: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.scanAppendingHeaders = exports.selectCover = exports.ratingToStars = exports.orderTags = exports.parseFromTokenizer = exports.parseBuffer = exports.parseStream = void 0; +const strtok3 = __webpack_require__(5849); +const ParserFactory_1 = __webpack_require__(3275); +const RandomUint8ArrayReader_1 = __webpack_require__(9461); +const APEv2Parser_1 = __webpack_require__(6742); +const ID3v1Parser_1 = __webpack_require__(2282); +const Lyrics3_1 = __webpack_require__(9941); +/** + * Parse audio from Node Stream.Readable + * @param stream - Stream to read the audio track from + * @param options - Parsing options + * @param fileInfo - File information object or MIME-type string + * @returns Metadata + */ +function parseStream(stream, fileInfo, options = {}) { + return parseFromTokenizer(strtok3.fromStream(stream, typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo), options); +} +exports.parseStream = parseStream; +/** + * Parse audio from Node Buffer + * @param uint8Array - Uint8Array holding audio data + * @param fileInfo - File information object or MIME-type string + * @param options - Parsing options + * @returns Metadata + * Ref: https://github.com/Borewit/strtok3/blob/e6938c81ff685074d5eb3064a11c0b03ca934c1d/src/index.ts#L15 + */ +async function parseBuffer(uint8Array, fileInfo, options = {}) { + const bufferReader = new RandomUint8ArrayReader_1.RandomUint8ArrayReader(uint8Array); + await scanAppendingHeaders(bufferReader, options); + const tokenizer = strtok3.fromBuffer(uint8Array, typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo); + return parseFromTokenizer(tokenizer, options); +} +exports.parseBuffer = parseBuffer; +/** + * Parse audio from ITokenizer source + * @param tokenizer - Audio source implementing the tokenizer interface + * @param options - Parsing options + * @returns Metadata + */ +function parseFromTokenizer(tokenizer, options) { + return ParserFactory_1.ParserFactory.parseOnContentType(tokenizer, options); +} +exports.parseFromTokenizer = parseFromTokenizer; +/** + * Create a dictionary ordered by their tag id (key) + * @param nativeTags list of tags + * @returns tags indexed by id + */ +function orderTags(nativeTags) { + const tags = {}; + for (const tag of nativeTags) { + (tags[tag.id] = (tags[tag.id] || [])).push(tag.value); + } + return tags; +} +exports.orderTags = orderTags; +/** + * Convert rating to 1-5 star rating + * @param rating: Normalized rating [0..1] (common.rating[n].rating) + * @returns Number of stars: 1, 2, 3, 4 or 5 stars + */ +function ratingToStars(rating) { + return rating === undefined ? 0 : 1 + Math.round(rating * 4); +} +exports.ratingToStars = ratingToStars; +/** + * Select most likely cover image. + * @param pictures Usually metadata.common.picture + * @return Cover image, if any, otherwise null + */ +function selectCover(pictures) { + return pictures ? pictures.reduce((acc, cur) => { + if (cur.name && cur.name.toLowerCase() in ['front', 'cover', 'cover (front)']) + return cur; + return acc; + }) : null; +} +exports.selectCover = selectCover; +async function scanAppendingHeaders(randomReader, options = {}) { + let apeOffset = randomReader.fileSize; + if (await (0, ID3v1Parser_1.hasID3v1Header)(randomReader)) { + apeOffset -= 128; + const lyricsLen = await (0, Lyrics3_1.getLyricsHeaderLength)(randomReader); + apeOffset -= lyricsLen; + } + options.apeHeader = await APEv2Parser_1.APEv2Parser.findApeFooterOffset(randomReader, apeOffset); +} +exports.scanAppendingHeaders = scanAppendingHeaders; + + +/***/ }), + +/***/ 6789: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.DsdiffParser = void 0; +const Token = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const strtok3 = __webpack_require__(5849); +const FourCC_1 = __webpack_require__(8049); +const BasicParser_1 = __webpack_require__(7805); +const ID3v2Parser_1 = __webpack_require__(8928); +const DsdiffToken_1 = __webpack_require__(9187); +const debug = (0, debug_1.default)('music-metadata:parser:aiff'); +/** + * DSDIFF - Direct Stream Digital Interchange File Format (Phillips) + * + * Ref: + * - http://www.sonicstudio.com/pdf/dsd/DSDIFF_1.5_Spec.pdf + */ +class DsdiffParser extends BasicParser_1.BasicParser { + async parse() { + const header = await this.tokenizer.readToken(DsdiffToken_1.ChunkHeader64); + if (header.chunkID !== 'FRM8') + throw new Error('Unexpected chunk-ID'); + const type = (await this.tokenizer.readToken(FourCC_1.FourCcToken)).trim(); + switch (type) { + case 'DSD': + this.metadata.setFormat('container', `DSDIFF/${type}`); + this.metadata.setFormat('lossless', true); + return this.readFmt8Chunks(header.chunkSize - BigInt(FourCC_1.FourCcToken.len)); + default: + throw Error(`Unsupported DSDIFF type: ${type}`); + } + } + async readFmt8Chunks(remainingSize) { + while (remainingSize >= DsdiffToken_1.ChunkHeader64.len) { + const chunkHeader = await this.tokenizer.readToken(DsdiffToken_1.ChunkHeader64); + // If the data is an odd number of bytes in length, a pad byte must be added at the end + debug(`Chunk id=${chunkHeader.chunkID}`); + await this.readData(chunkHeader); + remainingSize -= (BigInt(DsdiffToken_1.ChunkHeader64.len) + chunkHeader.chunkSize); + } + } + async readData(header) { + debug(`Reading data of chunk[ID=${header.chunkID}, size=${header.chunkSize}]`); + const p0 = this.tokenizer.position; + switch (header.chunkID.trim()) { + case 'FVER': // 3.1 FORMAT VERSION CHUNK + const version = await this.tokenizer.readToken(Token.UINT32_LE); + debug(`DSDIFF version=${version}`); + break; + case 'PROP': // 3.2 PROPERTY CHUNK + const propType = await this.tokenizer.readToken(FourCC_1.FourCcToken); + if (propType !== 'SND ') + throw new Error('Unexpected PROP-chunk ID'); + await this.handleSoundPropertyChunks(header.chunkSize - BigInt(FourCC_1.FourCcToken.len)); + break; + case 'ID3': // Unofficial ID3 tag support + const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(Number(header.chunkSize))); + const rst = strtok3.fromBuffer(id3_data); + await new ID3v2Parser_1.ID3v2Parser().parse(this.metadata, rst, this.options); + break; + default: + debug(`Ignore chunk[ID=${header.chunkID}, size=${header.chunkSize}]`); + break; + case 'DSD': + this.metadata.setFormat('numberOfSamples', Number(header.chunkSize * BigInt(8) / BigInt(this.metadata.format.numberOfChannels))); + this.metadata.setFormat('duration', this.metadata.format.numberOfSamples / this.metadata.format.sampleRate); + break; + } + const remaining = header.chunkSize - BigInt(this.tokenizer.position - p0); + if (remaining > 0) { + debug(`After Parsing chunk, remaining ${remaining} bytes`); + await this.tokenizer.ignore(Number(remaining)); + } + } + async handleSoundPropertyChunks(remainingSize) { + debug(`Parsing sound-property-chunks, remainingSize=${remainingSize}`); + while (remainingSize > 0) { + const sndPropHeader = await this.tokenizer.readToken(DsdiffToken_1.ChunkHeader64); + debug(`Sound-property-chunk[ID=${sndPropHeader.chunkID}, size=${sndPropHeader.chunkSize}]`); + const p0 = this.tokenizer.position; + switch (sndPropHeader.chunkID.trim()) { + case 'FS': // 3.2.1 Sample Rate Chunk + const sampleRate = await this.tokenizer.readToken(Token.UINT32_BE); + this.metadata.setFormat('sampleRate', sampleRate); + break; + case 'CHNL': // 3.2.2 Channels Chunk + const numChannels = await this.tokenizer.readToken(Token.UINT16_BE); + this.metadata.setFormat('numberOfChannels', numChannels); + await this.handleChannelChunks(sndPropHeader.chunkSize - BigInt(Token.UINT16_BE.len)); + break; + case 'CMPR': // 3.2.3 Compression Type Chunk + const compressionIdCode = (await this.tokenizer.readToken(FourCC_1.FourCcToken)).trim(); + const count = await this.tokenizer.readToken(Token.UINT8); + const compressionName = await this.tokenizer.readToken(new Token.StringType(count, 'ascii')); + if (compressionIdCode === 'DSD') { + this.metadata.setFormat('lossless', true); + this.metadata.setFormat('bitsPerSample', 1); + } + this.metadata.setFormat('codec', `${compressionIdCode} (${compressionName})`); + break; + case 'ABSS': // 3.2.4 Absolute Start Time Chunk + const hours = await this.tokenizer.readToken(Token.UINT16_BE); + const minutes = await this.tokenizer.readToken(Token.UINT8); + const seconds = await this.tokenizer.readToken(Token.UINT8); + const samples = await this.tokenizer.readToken(Token.UINT32_BE); + debug(`ABSS ${hours}:${minutes}:${seconds}.${samples}`); + break; + case 'LSCO': // 3.2.5 Loudspeaker Configuration Chunk + const lsConfig = await this.tokenizer.readToken(Token.UINT16_BE); + debug(`LSCO lsConfig=${lsConfig}`); + break; + case 'COMT': + default: + debug(`Unknown sound-property-chunk[ID=${sndPropHeader.chunkID}, size=${sndPropHeader.chunkSize}]`); + await this.tokenizer.ignore(Number(sndPropHeader.chunkSize)); + } + const remaining = sndPropHeader.chunkSize - BigInt(this.tokenizer.position - p0); + if (remaining > 0) { + debug(`After Parsing sound-property-chunk ${sndPropHeader.chunkSize}, remaining ${remaining} bytes`); + await this.tokenizer.ignore(Number(remaining)); + } + remainingSize -= BigInt(DsdiffToken_1.ChunkHeader64.len) + sndPropHeader.chunkSize; + debug(`Parsing sound-property-chunks, remainingSize=${remainingSize}`); + } + if (this.metadata.format.lossless && this.metadata.format.sampleRate && this.metadata.format.numberOfChannels && this.metadata.format.bitsPerSample) { + const bitrate = this.metadata.format.sampleRate * this.metadata.format.numberOfChannels * this.metadata.format.bitsPerSample; + this.metadata.setFormat('bitrate', bitrate); + } + } + async handleChannelChunks(remainingSize) { + debug(`Parsing channel-chunks, remainingSize=${remainingSize}`); + const channels = []; + while (remainingSize >= FourCC_1.FourCcToken.len) { + const channelId = await this.tokenizer.readToken(FourCC_1.FourCcToken); + debug(`Channel[ID=${channelId}]`); + channels.push(channelId); + remainingSize -= BigInt(FourCC_1.FourCcToken.len); + } + debug(`Channels: ${channels.join(', ')}`); + return channels; + } +} +exports.DsdiffParser = DsdiffParser; + + +/***/ }), + +/***/ 9187: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ChunkHeader64 = void 0; +const Token = __webpack_require__(3416); +const FourCC_1 = __webpack_require__(8049); +/** + * DSDIFF chunk header + * The data-size encoding is deviating from EA-IFF 85 + * Ref: http://www.sonicstudio.com/pdf/dsd/DSDIFF_1.5_Spec.pdf + */ +exports.ChunkHeader64 = { + len: 12, + get: (buf, off) => { + return { + // Group-ID + chunkID: FourCC_1.FourCcToken.get(buf, off), + // Size + chunkSize: Token.INT64_BE.get(buf, off + 4) + }; + } +}; + + +/***/ }), + +/***/ 4101: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.FormatChunk = exports.ChannelType = exports.DsdChunk = exports.ChunkHeader = void 0; +const Token = __webpack_require__(3416); +const FourCC_1 = __webpack_require__(8049); +/** + * Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size + */ +exports.ChunkHeader = { + len: 12, + get: (buf, off) => { + return { id: FourCC_1.FourCcToken.get(buf, off), size: Token.UINT64_LE.get(buf, off + 4) }; + } +}; +/** + * Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size + */ +exports.DsdChunk = { + len: 16, + get: (buf, off) => { + return { + fileSize: Token.INT64_LE.get(buf, off), + metadataPointer: Token.INT64_LE.get(buf, off + 8) + }; + } +}; +var ChannelType; +(function (ChannelType) { + ChannelType[ChannelType["mono"] = 1] = "mono"; + ChannelType[ChannelType["stereo"] = 2] = "stereo"; + ChannelType[ChannelType["channels"] = 3] = "channels"; + ChannelType[ChannelType["quad"] = 4] = "quad"; + ChannelType[ChannelType["4 channels"] = 5] = "4 channels"; + ChannelType[ChannelType["5 channels"] = 6] = "5 channels"; + ChannelType[ChannelType["5.1 channels"] = 7] = "5.1 channels"; +})(ChannelType = exports.ChannelType || (exports.ChannelType = {})); +/** + * Common chunk DSD header: the 'chunk name (Four-CC)' & chunk size + */ +exports.FormatChunk = { + len: 40, + get: (buf, off) => { + return { + formatVersion: Token.INT32_LE.get(buf, off), + formatID: Token.INT32_LE.get(buf, off + 4), + channelType: Token.INT32_LE.get(buf, off + 8), + channelNum: Token.INT32_LE.get(buf, off + 12), + samplingFrequency: Token.INT32_LE.get(buf, off + 16), + bitsPerSample: Token.INT32_LE.get(buf, off + 20), + sampleCount: Token.INT64_LE.get(buf, off + 24), + blockSizePerChannel: Token.INT32_LE.get(buf, off + 32) + }; + } +}; + + +/***/ }), + +/***/ 1533: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.DsfParser = void 0; +const debug_1 = __webpack_require__(1227); +const AbstractID3Parser_1 = __webpack_require__(5159); +const DsfChunk_1 = __webpack_require__(4101); +const ID3v2Parser_1 = __webpack_require__(8928); +const debug = (0, debug_1.default)('music-metadata:parser:DSF'); +/** + * DSF (dsd stream file) File Parser + * Ref: https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf + */ +class DsfParser extends AbstractID3Parser_1.AbstractID3Parser { + async postId3v2Parse() { + const p0 = this.tokenizer.position; // mark start position, normally 0 + const chunkHeader = await this.tokenizer.readToken(DsfChunk_1.ChunkHeader); + if (chunkHeader.id !== 'DSD ') + throw new Error('Invalid chunk signature'); + this.metadata.setFormat('container', 'DSF'); + this.metadata.setFormat('lossless', true); + const dsdChunk = await this.tokenizer.readToken(DsfChunk_1.DsdChunk); + if (dsdChunk.metadataPointer === BigInt(0)) { + debug(`No ID3v2 tag present`); + } + else { + debug(`expect ID3v2 at offset=${dsdChunk.metadataPointer}`); + await this.parseChunks(dsdChunk.fileSize - chunkHeader.size); + // Jump to ID3 header + await this.tokenizer.ignore(Number(dsdChunk.metadataPointer) - this.tokenizer.position - p0); + return new ID3v2Parser_1.ID3v2Parser().parse(this.metadata, this.tokenizer, this.options); + } + } + async parseChunks(bytesRemaining) { + while (bytesRemaining >= DsfChunk_1.ChunkHeader.len) { + const chunkHeader = await this.tokenizer.readToken(DsfChunk_1.ChunkHeader); + debug(`Parsing chunk name=${chunkHeader.id} size=${chunkHeader.size}`); + switch (chunkHeader.id) { + case 'fmt ': + const formatChunk = await this.tokenizer.readToken(DsfChunk_1.FormatChunk); + this.metadata.setFormat('numberOfChannels', formatChunk.channelNum); + this.metadata.setFormat('sampleRate', formatChunk.samplingFrequency); + this.metadata.setFormat('bitsPerSample', formatChunk.bitsPerSample); + this.metadata.setFormat('numberOfSamples', formatChunk.sampleCount); + this.metadata.setFormat('duration', Number(formatChunk.sampleCount) / formatChunk.samplingFrequency); + const bitrate = formatChunk.bitsPerSample * formatChunk.samplingFrequency * formatChunk.channelNum; + this.metadata.setFormat('bitrate', bitrate); + return; // We got what we want, stop further processing of chunks + default: + this.tokenizer.ignore(Number(chunkHeader.size) - DsfChunk_1.ChunkHeader.len); + break; + } + bytesRemaining -= chunkHeader.size; + } + } +} +exports.DsfParser = DsfParser; + + +/***/ }), + +/***/ 498: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.FlacParser = void 0; +const token_types_1 = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const util = __webpack_require__(3769); +const Vorbis_1 = __webpack_require__(2127); +const AbstractID3Parser_1 = __webpack_require__(5159); +const FourCC_1 = __webpack_require__(8049); +const VorbisParser_1 = __webpack_require__(4210); +const VorbisDecoder_1 = __webpack_require__(441); +const debug = (0, debug_1.default)('music-metadata:parser:FLAC'); +/** + * FLAC supports up to 128 kinds of metadata blocks; currently the following are defined: + * ref: https://xiph.org/flac/format.html#metadata_block + */ +var BlockType; +(function (BlockType) { + BlockType[BlockType["STREAMINFO"] = 0] = "STREAMINFO"; + BlockType[BlockType["PADDING"] = 1] = "PADDING"; + BlockType[BlockType["APPLICATION"] = 2] = "APPLICATION"; + BlockType[BlockType["SEEKTABLE"] = 3] = "SEEKTABLE"; + BlockType[BlockType["VORBIS_COMMENT"] = 4] = "VORBIS_COMMENT"; + BlockType[BlockType["CUESHEET"] = 5] = "CUESHEET"; + BlockType[BlockType["PICTURE"] = 6] = "PICTURE"; +})(BlockType || (BlockType = {})); +class FlacParser extends AbstractID3Parser_1.AbstractID3Parser { + constructor() { + super(...arguments); + this.padding = 0; + } + /** + * Initialize parser with output (metadata), input (tokenizer) & parsing options (options). + * @param {INativeMetadataCollector} metadata Output + * @param {ITokenizer} tokenizer Input + * @param {IOptions} options Parsing options + */ + init(metadata, tokenizer, options) { + super.init(metadata, tokenizer, options); + this.vorbisParser = new VorbisParser_1.VorbisParser(metadata, options); + return this; + } + async postId3v2Parse() { + const fourCC = await this.tokenizer.readToken(FourCC_1.FourCcToken); + if (fourCC.toString() !== 'fLaC') { + throw new Error('Invalid FLAC preamble'); + } + let blockHeader; + do { + // Read block header + blockHeader = await this.tokenizer.readToken(Metadata.BlockHeader); + // Parse block data + await this.parseDataBlock(blockHeader); + } while (!blockHeader.lastBlock); + if (this.tokenizer.fileInfo.size && this.metadata.format.duration) { + const dataSize = this.tokenizer.fileInfo.size - this.tokenizer.position; + this.metadata.setFormat('bitrate', 8 * dataSize / this.metadata.format.duration); + } + } + parseDataBlock(blockHeader) { + debug(`blockHeader type=${blockHeader.type}, length=${blockHeader.length}`); + switch (blockHeader.type) { + case BlockType.STREAMINFO: + return this.parseBlockStreamInfo(blockHeader.length); + case BlockType.PADDING: + this.padding += blockHeader.length; + break; + case BlockType.APPLICATION: + break; + case BlockType.SEEKTABLE: + break; + case BlockType.VORBIS_COMMENT: + return this.parseComment(blockHeader.length); + case BlockType.CUESHEET: + break; + case BlockType.PICTURE: + return this.parsePicture(blockHeader.length).then(); + default: + this.metadata.addWarning('Unknown block type: ' + blockHeader.type); + } + // Ignore data block + return this.tokenizer.ignore(blockHeader.length).then(); + } + /** + * Parse STREAMINFO + */ + async parseBlockStreamInfo(dataLen) { + if (dataLen !== Metadata.BlockStreamInfo.len) + throw new Error('Unexpected block-stream-info length'); + const streamInfo = await this.tokenizer.readToken(Metadata.BlockStreamInfo); + this.metadata.setFormat('container', 'FLAC'); + this.metadata.setFormat('codec', 'FLAC'); + this.metadata.setFormat('lossless', true); + this.metadata.setFormat('numberOfChannels', streamInfo.channels); + this.metadata.setFormat('bitsPerSample', streamInfo.bitsPerSample); + this.metadata.setFormat('sampleRate', streamInfo.sampleRate); + if (streamInfo.totalSamples > 0) { + this.metadata.setFormat('duration', streamInfo.totalSamples / streamInfo.sampleRate); + } + } + /** + * Parse VORBIS_COMMENT + * Ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3 + */ + async parseComment(dataLen) { + const data = await this.tokenizer.readToken(new token_types_1.Uint8ArrayType(dataLen)); + const decoder = new VorbisDecoder_1.VorbisDecoder(data, 0); + decoder.readStringUtf8(); // vendor (skip) + const commentListLength = decoder.readInt32(); + for (let i = 0; i < commentListLength; i++) { + const tag = decoder.parseUserComment(); + this.vorbisParser.addTag(tag.key, tag.value); + } + } + async parsePicture(dataLen) { + if (this.options.skipCovers) { + return this.tokenizer.ignore(dataLen); + } + else { + const picture = await this.tokenizer.readToken(new Vorbis_1.VorbisPictureToken(dataLen)); + this.vorbisParser.addTag('METADATA_BLOCK_PICTURE', picture); + } + } +} +exports.FlacParser = FlacParser; +class Metadata { +} +Metadata.BlockHeader = { + len: 4, + get: (buf, off) => { + return { + lastBlock: util.getBit(buf, off, 7), + type: util.getBitAllignedNumber(buf, off, 1, 7), + length: token_types_1.UINT24_BE.get(buf, off + 1) + }; + } +}; +/** + * METADATA_BLOCK_DATA + * Ref: https://xiph.org/flac/format.html#metadata_block_streaminfo + */ +Metadata.BlockStreamInfo = { + len: 34, + get: (buf, off) => { + return { + // The minimum block size (in samples) used in the stream. + minimumBlockSize: token_types_1.UINT16_BE.get(buf, off), + // The maximum block size (in samples) used in the stream. + // (Minimum blocksize == maximum blocksize) implies a fixed-blocksize stream. + maximumBlockSize: token_types_1.UINT16_BE.get(buf, off + 2) / 1000, + // The minimum frame size (in bytes) used in the stream. + // May be 0 to imply the value is not known. + minimumFrameSize: token_types_1.UINT24_BE.get(buf, off + 4), + // The maximum frame size (in bytes) used in the stream. + // May be 0 to imply the value is not known. + maximumFrameSize: token_types_1.UINT24_BE.get(buf, off + 7), + // Sample rate in Hz. Though 20 bits are available, + // the maximum sample rate is limited by the structure of frame headers to 655350Hz. + // Also, a value of 0 is invalid. + sampleRate: token_types_1.UINT24_BE.get(buf, off + 10) >> 4, + // probably slower: sampleRate: common.getBitAllignedNumber(buf, off + 10, 0, 20), + // (number of channels)-1. FLAC supports from 1 to 8 channels + channels: util.getBitAllignedNumber(buf, off + 12, 4, 3) + 1, + // bits per sample)-1. + // FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and decoders only support up to 24 bits per sample. + bitsPerSample: util.getBitAllignedNumber(buf, off + 12, 7, 5) + 1, + // Total samples in stream. + // 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will have 44100 samples regardless of the number of channels. + // A value of zero here means the number of total samples is unknown. + totalSamples: util.getBitAllignedNumber(buf, off + 13, 4, 36), + // the MD5 hash of the file (see notes for usage... it's a littly tricky) + fileMD5: new token_types_1.Uint8ArrayType(16).get(buf, off + 18) + }; + } +}; + + +/***/ }), + +/***/ 2282: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.hasID3v1Header = exports.ID3v1Parser = exports.Genres = void 0; +const debug_1 = __webpack_require__(1227); +const token_types_1 = __webpack_require__(3416); +const util = __webpack_require__(3769); +const BasicParser_1 = __webpack_require__(7805); +const APEv2Parser_1 = __webpack_require__(6742); +const debug = (0, debug_1.default)('music-metadata:parser:ID3v1'); +/** + * ID3v1 Genre mappings + * Ref: https://de.wikipedia.org/wiki/Liste_der_ID3v1-Genres + */ +exports.Genres = [ + 'Blues', 'Classic Rock', 'Country', 'Dance', 'Disco', 'Funk', 'Grunge', 'Hip-Hop', + 'Jazz', 'Metal', 'New Age', 'Oldies', 'Other', 'Pop', 'R&B', 'Rap', 'Reggae', 'Rock', + 'Techno', 'Industrial', 'Alternative', 'Ska', 'Death Metal', 'Pranks', 'Soundtrack', + 'Euro-Techno', 'Ambient', 'Trip-Hop', 'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', + 'Classical', 'Instrumental', 'Acid', 'House', 'Game', 'Sound Clip', 'Gospel', 'Noise', + 'Alt. Rock', 'Bass', 'Soul', 'Punk', 'Space', 'Meditative', 'Instrumental Pop', + 'Instrumental Rock', 'Ethnic', 'Gothic', 'Darkwave', 'Techno-Industrial', + 'Electronic', 'Pop-Folk', 'Eurodance', 'Dream', 'Southern Rock', 'Comedy', 'Cult', + 'Gangsta Rap', 'Top 40', 'Christian Rap', 'Pop/Funk', 'Jungle', 'Native American', + 'Cabaret', 'New Wave', 'Psychedelic', 'Rave', 'Showtunes', 'Trailer', 'Lo-Fi', 'Tribal', + 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro', 'Musical', 'Rock & Roll', 'Hard Rock', + 'Folk', 'Folk/Rock', 'National Folk', 'Swing', 'Fast-Fusion', 'Bebob', 'Latin', 'Revival', + 'Celtic', 'Bluegrass', 'Avantgarde', 'Gothic Rock', 'Progressive Rock', 'Psychedelic Rock', + 'Symphonic Rock', 'Slow Rock', 'Big Band', 'Chorus', 'Easy Listening', 'Acoustic', 'Humour', + 'Speech', 'Chanson', 'Opera', 'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass', 'Primus', + 'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba', 'Folklore', + 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle', 'Duet', 'Punk Rock', 'Drum Solo', + 'A Cappella', 'Euro-House', 'Dance Hall', 'Goa', 'Drum & Bass', 'Club-House', + 'Hardcore', 'Terror', 'Indie', 'BritPop', 'Negerpunk', 'Polsk Punk', 'Beat', + 'Christian Gangsta Rap', 'Heavy Metal', 'Black Metal', 'Crossover', 'Contemporary Christian', + 'Christian Rock', 'Merengue', 'Salsa', 'Thrash Metal', 'Anime', 'JPop', 'Synthpop', + 'Abstract', 'Art Rock', 'Baroque', 'Bhangra', 'Big Beat', 'Breakbeat', 'Chillout', + 'Downtempo', 'Dub', 'EBM', 'Eclectic', 'Electro', 'Electroclash', 'Emo', 'Experimental', + 'Garage', 'Global', 'IDM', 'Illbient', 'Industro-Goth', 'Jam Band', 'Krautrock', + 'Leftfield', 'Lounge', 'Math Rock', 'New Romantic', 'Nu-Breakz', 'Post-Punk', 'Post-Rock', + 'Psytrance', 'Shoegaze', 'Space Rock', 'Trop Rock', 'World Music', 'Neoclassical', 'Audiobook', + 'Audio Theatre', 'Neue Deutsche Welle', 'Podcast', 'Indie Rock', 'G-Funk', 'Dubstep', + 'Garage Rock', 'Psybient' +]; +/** + * Spec: http://id3.org/ID3v1 + * Wiki: https://en.wikipedia.org/wiki/ID3 + */ +const Iid3v1Token = { + len: 128, + /** + * @param buf Buffer possibly holding the 128 bytes ID3v1.1 metadata header + * @param off Offset in buffer in bytes + * @returns ID3v1.1 header if first 3 bytes equals 'TAG', otherwise null is returned + */ + get: (buf, off) => { + const header = new Id3v1StringType(3).get(buf, off); + return header === 'TAG' ? { + header, + title: new Id3v1StringType(30).get(buf, off + 3), + artist: new Id3v1StringType(30).get(buf, off + 33), + album: new Id3v1StringType(30).get(buf, off + 63), + year: new Id3v1StringType(4).get(buf, off + 93), + comment: new Id3v1StringType(28).get(buf, off + 97), + // ID3v1.1 separator for track + zeroByte: token_types_1.UINT8.get(buf, off + 127), + // track: ID3v1.1 field added by Michael Mutschler + track: token_types_1.UINT8.get(buf, off + 126), + genre: token_types_1.UINT8.get(buf, off + 127) + } : null; + } +}; +class Id3v1StringType extends token_types_1.StringType { + constructor(len) { + super(len, 'binary'); + } + get(buf, off) { + let value = super.get(buf, off); + value = util.trimRightNull(value); + value = value.trim(); + return value.length > 0 ? value : undefined; + } +} +class ID3v1Parser extends BasicParser_1.BasicParser { + static getGenre(genreIndex) { + if (genreIndex < exports.Genres.length) { + return exports.Genres[genreIndex]; + } + return undefined; // ToDO: generate warning + } + async parse() { + if (!this.tokenizer.fileInfo.size) { + debug('Skip checking for ID3v1 because the file-size is unknown'); + return; + } + if (this.options.apeHeader) { + this.tokenizer.ignore(this.options.apeHeader.offset - this.tokenizer.position); + const apeParser = new APEv2Parser_1.APEv2Parser(); + apeParser.init(this.metadata, this.tokenizer, this.options); + await apeParser.parseTags(this.options.apeHeader.footer); + } + const offset = this.tokenizer.fileInfo.size - Iid3v1Token.len; + if (this.tokenizer.position > offset) { + debug('Already consumed the last 128 bytes'); + return; + } + const header = await this.tokenizer.readToken(Iid3v1Token, offset); + if (header) { + debug('ID3v1 header found at: pos=%s', this.tokenizer.fileInfo.size - Iid3v1Token.len); + for (const id of ['title', 'artist', 'album', 'comment', 'track', 'year']) { + if (header[id] && header[id] !== '') + this.addTag(id, header[id]); + } + const genre = ID3v1Parser.getGenre(header.genre); + if (genre) + this.addTag('genre', genre); + } + else { + debug('ID3v1 header not found at: pos=%s', this.tokenizer.fileInfo.size - Iid3v1Token.len); + } + } + addTag(id, value) { + this.metadata.addTag('ID3v1', id, value); + } +} +exports.ID3v1Parser = ID3v1Parser; +async function hasID3v1Header(reader) { + if (reader.fileSize >= 128) { + const tag = Buffer.alloc(3); + await reader.randomRead(tag, 0, tag.length, reader.fileSize - 128); + return tag.toString('binary') === 'TAG'; + } + return false; +} +exports.hasID3v1Header = hasID3v1Header; + + +/***/ }), + +/***/ 2939: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ID3v1TagMapper = void 0; +const GenericTagMapper_1 = __webpack_require__(9918); +/** + * ID3v1 tag mappings + */ +const id3v1TagMap = { + title: 'title', + artist: 'artist', + album: 'album', + year: 'year', + comment: 'comment', + track: 'track', + genre: 'genre' +}; +class ID3v1TagMapper extends GenericTagMapper_1.CommonTagMapper { + constructor() { + super(['ID3v1'], id3v1TagMap); + } +} +exports.ID3v1TagMapper = ID3v1TagMapper; +//# sourceMappingURL=ID3v1TagMap.js.map + +/***/ }), + +/***/ 5159: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AbstractID3Parser = void 0; +const core_1 = __webpack_require__(5849); +const debug_1 = __webpack_require__(1227); +const ID3v2Token_1 = __webpack_require__(8281); +const ID3v2Parser_1 = __webpack_require__(8928); +const ID3v1Parser_1 = __webpack_require__(2282); +const BasicParser_1 = __webpack_require__(7805); +const debug = (0, debug_1.default)('music-metadata:parser:ID3'); +/** + * Abstract parser which tries take ID3v2 and ID3v1 headers. + */ +class AbstractID3Parser extends BasicParser_1.BasicParser { + constructor() { + super(...arguments); + this.id3parser = new ID3v2Parser_1.ID3v2Parser(); + } + static async startsWithID3v2Header(tokenizer) { + return (await tokenizer.peekToken(ID3v2Token_1.ID3v2Header)).fileIdentifier === 'ID3'; + } + async parse() { + try { + await this.parseID3v2(); + } + catch (err) { + if (err instanceof core_1.EndOfStreamError) { + debug(`End-of-stream`); + } + else { + throw err; + } + } + } + finalize() { + return; + } + async parseID3v2() { + await this.tryReadId3v2Headers(); + debug('End of ID3v2 header, go to MPEG-parser: pos=%s', this.tokenizer.position); + await this.postId3v2Parse(); + if (this.options.skipPostHeaders && this.metadata.hasAny()) { + this.finalize(); + } + else { + const id3v1parser = new ID3v1Parser_1.ID3v1Parser(); + await id3v1parser.init(this.metadata, this.tokenizer, this.options).parse(); + this.finalize(); + } + } + async tryReadId3v2Headers() { + const id3Header = await this.tokenizer.peekToken(ID3v2Token_1.ID3v2Header); + if (id3Header.fileIdentifier === 'ID3') { + debug('Found ID3v2 header, pos=%s', this.tokenizer.position); + await this.id3parser.parse(this.metadata, this.tokenizer, this.options); + return this.tryReadId3v2Headers(); + } + } +} +exports.AbstractID3Parser = AbstractID3Parser; + + +/***/ }), + +/***/ 907: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.FrameParser = exports.parseGenre = void 0; +const debug_1 = __webpack_require__(1227); +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +const ID3v2Token_1 = __webpack_require__(8281); +const ID3v1Parser_1 = __webpack_require__(2282); +const debug = (0, debug_1.default)('music-metadata:id3v2:frame-parser'); +const defaultEnc = 'latin1'; // latin1 == iso-8859-1; +function parseGenre(origVal) { + // match everything inside parentheses + const genres = []; + let code; + let word = ''; + for (const c of origVal) { + if (typeof code === 'string') { + if (c === '(' && code === '') { + word += '('; + code = undefined; + } + else if (c === ')') { + if (word !== '') { + genres.push(word); + word = ''; + } + const genre = parseGenreCode(code); + if (genre) { + genres.push(genre); + } + code = undefined; + } + else + code += c; + } + else if (c === '(') { + code = ''; + } + else { + word += c; + } + } + if (word) { + if (genres.length === 0 && word.match(/^\d*$/)) { + word = ID3v1Parser_1.Genres[word]; + } + genres.push(word); + } + return genres; +} +exports.parseGenre = parseGenre; +function parseGenreCode(code) { + if (code === 'RX') + return 'Remix'; + if (code === 'CR') + return 'Cover'; + if (code.match(/^\d*$/)) { + return ID3v1Parser_1.Genres[code]; + } +} +class FrameParser { + /** + * Create id3v2 frame parser + * @param major - Major version, e.g. (4) for id3v2.4 + * @param warningCollector - Used to collect decode issue + */ + constructor(major, warningCollector) { + this.major = major; + this.warningCollector = warningCollector; + } + readData(uint8Array, type, includeCovers) { + if (uint8Array.length === 0) { + this.warningCollector.addWarning(`id3v2.${this.major} header has empty tag type=${type}`); + return; + } + const { encoding, bom } = ID3v2Token_1.TextEncodingToken.get(uint8Array, 0); + const length = uint8Array.length; + let offset = 0; + let output = []; // ToDo + const nullTerminatorLength = FrameParser.getNullTerminatorLength(encoding); + let fzero; + const out = {}; + debug(`Parsing tag type=${type}, encoding=${encoding}, bom=${bom}`); + switch (type !== 'TXXX' && type[0] === 'T' ? 'T*' : type) { + case 'T*': // 4.2.1. Text information frames - details + case 'IPLS': // v2.3: Involved people list + case 'MVIN': + case 'MVNM': + case 'PCS': + case 'PCST': + let text; + try { + text = util.decodeString(uint8Array.slice(1), encoding).replace(/\x00+$/, ''); + } + catch (error) { + this.warningCollector.addWarning(`id3v2.${this.major} type=${type} header has invalid string value: ${error.message}`); + } + switch (type) { + case 'TMCL': // Musician credits list + case 'TIPL': // Involved people list + case 'IPLS': // Involved people list + output = this.splitValue(type, text); + output = FrameParser.functionList(output); + break; + case 'TRK': + case 'TRCK': + case 'TPOS': + output = text; + break; + case 'TCOM': + case 'TEXT': + case 'TOLY': + case 'TOPE': + case 'TPE1': + case 'TSRC': + // id3v2.3 defines that TCOM, TEXT, TOLY, TOPE & TPE1 values are separated by / + output = this.splitValue(type, text); + break; + case 'TCO': + case 'TCON': + output = this.splitValue(type, text).map(v => parseGenre(v)).reduce((acc, val) => acc.concat(val), []); + break; + case 'PCS': + case 'PCST': + // TODO: Why `default` not results `1` but `''`? + output = this.major >= 4 ? this.splitValue(type, text) : [text]; + output = (Array.isArray(output) && output[0] === '') ? 1 : 0; + break; + default: + output = this.major >= 4 ? this.splitValue(type, text) : [text]; + } + break; + case 'TXXX': + output = FrameParser.readIdentifierAndData(uint8Array, offset + 1, length, encoding); + output = { + description: output.id, + text: this.splitValue(type, util.decodeString(output.data, encoding).replace(/\x00+$/, '')) + }; + break; + case 'PIC': + case 'APIC': + if (includeCovers) { + const pic = {}; + offset += 1; + switch (this.major) { + case 2: + pic.format = util.decodeString(uint8Array.slice(offset, offset + 3), 'latin1'); // 'latin1'; // latin1 == iso-8859-1; + offset += 3; + break; + case 3: + case 4: + fzero = util.findZero(uint8Array, offset, length, defaultEnc); + pic.format = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc); + offset = fzero + 1; + break; + default: + throw new Error('Warning: unexpected major versionIndex: ' + this.major); + } + pic.format = FrameParser.fixPictureMimeType(pic.format); + pic.type = ID3v2Token_1.AttachedPictureType[uint8Array[offset]]; + offset += 1; + fzero = util.findZero(uint8Array, offset, length, encoding); + pic.description = util.decodeString(uint8Array.slice(offset, fzero), encoding); + offset = fzero + nullTerminatorLength; + pic.data = Buffer.from(uint8Array.slice(offset, length)); + output = pic; + } + break; + case 'CNT': + case 'PCNT': + output = Token.UINT32_BE.get(uint8Array, 0); + break; + case 'SYLT': + // skip text encoding (1 byte), + // language (3 bytes), + // time stamp format (1 byte), + // content tagTypes (1 byte), + // content descriptor (1 byte) + offset += 7; + output = []; + while (offset < length) { + const txt = uint8Array.slice(offset, offset = util.findZero(uint8Array, offset, length, encoding)); + offset += 5; // push offset forward one + 4 byte timestamp + output.push(util.decodeString(txt, encoding)); + } + break; + case 'ULT': + case 'USLT': + case 'COM': + case 'COMM': + offset += 1; + out.language = util.decodeString(uint8Array.slice(offset, offset + 3), defaultEnc); + offset += 3; + fzero = util.findZero(uint8Array, offset, length, encoding); + out.description = util.decodeString(uint8Array.slice(offset, fzero), encoding); + offset = fzero + nullTerminatorLength; + out.text = util.decodeString(uint8Array.slice(offset, length), encoding).replace(/\x00+$/, ''); + output = [out]; + break; + case 'UFID': + output = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc); + output = { owner_identifier: output.id, identifier: output.data }; + break; + case 'PRIV': // private frame + output = FrameParser.readIdentifierAndData(uint8Array, offset, length, defaultEnc); + output = { owner_identifier: output.id, data: output.data }; + break; + case 'POPM': // Popularimeter + fzero = util.findZero(uint8Array, offset, length, defaultEnc); + const email = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc); + offset = fzero + 1; + const dataLen = length - offset; + output = { + email, + rating: Token.UINT8.get(uint8Array, offset), + counter: dataLen >= 5 ? Token.UINT32_BE.get(uint8Array, offset + 1) : undefined + }; + break; + case 'GEOB': { // General encapsulated object + fzero = util.findZero(uint8Array, offset + 1, length, encoding); + const mimeType = util.decodeString(uint8Array.slice(offset + 1, fzero), defaultEnc); + offset = fzero + 1; + fzero = util.findZero(uint8Array, offset, length - offset, encoding); + const filename = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc); + offset = fzero + 1; + fzero = util.findZero(uint8Array, offset, length - offset, encoding); + const description = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc); + output = { + type: mimeType, + filename, + description, + data: uint8Array.slice(offset + 1, length) + }; + break; + } + // W-Frames: + case 'WCOM': + case 'WCOP': + case 'WOAF': + case 'WOAR': + case 'WOAS': + case 'WORS': + case 'WPAY': + case 'WPUB': + // Decode URL + output = util.decodeString(uint8Array.slice(offset, fzero), defaultEnc); + break; + case 'WXXX': { + // Decode URL + fzero = util.findZero(uint8Array, offset + 1, length, encoding); + const description = util.decodeString(uint8Array.slice(offset + 1, fzero), encoding); + offset = fzero + (encoding === 'utf16le' ? 2 : 1); + output = { description, url: util.decodeString(uint8Array.slice(offset, length), defaultEnc) }; + break; + } + case 'WFD': + case 'WFED': + output = util.decodeString(uint8Array.slice(offset + 1, util.findZero(uint8Array, offset + 1, length, encoding)), encoding); + break; + case 'MCDI': { + // Music CD identifier + output = uint8Array.slice(0, length); + break; + } + default: + debug('Warning: unsupported id3v2-tag-type: ' + type); + break; + } + return output; + } + static fixPictureMimeType(pictureType) { + pictureType = pictureType.toLocaleLowerCase(); + switch (pictureType) { + case 'jpg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + } + return pictureType; + } + /** + * Converts TMCL (Musician credits list) or TIPL (Involved people list) + * @param entries + */ + static functionList(entries) { + const res = {}; + for (let i = 0; i + 1 < entries.length; i += 2) { + const names = entries[i + 1].split(','); + res[entries[i]] = res.hasOwnProperty(entries[i]) ? res[entries[i]].concat(names) : names; + } + return res; + } + /** + * id3v2.4 defines that multiple T* values are separated by 0x00 + * id3v2.3 defines that TCOM, TEXT, TOLY, TOPE & TPE1 values are separated by / + * @param tag - Tag name + * @param text - Concatenated tag value + * @returns Split tag value + */ + splitValue(tag, text) { + let values; + if (this.major < 4) { + values = text.split(/\x00/g); + if (values.length > 1) { + this.warningCollector.addWarning(`ID3v2.${this.major} ${tag} uses non standard null-separator.`); + } + else { + values = text.split(/\//g); + } + } + else { + values = text.split(/\x00/g); + } + return FrameParser.trimArray(values); + } + static trimArray(values) { + return values.map(value => value.replace(/\x00+$/, '').trim()); + } + static readIdentifierAndData(uint8Array, offset, length, encoding) { + const fzero = util.findZero(uint8Array, offset, length, encoding); + const id = util.decodeString(uint8Array.slice(offset, fzero), encoding); + offset = fzero + FrameParser.getNullTerminatorLength(encoding); + return { id, data: uint8Array.slice(offset, length) }; + } + static getNullTerminatorLength(enc) { + return enc === 'utf16le' ? 2 : 1; + } +} +exports.FrameParser = FrameParser; + + +/***/ }), + +/***/ 7183: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ID3v22TagMapper = exports.id3v22TagMap = void 0; +const CaseInsensitiveTagMap_1 = __webpack_require__(4132); +/** + * ID3v2.2 tag mappings + */ +exports.id3v22TagMap = { + TT2: 'title', + TP1: 'artist', + TP2: 'albumartist', + TAL: 'album', + TYE: 'year', + COM: 'comment', + TRK: 'track', + TPA: 'disk', + TCO: 'genre', + PIC: 'picture', + TCM: 'composer', + TOR: 'originaldate', + TOT: 'originalalbum', + TXT: 'lyricist', + TP3: 'conductor', + TPB: 'label', + TT1: 'grouping', + TT3: 'subtitle', + TLA: 'language', + TCR: 'copyright', + WCP: 'license', + TEN: 'encodedby', + TSS: 'encodersettings', + WAR: 'website', + 'COM:iTunPGAP': 'gapless' + /* ToDo: iTunes tags: + 'COM:iTunNORM': , + 'COM:iTunSMPB': 'encoder delay', + 'COM:iTunes_CDDB_IDs' + */ , + PCS: 'podcast', + TCP: "compilation", + TDR: 'date', + TS2: 'albumartistsort', + TSA: 'albumsort', + TSC: 'composersort', + TSP: 'artistsort', + TST: 'titlesort', + WFD: 'podcasturl', + TBP: 'bpm' +}; +class ID3v22TagMapper extends CaseInsensitiveTagMap_1.CaseInsensitiveTagMap { + constructor() { + super(['ID3v2.2'], exports.id3v22TagMap); + } +} +exports.ID3v22TagMapper = ID3v22TagMapper; +//# sourceMappingURL=ID3v22TagMapper.js.map + +/***/ }), + +/***/ 4005: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ID3v24TagMapper = void 0; +const GenericTagMapper_1 = __webpack_require__(9918); +const CaseInsensitiveTagMap_1 = __webpack_require__(4132); +const util = __webpack_require__(3769); +/** + * ID3v2.3/ID3v2.4 tag mappings + */ +const id3v24TagMap = { + // id3v2.3 + TIT2: 'title', + TPE1: 'artist', + 'TXXX:Artists': 'artists', + TPE2: 'albumartist', + TALB: 'album', + TDRV: 'date', + /** + * Original release year + */ + TORY: 'originalyear', + TPOS: 'disk', + TCON: 'genre', + APIC: 'picture', + TCOM: 'composer', + 'USLT:description': 'lyrics', + TSOA: 'albumsort', + TSOT: 'titlesort', + TOAL: 'originalalbum', + TSOP: 'artistsort', + TSO2: 'albumartistsort', + TSOC: 'composersort', + TEXT: 'lyricist', + 'TXXX:Writer': 'writer', + TPE3: 'conductor', + // 'IPLS:instrument': 'performer:instrument', // ToDo + TPE4: 'remixer', + 'IPLS:arranger': 'arranger', + 'IPLS:engineer': 'engineer', + 'IPLS:producer': 'producer', + 'IPLS:DJ-mix': 'djmixer', + 'IPLS:mix': 'mixer', + TPUB: 'label', + TIT1: 'grouping', + TIT3: 'subtitle', + TRCK: 'track', + TCMP: 'compilation', + POPM: 'rating', + TBPM: 'bpm', + TMED: 'media', + 'TXXX:CATALOGNUMBER': 'catalognumber', + 'TXXX:MusicBrainz Album Status': 'releasestatus', + 'TXXX:MusicBrainz Album Type': 'releasetype', + /** + * Release country as documented: https://picard.musicbrainz.org/docs/mappings/#cite_note-0 + */ + 'TXXX:MusicBrainz Album Release Country': 'releasecountry', + /** + * Release country as implemented // ToDo: report + */ + 'TXXX:RELEASECOUNTRY': 'releasecountry', + 'TXXX:SCRIPT': 'script', + TLAN: 'language', + TCOP: 'copyright', + WCOP: 'license', + TENC: 'encodedby', + TSSE: 'encodersettings', + 'TXXX:BARCODE': 'barcode', + 'TXXX:ISRC': 'isrc', + TSRC: 'isrc', + 'TXXX:ASIN': 'asin', + 'TXXX:originalyear': 'originalyear', + 'UFID:http://musicbrainz.org': 'musicbrainz_recordingid', + 'TXXX:MusicBrainz Release Track Id': 'musicbrainz_trackid', + 'TXXX:MusicBrainz Album Id': 'musicbrainz_albumid', + 'TXXX:MusicBrainz Artist Id': 'musicbrainz_artistid', + 'TXXX:MusicBrainz Album Artist Id': 'musicbrainz_albumartistid', + 'TXXX:MusicBrainz Release Group Id': 'musicbrainz_releasegroupid', + 'TXXX:MusicBrainz Work Id': 'musicbrainz_workid', + 'TXXX:MusicBrainz TRM Id': 'musicbrainz_trmid', + 'TXXX:MusicBrainz Disc Id': 'musicbrainz_discid', + 'TXXX:ACOUSTID_ID': 'acoustid_id', + 'TXXX:Acoustid Id': 'acoustid_id', + 'TXXX:Acoustid Fingerprint': 'acoustid_fingerprint', + 'TXXX:MusicIP PUID': 'musicip_puid', + 'TXXX:MusicMagic Fingerprint': 'musicip_fingerprint', + WOAR: 'website', + // id3v2.4 + // ToDo: In same sequence as defined at http://id3.org/id3v2.4.0-frames + TDRC: 'date', + TYER: 'year', + TDOR: 'originaldate', + // 'TMCL:instrument': 'performer:instrument', + 'TIPL:arranger': 'arranger', + 'TIPL:engineer': 'engineer', + 'TIPL:producer': 'producer', + 'TIPL:DJ-mix': 'djmixer', + 'TIPL:mix': 'mixer', + TMOO: 'mood', + // additional mappings: + SYLT: 'lyrics', + TSST: 'discsubtitle', + TKEY: 'key', + COMM: 'comment', + TOPE: 'originalartist', + // Windows Media Player + 'PRIV:AverageLevel': 'averageLevel', + 'PRIV:PeakLevel': 'peakLevel', + // Discogs + 'TXXX:DISCOGS_ARTIST_ID': 'discogs_artist_id', + 'TXXX:DISCOGS_ARTISTS': 'artists', + 'TXXX:DISCOGS_ARTIST_NAME': 'artists', + 'TXXX:DISCOGS_ALBUM_ARTISTS': 'albumartist', + 'TXXX:DISCOGS_CATALOG': 'catalognumber', + 'TXXX:DISCOGS_COUNTRY': 'releasecountry', + 'TXXX:DISCOGS_DATE': 'originaldate', + 'TXXX:DISCOGS_LABEL': 'label', + 'TXXX:DISCOGS_LABEL_ID': 'discogs_label_id', + 'TXXX:DISCOGS_MASTER_RELEASE_ID': 'discogs_master_release_id', + 'TXXX:DISCOGS_RATING': 'discogs_rating', + 'TXXX:DISCOGS_RELEASED': 'date', + 'TXXX:DISCOGS_RELEASE_ID': 'discogs_release_id', + 'TXXX:DISCOGS_VOTES': 'discogs_votes', + 'TXXX:CATALOGID': 'catalognumber', + 'TXXX:STYLE': 'genre', + 'TXXX:REPLAYGAIN_TRACK_PEAK': 'replaygain_track_peak', + 'TXXX:REPLAYGAIN_TRACK_GAIN': 'replaygain_track_gain', + 'TXXX:REPLAYGAIN_ALBUM_PEAK': 'replaygain_album_peak', + 'TXXX:REPLAYGAIN_ALBUM_GAIN': 'replaygain_album_gain', + 'TXXX:MP3GAIN_MINMAX': 'replaygain_track_minmax', + 'TXXX:MP3GAIN_ALBUM_MINMAX': 'replaygain_album_minmax', + 'TXXX:MP3GAIN_UNDO': 'replaygain_undo', + MVNM: 'movement', + MVIN: 'movementIndex', + PCST: 'podcast', + TCAT: 'category', + TDES: 'description', + TDRL: 'date', + TGID: 'podcastId', + TKWD: 'keywords', + WFED: 'podcasturl' +}; +class ID3v24TagMapper extends CaseInsensitiveTagMap_1.CaseInsensitiveTagMap { + static toRating(popm) { + return { + source: popm.email, + rating: popm.rating > 0 ? (popm.rating - 1) / 254 * GenericTagMapper_1.CommonTagMapper.maxRatingScore : undefined + }; + } + constructor() { + super(['ID3v2.3', 'ID3v2.4'], id3v24TagMap); + } + /** + * Handle post mapping exceptions / correction + * @param tag to post map + * @param warnings Wil be used to register (collect) warnings + * @return Common value e.g. "Buena Vista Social Club" + */ + postMap(tag, warnings) { + switch (tag.id) { + case 'UFID': // decode MusicBrainz Recording Id + if (tag.value.owner_identifier === 'http://musicbrainz.org') { + tag.id += ':' + tag.value.owner_identifier; + tag.value = util.decodeString(tag.value.identifier, 'latin1'); // latin1 == iso-8859-1 + } + break; + case 'PRIV': + switch (tag.value.owner_identifier) { + // decode Windows Media Player + case 'AverageLevel': + case 'PeakValue': + tag.id += ':' + tag.value.owner_identifier; + tag.value = tag.value.data.length === 4 ? tag.value.data.readUInt32LE(0) : null; + if (tag.value === null) { + warnings.addWarning(`Failed to parse PRIV:PeakValue`); + } + break; + default: + warnings.addWarning(`Unknown PRIV owner-identifier: ${tag.value.owner_identifier}`); + } + break; + case 'COMM': + tag.value = tag.value ? tag.value.text : null; + break; + case 'POPM': + tag.value = ID3v24TagMapper.toRating(tag.value); + break; + default: + break; + } + } +} +exports.ID3v24TagMapper = ID3v24TagMapper; +//# sourceMappingURL=ID3v24TagMapper.js.map + +/***/ }), + +/***/ 8928: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ID3v2Parser = void 0; +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +const FrameParser_1 = __webpack_require__(907); +const ID3v2Token_1 = __webpack_require__(8281); +class ID3v2Parser { + static removeUnsyncBytes(buffer) { + let readI = 0; + let writeI = 0; + while (readI < buffer.length - 1) { + if (readI !== writeI) { + buffer[writeI] = buffer[readI]; + } + readI += (buffer[readI] === 0xFF && buffer[readI + 1] === 0) ? 2 : 1; + writeI++; + } + if (readI < buffer.length) { + buffer[writeI++] = buffer[readI]; + } + return buffer.slice(0, writeI); + } + static getFrameHeaderLength(majorVer) { + switch (majorVer) { + case 2: + return 6; + case 3: + case 4: + return 10; + default: + throw new Error('header versionIndex is incorrect'); + } + } + static readFrameFlags(b) { + return { + status: { + tag_alter_preservation: util.getBit(b, 0, 6), + file_alter_preservation: util.getBit(b, 0, 5), + read_only: util.getBit(b, 0, 4) + }, + format: { + grouping_identity: util.getBit(b, 1, 7), + compression: util.getBit(b, 1, 3), + encryption: util.getBit(b, 1, 2), + unsynchronisation: util.getBit(b, 1, 1), + data_length_indicator: util.getBit(b, 1, 0) + } + }; + } + static readFrameData(uint8Array, frameHeader, majorVer, includeCovers, warningCollector) { + const frameParser = new FrameParser_1.FrameParser(majorVer, warningCollector); + switch (majorVer) { + case 2: + return frameParser.readData(uint8Array, frameHeader.id, includeCovers); + case 3: + case 4: + if (frameHeader.flags.format.unsynchronisation) { + uint8Array = ID3v2Parser.removeUnsyncBytes(uint8Array); + } + if (frameHeader.flags.format.data_length_indicator) { + uint8Array = uint8Array.slice(4, uint8Array.length); + } + return frameParser.readData(uint8Array, frameHeader.id, includeCovers); + default: + throw new Error('Unexpected majorVer: ' + majorVer); + } + } + /** + * Create a combined tag key, of tag & description + * @param tag e.g.: COM + * @param description e.g. iTunPGAP + * @returns string e.g. COM:iTunPGAP + */ + static makeDescriptionTagName(tag, description) { + return tag + (description ? ':' + description : ''); + } + async parse(metadata, tokenizer, options) { + this.tokenizer = tokenizer; + this.metadata = metadata; + this.options = options; + const id3Header = await this.tokenizer.readToken(ID3v2Token_1.ID3v2Header); + if (id3Header.fileIdentifier !== 'ID3') { + throw new Error('expected ID3-header file-identifier \'ID3\' was not found'); + } + this.id3Header = id3Header; + this.headerType = ('ID3v2.' + id3Header.version.major); + return id3Header.flags.isExtendedHeader ? this.parseExtendedHeader() : this.parseId3Data(id3Header.size); + } + async parseExtendedHeader() { + const extendedHeader = await this.tokenizer.readToken(ID3v2Token_1.ExtendedHeader); + const dataRemaining = extendedHeader.size - ID3v2Token_1.ExtendedHeader.len; + return dataRemaining > 0 ? this.parseExtendedHeaderData(dataRemaining, extendedHeader.size) : this.parseId3Data(this.id3Header.size - extendedHeader.size); + } + async parseExtendedHeaderData(dataRemaining, extendedHeaderSize) { + await this.tokenizer.ignore(dataRemaining); + return this.parseId3Data(this.id3Header.size - extendedHeaderSize); + } + async parseId3Data(dataLen) { + const uint8Array = await this.tokenizer.readToken(new Token.Uint8ArrayType(dataLen)); + for (const tag of this.parseMetadata(uint8Array)) { + if (tag.id === 'TXXX') { + if (tag.value) { + for (const text of tag.value.text) { + this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, tag.value.description), text); + } + } + } + else if (tag.id === 'COM') { + for (const value of tag.value) { + this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value.text); + } + } + else if (tag.id === 'COMM') { + for (const value of tag.value) { + this.addTag(ID3v2Parser.makeDescriptionTagName(tag.id, value.description), value); + } + } + else if (Array.isArray(tag.value)) { + for (const value of tag.value) { + this.addTag(tag.id, value); + } + } + else { + this.addTag(tag.id, tag.value); + } + } + } + addTag(id, value) { + this.metadata.addTag(this.headerType, id, value); + } + parseMetadata(data) { + let offset = 0; + const tags = []; + while (true) { + if (offset === data.length) + break; + const frameHeaderLength = ID3v2Parser.getFrameHeaderLength(this.id3Header.version.major); + if (offset + frameHeaderLength > data.length) { + this.metadata.addWarning('Illegal ID3v2 tag length'); + break; + } + const frameHeaderBytes = data.slice(offset, offset += frameHeaderLength); + const frameHeader = this.readFrameHeader(frameHeaderBytes, this.id3Header.version.major); + const frameDataBytes = data.slice(offset, offset += frameHeader.length); + const values = ID3v2Parser.readFrameData(frameDataBytes, frameHeader, this.id3Header.version.major, !this.options.skipCovers, this.metadata); + if (values) { + tags.push({ id: frameHeader.id, value: values }); + } + } + return tags; + } + readFrameHeader(uint8Array, majorVer) { + let header; + switch (majorVer) { + case 2: + header = { + id: Buffer.from(uint8Array.slice(0, 3)).toString('ascii'), + length: Token.UINT24_BE.get(uint8Array, 3) + }; + if (!header.id.match(/[A-Z0-9]{3}/g)) { + this.metadata.addWarning(`Invalid ID3v2.${this.id3Header.version.major} frame-header-ID: ${header.id}`); + } + break; + case 3: + case 4: + header = { + id: Buffer.from(uint8Array.slice(0, 4)).toString('ascii'), + length: (majorVer === 4 ? ID3v2Token_1.UINT32SYNCSAFE : Token.UINT32_BE).get(uint8Array, 4), + flags: ID3v2Parser.readFrameFlags(uint8Array.slice(8, 10)) + }; + if (!header.id.match(/[A-Z0-9]{4}/g)) { + this.metadata.addWarning(`Invalid ID3v2.${this.id3Header.version.major} frame-header-ID: ${header.id}`); + } + break; + default: + throw new Error('Unexpected majorVer: ' + majorVer); + } + return header; + } +} +exports.ID3v2Parser = ID3v2Parser; + + +/***/ }), + +/***/ 8281: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.TextEncodingToken = exports.ExtendedHeader = exports.ID3v2Header = exports.UINT32SYNCSAFE = exports.AttachedPictureType = void 0; +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +/** + * The picture type according to the ID3v2 APIC frame + * Ref: http://id3.org/id3v2.3.0#Attached_picture + */ +var AttachedPictureType; +(function (AttachedPictureType) { + AttachedPictureType[AttachedPictureType["Other"] = 0] = "Other"; + AttachedPictureType[AttachedPictureType["32x32 pixels 'file icon' (PNG only)"] = 1] = "32x32 pixels 'file icon' (PNG only)"; + AttachedPictureType[AttachedPictureType["Other file icon"] = 2] = "Other file icon"; + AttachedPictureType[AttachedPictureType["Cover (front)"] = 3] = "Cover (front)"; + AttachedPictureType[AttachedPictureType["Cover (back)"] = 4] = "Cover (back)"; + AttachedPictureType[AttachedPictureType["Leaflet page"] = 5] = "Leaflet page"; + AttachedPictureType[AttachedPictureType["Media (e.g. label side of CD)"] = 6] = "Media (e.g. label side of CD)"; + AttachedPictureType[AttachedPictureType["Lead artist/lead performer/soloist"] = 7] = "Lead artist/lead performer/soloist"; + AttachedPictureType[AttachedPictureType["Artist/performer"] = 8] = "Artist/performer"; + AttachedPictureType[AttachedPictureType["Conductor"] = 9] = "Conductor"; + AttachedPictureType[AttachedPictureType["Band/Orchestra"] = 10] = "Band/Orchestra"; + AttachedPictureType[AttachedPictureType["Composer"] = 11] = "Composer"; + AttachedPictureType[AttachedPictureType["Lyricist/text writer"] = 12] = "Lyricist/text writer"; + AttachedPictureType[AttachedPictureType["Recording Location"] = 13] = "Recording Location"; + AttachedPictureType[AttachedPictureType["During recording"] = 14] = "During recording"; + AttachedPictureType[AttachedPictureType["During performance"] = 15] = "During performance"; + AttachedPictureType[AttachedPictureType["Movie/video screen capture"] = 16] = "Movie/video screen capture"; + AttachedPictureType[AttachedPictureType["A bright coloured fish"] = 17] = "A bright coloured fish"; + AttachedPictureType[AttachedPictureType["Illustration"] = 18] = "Illustration"; + AttachedPictureType[AttachedPictureType["Band/artist logotype"] = 19] = "Band/artist logotype"; + AttachedPictureType[AttachedPictureType["Publisher/Studio logotype"] = 20] = "Publisher/Studio logotype"; +})(AttachedPictureType = exports.AttachedPictureType || (exports.AttachedPictureType = {})); +/** + * 28 bits (representing up to 256MB) integer, the msb is 0 to avoid 'false syncsignals'. + * 4 * %0xxxxxxx + */ +exports.UINT32SYNCSAFE = { + get: (buf, off) => { + return buf[off + 3] & 0x7f | ((buf[off + 2]) << 7) | + ((buf[off + 1]) << 14) | ((buf[off]) << 21); + }, + len: 4 +}; +/** + * ID3v2 header + * Ref: http://id3.org/id3v2.3.0#ID3v2_header + * ToDo + */ +exports.ID3v2Header = { + len: 10, + get: (buf, off) => { + return { + // ID3v2/file identifier "ID3" + fileIdentifier: new Token.StringType(3, 'ascii').get(buf, off), + // ID3v2 versionIndex + version: { + major: Token.INT8.get(buf, off + 3), + revision: Token.INT8.get(buf, off + 4) + }, + // ID3v2 flags + flags: { + // Unsynchronisation + unsynchronisation: util.getBit(buf, off + 5, 7), + // Extended header + isExtendedHeader: util.getBit(buf, off + 5, 6), + // Experimental indicator + expIndicator: util.getBit(buf, off + 5, 5), + footer: util.getBit(buf, off + 5, 4) + }, + size: exports.UINT32SYNCSAFE.get(buf, off + 6) + }; + } +}; +exports.ExtendedHeader = { + len: 10, + get: (buf, off) => { + return { + // Extended header size + size: Token.UINT32_BE.get(buf, off), + // Extended Flags + extendedFlags: Token.UINT16_BE.get(buf, off + 4), + // Size of padding + sizeOfPadding: Token.UINT32_BE.get(buf, off + 6), + // CRC data present + crcDataPresent: util.getBit(buf, off + 4, 31) + }; + } +}; +exports.TextEncodingToken = { + len: 1, + get: (uint8Array, off) => { + switch (uint8Array[off]) { + case 0x00: + return { encoding: 'latin1' }; // binary + case 0x01: + return { encoding: 'utf16le', bom: true }; + case 0x02: + return { encoding: 'utf16le', bom: false }; + case 0x03: + return { encoding: 'utf8', bom: false }; + default: + return { encoding: 'utf8', bom: false }; + } + } +}; + + +/***/ }), + +/***/ 4633: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Header = void 0; +const Token = __webpack_require__(3416); +const FourCC_1 = __webpack_require__(8049); +/** + * Common AIFF chunk header + */ +exports.Header = { + len: 8, + get: (buf, off) => { + return { + // Chunk type ID + chunkID: FourCC_1.FourCcToken.get(buf, off), + // Chunk size + chunkSize: Number(BigInt(Token.UINT32_BE.get(buf, off + 4))) + }; + } +}; + + +/***/ }), + +/***/ 9941: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.getLyricsHeaderLength = exports.endTag2 = void 0; +exports.endTag2 = 'LYRICS200'; +async function getLyricsHeaderLength(reader) { + if (reader.fileSize >= 143) { + const buf = Buffer.alloc(15); + await reader.randomRead(buf, 0, buf.length, reader.fileSize - 143); + const txt = buf.toString('binary'); + const tag = txt.substr(6); + if (tag === exports.endTag2) { + return parseInt(txt.substr(0, 6), 10) + 15; + } + } + return 0; +} +exports.getLyricsHeaderLength = getLyricsHeaderLength; + + +/***/ }), + +/***/ 3121: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.elements = void 0; +const types_1 = __webpack_require__(8591); +/** + * Elements of document type description + * Derived from https://github.com/tungol/EBML/blob/master/doctypes/matroska.dtd + * Extended with: + * - https://www.matroska.org/technical/specs/index.html + */ +exports.elements = { + 0x1a45dfa3: { + name: 'ebml', + container: { + 0x4286: { name: 'ebmlVersion', value: types_1.DataType.uint }, + 0x42f7: { name: 'ebmlReadVersion', value: types_1.DataType.uint }, + 0x42f2: { name: 'ebmlMaxIDWidth', value: types_1.DataType.uint }, + 0x42f3: { name: 'ebmlMaxSizeWidth', value: types_1.DataType.uint }, + 0x4282: { name: 'docType', value: types_1.DataType.string }, + 0x4287: { name: 'docTypeVersion', value: types_1.DataType.uint }, + 0x4285: { name: 'docTypeReadVersion', value: types_1.DataType.uint } // 5.1.7 + } + }, + // Matroska segments + 0x18538067: { + name: 'segment', + container: { + // Meta Seek Information + 0x114d9b74: { + name: 'seekHead', + container: { + 0x4dbb: { + name: 'seek', + container: { + 0x53ab: { name: 'seekId', value: types_1.DataType.binary }, + 0x53ac: { name: 'seekPosition', value: types_1.DataType.uint } + } + } + } + }, + // Segment Information + 0x1549a966: { + name: 'info', + container: { + 0x73a4: { name: 'uid', value: types_1.DataType.uid }, + 0x7384: { name: 'filename', value: types_1.DataType.string }, + 0x3cb923: { name: 'prevUID', value: types_1.DataType.uid }, + 0x3c83ab: { name: 'prevFilename', value: types_1.DataType.string }, + 0x3eb923: { name: 'nextUID', value: types_1.DataType.uid }, + 0x3e83bb: { name: 'nextFilename', value: types_1.DataType.string }, + 0x2ad7b1: { name: 'timecodeScale', value: types_1.DataType.uint }, + 0x4489: { name: 'duration', value: types_1.DataType.float }, + 0x4461: { name: 'dateUTC', value: types_1.DataType.uint }, + 0x7ba9: { name: 'title', value: types_1.DataType.string }, + 0x4d80: { name: 'muxingApp', value: types_1.DataType.string }, + 0x5741: { name: 'writingApp', value: types_1.DataType.string } + } + }, + // Cluster + 0x1f43b675: { + name: 'cluster', + multiple: true, + container: { + 0xe7: { name: 'timecode', value: types_1.DataType.uid }, + 0xa3: { name: 'unknown', value: types_1.DataType.binary }, + 0xa7: { name: 'position', value: types_1.DataType.uid }, + 0xab: { name: 'prevSize', value: types_1.DataType.uid } + } + }, + // Track + 0x1654ae6b: { + name: 'tracks', + container: { + 0xae: { + name: 'entries', + multiple: true, + container: { + 0xd7: { name: 'trackNumber', value: types_1.DataType.uint }, + 0x73c5: { name: 'uid', value: types_1.DataType.uid }, + 0x83: { name: 'trackType', value: types_1.DataType.uint }, + 0xb9: { name: 'flagEnabled', value: types_1.DataType.bool }, + 0x88: { name: 'flagDefault', value: types_1.DataType.bool }, + 0x55aa: { name: 'flagForced', value: types_1.DataType.bool }, + 0x9c: { name: 'flagLacing', value: types_1.DataType.bool }, + 0x6de7: { name: 'minCache', value: types_1.DataType.uint }, + 0x6de8: { name: 'maxCache', value: types_1.DataType.uint }, + 0x23e383: { name: 'defaultDuration', value: types_1.DataType.uint }, + 0x23314f: { name: 'timecodeScale', value: types_1.DataType.float }, + 0x536e: { name: 'name', value: types_1.DataType.string }, + 0x22b59c: { name: 'language', value: types_1.DataType.string }, + 0x86: { name: 'codecID', value: types_1.DataType.string }, + 0x63a2: { name: 'codecPrivate', value: types_1.DataType.binary }, + 0x258688: { name: 'codecName', value: types_1.DataType.string }, + 0x3a9697: { name: 'codecSettings', value: types_1.DataType.string }, + 0x3b4040: { name: 'codecInfoUrl', value: types_1.DataType.string }, + 0x26b240: { name: 'codecDownloadUrl', value: types_1.DataType.string }, + 0xaa: { name: 'codecDecodeAll', value: types_1.DataType.bool }, + 0x6fab: { name: 'trackOverlay', value: types_1.DataType.uint }, + // Video + 0xe0: { + name: 'video', + container: { + 0x9a: { name: 'flagInterlaced', value: types_1.DataType.bool }, + 0x53b8: { name: 'stereoMode', value: types_1.DataType.uint }, + 0xb0: { name: 'pixelWidth', value: types_1.DataType.uint }, + 0xba: { name: 'pixelHeight', value: types_1.DataType.uint }, + 0x54b0: { name: 'displayWidth', value: types_1.DataType.uint }, + 0x54ba: { name: 'displayHeight', value: types_1.DataType.uint }, + 0x54b3: { name: 'aspectRatioType', value: types_1.DataType.uint }, + 0x2eb524: { name: 'colourSpace', value: types_1.DataType.uint }, + 0x2fb523: { name: 'gammaValue', value: types_1.DataType.float } + } + }, + // Audio + 0xe1: { + name: 'audio', + container: { + 0xb5: { name: 'samplingFrequency', value: types_1.DataType.float }, + 0x78b5: { name: 'outputSamplingFrequency', value: types_1.DataType.float }, + 0x9f: { name: 'channels', value: types_1.DataType.uint }, + 0x94: { name: 'channels', value: types_1.DataType.uint }, + 0x7d7b: { name: 'channelPositions', value: types_1.DataType.binary }, + 0x6264: { name: 'bitDepth', value: types_1.DataType.uint } + } + }, + // Content Encoding + 0x6d80: { + name: 'contentEncodings', + container: { + 0x6240: { + name: 'contentEncoding', + container: { + 0x5031: { name: 'order', value: types_1.DataType.uint }, + 0x5032: { name: 'scope', value: types_1.DataType.bool }, + 0x5033: { name: 'type', value: types_1.DataType.uint }, + 0x5034: { + name: 'contentEncoding', + container: { + 0x4254: { name: 'contentCompAlgo', value: types_1.DataType.uint }, + 0x4255: { name: 'contentCompSettings', value: types_1.DataType.binary } + } + }, + 0x5035: { + name: 'contentEncoding', + container: { + 0x47e1: { name: 'contentEncAlgo', value: types_1.DataType.uint }, + 0x47e2: { name: 'contentEncKeyID', value: types_1.DataType.binary }, + 0x47e3: { name: 'contentSignature ', value: types_1.DataType.binary }, + 0x47e4: { name: 'ContentSigKeyID ', value: types_1.DataType.binary }, + 0x47e5: { name: 'contentSigAlgo ', value: types_1.DataType.uint }, + 0x47e6: { name: 'contentSigHashAlgo ', value: types_1.DataType.uint } + } + }, + 0x6264: { name: 'bitDepth', value: types_1.DataType.uint } + } + } + } + } + } + } + } + }, + // Cueing Data + 0x1c53bb6b: { + name: 'cues', + container: { + 0xbb: { + name: 'cuePoint', + container: { + 0xb3: { name: 'cueTime', value: types_1.DataType.uid }, + 0xb7: { + name: 'positions', + container: { + 0xf7: { name: 'track', value: types_1.DataType.uint }, + 0xf1: { name: 'clusterPosition', value: types_1.DataType.uint }, + 0x5378: { name: 'blockNumber', value: types_1.DataType.uint }, + 0xea: { name: 'codecState', value: types_1.DataType.uint }, + 0xdb: { + name: 'reference', container: { + 0x96: { name: 'time', value: types_1.DataType.uint }, + 0x97: { name: 'cluster', value: types_1.DataType.uint }, + 0x535f: { name: 'number', value: types_1.DataType.uint }, + 0xeb: { name: 'codecState', value: types_1.DataType.uint } + } + }, + 0xf0: { name: 'relativePosition', value: types_1.DataType.uint } // extended + } + } + } + } + } + }, + // Attachment + 0x1941a469: { + name: 'attachments', + container: { + 0x61a7: { + name: 'attachedFiles', + multiple: true, + container: { + 0x467e: { name: 'description', value: types_1.DataType.string }, + 0x466e: { name: 'name', value: types_1.DataType.string }, + 0x4660: { name: 'mimeType', value: types_1.DataType.string }, + 0x465c: { name: 'data', value: types_1.DataType.binary }, + 0x46ae: { name: 'uid', value: types_1.DataType.uid } + } + } + } + }, + // Chapters + 0x1043a770: { + name: 'chapters', + container: { + 0x45b9: { + name: 'editionEntry', + container: { + 0xb6: { + name: 'chapterAtom', + container: { + 0x73c4: { name: 'uid', value: types_1.DataType.uid }, + 0x91: { name: 'timeStart', value: types_1.DataType.uint }, + 0x92: { name: 'timeEnd', value: types_1.DataType.uid }, + 0x98: { name: 'hidden', value: types_1.DataType.bool }, + 0x4598: { name: 'enabled', value: types_1.DataType.uid }, + 0x8f: { name: 'track', container: { + 0x89: { name: 'trackNumber', value: types_1.DataType.uid }, + 0x80: { + name: 'display', container: { + 0x85: { name: 'string', value: types_1.DataType.string }, + 0x437c: { name: 'language ', value: types_1.DataType.string }, + 0x437e: { name: 'country ', value: types_1.DataType.string } + } + } + } + } + } + } + } + } + } + }, + // Tagging + 0x1254c367: { + name: 'tags', + container: { + 0x7373: { + name: 'tag', + multiple: true, + container: { + 0x63c0: { + name: 'target', + container: { + 0x63c5: { name: 'tagTrackUID', value: types_1.DataType.uid }, + 0x63c4: { name: 'tagChapterUID', value: types_1.DataType.uint }, + 0x63c6: { name: 'tagAttachmentUID', value: types_1.DataType.uid }, + 0x63ca: { name: 'targetType', value: types_1.DataType.string }, + 0x68ca: { name: 'targetTypeValue', value: types_1.DataType.uint }, + 0x63c9: { name: 'tagEditionUID', value: types_1.DataType.uid } // extended + } + }, + 0x67c8: { + name: 'simpleTags', + multiple: true, + container: { + 0x45a3: { name: 'name', value: types_1.DataType.string }, + 0x4487: { name: 'string', value: types_1.DataType.string }, + 0x4485: { name: 'binary', value: types_1.DataType.binary }, + 0x447a: { name: 'language', value: types_1.DataType.string }, + 0x447b: { name: 'languageIETF', value: types_1.DataType.string }, + 0x4484: { name: 'default', value: types_1.DataType.bool } // extended + } + } + } + } + } + } + } + } +}; + + +/***/ }), + +/***/ 78: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MatroskaParser = void 0; +const token_types_1 = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const BasicParser_1 = __webpack_require__(7805); +const types_1 = __webpack_require__(8591); +const matroskaDtd = __webpack_require__(3121); +const debug = (0, debug_1.default)('music-metadata:parser:matroska'); +/** + * Extensible Binary Meta Language (EBML) parser + * https://en.wikipedia.org/wiki/Extensible_Binary_Meta_Language + * http://matroska.sourceforge.net/technical/specs/rfc/index.html + * + * WEBM VP8 AUDIO FILE + */ +class MatroskaParser extends BasicParser_1.BasicParser { + constructor() { + super(); + this.padding = 0; + this.parserMap = new Map(); + this.ebmlMaxIDLength = 4; + this.ebmlMaxSizeLength = 8; + this.parserMap.set(types_1.DataType.uint, e => this.readUint(e)); + this.parserMap.set(types_1.DataType.string, e => this.readString(e)); + this.parserMap.set(types_1.DataType.binary, e => this.readBuffer(e)); + this.parserMap.set(types_1.DataType.uid, async (e) => await this.readUint(e) === 1); + this.parserMap.set(types_1.DataType.bool, e => this.readFlag(e)); + this.parserMap.set(types_1.DataType.float, e => this.readFloat(e)); + } + /** + * Initialize parser with output (metadata), input (tokenizer) & parsing options (options). + * @param {INativeMetadataCollector} metadata Output + * @param {ITokenizer} tokenizer Input + * @param {IOptions} options Parsing options + */ + init(metadata, tokenizer, options) { + super.init(metadata, tokenizer, options); + return this; + } + async parse() { + const matroska = await this.parseContainer(matroskaDtd.elements, this.tokenizer.fileInfo.size, []); + this.metadata.setFormat('container', `EBML/${matroska.ebml.docType}`); + if (matroska.segment) { + const info = matroska.segment.info; + if (info) { + const timecodeScale = info.timecodeScale ? info.timecodeScale : 1000000; + const duration = info.duration * timecodeScale / 1000000000; + this.addTag('segment:title', info.title); + this.metadata.setFormat('duration', duration); + } + const audioTracks = matroska.segment.tracks; + if (audioTracks && audioTracks.entries) { + audioTracks.entries.forEach(entry => { + const stream = { + codecName: entry.codecID.replace('A_', '').replace('V_', ''), + codecSettings: entry.codecSettings, + flagDefault: entry.flagDefault, + flagLacing: entry.flagLacing, + flagEnabled: entry.flagEnabled, + language: entry.language, + name: entry.name, + type: entry.trackType, + audio: entry.audio, + video: entry.video + }; + this.metadata.addStreamInfo(stream); + }); + const audioTrack = audioTracks.entries + .filter(entry => { + return entry.trackType === types_1.TrackType.audio.valueOf(); + }) + .reduce((acc, cur) => { + if (!acc) { + return cur; + } + if (!acc.flagDefault && cur.flagDefault) { + return cur; + } + if (cur.trackNumber && cur.trackNumber < acc.trackNumber) { + return cur; + } + return acc; + }, null); + if (audioTrack) { + this.metadata.setFormat('codec', audioTrack.codecID.replace('A_', '')); + this.metadata.setFormat('sampleRate', audioTrack.audio.samplingFrequency); + this.metadata.setFormat('numberOfChannels', audioTrack.audio.channels); + } + if (matroska.segment.tags) { + matroska.segment.tags.tag.forEach(tag => { + const target = tag.target; + const targetType = (target === null || target === void 0 ? void 0 : target.targetTypeValue) ? types_1.TargetType[target.targetTypeValue] : ((target === null || target === void 0 ? void 0 : target.targetType) ? target.targetType : 'track'); + tag.simpleTags.forEach(simpleTag => { + const value = simpleTag.string ? simpleTag.string : simpleTag.binary; + this.addTag(`${targetType}:${simpleTag.name}`, value); + }); + }); + } + if (matroska.segment.attachments) { + matroska.segment.attachments.attachedFiles + .filter(file => file.mimeType.startsWith('image/')) + .map(file => { + return { + data: file.data, + format: file.mimeType, + description: file.description, + name: file.name + }; + }).forEach(picture => { + this.addTag('picture', picture); + }); + } + } + } + } + async parseContainer(container, posDone, path) { + const tree = {}; + while (this.tokenizer.position < posDone) { + let element; + try { + element = await this.readElement(); + } + catch (error) { + if (error.message === 'End-Of-Stream') { + break; + } + throw error; + } + const type = container[element.id]; + if (type) { + debug(`Element: name=${type.name}, container=${!!type.container}`); + if (type.container) { + const res = await this.parseContainer(type.container, element.len >= 0 ? this.tokenizer.position + element.len : -1, path.concat([type.name])); + if (type.multiple) { + if (!tree[type.name]) { + tree[type.name] = []; + } + tree[type.name].push(res); + } + else { + tree[type.name] = res; + } + } + else { + tree[type.name] = await this.parserMap.get(type.value)(element); + } + } + else { + switch (element.id) { + case 0xec: // void + this.padding += element.len; + await this.tokenizer.ignore(element.len); + break; + default: + debug(`parseEbml: path=${path.join('/')}, unknown element: id=${element.id.toString(16)}`); + this.padding += element.len; + await this.tokenizer.ignore(element.len); + } + } + } + return tree; + } + async readVintData(maxLength) { + const msb = await this.tokenizer.peekNumber(token_types_1.UINT8); + let mask = 0x80; + let oc = 1; + // Calculate VINT_WIDTH + while ((msb & mask) === 0) { + if (oc > maxLength) { + throw new Error('VINT value exceeding maximum size'); + } + ++oc; + mask >>= 1; + } + const id = Buffer.alloc(oc); + await this.tokenizer.readBuffer(id); + return id; + } + async readElement() { + const id = await this.readVintData(this.ebmlMaxIDLength); + const lenField = await this.readVintData(this.ebmlMaxSizeLength); + lenField[0] ^= 0x80 >> (lenField.length - 1); + const nrLen = Math.min(6, lenField.length); // JavaScript can max read 6 bytes integer + return { + id: id.readUIntBE(0, id.length), + len: lenField.readUIntBE(lenField.length - nrLen, nrLen) + }; + } + isMaxValue(vintData) { + if (vintData.length === this.ebmlMaxSizeLength) { + for (let n = 1; n < this.ebmlMaxSizeLength; ++n) { + if (vintData[n] !== 0xff) + return false; + } + return true; + } + return false; + } + async readFloat(e) { + switch (e.len) { + case 0: + return 0.0; + case 4: + return this.tokenizer.readNumber(token_types_1.Float32_BE); + case 8: + return this.tokenizer.readNumber(token_types_1.Float64_BE); + case 10: + return this.tokenizer.readNumber(token_types_1.Float64_BE); + default: + throw new Error(`Invalid IEEE-754 float length: ${e.len}`); + } + } + async readFlag(e) { + return (await this.readUint(e)) === 1; + } + async readUint(e) { + const buf = await this.readBuffer(e); + const nrLen = Math.min(6, e.len); // JavaScript can max read 6 bytes integer + return buf.readUIntBE(e.len - nrLen, nrLen); + } + async readString(e) { + const rawString = await this.tokenizer.readToken(new token_types_1.StringType(e.len, 'utf-8')); + return rawString.replace(/\00.*$/g, ''); + } + async readBuffer(e) { + const buf = Buffer.alloc(e.len); + await this.tokenizer.readBuffer(buf); + return buf; + } + addTag(tagId, value) { + this.metadata.addTag('matroska', tagId, value); + } +} +exports.MatroskaParser = MatroskaParser; + + +/***/ }), + +/***/ 5481: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MatroskaTagMapper = void 0; +const CaseInsensitiveTagMap_1 = __webpack_require__(4132); +/** + * EBML Tag map + */ +const ebmlTagMap = { + 'segment:title': 'title', + 'album:ARTIST': 'albumartist', + 'album:ARTISTSORT': 'albumartistsort', + 'album:TITLE': 'album', + 'album:DATE_RECORDED': 'originaldate', + 'album:PART_NUMBER': 'disk', + 'album:TOTAL_PARTS': 'totaltracks', + 'track:ARTIST': 'artist', + 'track:ARTISTSORT': 'artistsort', + 'track:TITLE': 'title', + 'track:PART_NUMBER': 'track', + 'track:MUSICBRAINZ_TRACKID': 'musicbrainz_recordingid', + 'track:MUSICBRAINZ_ALBUMID': 'musicbrainz_albumid', + 'track:MUSICBRAINZ_ARTISTID': 'musicbrainz_artistid', + 'track:PUBLISHER': 'label', + 'track:GENRE': 'genre', + 'track:ENCODER': 'encodedby', + 'track:ENCODER_OPTIONS': 'encodersettings', + 'edition:TOTAL_PARTS': 'totaldiscs', + picture: 'picture' +}; +class MatroskaTagMapper extends CaseInsensitiveTagMap_1.CaseInsensitiveTagMap { + constructor() { + super(['matroska'], ebmlTagMap); + } +} +exports.MatroskaTagMapper = MatroskaTagMapper; +//# sourceMappingURL=MatroskaTagMapper.js.map + +/***/ }), + +/***/ 8591: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.TrackType = exports.TargetType = exports.DataType = void 0; +var DataType; +(function (DataType) { + DataType[DataType["string"] = 0] = "string"; + DataType[DataType["uint"] = 1] = "uint"; + DataType[DataType["uid"] = 2] = "uid"; + DataType[DataType["bool"] = 3] = "bool"; + DataType[DataType["binary"] = 4] = "binary"; + DataType[DataType["float"] = 5] = "float"; +})(DataType = exports.DataType || (exports.DataType = {})); +var TargetType; +(function (TargetType) { + TargetType[TargetType["shot"] = 10] = "shot"; + TargetType[TargetType["scene"] = 20] = "scene"; + TargetType[TargetType["track"] = 30] = "track"; + TargetType[TargetType["part"] = 40] = "part"; + TargetType[TargetType["album"] = 50] = "album"; + TargetType[TargetType["edition"] = 60] = "edition"; + TargetType[TargetType["collection"] = 70] = "collection"; +})(TargetType = exports.TargetType || (exports.TargetType = {})); +var TrackType; +(function (TrackType) { + TrackType[TrackType["video"] = 1] = "video"; + TrackType[TrackType["audio"] = 2] = "audio"; + TrackType[TrackType["complex"] = 3] = "complex"; + TrackType[TrackType["logo"] = 4] = "logo"; + TrackType[TrackType["subtitle"] = 17] = "subtitle"; + TrackType[TrackType["button"] = 18] = "button"; + TrackType[TrackType["control"] = 32] = "control"; +})(TrackType = exports.TrackType || (exports.TrackType = {})); +//# sourceMappingURL=types.js.map + +/***/ }), + +/***/ 9134: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Atom = void 0; +const debug_1 = __webpack_require__(1227); +const AtomToken = __webpack_require__(1060); +const debug = (0, debug_1.default)('music-metadata:parser:MP4:Atom'); +class Atom { + constructor(header, extended, parent) { + this.header = header; + this.extended = extended; + this.parent = parent; + this.children = []; + this.atomPath = (this.parent ? this.parent.atomPath + '.' : '') + this.header.name; + } + static async readAtom(tokenizer, dataHandler, parent, remaining) { + // Parse atom header + const offset = tokenizer.position; + // debug(`Reading next token on offset=${offset}...`); // buf.toString('ascii') + const header = await tokenizer.readToken(AtomToken.Header); + const extended = header.length === BigInt(1); + if (extended) { + header.length = await tokenizer.readToken(AtomToken.ExtendedSize); + } + const atomBean = new Atom(header, header.length === BigInt(1), parent); + const payloadLength = atomBean.getPayloadLength(remaining); + debug(`parse atom name=${atomBean.atomPath}, extended=${atomBean.extended}, offset=${offset}, len=${atomBean.header.length}`); // buf.toString('ascii') + await atomBean.readData(tokenizer, dataHandler, payloadLength); + return atomBean; + } + getHeaderLength() { + return this.extended ? 16 : 8; + } + getPayloadLength(remaining) { + return (this.header.length === BigInt(0) ? remaining : Number(this.header.length)) - this.getHeaderLength(); + } + async readAtoms(tokenizer, dataHandler, size) { + while (size > 0) { + const atomBean = await Atom.readAtom(tokenizer, dataHandler, this, size); + this.children.push(atomBean); + size -= atomBean.header.length === BigInt(0) ? size : Number(atomBean.header.length); + } + } + async readData(tokenizer, dataHandler, remaining) { + switch (this.header.name) { + // "Container" atoms, contains nested atoms + case 'moov': // The Movie Atom: contains other atoms + case 'udta': // User defined atom + case 'trak': + case 'mdia': // Media atom + case 'minf': // Media Information Atom + case 'stbl': // The Sample Table Atom + case '': + case 'ilst': + case 'tref': + return this.readAtoms(tokenizer, dataHandler, this.getPayloadLength(remaining)); + case 'meta': // Metadata Atom, ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW8 + // meta has 4 bytes of padding, ignore + await tokenizer.ignore(4); + return this.readAtoms(tokenizer, dataHandler, this.getPayloadLength(remaining) - 4); + case 'mdhd': // Media header atom + case 'mvhd': // 'movie' => 'mvhd': movie header atom; child of Movie Atom + case 'tkhd': + case 'stsz': + case 'mdat': + default: + return dataHandler(this, remaining); + } + } +} +exports.Atom = Atom; + + +/***/ }), + +/***/ 1060: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ChapterText = exports.StcoAtom = exports.StszAtom = exports.StscAtom = exports.SampleToChunkToken = exports.SttsAtom = exports.TimeToSampleToken = exports.SoundSampleDescriptionV0 = exports.SoundSampleDescriptionVersion = exports.StsdAtom = exports.TrackHeaderAtom = exports.NameAtom = exports.DataAtom = exports.MvhdAtom = exports.MdhdAtom = exports.FixedLengthAtom = exports.mhdr = exports.tkhd = exports.ftyp = exports.ExtendedSize = exports.Header = void 0; +const Token = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const FourCC_1 = __webpack_require__(8049); +const debug = (0, debug_1.default)('music-metadata:parser:MP4:atom'); +exports.Header = { + len: 8, + get: (buf, off) => { + const length = Token.UINT32_BE.get(buf, off); + if (length < 0) + throw new Error('Invalid atom header length'); + return { + length: BigInt(length), + name: new Token.StringType(4, 'binary').get(buf, off + 4) + }; + }, + put: (buf, off, hdr) => { + Token.UINT32_BE.put(buf, off, Number(hdr.length)); + return FourCC_1.FourCcToken.put(buf, off + 4, hdr.name); + } +}; +/** + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html#//apple_ref/doc/uid/TP40000939-CH203-38190 + */ +exports.ExtendedSize = Token.UINT64_BE; +exports.ftyp = { + len: 4, + get: (buf, off) => { + return { + type: new Token.StringType(4, 'ascii').get(buf, off) + }; + } +}; +exports.tkhd = { + len: 4, + get: (buf, off) => { + return { + type: new Token.StringType(4, 'ascii').get(buf, off) + }; + } +}; +/** + * Token: Movie Header Atom + */ +exports.mhdr = { + len: 8, + get: (buf, off) => { + return { + version: Token.UINT8.get(buf, off), + flags: Token.UINT24_BE.get(buf, off + 1), + nextItemID: Token.UINT32_BE.get(buf, off + 4) + }; + } +}; +/** + * Base class for 'fixed' length atoms. + * In some cases these atoms are longer then the sum of the described fields. + * Issue: https://github.com/Borewit/music-metadata/issues/120 + */ +class FixedLengthAtom { + /** + * + * @param {number} len Length as specified in the size field + * @param {number} expLen Total length of sum of specified fields in the standard + */ + constructor(len, expLen, atomId) { + this.len = len; + if (len < expLen) { + throw new Error(`Atom ${atomId} expected to be ${expLen}, but specifies ${len} bytes long.`); + } + else if (len > expLen) { + debug(`Warning: atom ${atomId} expected to be ${expLen}, but was actually ${len} bytes long.`); + } + } +} +exports.FixedLengthAtom = FixedLengthAtom; +/** + * Timestamp stored in seconds since Mac Epoch (1 January 1904) + */ +const SecondsSinceMacEpoch = { + len: 4, + get: (buf, off) => { + const secondsSinceUnixEpoch = Token.UINT32_BE.get(buf, off) - 2082844800; + return new Date(secondsSinceUnixEpoch * 1000); + } +}; +/** + * Token: Media Header Atom + * Ref: + * - https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-SW34 + * - https://wiki.multimedia.cx/index.php/QuickTime_container#mdhd + */ +class MdhdAtom extends FixedLengthAtom { + constructor(len) { + super(len, 24, 'mdhd'); + this.len = len; + } + get(buf, off) { + return { + version: Token.UINT8.get(buf, off + 0), + flags: Token.UINT24_BE.get(buf, off + 1), + creationTime: SecondsSinceMacEpoch.get(buf, off + 4), + modificationTime: SecondsSinceMacEpoch.get(buf, off + 8), + timeScale: Token.UINT32_BE.get(buf, off + 12), + duration: Token.UINT32_BE.get(buf, off + 16), + language: Token.UINT16_BE.get(buf, off + 20), + quality: Token.UINT16_BE.get(buf, off + 22) + }; + } +} +exports.MdhdAtom = MdhdAtom; +/** + * Token: Movie Header Atom + */ +class MvhdAtom extends FixedLengthAtom { + constructor(len) { + super(len, 100, 'mvhd'); + this.len = len; + } + get(buf, off) { + return { + version: Token.UINT8.get(buf, off), + flags: Token.UINT24_BE.get(buf, off + 1), + creationTime: SecondsSinceMacEpoch.get(buf, off + 4), + modificationTime: SecondsSinceMacEpoch.get(buf, off + 8), + timeScale: Token.UINT32_BE.get(buf, off + 12), + duration: Token.UINT32_BE.get(buf, off + 16), + preferredRate: Token.UINT32_BE.get(buf, off + 20), + preferredVolume: Token.UINT16_BE.get(buf, off + 24), + // ignore reserver: 10 bytes + // ignore matrix structure: 36 bytes + previewTime: Token.UINT32_BE.get(buf, off + 72), + previewDuration: Token.UINT32_BE.get(buf, off + 76), + posterTime: Token.UINT32_BE.get(buf, off + 80), + selectionTime: Token.UINT32_BE.get(buf, off + 84), + selectionDuration: Token.UINT32_BE.get(buf, off + 88), + currentTime: Token.UINT32_BE.get(buf, off + 92), + nextTrackID: Token.UINT32_BE.get(buf, off + 96) + }; + } +} +exports.MvhdAtom = MvhdAtom; +/** + * Data Atom Structure + */ +class DataAtom { + constructor(len) { + this.len = len; + } + get(buf, off) { + return { + type: { + set: Token.UINT8.get(buf, off + 0), + type: Token.UINT24_BE.get(buf, off + 1) + }, + locale: Token.UINT24_BE.get(buf, off + 4), + value: Buffer.from(new Token.Uint8ArrayType(this.len - 8).get(buf, off + 8)) + }; + } +} +exports.DataAtom = DataAtom; +/** + * Data Atom Structure + * Ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW31 + */ +class NameAtom { + constructor(len) { + this.len = len; + } + get(buf, off) { + return { + version: Token.UINT8.get(buf, off), + flags: Token.UINT24_BE.get(buf, off + 1), + name: new Token.StringType(this.len - 4, 'utf-8').get(buf, off + 4) + }; + } +} +exports.NameAtom = NameAtom; +/** + * Track Header Atoms structure + * Ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25550 + */ +class TrackHeaderAtom { + constructor(len) { + this.len = len; + } + get(buf, off) { + return { + version: Token.UINT8.get(buf, off), + flags: Token.UINT24_BE.get(buf, off + 1), + creationTime: SecondsSinceMacEpoch.get(buf, off + 4), + modificationTime: SecondsSinceMacEpoch.get(buf, off + 8), + trackId: Token.UINT32_BE.get(buf, off + 12), + // reserved 4 bytes + duration: Token.UINT32_BE.get(buf, off + 20), + layer: Token.UINT16_BE.get(buf, off + 24), + alternateGroup: Token.UINT16_BE.get(buf, off + 26), + volume: Token.UINT16_BE.get(buf, off + 28) // ToDo: fixed point + // ToDo: add remaining fields + }; + } +} +exports.TrackHeaderAtom = TrackHeaderAtom; +/** + * Atom: Sample Description Atom ('stsd') + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691 + */ +const stsdHeader = { + len: 8, + get: (buf, off) => { + return { + version: Token.UINT8.get(buf, off), + flags: Token.UINT24_BE.get(buf, off + 1), + numberOfEntries: Token.UINT32_BE.get(buf, off + 4) + }; + } +}; +/** + * Atom: Sample Description Atom ('stsd') + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691 + */ +class SampleDescriptionTable { + constructor(len) { + this.len = len; + } + get(buf, off) { + return { + dataFormat: FourCC_1.FourCcToken.get(buf, off), + dataReferenceIndex: Token.UINT16_BE.get(buf, off + 10), + description: new Token.Uint8ArrayType(this.len - 12).get(buf, off + 12) + }; + } +} +/** + * Atom: Sample-description Atom ('stsd') + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25691 + */ +class StsdAtom { + constructor(len) { + this.len = len; + } + get(buf, off) { + const header = stsdHeader.get(buf, off); + off += stsdHeader.len; + const table = []; + for (let n = 0; n < header.numberOfEntries; ++n) { + const size = Token.UINT32_BE.get(buf, off); // Sample description size + off += Token.UINT32_BE.len; + table.push(new SampleDescriptionTable(size).get(buf, off)); + off += size; + } + return { + header, + table + }; + } +} +exports.StsdAtom = StsdAtom; +/** + * Common Sound Sample Description (version & revision) + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-57317 + */ +exports.SoundSampleDescriptionVersion = { + len: 8, + get(buf, off) { + return { + version: Token.INT16_BE.get(buf, off), + revision: Token.INT16_BE.get(buf, off + 2), + vendor: Token.INT32_BE.get(buf, off + 4) + }; + } +}; +/** + * Sound Sample Description (Version 0) + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-130736 + */ +exports.SoundSampleDescriptionV0 = { + len: 12, + get(buf, off) { + return { + numAudioChannels: Token.INT16_BE.get(buf, off + 0), + sampleSize: Token.INT16_BE.get(buf, off + 2), + compressionId: Token.INT16_BE.get(buf, off + 4), + packetSize: Token.INT16_BE.get(buf, off + 6), + sampleRate: Token.UINT16_BE.get(buf, off + 8) + Token.UINT16_BE.get(buf, off + 10) / 10000 + }; + } +}; +class SimpleTableAtom { + constructor(len, token) { + this.len = len; + this.token = token; + } + get(buf, off) { + const nrOfEntries = Token.INT32_BE.get(buf, off + 4); + return { + version: Token.INT8.get(buf, off + 0), + flags: Token.INT24_BE.get(buf, off + 1), + numberOfEntries: nrOfEntries, + entries: readTokenTable(buf, this.token, off + 8, this.len - 8, nrOfEntries) + }; + } +} +exports.TimeToSampleToken = { + len: 8, + get(buf, off) { + return { + count: Token.INT32_BE.get(buf, off + 0), + duration: Token.INT32_BE.get(buf, off + 4) + }; + } +}; +/** + * Time-to-sample('stts') atom. + * Store duration information for a media’s samples. + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25696 + */ +class SttsAtom extends SimpleTableAtom { + constructor(len) { + super(len, exports.TimeToSampleToken); + this.len = len; + } +} +exports.SttsAtom = SttsAtom; +exports.SampleToChunkToken = { + len: 12, + get(buf, off) { + return { + firstChunk: Token.INT32_BE.get(buf, off), + samplesPerChunk: Token.INT32_BE.get(buf, off + 4), + sampleDescriptionId: Token.INT32_BE.get(buf, off + 8) + }; + } +}; +/** + * Sample-to-Chunk ('stsc') atom interface + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25706 + */ +class StscAtom extends SimpleTableAtom { + constructor(len) { + super(len, exports.SampleToChunkToken); + this.len = len; + } +} +exports.StscAtom = StscAtom; +/** + * Sample-size ('stsz') atom + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25710 + */ +class StszAtom { + constructor(len) { + this.len = len; + } + get(buf, off) { + const nrOfEntries = Token.INT32_BE.get(buf, off + 8); + return { + version: Token.INT8.get(buf, off), + flags: Token.INT24_BE.get(buf, off + 1), + sampleSize: Token.INT32_BE.get(buf, off + 4), + numberOfEntries: nrOfEntries, + entries: readTokenTable(buf, Token.INT32_BE, off + 12, this.len - 12, nrOfEntries) + }; + } +} +exports.StszAtom = StszAtom; +/** + * Chunk offset atom, 'stco' + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25715 + */ +class StcoAtom extends SimpleTableAtom { + constructor(len) { + super(len, Token.INT32_BE); + this.len = len; + } +} +exports.StcoAtom = StcoAtom; +/** + * Token used to decode text-track from 'mdat' atom (raw data stream) + */ +class ChapterText { + constructor(len) { + this.len = len; + } + get(buf, off) { + const titleLen = Token.INT16_BE.get(buf, off + 0); + const str = new Token.StringType(titleLen, 'utf-8'); + return str.get(buf, off + 2); + } +} +exports.ChapterText = ChapterText; +function readTokenTable(buf, token, off, remainingLen, numberOfEntries) { + debug(`remainingLen=${remainingLen}, numberOfEntries=${numberOfEntries} * token-len=${token.len}`); + if (remainingLen === 0) + return []; + if (remainingLen !== numberOfEntries * token.len) + throw new Error('mismatch number-of-entries with remaining atom-length'); + const entries = []; + // parse offset-table + for (let n = 0; n < numberOfEntries; ++n) { + entries.push(token.get(buf, off)); + off += token.len; + } + return entries; +} + + +/***/ }), + +/***/ 8841: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MP4Parser = void 0; +const debug_1 = __webpack_require__(1227); +const Token = __webpack_require__(3416); +const BasicParser_1 = __webpack_require__(7805); +const ID3v1Parser_1 = __webpack_require__(2282); +const type_1 = __webpack_require__(6032); +const Atom_1 = __webpack_require__(9134); +const AtomToken = __webpack_require__(1060); +const debug = (0, debug_1.default)('music-metadata:parser:MP4'); +const tagFormat = 'iTunes'; +const encoderDict = { + raw: { + lossy: false, + format: 'raw' + }, + MAC3: { + lossy: true, + format: 'MACE 3:1' + }, + MAC6: { + lossy: true, + format: 'MACE 6:1' + }, + ima4: { + lossy: true, + format: 'IMA 4:1' + }, + ulaw: { + lossy: true, + format: 'uLaw 2:1' + }, + alaw: { + lossy: true, + format: 'uLaw 2:1' + }, + Qclp: { + lossy: true, + format: 'QUALCOMM PureVoice' + }, + '.mp3': { + lossy: true, + format: 'MPEG-1 layer 3' + }, + alac: { + lossy: false, + format: 'ALAC' + }, + 'ac-3': { + lossy: true, + format: 'AC-3' + }, + mp4a: { + lossy: true, + format: 'MPEG-4/AAC' + }, + mp4s: { + lossy: true, + format: 'MP4S' + }, + // Closed Captioning Media, https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW87 + c608: { + lossy: true, + format: 'CEA-608' + }, + c708: { + lossy: true, + format: 'CEA-708' + } +}; +function distinct(value, index, self) { + return self.indexOf(value) === index; +} +/* + * Parser for the MP4 (MPEG-4 Part 14) container format + * Standard: ISO/IEC 14496-14 + * supporting: + * - QuickTime container + * - MP4 File Format + * - 3GPP file format + * - 3GPP2 file format + * + * MPEG-4 Audio / Part 3 (.m4a)& MPEG 4 Video (m4v, mp4) extension. + * Support for Apple iTunes tags as found in a M4A/M4V files. + * Ref: + * https://en.wikipedia.org/wiki/ISO_base_media_file_format + * https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/Metadata/Metadata.html + * http://atomicparsley.sourceforge.net/mpeg-4files.html + * https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata + * https://wiki.multimedia.cx/index.php/QuickTime_container + */ +class MP4Parser extends BasicParser_1.BasicParser { + constructor() { + super(...arguments); + this.atomParsers = { + /** + * Parse movie header (mvhd) atom + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-56313 + */ + mvhd: async (len) => { + const mvhd = await this.tokenizer.readToken(new AtomToken.MvhdAtom(len)); + this.metadata.setFormat('creationTime', mvhd.creationTime); + this.metadata.setFormat('modificationTime', mvhd.modificationTime); + }, + /** + * Parse media header (mdhd) atom + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-25615 + */ + mdhd: async (len) => { + const mdhd_data = await this.tokenizer.readToken(new AtomToken.MdhdAtom(len)); + // this.parse_mxhd(mdhd_data, this.currentTrack); + const td = this.getTrackDescription(); + td.creationTime = mdhd_data.creationTime; + td.modificationTime = mdhd_data.modificationTime; + td.timeScale = mdhd_data.timeScale; + td.duration = mdhd_data.duration; + }, + chap: async (len) => { + const td = this.getTrackDescription(); + const trackIds = []; + while (len >= Token.UINT32_BE.len) { + trackIds.push(await this.tokenizer.readNumber(Token.UINT32_BE)); + len -= Token.UINT32_BE.len; + } + td.chapterList = trackIds; + }, + tkhd: async (len) => { + const track = (await this.tokenizer.readToken(new AtomToken.TrackHeaderAtom(len))); + this.tracks.push(track); + }, + /** + * Parse mdat atom. + * Will scan for chapters + */ + mdat: async (len) => { + this.audioLengthInBytes = len; + this.calculateBitRate(); + if (this.options.includeChapters) { + const trackWithChapters = this.tracks.filter(track => track.chapterList); + if (trackWithChapters.length === 1) { + const chapterTrackIds = trackWithChapters[0].chapterList; + const chapterTracks = this.tracks.filter(track => chapterTrackIds.indexOf(track.trackId) !== -1); + if (chapterTracks.length === 1) { + return this.parseChapterTrack(chapterTracks[0], trackWithChapters[0], len); + } + } + } + await this.tokenizer.ignore(len); + }, + ftyp: async (len) => { + const types = []; + while (len > 0) { + const ftype = await this.tokenizer.readToken(AtomToken.ftyp); + len -= AtomToken.ftyp.len; + const value = ftype.type.replace(/\W/g, ''); + if (value.length > 0) { + types.push(value); // unshift for backward compatibility + } + } + debug(`ftyp: ${types.join('/')}`); + const x = types.filter(distinct).join('/'); + this.metadata.setFormat('container', x); + }, + /** + * Parse sample description atom + */ + stsd: async (len) => { + const stsd = await this.tokenizer.readToken(new AtomToken.StsdAtom(len)); + const trackDescription = this.getTrackDescription(); + trackDescription.soundSampleDescription = stsd.table.map(dfEntry => this.parseSoundSampleDescription(dfEntry)); + }, + /** + * sample-to-Chunk Atoms + */ + stsc: async (len) => { + const stsc = await this.tokenizer.readToken(new AtomToken.StscAtom(len)); + this.getTrackDescription().sampleToChunkTable = stsc.entries; + }, + /** + * time to sample + */ + stts: async (len) => { + const stts = await this.tokenizer.readToken(new AtomToken.SttsAtom(len)); + this.getTrackDescription().timeToSampleTable = stts.entries; + }, + /** + * Parse sample-sizes atom ('stsz') + */ + stsz: async (len) => { + const stsz = await this.tokenizer.readToken(new AtomToken.StszAtom(len)); + const td = this.getTrackDescription(); + td.sampleSize = stsz.sampleSize; + td.sampleSizeTable = stsz.entries; + }, + /** + * Parse chunk-offset atom ('stco') + */ + stco: async (len) => { + const stco = await this.tokenizer.readToken(new AtomToken.StcoAtom(len)); + this.getTrackDescription().chunkOffsetTable = stco.entries; // remember chunk offsets + }, + date: async (len) => { + const date = await this.tokenizer.readToken(new Token.StringType(len, 'utf-8')); + this.addTag('date', date); + } + }; + } + static read_BE_Integer(array, signed) { + const integerType = (signed ? 'INT' : 'UINT') + array.length * 8 + (array.length > 1 ? '_BE' : ''); + const token = Token[integerType]; + if (!token) { + throw new Error('Token for integer type not found: "' + integerType + '"'); + } + return Number(token.get(array, 0)); + } + async parse() { + this.tracks = []; + let remainingFileSize = this.tokenizer.fileInfo.size; + while (!this.tokenizer.fileInfo.size || remainingFileSize > 0) { + try { + const token = await this.tokenizer.peekToken(AtomToken.Header); + if (token.name === '\0\0\0\0') { + const errMsg = `Error at offset=${this.tokenizer.position}: box.id=0`; + debug(errMsg); + this.addWarning(errMsg); + break; + } + } + catch (error) { + const errMsg = `Error at offset=${this.tokenizer.position}: ${error.message}`; + debug(errMsg); + this.addWarning(errMsg); + break; + } + const rootAtom = await Atom_1.Atom.readAtom(this.tokenizer, (atom, remaining) => this.handleAtom(atom, remaining), null, remainingFileSize); + remainingFileSize -= rootAtom.header.length === BigInt(0) ? remainingFileSize : Number(rootAtom.header.length); + } + // Post process metadata + const formatList = []; + this.tracks.forEach(track => { + const trackFormats = []; + track.soundSampleDescription.forEach(ssd => { + const streamInfo = {}; + const encoderInfo = encoderDict[ssd.dataFormat]; + if (encoderInfo) { + trackFormats.push(encoderInfo.format); + streamInfo.codecName = encoderInfo.format; + } + else { + streamInfo.codecName = `<${ssd.dataFormat}>`; + } + if (ssd.description) { + const { description } = ssd; + if (description.sampleRate > 0) { + streamInfo.type = type_1.TrackType.audio; + streamInfo.audio = { + samplingFrequency: description.sampleRate, + bitDepth: description.sampleSize, + channels: description.numAudioChannels + }; + } + } + this.metadata.addStreamInfo(streamInfo); + }); + if (trackFormats.length >= 1) { + formatList.push(trackFormats.join('/')); + } + }); + if (formatList.length > 0) { + this.metadata.setFormat('codec', formatList.filter(distinct).join('+')); + } + const audioTracks = this.tracks.filter(track => { + return track.soundSampleDescription.length >= 1 && track.soundSampleDescription[0].description && track.soundSampleDescription[0].description.numAudioChannels > 0; + }); + if (audioTracks.length >= 1) { + const audioTrack = audioTracks[0]; + const duration = audioTrack.duration / audioTrack.timeScale; + this.metadata.setFormat('duration', duration); // calculate duration in seconds + const ssd = audioTrack.soundSampleDescription[0]; + if (ssd.description) { + this.metadata.setFormat('sampleRate', ssd.description.sampleRate); + this.metadata.setFormat('bitsPerSample', ssd.description.sampleSize); + this.metadata.setFormat('numberOfChannels', ssd.description.numAudioChannels); + } + const encoderInfo = encoderDict[ssd.dataFormat]; + if (encoderInfo) { + this.metadata.setFormat('lossless', !encoderInfo.lossy); + } + this.calculateBitRate(); + } + } + async handleAtom(atom, remaining) { + if (atom.parent) { + switch (atom.parent.header.name) { + case 'ilst': + case '': + return this.parseMetadataItemData(atom); + } + } + // const payloadLength = atom.getPayloadLength(remaining); + if (this.atomParsers[atom.header.name]) { + return this.atomParsers[atom.header.name](remaining); + } + else { + debug(`No parser for atom path=${atom.atomPath}, payload-len=${remaining}, ignoring atom`); + await this.tokenizer.ignore(remaining); + } + } + getTrackDescription() { + return this.tracks[this.tracks.length - 1]; + } + calculateBitRate() { + if (this.audioLengthInBytes && this.metadata.format.duration) { + this.metadata.setFormat('bitrate', 8 * this.audioLengthInBytes / this.metadata.format.duration); + } + } + addTag(id, value) { + this.metadata.addTag(tagFormat, id, value); + } + addWarning(message) { + debug('Warning: ' + message); + this.metadata.addWarning(message); + } + /** + * Parse data of Meta-item-list-atom (item of 'ilst' atom) + * @param metaAtom + * Ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW8 + */ + parseMetadataItemData(metaAtom) { + let tagKey = metaAtom.header.name; + return metaAtom.readAtoms(this.tokenizer, async (child, remaining) => { + const payLoadLength = child.getPayloadLength(remaining); + switch (child.header.name) { + case 'data': // value atom + return this.parseValueAtom(tagKey, child); + case 'name': // name atom (optional) + const name = await this.tokenizer.readToken(new AtomToken.NameAtom(payLoadLength)); + tagKey += ':' + name.name; + break; + case 'mean': // name atom (optional) + const mean = await this.tokenizer.readToken(new AtomToken.NameAtom(payLoadLength)); + // console.log(" %s[%s] = %s", tagKey, header.name, mean.name); + tagKey += ':' + mean.name; + break; + default: + const dataAtom = await this.tokenizer.readToken(new Token.BufferType(payLoadLength)); + this.addWarning('Unsupported meta-item: ' + tagKey + '[' + child.header.name + '] => value=' + dataAtom.toString('hex') + ' ascii=' + dataAtom.toString('ascii')); + } + }, metaAtom.getPayloadLength(0)); + } + async parseValueAtom(tagKey, metaAtom) { + const dataAtom = await this.tokenizer.readToken(new AtomToken.DataAtom(Number(metaAtom.header.length) - AtomToken.Header.len)); + if (dataAtom.type.set !== 0) { + throw new Error('Unsupported type-set != 0: ' + dataAtom.type.set); + } + // Use well-known-type table + // Ref: https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35 + switch (dataAtom.type.type) { + case 0: // reserved: Reserved for use where no type needs to be indicated + switch (tagKey) { + case 'trkn': + case 'disk': + const num = Token.UINT8.get(dataAtom.value, 3); + const of = Token.UINT8.get(dataAtom.value, 5); + // console.log(" %s[data] = %s/%s", tagKey, num, of); + this.addTag(tagKey, num + '/' + of); + break; + case 'gnre': + const genreInt = Token.UINT8.get(dataAtom.value, 1); + const genreStr = ID3v1Parser_1.Genres[genreInt - 1]; + // console.log(" %s[data] = %s", tagKey, genreStr); + this.addTag(tagKey, genreStr); + break; + default: + // console.log(" reserved-data: name=%s, len=%s, set=%s, type=%s, locale=%s, value{ hex=%s, ascii=%s }", + // header.name, header.length, dataAtom.type.set, dataAtom.type.type, dataAtom.locale, dataAtom.value.toString('hex'), dataAtom.value.toString('ascii')); + } + break; + case 1: // UTF-8: Without any count or NULL terminator + case 18: // Unknown: Found in m4b in combination with a '©gen' tag + this.addTag(tagKey, dataAtom.value.toString('utf-8')); + break; + case 13: // JPEG + if (this.options.skipCovers) + break; + this.addTag(tagKey, { + format: 'image/jpeg', + data: Buffer.from(dataAtom.value) + }); + break; + case 14: // PNG + if (this.options.skipCovers) + break; + this.addTag(tagKey, { + format: 'image/png', + data: Buffer.from(dataAtom.value) + }); + break; + case 21: // BE Signed Integer + this.addTag(tagKey, MP4Parser.read_BE_Integer(dataAtom.value, true)); + break; + case 22: // BE Unsigned Integer + this.addTag(tagKey, MP4Parser.read_BE_Integer(dataAtom.value, false)); + break; + case 65: // An 8-bit signed integer + this.addTag(tagKey, dataAtom.value.readInt8(0)); + break; + case 66: // A big-endian 16-bit signed integer + this.addTag(tagKey, dataAtom.value.readInt16BE(0)); + break; + case 67: // A big-endian 32-bit signed integer + this.addTag(tagKey, dataAtom.value.readInt32BE(0)); + break; + default: + this.addWarning(`atom key=${tagKey}, has unknown well-known-type (data-type): ${dataAtom.type.type}`); + } + } + /** + * @param sampleDescription + * Ref: https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-128916 + */ + parseSoundSampleDescription(sampleDescription) { + const ssd = { + dataFormat: sampleDescription.dataFormat, + dataReferenceIndex: sampleDescription.dataReferenceIndex + }; + let offset = 0; + const version = AtomToken.SoundSampleDescriptionVersion.get(sampleDescription.description, offset); + offset += AtomToken.SoundSampleDescriptionVersion.len; + if (version.version === 0 || version.version === 1) { + // Sound Sample Description (Version 0) + ssd.description = AtomToken.SoundSampleDescriptionV0.get(sampleDescription.description, offset); + } + else { + debug(`Warning: sound-sample-description ${version} not implemented`); + } + return ssd; + } + async parseChapterTrack(chapterTrack, track, len) { + if (!chapterTrack.sampleSize) { + if (chapterTrack.chunkOffsetTable.length !== chapterTrack.sampleSizeTable.length) + throw new Error('Expected equal chunk-offset-table & sample-size-table length.'); + } + const chapters = []; + for (let i = 0; i < chapterTrack.chunkOffsetTable.length && len > 0; ++i) { + const chunkOffset = chapterTrack.chunkOffsetTable[i]; + const nextChunkLen = chunkOffset - this.tokenizer.position; + const sampleSize = chapterTrack.sampleSize > 0 ? chapterTrack.sampleSize : chapterTrack.sampleSizeTable[i]; + len -= nextChunkLen + sampleSize; + if (len < 0) + throw new Error('Chapter chunk exceeding token length'); + await this.tokenizer.ignore(nextChunkLen); + const title = await this.tokenizer.readToken(new AtomToken.ChapterText(sampleSize)); + debug(`Chapter ${i + 1}: ${title}`); + const chapter = { + title, + sampleOffset: this.findSampleOffset(track, this.tokenizer.position) + }; + debug(`Chapter title=${chapter.title}, offset=${chapter.sampleOffset}/${this.tracks[0].duration}`); + chapters.push(chapter); + } + this.metadata.setFormat('chapters', chapters); + await this.tokenizer.ignore(len); + } + findSampleOffset(track, chapterOffset) { + let totalDuration = 0; + track.timeToSampleTable.forEach(e => { + totalDuration += e.count * e.duration; + }); + debug(`Total duration=${totalDuration}`); + let chunkIndex = 0; + while (chunkIndex < track.chunkOffsetTable.length && track.chunkOffsetTable[chunkIndex] < chapterOffset) { + ++chunkIndex; + } + return this.getChunkDuration(chunkIndex + 1, track); + } + getChunkDuration(chunkId, track) { + let ttsi = 0; + let ttsc = track.timeToSampleTable[ttsi].count; + let ttsd = track.timeToSampleTable[ttsi].duration; + let curChunkId = 1; + let samplesPerChunk = this.getSamplesPerChunk(curChunkId, track.sampleToChunkTable); + let totalDuration = 0; + while (curChunkId < chunkId) { + const nrOfSamples = Math.min(ttsc, samplesPerChunk); + totalDuration += nrOfSamples * ttsd; + ttsc -= nrOfSamples; + samplesPerChunk -= nrOfSamples; + if (samplesPerChunk === 0) { + ++curChunkId; + samplesPerChunk = this.getSamplesPerChunk(curChunkId, track.sampleToChunkTable); + } + else { + ++ttsi; + ttsc = track.timeToSampleTable[ttsi].count; + ttsd = track.timeToSampleTable[ttsi].duration; + } + } + return totalDuration; + } + getSamplesPerChunk(chunkId, stcTable) { + for (let i = 0; i < stcTable.length - 1; ++i) { + if (chunkId >= stcTable[i].firstChunk && chunkId < stcTable[i + 1].firstChunk) { + return stcTable[i].samplesPerChunk; + } + } + return stcTable[stcTable.length - 1].samplesPerChunk; + } +} +exports.MP4Parser = MP4Parser; + + +/***/ }), + +/***/ 7852: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MP4TagMapper = exports.tagType = void 0; +const CaseInsensitiveTagMap_1 = __webpack_require__(4132); +/** + * Ref: https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata + */ +const mp4TagMap = { + '©nam': 'title', + '©ART': 'artist', + aART: 'albumartist', + /** + * ToDo: Album artist seems to be stored here while Picard documentation says: aART + */ + '----:com.apple.iTunes:Band': 'albumartist', + '©alb': 'album', + '©day': 'date', + '©cmt': 'comment', + '©com': 'comment', + trkn: 'track', + disk: 'disk', + '©gen': 'genre', + covr: 'picture', + '©wrt': 'composer', + '©lyr': 'lyrics', + soal: 'albumsort', + sonm: 'titlesort', + soar: 'artistsort', + soaa: 'albumartistsort', + soco: 'composersort', + '----:com.apple.iTunes:LYRICIST': 'lyricist', + '----:com.apple.iTunes:CONDUCTOR': 'conductor', + '----:com.apple.iTunes:REMIXER': 'remixer', + '----:com.apple.iTunes:ENGINEER': 'engineer', + '----:com.apple.iTunes:PRODUCER': 'producer', + '----:com.apple.iTunes:DJMIXER': 'djmixer', + '----:com.apple.iTunes:MIXER': 'mixer', + '----:com.apple.iTunes:LABEL': 'label', + '©grp': 'grouping', + '----:com.apple.iTunes:SUBTITLE': 'subtitle', + '----:com.apple.iTunes:DISCSUBTITLE': 'discsubtitle', + cpil: 'compilation', + tmpo: 'bpm', + '----:com.apple.iTunes:MOOD': 'mood', + '----:com.apple.iTunes:MEDIA': 'media', + '----:com.apple.iTunes:CATALOGNUMBER': 'catalognumber', + tvsh: 'tvShow', + tvsn: 'tvSeason', + tves: 'tvEpisode', + sosn: 'tvShowSort', + tven: 'tvEpisodeId', + tvnn: 'tvNetwork', + pcst: 'podcast', + purl: 'podcasturl', + '----:com.apple.iTunes:MusicBrainz Album Status': 'releasestatus', + '----:com.apple.iTunes:MusicBrainz Album Type': 'releasetype', + '----:com.apple.iTunes:MusicBrainz Album Release Country': 'releasecountry', + '----:com.apple.iTunes:SCRIPT': 'script', + '----:com.apple.iTunes:LANGUAGE': 'language', + cprt: 'copyright', + '©cpy': 'copyright', + '----:com.apple.iTunes:LICENSE': 'license', + '©too': 'encodedby', + pgap: 'gapless', + '----:com.apple.iTunes:BARCODE': 'barcode', + '----:com.apple.iTunes:ISRC': 'isrc', + '----:com.apple.iTunes:ASIN': 'asin', + '----:com.apple.iTunes:NOTES': 'comment', + '----:com.apple.iTunes:MusicBrainz Track Id': 'musicbrainz_recordingid', + '----:com.apple.iTunes:MusicBrainz Release Track Id': 'musicbrainz_trackid', + '----:com.apple.iTunes:MusicBrainz Album Id': 'musicbrainz_albumid', + '----:com.apple.iTunes:MusicBrainz Artist Id': 'musicbrainz_artistid', + '----:com.apple.iTunes:MusicBrainz Album Artist Id': 'musicbrainz_albumartistid', + '----:com.apple.iTunes:MusicBrainz Release Group Id': 'musicbrainz_releasegroupid', + '----:com.apple.iTunes:MusicBrainz Work Id': 'musicbrainz_workid', + '----:com.apple.iTunes:MusicBrainz TRM Id': 'musicbrainz_trmid', + '----:com.apple.iTunes:MusicBrainz Disc Id': 'musicbrainz_discid', + '----:com.apple.iTunes:Acoustid Id': 'acoustid_id', + '----:com.apple.iTunes:Acoustid Fingerprint': 'acoustid_fingerprint', + '----:com.apple.iTunes:MusicIP PUID': 'musicip_puid', + '----:com.apple.iTunes:fingerprint': 'musicip_fingerprint', + '----:com.apple.iTunes:replaygain_track_gain': 'replaygain_track_gain', + '----:com.apple.iTunes:replaygain_track_peak': 'replaygain_track_peak', + '----:com.apple.iTunes:replaygain_album_gain': 'replaygain_album_gain', + '----:com.apple.iTunes:replaygain_album_peak': 'replaygain_album_peak', + '----:com.apple.iTunes:replaygain_track_minmax': 'replaygain_track_minmax', + '----:com.apple.iTunes:replaygain_album_minmax': 'replaygain_album_minmax', + '----:com.apple.iTunes:replaygain_undo': 'replaygain_undo', + // Additional mappings: + gnre: 'genre', + '----:com.apple.iTunes:ALBUMARTISTSORT': 'albumartistsort', + '----:com.apple.iTunes:ARTISTS': 'artists', + '----:com.apple.iTunes:ORIGINALDATE': 'originaldate', + '----:com.apple.iTunes:ORIGINALYEAR': 'originalyear', + // '----:com.apple.iTunes:PERFORMER': 'performer' + desc: 'description', + ldes: 'longDescription', + '©mvn': 'movement', + '©mvi': 'movementIndex', + '©mvc': 'movementTotal', + '©wrk': 'work', + catg: 'category', + egid: 'podcastId', + hdvd: 'hdVideo', + keyw: 'keywords', + shwm: 'showMovement', + stik: 'stik' +}; +exports.tagType = 'iTunes'; +class MP4TagMapper extends CaseInsensitiveTagMap_1.CaseInsensitiveTagMap { + constructor() { + super([exports.tagType], mp4TagMap); + } +} +exports.MP4TagMapper = MP4TagMapper; +//# sourceMappingURL=MP4TagMapper.js.map + +/***/ }), + +/***/ 5261: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +/** + * Extended Lame Header + */ +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ExtendedLameHeader = void 0; +const Token = __webpack_require__(3416); +const common = __webpack_require__(3769); +const ReplayGainDataFormat_1 = __webpack_require__(6118); +/** + * Info Tag + * @link http://gabriel.mp3-tech.org/mp3infotag.html + * @link https://github.com/quodlibet/mutagen/blob/abd58ee58772224334a18817c3fb31103572f70e/mutagen/mp3/_util.py#L112 + */ +exports.ExtendedLameHeader = { + len: 27, + get: (buf, off) => { + const track_peak = Token.UINT32_BE.get(buf, off + 2); + return { + revision: common.getBitAllignedNumber(buf, off, 0, 4), + vbr_method: common.getBitAllignedNumber(buf, off, 4, 4), + lowpass_filter: 100 * Token.UINT8.get(buf, off + 1), + track_peak: track_peak === 0 ? undefined : track_peak / Math.pow(2, 23), + track_gain: ReplayGainDataFormat_1.ReplayGain.get(buf, 6), + album_gain: ReplayGainDataFormat_1.ReplayGain.get(buf, 8), + music_length: Token.UINT32_BE.get(buf, off + 20), + music_crc: Token.UINT8.get(buf, off + 24), + header_crc: Token.UINT16_BE.get(buf, off + 24) + }; + } +}; + + +/***/ }), + +/***/ 60: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MpegParser = void 0; +const Token = __webpack_require__(3416); +const core_1 = __webpack_require__(5849); +const debug_1 = __webpack_require__(1227); +const common = __webpack_require__(3769); +const AbstractID3Parser_1 = __webpack_require__(5159); +const XingTag_1 = __webpack_require__(3566); +const debug = (0, debug_1.default)('music-metadata:parser:mpeg'); +/** + * Cache buffer size used for searching synchronization preabmle + */ +const maxPeekLen = 1024; +/** + * MPEG-4 Audio definitions + * Ref: https://wiki.multimedia.cx/index.php/MPEG-4_Audio + */ +const MPEG4 = { + /** + * Audio Object Types + */ + AudioObjectTypes: [ + 'AAC Main', + 'AAC LC', + 'AAC SSR', + 'AAC LTP' // Long Term Prediction + ], + /** + * Sampling Frequencies + * https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Sampling_Frequencies + */ + SamplingFrequencies: [ + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350, undefined, undefined, -1 + ] + /** + * Channel Configurations + */ +}; +const MPEG4_ChannelConfigurations = [ + undefined, + ['front-center'], + ['front-left', 'front-right'], + ['front-center', 'front-left', 'front-right'], + ['front-center', 'front-left', 'front-right', 'back-center'], + ['front-center', 'front-left', 'front-right', 'back-left', 'back-right'], + ['front-center', 'front-left', 'front-right', 'back-left', 'back-right', 'LFE-channel'], + ['front-center', 'front-left', 'front-right', 'side-left', 'side-right', 'back-left', 'back-right', 'LFE-channel'] +]; +/** + * MPEG Audio Layer I/II/III frame header + * Ref: https://www.mp3-tech.org/programmer/frame_header.html + * Bit layout: AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM + * Ref: https://wiki.multimedia.cx/index.php/ADTS + */ +class MpegFrameHeader { + constructor(buf, off) { + // B(20,19): MPEG Audio versionIndex ID + this.versionIndex = common.getBitAllignedNumber(buf, off + 1, 3, 2); + // C(18,17): Layer description + this.layer = MpegFrameHeader.LayerDescription[common.getBitAllignedNumber(buf, off + 1, 5, 2)]; + if (this.versionIndex > 1 && this.layer === 0) { + this.parseAdtsHeader(buf, off); // Audio Data Transport Stream (ADTS) + } + else { + this.parseMpegHeader(buf, off); // Conventional MPEG header + } + // D(16): Protection bit (if true 16-bit CRC follows header) + this.isProtectedByCRC = !common.isBitSet(buf, off + 1, 7); + } + calcDuration(numFrames) { + return numFrames * this.calcSamplesPerFrame() / this.samplingRate; + } + calcSamplesPerFrame() { + return MpegFrameHeader.samplesInFrameTable[this.version === 1 ? 0 : 1][this.layer]; + } + calculateSideInfoLength() { + if (this.layer !== 3) + return 2; + if (this.channelModeIndex === 3) { + // mono + if (this.version === 1) { + return 17; + } + else if (this.version === 2 || this.version === 2.5) { + return 9; + } + } + else { + if (this.version === 1) { + return 32; + } + else if (this.version === 2 || this.version === 2.5) { + return 17; + } + } + } + calcSlotSize() { + return [null, 4, 1, 1][this.layer]; + } + parseMpegHeader(buf, off) { + this.container = 'MPEG'; + // E(15,12): Bitrate index + this.bitrateIndex = common.getBitAllignedNumber(buf, off + 2, 0, 4); + // F(11,10): Sampling rate frequency index + this.sampRateFreqIndex = common.getBitAllignedNumber(buf, off + 2, 4, 2); + // G(9): Padding bit + this.padding = common.isBitSet(buf, off + 2, 6); + // H(8): Private bit + this.privateBit = common.isBitSet(buf, off + 2, 7); + // I(7,6): Channel Mode + this.channelModeIndex = common.getBitAllignedNumber(buf, off + 3, 0, 2); + // J(5,4): Mode extension (Only used in Joint stereo) + this.modeExtension = common.getBitAllignedNumber(buf, off + 3, 2, 2); + // K(3): Copyright + this.isCopyrighted = common.isBitSet(buf, off + 3, 4); + // L(2): Original + this.isOriginalMedia = common.isBitSet(buf, off + 3, 5); + // M(3): The original bit indicates, if it is set, that the frame is located on its original media. + this.emphasis = common.getBitAllignedNumber(buf, off + 3, 7, 2); + this.version = MpegFrameHeader.VersionID[this.versionIndex]; + this.channelMode = MpegFrameHeader.ChannelMode[this.channelModeIndex]; + this.codec = `MPEG ${this.version} Layer ${this.layer}`; + // Calculate bitrate + const bitrateInKbps = this.calcBitrate(); + if (!bitrateInKbps) { + throw new Error('Cannot determine bit-rate'); + } + this.bitrate = bitrateInKbps * 1000; + // Calculate sampling rate + this.samplingRate = this.calcSamplingRate(); + if (this.samplingRate == null) { + throw new Error('Cannot determine sampling-rate'); + } + } + parseAdtsHeader(buf, off) { + debug(`layer=0 => ADTS`); + this.version = this.versionIndex === 2 ? 4 : 2; + this.container = 'ADTS/MPEG-' + this.version; + const profileIndex = common.getBitAllignedNumber(buf, off + 2, 0, 2); + this.codec = 'AAC'; + this.codecProfile = MPEG4.AudioObjectTypes[profileIndex]; + debug(`MPEG-4 audio-codec=${this.codec}`); + const samplingFrequencyIndex = common.getBitAllignedNumber(buf, off + 2, 2, 4); + this.samplingRate = MPEG4.SamplingFrequencies[samplingFrequencyIndex]; + debug(`sampling-rate=${this.samplingRate}`); + const channelIndex = common.getBitAllignedNumber(buf, off + 2, 7, 3); + this.mp4ChannelConfig = MPEG4_ChannelConfigurations[channelIndex]; + debug(`channel-config=${this.mp4ChannelConfig.join('+')}`); + this.frameLength = common.getBitAllignedNumber(buf, off + 3, 6, 2) << 11; + } + calcBitrate() { + if (this.bitrateIndex === 0x00 || // free + this.bitrateIndex === 0x0F) { // reserved + return; + } + const codecIndex = `${Math.floor(this.version)}${this.layer}`; + return MpegFrameHeader.bitrate_index[this.bitrateIndex][codecIndex]; + } + calcSamplingRate() { + if (this.sampRateFreqIndex === 0x03) + return null; // 'reserved' + return MpegFrameHeader.sampling_rate_freq_index[this.version][this.sampRateFreqIndex]; + } +} +MpegFrameHeader.SyncByte1 = 0xFF; +MpegFrameHeader.SyncByte2 = 0xE0; +MpegFrameHeader.VersionID = [2.5, null, 2, 1]; +MpegFrameHeader.LayerDescription = [0, 3, 2, 1]; +MpegFrameHeader.ChannelMode = ['stereo', 'joint_stereo', 'dual_channel', 'mono']; +MpegFrameHeader.bitrate_index = { + 0x01: { 11: 32, 12: 32, 13: 32, 21: 32, 22: 8, 23: 8 }, + 0x02: { 11: 64, 12: 48, 13: 40, 21: 48, 22: 16, 23: 16 }, + 0x03: { 11: 96, 12: 56, 13: 48, 21: 56, 22: 24, 23: 24 }, + 0x04: { 11: 128, 12: 64, 13: 56, 21: 64, 22: 32, 23: 32 }, + 0x05: { 11: 160, 12: 80, 13: 64, 21: 80, 22: 40, 23: 40 }, + 0x06: { 11: 192, 12: 96, 13: 80, 21: 96, 22: 48, 23: 48 }, + 0x07: { 11: 224, 12: 112, 13: 96, 21: 112, 22: 56, 23: 56 }, + 0x08: { 11: 256, 12: 128, 13: 112, 21: 128, 22: 64, 23: 64 }, + 0x09: { 11: 288, 12: 160, 13: 128, 21: 144, 22: 80, 23: 80 }, + 0x0A: { 11: 320, 12: 192, 13: 160, 21: 160, 22: 96, 23: 96 }, + 0x0B: { 11: 352, 12: 224, 13: 192, 21: 176, 22: 112, 23: 112 }, + 0x0C: { 11: 384, 12: 256, 13: 224, 21: 192, 22: 128, 23: 128 }, + 0x0D: { 11: 416, 12: 320, 13: 256, 21: 224, 22: 144, 23: 144 }, + 0x0E: { 11: 448, 12: 384, 13: 320, 21: 256, 22: 160, 23: 160 } +}; +MpegFrameHeader.sampling_rate_freq_index = { + 1: { 0x00: 44100, 0x01: 48000, 0x02: 32000 }, + 2: { 0x00: 22050, 0x01: 24000, 0x02: 16000 }, + 2.5: { 0x00: 11025, 0x01: 12000, 0x02: 8000 } +}; +MpegFrameHeader.samplesInFrameTable = [ + /* Layer I II III */ + [0, 384, 1152, 1152], + [0, 384, 1152, 576] // MPEG-2(.5 +]; +/** + * MPEG Audio Layer I/II/III + */ +const FrameHeader = { + len: 4, + get: (buf, off) => { + return new MpegFrameHeader(buf, off); + } +}; +function getVbrCodecProfile(vbrScale) { + return 'V' + Math.floor((100 - vbrScale) / 10); +} +class MpegParser extends AbstractID3Parser_1.AbstractID3Parser { + constructor() { + super(...arguments); + this.frameCount = 0; + this.syncFrameCount = -1; + this.countSkipFrameData = 0; + this.totalDataLength = 0; + this.bitrates = []; + this.calculateEofDuration = false; + this.buf_frame_header = Buffer.alloc(4); + this.syncPeek = { + buf: Buffer.alloc(maxPeekLen), + len: 0 + }; + } + /** + * Called after ID3 headers have been parsed + */ + async postId3v2Parse() { + this.metadata.setFormat('lossless', false); + try { + let quit = false; + while (!quit) { + await this.sync(); + quit = await this.parseCommonMpegHeader(); + } + } + catch (err) { + if (err instanceof core_1.EndOfStreamError) { + debug(`End-of-stream`); + if (this.calculateEofDuration) { + const numberOfSamples = this.frameCount * this.samplesPerFrame; + this.metadata.setFormat('numberOfSamples', numberOfSamples); + const duration = numberOfSamples / this.metadata.format.sampleRate; + debug(`Calculate duration at EOF: ${duration} sec.`, duration); + this.metadata.setFormat('duration', duration); + } + } + else { + throw err; + } + } + } + /** + * Called after file has been fully parsed, this allows, if present, to exclude the ID3v1.1 header length + */ + finalize() { + const format = this.metadata.format; + const hasID3v1 = this.metadata.native.hasOwnProperty('ID3v1'); + if (format.duration && this.tokenizer.fileInfo.size) { + const mpegSize = this.tokenizer.fileInfo.size - this.mpegOffset - (hasID3v1 ? 128 : 0); + if (format.codecProfile && format.codecProfile[0] === 'V') { + this.metadata.setFormat('bitrate', mpegSize * 8 / format.duration); + } + } + else if (this.tokenizer.fileInfo.size && format.codecProfile === 'CBR') { + const mpegSize = this.tokenizer.fileInfo.size - this.mpegOffset - (hasID3v1 ? 128 : 0); + const numberOfSamples = Math.round(mpegSize / this.frame_size) * this.samplesPerFrame; + this.metadata.setFormat('numberOfSamples', numberOfSamples); + const duration = numberOfSamples / format.sampleRate; + debug("Calculate CBR duration based on file size: %s", duration); + this.metadata.setFormat('duration', duration); + } + } + async sync() { + let gotFirstSync = false; + while (true) { + let bo = 0; + this.syncPeek.len = await this.tokenizer.peekBuffer(this.syncPeek.buf, { length: maxPeekLen, mayBeLess: true }); + if (this.syncPeek.len <= 163) { + throw new core_1.EndOfStreamError(); + } + while (true) { + if (gotFirstSync && (this.syncPeek.buf[bo] & 0xE0) === 0xE0) { + this.buf_frame_header[0] = MpegFrameHeader.SyncByte1; + this.buf_frame_header[1] = this.syncPeek.buf[bo]; + await this.tokenizer.ignore(bo); + debug(`Sync at offset=${this.tokenizer.position - 1}, frameCount=${this.frameCount}`); + if (this.syncFrameCount === this.frameCount) { + debug(`Re-synced MPEG stream, frameCount=${this.frameCount}`); + this.frameCount = 0; + this.frame_size = 0; + } + this.syncFrameCount = this.frameCount; + return; // sync + } + else { + gotFirstSync = false; + bo = this.syncPeek.buf.indexOf(MpegFrameHeader.SyncByte1, bo); + if (bo === -1) { + if (this.syncPeek.len < this.syncPeek.buf.length) { + throw new core_1.EndOfStreamError(); + } + await this.tokenizer.ignore(this.syncPeek.len); + break; // continue with next buffer + } + else { + ++bo; + gotFirstSync = true; + } + } + } + } + } + /** + * Combined ADTS & MPEG (MP2 & MP3) header handling + * @return {Promise} true if parser should quit + */ + async parseCommonMpegHeader() { + if (this.frameCount === 0) { + this.mpegOffset = this.tokenizer.position - 1; + } + await this.tokenizer.peekBuffer(this.buf_frame_header, { offset: 1, length: 3 }); + let header; + try { + header = FrameHeader.get(this.buf_frame_header, 0); + } + catch (err) { + await this.tokenizer.ignore(1); + this.metadata.addWarning('Parse error: ' + err.message); + return false; // sync + } + await this.tokenizer.ignore(3); + this.metadata.setFormat('container', header.container); + this.metadata.setFormat('codec', header.codec); + this.metadata.setFormat('lossless', false); + this.metadata.setFormat('sampleRate', header.samplingRate); + this.frameCount++; + return header.version >= 2 && header.layer === 0 ? this.parseAdts(header) : this.parseAudioFrameHeader(header); + } + /** + * @return {Promise} true if parser should quit + */ + async parseAudioFrameHeader(header) { + this.metadata.setFormat('numberOfChannels', header.channelMode === 'mono' ? 1 : 2); + this.metadata.setFormat('bitrate', header.bitrate); + if (this.frameCount < 20 * 10000) { + debug('offset=%s MP%s bitrate=%s sample-rate=%s', this.tokenizer.position - 4, header.layer, header.bitrate, header.samplingRate); + } + const slot_size = header.calcSlotSize(); + if (slot_size === null) { + throw new Error('invalid slot_size'); + } + const samples_per_frame = header.calcSamplesPerFrame(); + debug(`samples_per_frame=${samples_per_frame}`); + const bps = samples_per_frame / 8.0; + const fsize = (bps * header.bitrate / header.samplingRate) + + ((header.padding) ? slot_size : 0); + this.frame_size = Math.floor(fsize); + this.audioFrameHeader = header; + this.bitrates.push(header.bitrate); + // xtra header only exists in first frame + if (this.frameCount === 1) { + this.offset = FrameHeader.len; + await this.skipSideInformation(); + return false; + } + if (this.frameCount === 3) { + // the stream is CBR if the first 3 frame bitrates are the same + if (this.areAllSame(this.bitrates)) { + // Actual calculation will be done in finalize + this.samplesPerFrame = samples_per_frame; + this.metadata.setFormat('codecProfile', 'CBR'); + if (this.tokenizer.fileInfo.size) + return true; // Will calculate duration based on the file size + } + else if (this.metadata.format.duration) { + return true; // We already got the duration, stop processing MPEG stream any further + } + if (!this.options.duration) { + return true; // Enforce duration not enabled, stop processing entire stream + } + } + // once we know the file is VBR attach listener to end of + // stream so we can do the duration calculation when we + // have counted all the frames + if (this.options.duration && this.frameCount === 4) { + this.samplesPerFrame = samples_per_frame; + this.calculateEofDuration = true; + } + this.offset = 4; + if (header.isProtectedByCRC) { + await this.parseCrc(); + return false; + } + else { + await this.skipSideInformation(); + return false; + } + } + async parseAdts(header) { + const buf = Buffer.alloc(3); + await this.tokenizer.readBuffer(buf); + header.frameLength += common.getBitAllignedNumber(buf, 0, 0, 11); + this.totalDataLength += header.frameLength; + this.samplesPerFrame = 1024; + const framesPerSec = header.samplingRate / this.samplesPerFrame; + const bytesPerFrame = this.frameCount === 0 ? 0 : this.totalDataLength / this.frameCount; + const bitrate = 8 * bytesPerFrame * framesPerSec + 0.5; + this.metadata.setFormat('bitrate', bitrate); + debug(`frame-count=${this.frameCount}, size=${header.frameLength} bytes, bit-rate=${bitrate}`); + await this.tokenizer.ignore(header.frameLength > 7 ? header.frameLength - 7 : 1); + // Consume remaining header and frame data + if (this.frameCount === 3) { + this.metadata.setFormat('codecProfile', header.codecProfile); + if (header.mp4ChannelConfig) { + this.metadata.setFormat('numberOfChannels', header.mp4ChannelConfig.length); + } + if (this.options.duration) { + this.calculateEofDuration = true; + } + else { + return true; // Stop parsing after the third frame + } + } + return false; + } + async parseCrc() { + this.crc = await this.tokenizer.readNumber(Token.INT16_BE); + this.offset += 2; + return this.skipSideInformation(); + } + async skipSideInformation() { + const sideinfo_length = this.audioFrameHeader.calculateSideInfoLength(); + // side information + await this.tokenizer.readToken(new Token.Uint8ArrayType(sideinfo_length)); + this.offset += sideinfo_length; + await this.readXtraInfoHeader(); + return; + } + async readXtraInfoHeader() { + const headerTag = await this.tokenizer.readToken(XingTag_1.InfoTagHeaderTag); + this.offset += XingTag_1.InfoTagHeaderTag.len; // 12 + switch (headerTag) { + case 'Info': + this.metadata.setFormat('codecProfile', 'CBR'); + return this.readXingInfoHeader(); + case 'Xing': + const infoTag = await this.readXingInfoHeader(); + const codecProfile = getVbrCodecProfile(infoTag.vbrScale); + this.metadata.setFormat('codecProfile', codecProfile); + return null; + case 'Xtra': + // ToDo: ??? + break; + case 'LAME': + const version = await this.tokenizer.readToken(XingTag_1.LameEncoderVersion); + if (this.frame_size >= this.offset + XingTag_1.LameEncoderVersion.len) { + this.offset += XingTag_1.LameEncoderVersion.len; + this.metadata.setFormat('tool', 'LAME ' + version); + await this.skipFrameData(this.frame_size - this.offset); + return null; + } + else { + this.metadata.addWarning('Corrupt LAME header'); + break; + } + // ToDo: ??? + } + // ToDo: promise duration??? + const frameDataLeft = this.frame_size - this.offset; + if (frameDataLeft < 0) { + this.metadata.addWarning('Frame ' + this.frameCount + 'corrupt: negative frameDataLeft'); + } + else { + await this.skipFrameData(frameDataLeft); + } + return null; + } + /** + * Ref: http://gabriel.mp3-tech.org/mp3infotag.html + * @returns {Promise} + */ + async readXingInfoHeader() { + const offset = this.tokenizer.position; + const infoTag = await (0, XingTag_1.readXingHeader)(this.tokenizer); + this.offset += this.tokenizer.position - offset; + if (infoTag.lame) { + this.metadata.setFormat('tool', 'LAME ' + common.stripNulls(infoTag.lame.version)); + if (infoTag.lame.extended) { + // this.metadata.setFormat('trackGain', infoTag.lame.extended.track_gain); + this.metadata.setFormat('trackPeakLevel', infoTag.lame.extended.track_peak); + if (infoTag.lame.extended.track_gain) { + this.metadata.setFormat('trackGain', infoTag.lame.extended.track_gain.adjustment); + } + if (infoTag.lame.extended.album_gain) { + this.metadata.setFormat('albumGain', infoTag.lame.extended.album_gain.adjustment); + } + this.metadata.setFormat('duration', infoTag.lame.extended.music_length / 1000); + } + } + if (infoTag.streamSize) { + const duration = this.audioFrameHeader.calcDuration(infoTag.numFrames); + this.metadata.setFormat('duration', duration); + debug('Get duration from Xing header: %s', this.metadata.format.duration); + return infoTag; + } + // frames field is not present + const frameDataLeft = this.frame_size - this.offset; + await this.skipFrameData(frameDataLeft); + return infoTag; + } + async skipFrameData(frameDataLeft) { + if (frameDataLeft < 0) + throw new Error('frame-data-left cannot be negative'); + await this.tokenizer.ignore(frameDataLeft); + this.countSkipFrameData += frameDataLeft; + } + areAllSame(array) { + const first = array[0]; + return array.every(element => { + return element === first; + }); + } +} +exports.MpegParser = MpegParser; + + +/***/ }), + +/***/ 6118: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ReplayGain = void 0; +const common = __webpack_require__(3769); +/** + * https://github.com/Borewit/music-metadata/wiki/Replay-Gain-Data-Format#name-code + */ +var NameCode; +(function (NameCode) { + /** + * not set + */ + NameCode[NameCode["not_set"] = 0] = "not_set"; + /** + * Radio Gain Adjustment + */ + NameCode[NameCode["radio"] = 1] = "radio"; + /** + * Audiophile Gain Adjustment + */ + NameCode[NameCode["audiophile"] = 2] = "audiophile"; +})(NameCode || (NameCode = {})); +/** + * https://github.com/Borewit/music-metadata/wiki/Replay-Gain-Data-Format#originator-code + */ +var ReplayGainOriginator; +(function (ReplayGainOriginator) { + /** + * Replay Gain unspecified + */ + ReplayGainOriginator[ReplayGainOriginator["unspecified"] = 0] = "unspecified"; + /** + * Replay Gain pre-set by artist/producer/mastering engineer + */ + ReplayGainOriginator[ReplayGainOriginator["engineer"] = 1] = "engineer"; + /** + * Replay Gain set by user + */ + ReplayGainOriginator[ReplayGainOriginator["user"] = 2] = "user"; + /** + * Replay Gain determined automatically, as described on this site + */ + ReplayGainOriginator[ReplayGainOriginator["automatic"] = 3] = "automatic"; + /** + * Set by simple RMS average + */ + ReplayGainOriginator[ReplayGainOriginator["rms_average"] = 4] = "rms_average"; +})(ReplayGainOriginator || (ReplayGainOriginator = {})); +/** + * Replay Gain Data Format + * + * https://github.com/Borewit/music-metadata/wiki/Replay-Gain-Data-Format + */ +exports.ReplayGain = { + len: 2, + get: (buf, off) => { + const gain_type = common.getBitAllignedNumber(buf, off, 0, 3); + const sign = common.getBitAllignedNumber(buf, off, 6, 1); + const gain_adj = common.getBitAllignedNumber(buf, off, 7, 9) / 10.0; + if (gain_type > 0) { + return { + type: common.getBitAllignedNumber(buf, off, 0, 3), + origin: common.getBitAllignedNumber(buf, off, 3, 3), + adjustment: (sign ? -gain_adj : gain_adj) + }; + } + return undefined; + } +}; + + +/***/ }), + +/***/ 3566: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.readXingHeader = exports.XingHeaderFlags = exports.LameEncoderVersion = exports.InfoTagHeaderTag = void 0; +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +const ExtendedLameHeader_1 = __webpack_require__(5261); +/** + * Info Tag: Xing, LAME + */ +exports.InfoTagHeaderTag = new Token.StringType(4, 'ascii'); +/** + * LAME TAG value + * Did not find any official documentation for this + * Value e.g.: "3.98.4" + */ +exports.LameEncoderVersion = new Token.StringType(6, 'ascii'); +/** + * Info Tag + * Ref: http://gabriel.mp3-tech.org/mp3infotag.html + */ +exports.XingHeaderFlags = { + len: 4, + get: (buf, off) => { + return { + frames: util.isBitSet(buf, off, 31), + bytes: util.isBitSet(buf, off, 30), + toc: util.isBitSet(buf, off, 29), + vbrScale: util.isBitSet(buf, off, 28) + }; + } +}; +// /** +// * XING Header Tag +// * Ref: http://gabriel.mp3-tech.org/mp3infotag.html +// */ +async function readXingHeader(tokenizer) { + const flags = await tokenizer.readToken(exports.XingHeaderFlags); + const xingInfoTag = {}; + if (flags.frames) { + xingInfoTag.numFrames = await tokenizer.readToken(Token.UINT32_BE); + } + if (flags.bytes) { + xingInfoTag.streamSize = await tokenizer.readToken(Token.UINT32_BE); + } + if (flags.toc) { + xingInfoTag.toc = Buffer.alloc(100); + await tokenizer.readBuffer(xingInfoTag.toc); + } + if (flags.vbrScale) { + xingInfoTag.vbrScale = await tokenizer.readToken(Token.UINT32_BE); + } + const lameTag = await tokenizer.peekToken(new Token.StringType(4, 'ascii')); + if (lameTag === 'LAME') { + await tokenizer.ignore(4); + xingInfoTag.lame = { + version: await tokenizer.readToken(new Token.StringType(5, 'ascii')) + }; + const match = xingInfoTag.lame.version.match(/\d+.\d+/g); + if (match) { + const majorMinorVersion = xingInfoTag.lame.version.match(/\d+.\d+/g)[0]; // e.g. 3.97 + const version = majorMinorVersion.split('.').map(n => parseInt(n, 10)); + if (version[0] >= 3 && version[1] >= 90) { + xingInfoTag.lame.extended = await tokenizer.readToken(ExtendedLameHeader_1.ExtendedLameHeader); + } + } + } + return xingInfoTag; +} +exports.readXingHeader = readXingHeader; + + +/***/ }), + +/***/ 9606: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +const debug_1 = __webpack_require__(1227); +const Token = __webpack_require__(3416); +const AbstractID3Parser_1 = __webpack_require__(5159); +const MpcSv8Parser_1 = __webpack_require__(5170); +const MpcSv7Parser_1 = __webpack_require__(3928); +const debug = (0, debug_1.default)('music-metadata:parser:musepack'); +class MusepackParser extends AbstractID3Parser_1.AbstractID3Parser { + async postId3v2Parse() { + const signature = await this.tokenizer.peekToken(new Token.StringType(3, 'binary')); + let mpcParser; + switch (signature) { + case 'MP+': { + debug('Musepack stream-version 7'); + mpcParser = new MpcSv7Parser_1.MpcSv7Parser(); + break; + } + case 'MPC': { + debug('Musepack stream-version 8'); + mpcParser = new MpcSv8Parser_1.MpcSv8Parser(); + break; + } + default: { + throw new Error('Invalid Musepack signature prefix'); + } + } + mpcParser.init(this.metadata, this.tokenizer, this.options); + return mpcParser.parse(); + } +} +exports["default"] = MusepackParser; + + +/***/ }), + +/***/ 2812: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BitReader = void 0; +const Token = __webpack_require__(3416); +class BitReader { + constructor(tokenizer) { + this.tokenizer = tokenizer; + this.pos = 0; + this.dword = undefined; + } + /** + * + * @param bits 1..30 bits + */ + async read(bits) { + while (this.dword === undefined) { + this.dword = await this.tokenizer.readToken(Token.UINT32_LE); + } + let out = this.dword; + this.pos += bits; + if (this.pos < 32) { + out >>>= (32 - this.pos); + return out & ((1 << bits) - 1); + } + else { + this.pos -= 32; + if (this.pos === 0) { + this.dword = undefined; + return out & ((1 << bits) - 1); + } + else { + this.dword = await this.tokenizer.readToken(Token.UINT32_LE); + if (this.pos) { + out <<= this.pos; + out |= this.dword >>> (32 - this.pos); + } + return out & ((1 << bits) - 1); + } + } + } + async ignore(bits) { + if (this.pos > 0) { + const remaining = 32 - this.pos; + this.dword = undefined; + bits -= remaining; + this.pos = 0; + } + const remainder = bits % 32; + const numOfWords = (bits - remainder) / 32; + await this.tokenizer.ignore(numOfWords * 4); + return this.read(remainder); + } +} +exports.BitReader = BitReader; + + +/***/ }), + +/***/ 3928: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MpcSv7Parser = void 0; +const debug_1 = __webpack_require__(1227); +const BasicParser_1 = __webpack_require__(7805); +const APEv2Parser_1 = __webpack_require__(6742); +const BitReader_1 = __webpack_require__(2812); +const SV7 = __webpack_require__(8153); +const debug = (0, debug_1.default)('music-metadata:parser:musepack'); +class MpcSv7Parser extends BasicParser_1.BasicParser { + constructor() { + super(...arguments); + this.audioLength = 0; + } + async parse() { + const header = await this.tokenizer.readToken(SV7.Header); + if (header.signature !== 'MP+') + throw new Error('Unexpected magic number'); + debug(`stream-version=${header.streamMajorVersion}.${header.streamMinorVersion}`); + this.metadata.setFormat('container', 'Musepack, SV7'); + this.metadata.setFormat('sampleRate', header.sampleFrequency); + const numberOfSamples = 1152 * (header.frameCount - 1) + header.lastFrameLength; + this.metadata.setFormat('numberOfSamples', numberOfSamples); + this.duration = numberOfSamples / header.sampleFrequency; + this.metadata.setFormat('duration', this.duration); + this.bitreader = new BitReader_1.BitReader(this.tokenizer); + this.metadata.setFormat('numberOfChannels', header.midSideStereo || header.intensityStereo ? 2 : 1); + const version = await this.bitreader.read(8); + this.metadata.setFormat('codec', (version / 100).toFixed(2)); + await this.skipAudioData(header.frameCount); + debug(`End of audio stream, switching to APEv2, offset=${this.tokenizer.position}`); + return APEv2Parser_1.APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options); + } + async skipAudioData(frameCount) { + while (frameCount-- > 0) { + const frameLength = await this.bitreader.read(20); + this.audioLength += 20 + frameLength; + await this.bitreader.ignore(frameLength); + } + // last frame + const lastFrameLength = await this.bitreader.read(11); + this.audioLength += lastFrameLength; + this.metadata.setFormat('bitrate', this.audioLength / this.duration); + } +} +exports.MpcSv7Parser = MpcSv7Parser; + + +/***/ }), + +/***/ 8153: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Header = void 0; +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +/** + * BASIC STRUCTURE + */ +exports.Header = { + len: 6 * 4, + get: (buf, off) => { + const header = { + // word 0 + signature: Buffer.from(buf).toString('latin1', off, off + 3), + // versionIndex number * 1000 (3.81 = 3810) (remember that 4-byte alignment causes this to take 4-bytes) + streamMinorVersion: util.getBitAllignedNumber(buf, off + 3, 0, 4), + streamMajorVersion: util.getBitAllignedNumber(buf, off + 3, 4, 4), + // word 1 + frameCount: Token.UINT32_LE.get(buf, off + 4), + // word 2 + maxLevel: Token.UINT16_LE.get(buf, off + 8), + sampleFrequency: [44100, 48000, 37800, 32000][util.getBitAllignedNumber(buf, off + 10, 0, 2)], + link: util.getBitAllignedNumber(buf, off + 10, 2, 2), + profile: util.getBitAllignedNumber(buf, off + 10, 4, 4), + maxBand: util.getBitAllignedNumber(buf, off + 11, 0, 6), + intensityStereo: util.isBitSet(buf, off + 11, 6), + midSideStereo: util.isBitSet(buf, off + 11, 7), + // word 3 + titlePeak: Token.UINT16_LE.get(buf, off + 12), + titleGain: Token.UINT16_LE.get(buf, off + 14), + // word 4 + albumPeak: Token.UINT16_LE.get(buf, off + 16), + albumGain: Token.UINT16_LE.get(buf, off + 18), + // word + lastFrameLength: (Token.UINT32_LE.get(buf, off + 20) >>> 20) & 0x7FF, + trueGapless: util.isBitSet(buf, off + 23, 0) + }; + header.lastFrameLength = header.trueGapless ? (Token.UINT32_LE.get(buf, 20) >>> 20) & 0x7FF : 0; + return header; + } +}; + + +/***/ }), + +/***/ 5170: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.MpcSv8Parser = void 0; +const debug_1 = __webpack_require__(1227); +const BasicParser_1 = __webpack_require__(7805); +const APEv2Parser_1 = __webpack_require__(6742); +const FourCC_1 = __webpack_require__(8049); +const SV8 = __webpack_require__(8850); +const debug = (0, debug_1.default)('music-metadata:parser:musepack'); +class MpcSv8Parser extends BasicParser_1.BasicParser { + constructor() { + super(...arguments); + this.audioLength = 0; + } + async parse() { + const signature = await this.tokenizer.readToken(FourCC_1.FourCcToken); + if (signature !== 'MPCK') + throw new Error('Invalid Magic number'); + this.metadata.setFormat('container', 'Musepack, SV8'); + return this.parsePacket(); + } + async parsePacket() { + const sv8reader = new SV8.StreamReader(this.tokenizer); + do { + const header = await sv8reader.readPacketHeader(); + debug(`packet-header key=${header.key}, payloadLength=${header.payloadLength}`); + switch (header.key) { + case 'SH': // Stream Header + const sh = await sv8reader.readStreamHeader(header.payloadLength); + this.metadata.setFormat('numberOfSamples', sh.sampleCount); + this.metadata.setFormat('sampleRate', sh.sampleFrequency); + this.metadata.setFormat('duration', sh.sampleCount / sh.sampleFrequency); + this.metadata.setFormat('numberOfChannels', sh.channelCount); + break; + case 'AP': // Audio Packet + this.audioLength += header.payloadLength; + await this.tokenizer.ignore(header.payloadLength); + break; + case 'RG': // Replaygain + case 'EI': // Encoder Info + case 'SO': // Seek Table Offset + case 'ST': // Seek Table + case 'CT': // Chapter-Tag + await this.tokenizer.ignore(header.payloadLength); + break; + case 'SE': // Stream End + this.metadata.setFormat('bitrate', this.audioLength * 8 / this.metadata.format.duration); + return APEv2Parser_1.APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options); + default: + throw new Error(`Unexpected header: ${header.key}`); + } + } while (true); + } +} +exports.MpcSv8Parser = MpcSv8Parser; + + +/***/ }), + +/***/ 8850: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.StreamReader = void 0; +const Token = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const util = __webpack_require__(3769); +const debug = (0, debug_1.default)('music-metadata:parser:musepack:sv8'); +const PacketKey = new Token.StringType(2, 'binary'); +/** + * Stream Header Packet part 1 + * Ref: http://trac.musepack.net/musepack/wiki/SV8Specification#StreamHeaderPacket + */ +const SH_part1 = { + len: 5, + get: (buf, off) => { + return { + crc: Token.UINT32_LE.get(buf, off), + streamVersion: Token.UINT8.get(buf, off + 4) + }; + } +}; +/** + * Stream Header Packet part 3 + * Ref: http://trac.musepack.net/musepack/wiki/SV8Specification#StreamHeaderPacket + */ +const SH_part3 = { + len: 2, + get: (buf, off) => { + return { + sampleFrequency: [44100, 48000, 37800, 32000][util.getBitAllignedNumber(buf, off, 0, 3)], + maxUsedBands: util.getBitAllignedNumber(buf, off, 3, 5), + channelCount: util.getBitAllignedNumber(buf, off + 1, 0, 4) + 1, + msUsed: util.isBitSet(buf, off + 1, 4), + audioBlockFrames: util.getBitAllignedNumber(buf, off + 1, 5, 3) + }; + } +}; +class StreamReader { + constructor(tokenizer) { + this.tokenizer = tokenizer; + } + async readPacketHeader() { + const key = await this.tokenizer.readToken(PacketKey); + const size = await this.readVariableSizeField(); + return { + key, + payloadLength: size.value - 2 - size.len + }; + } + async readStreamHeader(size) { + const streamHeader = {}; + debug(`Reading SH at offset=${this.tokenizer.position}`); + const part1 = await this.tokenizer.readToken(SH_part1); + size -= SH_part1.len; + Object.assign(streamHeader, part1); + debug(`SH.streamVersion = ${part1.streamVersion}`); + const sampleCount = await this.readVariableSizeField(); + size -= sampleCount.len; + streamHeader.sampleCount = sampleCount.value; + const bs = await this.readVariableSizeField(); + size -= bs.len; + streamHeader.beginningOfSilence = bs.value; + const part3 = await this.tokenizer.readToken(SH_part3); + size -= SH_part3.len; + Object.assign(streamHeader, part3); + // assert.equal(size, 0); + await this.tokenizer.ignore(size); + return streamHeader; + } + async readVariableSizeField(len = 1, hb = 0) { + let n = await this.tokenizer.readNumber(Token.UINT8); + if ((n & 0x80) === 0) { + return { len, value: hb + n }; + } + n &= 0x7F; + n += hb; + return this.readVariableSizeField(len + 1, n << 7); + } +} +exports.StreamReader = StreamReader; + + +/***/ }), + +/***/ 1915: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.OggParser = exports.SegmentTable = void 0; +const Token = __webpack_require__(3416); +const core_1 = __webpack_require__(5849); +const debug_1 = __webpack_require__(1227); +const util = __webpack_require__(3769); +const FourCC_1 = __webpack_require__(8049); +const BasicParser_1 = __webpack_require__(7805); +const VorbisParser_1 = __webpack_require__(4210); +const OpusParser_1 = __webpack_require__(1272); +const SpeexParser_1 = __webpack_require__(573); +const TheoraParser_1 = __webpack_require__(2630); +const debug = (0, debug_1.default)('music-metadata:parser:ogg'); +class SegmentTable { + constructor(header) { + this.len = header.page_segments; + } + static sum(buf, off, len) { + let s = 0; + for (let i = off; i < off + len; ++i) { + s += buf[i]; + } + return s; + } + get(buf, off) { + return { + totalPageSize: SegmentTable.sum(buf, off, this.len) + }; + } +} +exports.SegmentTable = SegmentTable; +/** + * Parser for Ogg logical bitstream framing + */ +class OggParser extends BasicParser_1.BasicParser { + /** + * Parse page + * @returns {Promise} + */ + async parse() { + debug('pos=%s, parsePage()', this.tokenizer.position); + try { + let header; + do { + header = await this.tokenizer.readToken(OggParser.Header); + if (header.capturePattern !== 'OggS') + throw new Error('Invalid Ogg capture pattern'); + this.metadata.setFormat('container', 'Ogg'); + this.header = header; + this.pageNumber = header.pageSequenceNo; + debug('page#=%s, Ogg.id=%s', header.pageSequenceNo, header.capturePattern); + const segmentTable = await this.tokenizer.readToken(new SegmentTable(header)); + debug('totalPageSize=%s', segmentTable.totalPageSize); + const pageData = await this.tokenizer.readToken(new Token.Uint8ArrayType(segmentTable.totalPageSize)); + debug('firstPage=%s, lastPage=%s, continued=%s', header.headerType.firstPage, header.headerType.lastPage, header.headerType.continued); + if (header.headerType.firstPage) { + const id = new Token.StringType(7, 'ascii').get(Buffer.from(pageData), 0); + switch (id) { + case '\x01vorbis': // Ogg/Vorbis + debug('Set page consumer to Ogg/Vorbis'); + this.pageConsumer = new VorbisParser_1.VorbisParser(this.metadata, this.options); + break; + case 'OpusHea': // Ogg/Opus + debug('Set page consumer to Ogg/Opus'); + this.pageConsumer = new OpusParser_1.OpusParser(this.metadata, this.options, this.tokenizer); + break; + case 'Speex ': // Ogg/Speex + debug('Set page consumer to Ogg/Speex'); + this.pageConsumer = new SpeexParser_1.SpeexParser(this.metadata, this.options, this.tokenizer); + break; + case 'fishead': + case '\x00theora': // Ogg/Theora + debug('Set page consumer to Ogg/Theora'); + this.pageConsumer = new TheoraParser_1.TheoraParser(this.metadata, this.options, this.tokenizer); + break; + default: + throw new Error('gg audio-codec not recognized (id=' + id + ')'); + } + } + this.pageConsumer.parsePage(header, pageData); + } while (!header.headerType.lastPage); + } + catch (err) { + if (err instanceof core_1.EndOfStreamError) { + this.metadata.addWarning('Last OGG-page is not marked with last-page flag'); + debug(`End-of-stream`); + this.metadata.addWarning('Last OGG-page is not marked with last-page flag'); + if (this.header) { + this.pageConsumer.calculateDuration(this.header); + } + } + else if (err.message.startsWith('FourCC')) { + if (this.pageNumber > 0) { + // ignore this error: work-around if last OGG-page is not marked with last-page flag + this.metadata.addWarning('Invalid FourCC ID, maybe last OGG-page is not marked with last-page flag'); + this.pageConsumer.flush(); + } + } + else { + throw err; + } + } + } +} +exports.OggParser = OggParser; +OggParser.Header = { + len: 27, + get: (buf, off) => { + return { + capturePattern: FourCC_1.FourCcToken.get(buf, off), + version: Token.UINT8.get(buf, off + 4), + headerType: { + continued: util.getBit(buf, off + 5, 0), + firstPage: util.getBit(buf, off + 5, 1), + lastPage: util.getBit(buf, off + 5, 2) + }, + // packet_flag: buf.readUInt8(off + 5), + absoluteGranulePosition: Number(Token.UINT64_LE.get(buf, off + 6)), + streamSerialNumber: Token.UINT32_LE.get(buf, off + 14), + pageSequenceNo: Token.UINT32_LE.get(buf, off + 18), + pageChecksum: Token.UINT32_LE.get(buf, off + 22), + page_segments: Token.UINT8.get(buf, off + 26) + }; + } +}; + + +/***/ }), + +/***/ 5044: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.IdHeader = void 0; +const Token = __webpack_require__(3416); +/** + * Opus ID Header parser + * Ref: https://wiki.xiph.org/OggOpus#ID_Header + */ +class IdHeader { + constructor(len) { + this.len = len; + if (len < 19) { + throw new Error("ID-header-page 0 should be at least 19 bytes long"); + } + } + get(buf, off) { + return { + magicSignature: new Token.StringType(8, 'ascii').get(buf, off + 0), + version: buf.readUInt8(off + 8), + channelCount: buf.readUInt8(off + 9), + preSkip: buf.readInt16LE(off + 10), + inputSampleRate: buf.readInt32LE(off + 12), + outputGain: buf.readInt16LE(off + 16), + channelMapping: buf.readUInt8(off + 18) + }; + } +} +exports.IdHeader = IdHeader; + + +/***/ }), + +/***/ 1272: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.OpusParser = void 0; +const Token = __webpack_require__(3416); +const VorbisParser_1 = __webpack_require__(4210); +const Opus = __webpack_require__(5044); +/** + * Opus parser + * Internet Engineering Task Force (IETF) - RFC 6716 + * Used by OggParser + */ +class OpusParser extends VorbisParser_1.VorbisParser { + constructor(metadata, options, tokenizer) { + super(metadata, options); + this.tokenizer = tokenizer; + this.lastPos = -1; + } + /** + * Parse first Opus Ogg page + * @param {IPageHeader} header + * @param {Buffer} pageData + */ + parseFirstPage(header, pageData) { + this.metadata.setFormat('codec', 'Opus'); + // Parse Opus ID Header + this.idHeader = new Opus.IdHeader(pageData.length).get(pageData, 0); + if (this.idHeader.magicSignature !== "OpusHead") + throw new Error("Illegal ogg/Opus magic-signature"); + this.metadata.setFormat('sampleRate', this.idHeader.inputSampleRate); + this.metadata.setFormat('numberOfChannels', this.idHeader.channelCount); + } + parseFullPage(pageData) { + const magicSignature = new Token.StringType(8, 'ascii').get(pageData, 0); + switch (magicSignature) { + case 'OpusTags': + this.parseUserCommentList(pageData, 8); + this.lastPos = this.tokenizer.position - pageData.length; + break; + default: + break; + } + } + calculateDuration(header) { + if (this.metadata.format.sampleRate && header.absoluteGranulePosition >= 0) { + // Calculate duration + const pos_48bit = header.absoluteGranulePosition - this.idHeader.preSkip; + this.metadata.setFormat('numberOfSamples', pos_48bit); + this.metadata.setFormat('duration', pos_48bit / 48000); + if (this.lastPos !== -1 && this.tokenizer.fileInfo.size && this.metadata.format.duration) { + const dataSize = this.tokenizer.fileInfo.size - this.lastPos; + this.metadata.setFormat('bitrate', 8 * dataSize / this.metadata.format.duration); + } + } + } +} +exports.OpusParser = OpusParser; + + +/***/ }), + +/***/ 6666: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Header = void 0; +const Token = __webpack_require__(3416); +const util = __webpack_require__(3769); +/** + * Speex Header Packet + * Ref: https://www.speex.org/docs/manual/speex-manual/node8.html#SECTION00830000000000000000 + */ +exports.Header = { + len: 80, + get: (buf, off) => { + return { + speex: new Token.StringType(8, 'ascii').get(buf, off + 0), + version: util.trimRightNull(new Token.StringType(20, 'ascii').get(buf, off + 8)), + version_id: buf.readInt32LE(off + 28), + header_size: buf.readInt32LE(off + 32), + rate: buf.readInt32LE(off + 36), + mode: buf.readInt32LE(off + 40), + mode_bitstream_version: buf.readInt32LE(off + 44), + nb_channels: buf.readInt32LE(off + 48), + bitrate: buf.readInt32LE(off + 52), + frame_size: buf.readInt32LE(off + 56), + vbr: buf.readInt32LE(off + 60), + frames_per_packet: buf.readInt32LE(off + 64), + extra_headers: buf.readInt32LE(off + 68), + reserved1: buf.readInt32LE(off + 72), + reserved2: buf.readInt32LE(off + 76) + }; + } +}; + + +/***/ }), + +/***/ 573: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.SpeexParser = void 0; +const debug_1 = __webpack_require__(1227); +const VorbisParser_1 = __webpack_require__(4210); +const Speex = __webpack_require__(6666); +const debug = (0, debug_1.default)('music-metadata:parser:ogg:speex'); +/** + * Speex, RFC 5574 + * Ref: + * - https://www.speex.org/docs/manual/speex-manual/ + * - https://tools.ietf.org/html/rfc5574 + */ +class SpeexParser extends VorbisParser_1.VorbisParser { + constructor(metadata, options, tokenizer) { + super(metadata, options); + this.tokenizer = tokenizer; + } + /** + * Parse first Speex Ogg page + * @param {IPageHeader} header + * @param {Buffer} pageData + */ + parseFirstPage(header, pageData) { + debug('First Ogg/Speex page'); + const speexHeader = Speex.Header.get(pageData, 0); + this.metadata.setFormat('codec', `Speex ${speexHeader.version}`); + this.metadata.setFormat('numberOfChannels', speexHeader.nb_channels); + this.metadata.setFormat('sampleRate', speexHeader.rate); + if (speexHeader.bitrate !== -1) { + this.metadata.setFormat('bitrate', speexHeader.bitrate); + } + } +} +exports.SpeexParser = SpeexParser; + + +/***/ }), + +/***/ 5177: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.IdentificationHeader = void 0; +const Token = __webpack_require__(3416); +/** + * 6.2 Identification Header + * Ref: https://theora.org/doc/Theora.pdf: 6.2 Identification Header Decode + */ +exports.IdentificationHeader = { + len: 42, + get: (buf, off) => { + return { + id: new Token.StringType(7, 'ascii').get(buf, off), + vmaj: buf.readUInt8(off + 7), + vmin: buf.readUInt8(off + 8), + vrev: buf.readUInt8(off + 9), + vmbw: buf.readUInt16BE(off + 10), + vmbh: buf.readUInt16BE(off + 17), + nombr: Token.UINT24_BE.get(buf, off + 37), + nqual: buf.readUInt8(off + 40) + }; + } +}; + + +/***/ }), + +/***/ 2630: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.TheoraParser = void 0; +const debug_1 = __webpack_require__(1227); +const Theora_1 = __webpack_require__(5177); +const debug = (0, debug_1.default)('music-metadata:parser:ogg:theora'); +/** + * Ref: + * - https://theora.org/doc/Theora.pdf + */ +class TheoraParser { + constructor(metadata, options, tokenizer) { + this.metadata = metadata; + this.tokenizer = tokenizer; + } + /** + * Vorbis 1 parser + * @param header Ogg Page Header + * @param pageData Page data + */ + parsePage(header, pageData) { + if (header.headerType.firstPage) { + this.parseFirstPage(header, pageData); + } + } + flush() { + debug('flush'); + } + calculateDuration(header) { + debug('duration calculation not implemented'); + } + /** + * Parse first Theora Ogg page. the initial identification header packet + * @param {IPageHeader} header + * @param {Buffer} pageData + */ + parseFirstPage(header, pageData) { + debug('First Ogg/Theora page'); + this.metadata.setFormat('codec', 'Theora'); + const idHeader = Theora_1.IdentificationHeader.get(pageData, 0); + this.metadata.setFormat('bitrate', idHeader.nombr); + } +} +exports.TheoraParser = TheoraParser; + + +/***/ }), + +/***/ 2127: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.IdentificationHeader = exports.CommonHeader = exports.VorbisPictureToken = void 0; +const Token = __webpack_require__(3416); +const ID3v2Token_1 = __webpack_require__(8281); +/** + * Parse the METADATA_BLOCK_PICTURE + * Ref: https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE + * Ref: https://xiph.org/flac/format.html#metadata_block_picture + * // ToDo: move to ID3 / APIC? + */ +class VorbisPictureToken { + constructor(len) { + this.len = len; + } + static fromBase64(base64str) { + return this.fromBuffer(Buffer.from(base64str, 'base64')); + } + static fromBuffer(buffer) { + const pic = new VorbisPictureToken(buffer.length); + return pic.get(buffer, 0); + } + get(buffer, offset) { + const type = ID3v2Token_1.AttachedPictureType[Token.UINT32_BE.get(buffer, offset)]; + const mimeLen = Token.UINT32_BE.get(buffer, offset += 4); + const format = buffer.toString('utf-8', offset += 4, offset + mimeLen); + const descLen = Token.UINT32_BE.get(buffer, offset += mimeLen); + const description = buffer.toString('utf-8', offset += 4, offset + descLen); + const width = Token.UINT32_BE.get(buffer, offset += descLen); + const height = Token.UINT32_BE.get(buffer, offset += 4); + const colour_depth = Token.UINT32_BE.get(buffer, offset += 4); + const indexed_color = Token.UINT32_BE.get(buffer, offset += 4); + const picDataLen = Token.UINT32_BE.get(buffer, offset += 4); + const data = Buffer.from(buffer.slice(offset += 4, offset + picDataLen)); + return { + type, + format, + description, + width, + height, + colour_depth, + indexed_color, + data + }; + } +} +exports.VorbisPictureToken = VorbisPictureToken; +/** + * Comment header decoder + * Ref: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-620004.2.1 + */ +exports.CommonHeader = { + len: 7, + get: (buf, off) => { + return { + packetType: buf.readUInt8(off), + vorbis: new Token.StringType(6, 'ascii').get(buf, off + 1) + }; + } +}; +/** + * Identification header decoder + * Ref: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-630004.2.2 + */ +exports.IdentificationHeader = { + len: 23, + get: (uint8Array, off) => { + const dataView = new DataView(uint8Array.buffer, uint8Array.byteOffset); + return { + version: dataView.getUint32(off + 0, true), + channelMode: dataView.getUint8(off + 4), + sampleRate: dataView.getUint32(off + 5, true), + bitrateMax: dataView.getUint32(off + 9, true), + bitrateNominal: dataView.getUint32(off + 13, true), + bitrateMin: dataView.getUint32(off + 17, true) + }; + } +}; + + +/***/ }), + +/***/ 441: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.VorbisDecoder = void 0; +const Token = __webpack_require__(3416); +class VorbisDecoder { + constructor(data, offset) { + this.data = data; + this.offset = offset; + } + readInt32() { + const value = Token.UINT32_LE.get(this.data, this.offset); + this.offset += 4; + return value; + } + readStringUtf8() { + const len = this.readInt32(); + const value = Buffer.from(this.data).toString('utf-8', this.offset, this.offset + len); + this.offset += len; + return value; + } + parseUserComment() { + const offset0 = this.offset; + const v = this.readStringUtf8(); + const idx = v.indexOf('='); + return { + key: v.slice(0, idx).toUpperCase(), + value: v.slice(idx + 1), + len: this.offset - offset0 + }; + } +} +exports.VorbisDecoder = VorbisDecoder; + + +/***/ }), + +/***/ 4210: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.VorbisParser = void 0; +const Token = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const VorbisDecoder_1 = __webpack_require__(441); +const Vorbis_1 = __webpack_require__(2127); +const debug = (0, debug_1.default)('music-metadata:parser:ogg:vorbis1'); +/** + * Vorbis 1 Parser. + * Used by OggParser + */ +class VorbisParser { + constructor(metadata, options) { + this.metadata = metadata; + this.options = options; + this.pageSegments = []; + } + /** + * Vorbis 1 parser + * @param header Ogg Page Header + * @param pageData Page data + */ + parsePage(header, pageData) { + if (header.headerType.firstPage) { + this.parseFirstPage(header, pageData); + } + else { + if (header.headerType.continued) { + if (this.pageSegments.length === 0) { + throw new Error("Cannot continue on previous page"); + } + this.pageSegments.push(pageData); + } + if (header.headerType.lastPage || !header.headerType.continued) { + // Flush page segments + if (this.pageSegments.length > 0) { + const fullPage = Buffer.concat(this.pageSegments); + this.parseFullPage(fullPage); + } + // Reset page segments + this.pageSegments = header.headerType.lastPage ? [] : [pageData]; + } + } + if (header.headerType.lastPage) { + this.calculateDuration(header); + } + } + flush() { + this.parseFullPage(Buffer.concat(this.pageSegments)); + } + parseUserComment(pageData, offset) { + const decoder = new VorbisDecoder_1.VorbisDecoder(pageData, offset); + const tag = decoder.parseUserComment(); + this.addTag(tag.key, tag.value); + return tag.len; + } + addTag(id, value) { + if (id === 'METADATA_BLOCK_PICTURE' && (typeof value === 'string')) { + if (this.options.skipCovers) { + debug(`Ignore picture`); + return; + } + value = Vorbis_1.VorbisPictureToken.fromBase64(value); + debug(`Push picture: id=${id}, format=${value.format}`); + } + else { + debug(`Push tag: id=${id}, value=${value}`); + } + this.metadata.addTag('vorbis', id, value); + } + calculateDuration(header) { + if (this.metadata.format.sampleRate && header.absoluteGranulePosition >= 0) { + // Calculate duration + this.metadata.setFormat('numberOfSamples', header.absoluteGranulePosition); + this.metadata.setFormat('duration', this.metadata.format.numberOfSamples / this.metadata.format.sampleRate); + } + } + /** + * Parse first Ogg/Vorbis page + * @param {IPageHeader} header + * @param {Buffer} pageData + */ + parseFirstPage(header, pageData) { + this.metadata.setFormat('codec', 'Vorbis I'); + debug("Parse first page"); + // Parse Vorbis common header + const commonHeader = Vorbis_1.CommonHeader.get(pageData, 0); + if (commonHeader.vorbis !== 'vorbis') + throw new Error('Metadata does not look like Vorbis'); + if (commonHeader.packetType === 1) { + const idHeader = Vorbis_1.IdentificationHeader.get(pageData, Vorbis_1.CommonHeader.len); + this.metadata.setFormat('sampleRate', idHeader.sampleRate); + this.metadata.setFormat('bitrate', idHeader.bitrateNominal); + this.metadata.setFormat('numberOfChannels', idHeader.channelMode); + debug("sample-rate=%s[hz], bitrate=%s[b/s], channel-mode=%s", idHeader.sampleRate, idHeader.bitrateNominal, idHeader.channelMode); + } + else + throw new Error('First Ogg page should be type 1: the identification header'); + } + parseFullPage(pageData) { + // New page + const commonHeader = Vorbis_1.CommonHeader.get(pageData, 0); + debug("Parse full page: type=%s, byteLength=%s", commonHeader.packetType, pageData.byteLength); + switch (commonHeader.packetType) { + case 3: // type 3: comment header + return this.parseUserCommentList(pageData, Vorbis_1.CommonHeader.len); + case 1: // type 1: the identification header + case 5: // type 5: setup header type + break; // ignore + } + } + /** + * Ref: https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-840005.2 + */ + parseUserCommentList(pageData, offset) { + const strLen = Token.UINT32_LE.get(pageData, offset); + offset += 4; + // const vendorString = new Token.StringType(strLen, 'utf-8').get(pageData, offset); + offset += strLen; + let userCommentListLength = Token.UINT32_LE.get(pageData, offset); + offset += 4; + while (userCommentListLength-- > 0) { + offset += this.parseUserComment(pageData, offset); + } + } +} +exports.VorbisParser = VorbisParser; + + +/***/ }), + +/***/ 9860: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.VorbisTagMapper = void 0; +const GenericTagMapper_1 = __webpack_require__(9918); +/** + * Vorbis tag mappings + * + * Mapping from native header format to one or possibly more 'common' entries + * The common entries aim to read the same information from different media files + * independent of the underlying format + */ +const vorbisTagMap = { + TITLE: 'title', + ARTIST: 'artist', + ARTISTS: 'artists', + ALBUMARTIST: 'albumartist', + 'ALBUM ARTIST': 'albumartist', + ALBUM: 'album', + DATE: 'date', + ORIGINALDATE: 'originaldate', + ORIGINALYEAR: 'originalyear', + COMMENT: 'comment', + TRACKNUMBER: 'track', + DISCNUMBER: 'disk', + GENRE: 'genre', + METADATA_BLOCK_PICTURE: 'picture', + COMPOSER: 'composer', + LYRICS: 'lyrics', + ALBUMSORT: 'albumsort', + TITLESORT: 'titlesort', + WORK: 'work', + ARTISTSORT: 'artistsort', + ALBUMARTISTSORT: 'albumartistsort', + COMPOSERSORT: 'composersort', + LYRICIST: 'lyricist', + WRITER: 'writer', + CONDUCTOR: 'conductor', + // 'PERFORMER=artist (instrument)': 'performer:instrument', // ToDo + REMIXER: 'remixer', + ARRANGER: 'arranger', + ENGINEER: 'engineer', + PRODUCER: 'producer', + DJMIXER: 'djmixer', + MIXER: 'mixer', + LABEL: 'label', + GROUPING: 'grouping', + SUBTITLE: 'subtitle', + DISCSUBTITLE: 'discsubtitle', + TRACKTOTAL: 'totaltracks', + DISCTOTAL: 'totaldiscs', + COMPILATION: 'compilation', + RATING: 'rating', + BPM: 'bpm', + KEY: 'key', + MOOD: 'mood', + MEDIA: 'media', + CATALOGNUMBER: 'catalognumber', + RELEASESTATUS: 'releasestatus', + RELEASETYPE: 'releasetype', + RELEASECOUNTRY: 'releasecountry', + SCRIPT: 'script', + LANGUAGE: 'language', + COPYRIGHT: 'copyright', + LICENSE: 'license', + ENCODEDBY: 'encodedby', + ENCODERSETTINGS: 'encodersettings', + BARCODE: 'barcode', + ISRC: 'isrc', + ASIN: 'asin', + MUSICBRAINZ_TRACKID: 'musicbrainz_recordingid', + MUSICBRAINZ_RELEASETRACKID: 'musicbrainz_trackid', + MUSICBRAINZ_ALBUMID: 'musicbrainz_albumid', + MUSICBRAINZ_ARTISTID: 'musicbrainz_artistid', + MUSICBRAINZ_ALBUMARTISTID: 'musicbrainz_albumartistid', + MUSICBRAINZ_RELEASEGROUPID: 'musicbrainz_releasegroupid', + MUSICBRAINZ_WORKID: 'musicbrainz_workid', + MUSICBRAINZ_TRMID: 'musicbrainz_trmid', + MUSICBRAINZ_DISCID: 'musicbrainz_discid', + ACOUSTID_ID: 'acoustid_id', + ACOUSTID_ID_FINGERPRINT: 'acoustid_fingerprint', + MUSICIP_PUID: 'musicip_puid', + // 'FINGERPRINT=MusicMagic Fingerprint {fingerprint}': 'musicip_fingerprint', // ToDo + WEBSITE: 'website', + NOTES: 'notes', + TOTALTRACKS: 'totaltracks', + TOTALDISCS: 'totaldiscs', + // Discogs + DISCOGS_ARTIST_ID: 'discogs_artist_id', + DISCOGS_ARTISTS: 'artists', + DISCOGS_ARTIST_NAME: 'artists', + DISCOGS_ALBUM_ARTISTS: 'albumartist', + DISCOGS_CATALOG: 'catalognumber', + DISCOGS_COUNTRY: 'releasecountry', + DISCOGS_DATE: 'originaldate', + DISCOGS_LABEL: 'label', + DISCOGS_LABEL_ID: 'discogs_label_id', + DISCOGS_MASTER_RELEASE_ID: 'discogs_master_release_id', + DISCOGS_RATING: 'discogs_rating', + DISCOGS_RELEASED: 'date', + DISCOGS_RELEASE_ID: 'discogs_release_id', + DISCOGS_VOTES: 'discogs_votes', + CATALOGID: 'catalognumber', + STYLE: 'genre', + // + REPLAYGAIN_TRACK_GAIN: 'replaygain_track_gain', + REPLAYGAIN_TRACK_PEAK: 'replaygain_track_peak', + REPLAYGAIN_ALBUM_GAIN: 'replaygain_album_gain', + REPLAYGAIN_ALBUM_PEAK: 'replaygain_album_peak', + // To Sure if these (REPLAYGAIN_MINMAX, REPLAYGAIN_ALBUM_MINMAX & REPLAYGAIN_UNDO) are used for Vorbis: + REPLAYGAIN_MINMAX: 'replaygain_track_minmax', + REPLAYGAIN_ALBUM_MINMAX: 'replaygain_album_minmax', + REPLAYGAIN_UNDO: 'replaygain_undo' +}; +class VorbisTagMapper extends GenericTagMapper_1.CommonTagMapper { + static toRating(email, rating) { + return { + source: email ? email.toLowerCase() : email, + rating: parseFloat(rating) * GenericTagMapper_1.CommonTagMapper.maxRatingScore + }; + } + constructor() { + super(['vorbis'], vorbisTagMap); + } + postMap(tag) { + if (tag.id.indexOf('RATING:') === 0) { + const keys = tag.id.split(':'); + tag.value = VorbisTagMapper.toRating(keys[1], tag.value); + tag.id = keys[0]; + } + } +} +exports.VorbisTagMapper = VorbisTagMapper; +//# sourceMappingURL=VorbisTagMapper.js.map + +/***/ }), + +/***/ 3211: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ListInfoTagValue = exports.Header = void 0; +const Token = __webpack_require__(3416); +/** + * Common RIFF chunk header + */ +exports.Header = { + len: 8, + get: (buf, off) => { + return { + // Group-ID + chunkID: buf.toString('binary', off, off + 4), + // Size + chunkSize: Token.UINT32_LE.get(buf, 4) + }; + } +}; +/** + * Token to parse RIFF-INFO tag value + */ +class ListInfoTagValue { + constructor(tagHeader) { + this.tagHeader = tagHeader; + this.len = tagHeader.chunkSize; + this.len += this.len & 1; // if it is an odd length, round up to even + } + get(buf, off) { + return new Token.StringType(this.tagHeader.chunkSize, 'ascii').get(buf, off); + } +} +exports.ListInfoTagValue = ListInfoTagValue; + + +/***/ }), + +/***/ 5756: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.RiffInfoTagMapper = exports.riffInfoTagMap = void 0; +const GenericTagMapper_1 = __webpack_require__(9918); +/** + * RIFF Info Tags; part of the EXIF 2.3 + * Ref: http://owl.phy.queensu.ca/~phil/exiftool/TagNames/RIFF.html#Info + */ +exports.riffInfoTagMap = { + IART: 'artist', + ICRD: 'date', + INAM: 'title', + TITL: 'title', + IPRD: 'album', + ITRK: 'track', + COMM: 'comment', + ICMT: 'comment', + ICNT: 'releasecountry', + GNRE: 'genre', + IWRI: 'writer', + RATE: 'rating', + YEAR: 'year', + ISFT: 'encodedby', + CODE: 'encodedby', + TURL: 'website', + IGNR: 'genre', + IENG: 'engineer', + ITCH: 'technician', + IMED: 'media', + IRPD: 'album' // Product, where the file was intended for +}; +class RiffInfoTagMapper extends GenericTagMapper_1.CommonTagMapper { + constructor() { + super(['exif'], exports.riffInfoTagMap); + } +} +exports.RiffInfoTagMapper = RiffInfoTagMapper; +//# sourceMappingURL=RiffInfoTagMap.js.map + +/***/ }), + +/***/ 6032: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.TrackType = void 0; +var types_1 = __webpack_require__(8591); +Object.defineProperty(exports, "TrackType", ({ enumerable: true, get: function () { return types_1.TrackType; } })); +//# sourceMappingURL=type.js.map + +/***/ }), + +/***/ 8053: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BroadcastAudioExtensionChunk = void 0; +const Token = __webpack_require__(3416); +/** + * Broadcast Audio Extension Chunk + * Ref: https://tech.ebu.ch/docs/tech/tech3285.pdf + */ +exports.BroadcastAudioExtensionChunk = { + len: 420, + get: (uint8array, off) => { + return { + description: new Token.StringType(256, 'ascii').get(uint8array, off).trim(), + originator: new Token.StringType(32, 'ascii').get(uint8array, off + 256).trim(), + originatorReference: new Token.StringType(32, 'ascii').get(uint8array, off + 288).trim(), + originationDate: new Token.StringType(10, 'ascii').get(uint8array, off + 320).trim(), + originationTime: new Token.StringType(8, 'ascii').get(uint8array, off + 330).trim(), + timeReferenceLow: Token.UINT32_LE.get(uint8array, off + 338), + timeReferenceHigh: Token.UINT32_LE.get(uint8array, off + 342), + version: Token.UINT16_LE.get(uint8array, off + 346), + umid: new Token.Uint8ArrayType(64).get(uint8array, off + 348), + loudnessValue: Token.UINT16_LE.get(uint8array, off + 412), + maxTruePeakLevel: Token.UINT16_LE.get(uint8array, off + 414), + maxMomentaryLoudness: Token.UINT16_LE.get(uint8array, off + 416), + maxShortTermLoudness: Token.UINT16_LE.get(uint8array, off + 418) + }; + } +}; + + +/***/ }), + +/***/ 9975: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.FactChunk = exports.Format = exports.WaveFormat = void 0; +/** + * Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317599(v=vs.85).aspx + */ +var WaveFormat; +(function (WaveFormat) { + WaveFormat[WaveFormat["PCM"] = 1] = "PCM"; + // MPEG-4 and AAC Audio Types + WaveFormat[WaveFormat["ADPCM"] = 2] = "ADPCM"; + WaveFormat[WaveFormat["IEEE_FLOAT"] = 3] = "IEEE_FLOAT"; + WaveFormat[WaveFormat["MPEG_ADTS_AAC"] = 5632] = "MPEG_ADTS_AAC"; + WaveFormat[WaveFormat["MPEG_LOAS"] = 5634] = "MPEG_LOAS"; + WaveFormat[WaveFormat["RAW_AAC1"] = 255] = "RAW_AAC1"; + // Dolby Audio Types + WaveFormat[WaveFormat["DOLBY_AC3_SPDIF"] = 146] = "DOLBY_AC3_SPDIF"; + WaveFormat[WaveFormat["DVM"] = 8192] = "DVM"; + WaveFormat[WaveFormat["RAW_SPORT"] = 576] = "RAW_SPORT"; + WaveFormat[WaveFormat["ESST_AC3"] = 577] = "ESST_AC3"; + WaveFormat[WaveFormat["DRM"] = 9] = "DRM"; + WaveFormat[WaveFormat["DTS2"] = 8193] = "DTS2"; + WaveFormat[WaveFormat["MPEG"] = 80] = "MPEG"; +})(WaveFormat = exports.WaveFormat || (exports.WaveFormat = {})); +/** + * format chunk; chunk-id is "fmt " + * http://soundfile.sapp.org/doc/WaveFormat/ + */ +class Format { + constructor(header) { + if (header.chunkSize < 16) + throw new Error('Invalid chunk size'); + this.len = header.chunkSize; + } + get(buf, off) { + return { + wFormatTag: buf.readUInt16LE(off), + nChannels: buf.readUInt16LE(off + 2), + nSamplesPerSec: buf.readUInt32LE(off + 4), + nAvgBytesPerSec: buf.readUInt32LE(off + 8), + nBlockAlign: buf.readUInt16LE(off + 12), + wBitsPerSample: buf.readUInt16LE(off + 14) + }; + } +} +exports.Format = Format; +/** + * Fact chunk; chunk-id is "fact" + * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html + * http://www.recordingblogs.com/wiki/fact-chunk-of-a-wave-file + */ +class FactChunk { + constructor(header) { + if (header.chunkSize < 4) { + throw new Error('Invalid fact chunk size.'); + } + this.len = header.chunkSize; + } + get(buf, off) { + return { + dwSampleLength: buf.readUInt32LE(off) + }; + } +} +exports.FactChunk = FactChunk; + + +/***/ }), + +/***/ 2682: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.WaveParser = void 0; +const strtok3 = __webpack_require__(5849); +const Token = __webpack_require__(3416); +const debug_1 = __webpack_require__(1227); +const riff = __webpack_require__(3211); +const WaveChunk = __webpack_require__(9975); +const ID3v2Parser_1 = __webpack_require__(8928); +const util = __webpack_require__(3769); +const FourCC_1 = __webpack_require__(8049); +const BasicParser_1 = __webpack_require__(7805); +const BwfChunk_1 = __webpack_require__(8053); +const debug = (0, debug_1.default)('music-metadata:parser:RIFF'); +/** + * Resource Interchange File Format (RIFF) Parser + * + * WAVE PCM soundfile format + * + * Ref: + * - http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html + * - http://soundfile.sapp.org/doc/WaveFormat + * + * ToDo: Split WAVE part from RIFF parser + */ +class WaveParser extends BasicParser_1.BasicParser { + async parse() { + const riffHeader = await this.tokenizer.readToken(riff.Header); + debug(`pos=${this.tokenizer.position}, parse: chunkID=${riffHeader.chunkID}`); + if (riffHeader.chunkID !== 'RIFF') + return; // Not RIFF format + return this.parseRiffChunk(riffHeader.chunkSize).catch(err => { + if (!(err instanceof strtok3.EndOfStreamError)) { + throw err; + } + }); + } + async parseRiffChunk(chunkSize) { + const type = await this.tokenizer.readToken(FourCC_1.FourCcToken); + this.metadata.setFormat('container', type); + switch (type) { + case 'WAVE': + return this.readWaveChunk(chunkSize - FourCC_1.FourCcToken.len); + default: + throw new Error(`Unsupported RIFF format: RIFF/${type}`); + } + } + async readWaveChunk(remaining) { + while (remaining >= riff.Header.len) { + const header = await this.tokenizer.readToken(riff.Header); + remaining -= riff.Header.len + header.chunkSize; + if (header.chunkSize > remaining) { + this.metadata.addWarning('Data chunk size exceeds file size'); + } + this.header = header; + debug(`pos=${this.tokenizer.position}, readChunk: chunkID=RIFF/WAVE/${header.chunkID}`); + switch (header.chunkID) { + case 'LIST': + await this.parseListTag(header); + break; + case 'fact': // extended Format chunk, + this.metadata.setFormat('lossless', false); + this.fact = await this.tokenizer.readToken(new WaveChunk.FactChunk(header)); + break; + case 'fmt ': // The Util Chunk, non-PCM Formats + const fmt = await this.tokenizer.readToken(new WaveChunk.Format(header)); + let subFormat = WaveChunk.WaveFormat[fmt.wFormatTag]; + if (!subFormat) { + debug('WAVE/non-PCM format=' + fmt.wFormatTag); + subFormat = 'non-PCM (' + fmt.wFormatTag + ')'; + } + this.metadata.setFormat('codec', subFormat); + this.metadata.setFormat('bitsPerSample', fmt.wBitsPerSample); + this.metadata.setFormat('sampleRate', fmt.nSamplesPerSec); + this.metadata.setFormat('numberOfChannels', fmt.nChannels); + this.metadata.setFormat('bitrate', fmt.nBlockAlign * fmt.nSamplesPerSec * 8); + this.blockAlign = fmt.nBlockAlign; + break; + case 'id3 ': // The way Picard, FooBar currently stores, ID3 meta-data + case 'ID3 ': // The way Mp3Tags stores ID3 meta-data + const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(header.chunkSize)); + const rst = strtok3.fromBuffer(id3_data); + await new ID3v2Parser_1.ID3v2Parser().parse(this.metadata, rst, this.options); + break; + case 'data': // PCM-data + if (this.metadata.format.lossless !== false) { + this.metadata.setFormat('lossless', true); + } + let chunkSize = header.chunkSize; + if (this.tokenizer.fileInfo.size) { + const calcRemaining = this.tokenizer.fileInfo.size - this.tokenizer.position; + if (calcRemaining < chunkSize) { + this.metadata.addWarning('data chunk length exceeding file length'); + chunkSize = calcRemaining; + } + } + const numberOfSamples = this.fact ? this.fact.dwSampleLength : (chunkSize === 0xffffffff ? undefined : chunkSize / this.blockAlign); + if (numberOfSamples) { + this.metadata.setFormat('numberOfSamples', numberOfSamples); + this.metadata.setFormat('duration', numberOfSamples / this.metadata.format.sampleRate); + } + this.metadata.setFormat('bitrate', this.metadata.format.numberOfChannels * this.blockAlign * this.metadata.format.sampleRate); // ToDo: check me + await this.tokenizer.ignore(header.chunkSize); + break; + case 'bext': // Broadcast Audio Extension chunk https://tech.ebu.ch/docs/tech/tech3285.pdf + const bext = await this.tokenizer.readToken(BwfChunk_1.BroadcastAudioExtensionChunk); + Object.keys(bext).forEach(key => { + this.metadata.addTag('exif', 'bext.' + key, bext[key]); + }); + break; + case '\x00\x00\x00\x00': // padding ?? + debug(`Ignore padding chunk: RIFF/${header.chunkID} of ${header.chunkSize} bytes`); + this.metadata.addWarning('Ignore chunk: RIFF/' + header.chunkID); + await this.tokenizer.ignore(header.chunkSize); + break; + default: + debug(`Ignore chunk: RIFF/${header.chunkID} of ${header.chunkSize} bytes`); + this.metadata.addWarning('Ignore chunk: RIFF/' + header.chunkID); + await this.tokenizer.ignore(header.chunkSize); + } + if (this.header.chunkSize % 2 === 1) { + debug('Read odd padding byte'); // https://wiki.multimedia.cx/index.php/RIFF + await this.tokenizer.ignore(1); + } + } + } + async parseListTag(listHeader) { + const listType = await this.tokenizer.readToken(new Token.StringType(4, 'binary')); + debug('pos=%s, parseListTag: chunkID=RIFF/WAVE/LIST/%s', this.tokenizer.position, listType); + switch (listType) { + case 'INFO': + return this.parseRiffInfoTags(listHeader.chunkSize - 4); + case 'adtl': + default: + this.metadata.addWarning('Ignore chunk: RIFF/WAVE/LIST/' + listType); + debug('Ignoring chunkID=RIFF/WAVE/LIST/' + listType); + return this.tokenizer.ignore(listHeader.chunkSize - 4).then(); + } + } + async parseRiffInfoTags(chunkSize) { + while (chunkSize >= 8) { + const header = await this.tokenizer.readToken(riff.Header); + const valueToken = new riff.ListInfoTagValue(header); + const value = await this.tokenizer.readToken(valueToken); + this.addTag(header.chunkID, util.stripNulls(value)); + chunkSize -= (8 + valueToken.len); + } + if (chunkSize !== 0) { + throw Error('Illegal remaining size: ' + chunkSize); + } + } + addTag(id, value) { + this.metadata.addTag('exif', id, value); + } +} +exports.WaveParser = WaveParser; + + +/***/ }), + +/***/ 5870: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.WavPackParser = void 0; +const Token = __webpack_require__(3416); +const APEv2Parser_1 = __webpack_require__(6742); +const FourCC_1 = __webpack_require__(8049); +const BasicParser_1 = __webpack_require__(7805); +const WavPackToken_1 = __webpack_require__(2989); +const debug_1 = __webpack_require__(1227); +const debug = (0, debug_1.default)('music-metadata:parser:WavPack'); +/** + * WavPack Parser + */ +class WavPackParser extends BasicParser_1.BasicParser { + async parse() { + this.audioDataSize = 0; + // First parse all WavPack blocks + await this.parseWavPackBlocks(); + // try to parse APEv2 header + return APEv2Parser_1.APEv2Parser.tryParseApeHeader(this.metadata, this.tokenizer, this.options); + } + async parseWavPackBlocks() { + do { + const blockId = await this.tokenizer.peekToken(FourCC_1.FourCcToken); + if (blockId !== 'wvpk') + break; + const header = await this.tokenizer.readToken(WavPackToken_1.WavPack.BlockHeaderToken); + if (header.BlockID !== 'wvpk') + throw new Error('Invalid WavPack Block-ID'); + debug(`WavPack header blockIndex=${header.blockIndex}, len=${WavPackToken_1.WavPack.BlockHeaderToken.len}`); + if (header.blockIndex === 0 && !this.metadata.format.container) { + this.metadata.setFormat('container', 'WavPack'); + this.metadata.setFormat('lossless', !header.flags.isHybrid); + // tagTypes: this.type, + this.metadata.setFormat('bitsPerSample', header.flags.bitsPerSample); + if (!header.flags.isDSD) { + // In case isDSD, these values will ne set in ID_DSD_BLOCK + this.metadata.setFormat('sampleRate', header.flags.samplingRate); + this.metadata.setFormat('duration', header.totalSamples / header.flags.samplingRate); + } + this.metadata.setFormat('numberOfChannels', header.flags.isMono ? 1 : 2); + this.metadata.setFormat('numberOfSamples', header.totalSamples); + this.metadata.setFormat('codec', header.flags.isDSD ? 'DSD' : 'PCM'); + } + const ignoreBytes = header.blockSize - (WavPackToken_1.WavPack.BlockHeaderToken.len - 8); + await (header.blockIndex === 0 ? this.parseMetadataSubBlock(header, ignoreBytes) : this.tokenizer.ignore(ignoreBytes)); + if (header.blockSamples > 0) { + this.audioDataSize += header.blockSize; // Count audio data for bit-rate calculation + } + } while (!this.tokenizer.fileInfo.size || this.tokenizer.fileInfo.size - this.tokenizer.position >= WavPackToken_1.WavPack.BlockHeaderToken.len); + this.metadata.setFormat('bitrate', this.audioDataSize * 8 / this.metadata.format.duration); + } + /** + * Ref: http://www.wavpack.com/WavPack5FileFormat.pdf, 3.0 Metadata Sub-blocks + * @param remainingLength + */ + async parseMetadataSubBlock(header, remainingLength) { + while (remainingLength > WavPackToken_1.WavPack.MetadataIdToken.len) { + const id = await this.tokenizer.readToken(WavPackToken_1.WavPack.MetadataIdToken); + const dataSizeInWords = await this.tokenizer.readNumber(id.largeBlock ? Token.UINT24_LE : Token.UINT8); + const data = Buffer.alloc(dataSizeInWords * 2 - (id.isOddSize ? 1 : 0)); + await this.tokenizer.readBuffer(data); + debug(`Metadata Sub-Blocks functionId=0x${id.functionId.toString(16)}, id.largeBlock=${id.largeBlock},data-size=${data.length}`); + switch (id.functionId) { + case 0x0: // ID_DUMMY: could be used to pad WavPack blocks + break; + case 0xe: // ID_DSD_BLOCK + debug('ID_DSD_BLOCK'); + // https://github.com/dbry/WavPack/issues/71#issuecomment-483094813 + const mp = 1 << data.readUInt8(0); + const samplingRate = header.flags.samplingRate * mp * 8; // ToDo: second factor should be read from DSD-metadata block https://github.com/dbry/WavPack/issues/71#issuecomment-483094813 + if (!header.flags.isDSD) + throw new Error('Only expect DSD block if DSD-flag is set'); + this.metadata.setFormat('sampleRate', samplingRate); + this.metadata.setFormat('duration', header.totalSamples / samplingRate); + break; + case 0x24: // ID_ALT_TRAILER: maybe used to embed original ID3 tag header + debug('ID_ALT_TRAILER: trailer for non-wav files'); + break; + case 0x26: // ID_MD5_CHECKSUM + this.metadata.setFormat('audioMD5', data); + break; + case 0x2f: // ID_BLOCK_CHECKSUM + debug(`ID_BLOCK_CHECKSUM: checksum=${data.toString('hex')}`); + break; + default: + debug(`Ignore unsupported meta-sub-block-id functionId=0x${id.functionId.toString(16)}`); + break; + } + remainingLength -= WavPackToken_1.WavPack.MetadataIdToken.len + (id.largeBlock ? Token.UINT24_LE.len : Token.UINT8.len) + dataSizeInWords * 2; + debug(`remainingLength=${remainingLength}`); + if (id.isOddSize) + this.tokenizer.ignore(1); + } + if (remainingLength !== 0) + throw new Error('metadata-sub-block should fit it remaining length'); + } +} +exports.WavPackParser = WavPackParser; + + +/***/ }), + +/***/ 2989: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.WavPack = void 0; +const Token = __webpack_require__(3416); +const FourCC_1 = __webpack_require__(8049); +const SampleRates = [6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, + 48000, 64000, 88200, 96000, 192000, -1]; +class WavPack { + static isBitSet(flags, bitOffset) { + return WavPack.getBitAllignedNumber(flags, bitOffset, 1) === 1; + } + static getBitAllignedNumber(flags, bitOffset, len) { + return (flags >>> bitOffset) & (0xffffffff >>> (32 - len)); + } +} +exports.WavPack = WavPack; +/** + * WavPack Block Header + * + * 32-byte little-endian header at the front of every WavPack block + * + * Ref: http://www.wavpack.com/WavPack5FileFormat.pdf (page 2/6: 2.0 "Block Header") + */ +WavPack.BlockHeaderToken = { + len: 32, + get: (buf, off) => { + const flags = Token.UINT32_LE.get(buf, off + 24); + const res = { + // should equal 'wvpk' + BlockID: FourCC_1.FourCcToken.get(buf, off), + // 0x402 to 0x410 are valid for decode + blockSize: Token.UINT32_LE.get(buf, off + 4), + // 0x402 (1026) to 0x410 are valid for decode + version: Token.UINT16_LE.get(buf, off + 8), + // 40-bit total samples for entire file (if block_index == 0 and a value of -1 indicates an unknown length) + totalSamples: /* replace with bigint? (Token.UINT8.get(buf, off + 11) << 32) + */ Token.UINT32_LE.get(buf, off + 12), + // 40-bit block_index + blockIndex: /* replace with bigint? (Token.UINT8.get(buf, off + 10) << 32) + */ Token.UINT32_LE.get(buf, off + 16), + // 40-bit total samples for entire file (if block_index == 0 and a value of -1 indicates an unknown length) + blockSamples: Token.UINT32_LE.get(buf, off + 20), + // various flags for id and decoding + flags: { + bitsPerSample: (1 + WavPack.getBitAllignedNumber(flags, 0, 2)) * 8, + isMono: WavPack.isBitSet(flags, 2), + isHybrid: WavPack.isBitSet(flags, 3), + isJointStereo: WavPack.isBitSet(flags, 4), + crossChannel: WavPack.isBitSet(flags, 5), + hybridNoiseShaping: WavPack.isBitSet(flags, 6), + floatingPoint: WavPack.isBitSet(flags, 7), + samplingRate: SampleRates[WavPack.getBitAllignedNumber(flags, 23, 4)], + isDSD: WavPack.isBitSet(flags, 31) + }, + // crc for actual decoded data + crc: new Token.Uint8ArrayType(4).get(buf, off + 28) + }; + if (res.flags.isDSD) { + res.totalSamples *= 8; + } + return res; + } +}; +/** + * 3.0 Metadata Sub-Blocks + * Ref: http://www.wavpack.com/WavPack5FileFormat.pdf (page 4/6: 3.0 "Metadata Sub-Block") + */ +WavPack.MetadataIdToken = { + len: 1, + get: (buf, off) => { + return { + functionId: WavPack.getBitAllignedNumber(buf[off], 0, 6), + isOptional: WavPack.isBitSet(buf[off], 5), + isOddSize: WavPack.isBitSet(buf[off], 6), + largeBlock: WavPack.isBitSet(buf[off], 7) + }; + } +}; + + +/***/ }), + +/***/ 8985: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.Deferred = void 0; +class Deferred { + constructor() { + this.resolve = () => null; + this.reject = () => null; + this.promise = new Promise((resolve, reject) => { + this.reject = reject; + this.resolve = resolve; + }); + } +} +exports.Deferred = Deferred; + + +/***/ }), + +/***/ 7279: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.EndOfStreamError = exports.defaultMessages = void 0; +exports.defaultMessages = 'End-Of-Stream'; +/** + * Thrown on read operation of the end of file or stream has been reached + */ +class EndOfStreamError extends Error { + constructor() { + super(exports.defaultMessages); + } +} +exports.EndOfStreamError = EndOfStreamError; + + +/***/ }), + +/***/ 6654: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.StreamReader = exports.EndOfStreamError = void 0; +const EndOfFileStream_1 = __webpack_require__(7279); +const Deferred_1 = __webpack_require__(8985); +var EndOfFileStream_2 = __webpack_require__(7279); +Object.defineProperty(exports, "EndOfStreamError", ({ enumerable: true, get: function () { return EndOfFileStream_2.EndOfStreamError; } })); +const maxStreamReadSize = 1 * 1024 * 1024; // Maximum request length on read-stream operation +class StreamReader { + constructor(s) { + this.s = s; + /** + * Deferred used for postponed read request (as not data is yet available to read) + */ + this.deferred = null; + this.endOfStream = false; + /** + * Store peeked data + * @type {Array} + */ + this.peekQueue = []; + if (!s.read || !s.once) { + throw new Error('Expected an instance of stream.Readable'); + } + this.s.once('end', () => this.reject(new EndOfFileStream_1.EndOfStreamError())); + this.s.once('error', err => this.reject(err)); + this.s.once('close', () => this.reject(new Error('Stream closed'))); + } + /** + * Read ahead (peek) from stream. Subsequent read or peeks will return the same data + * @param uint8Array - Uint8Array (or Buffer) to store data read from stream in + * @param offset - Offset target + * @param length - Number of bytes to read + * @returns Number of bytes peeked + */ + async peek(uint8Array, offset, length) { + const bytesRead = await this.read(uint8Array, offset, length); + this.peekQueue.push(uint8Array.subarray(offset, offset + bytesRead)); // Put read data back to peek buffer + return bytesRead; + } + /** + * Read chunk from stream + * @param buffer - Target Uint8Array (or Buffer) to store data read from stream in + * @param offset - Offset target + * @param length - Number of bytes to read + * @returns Number of bytes read + */ + async read(buffer, offset, length) { + if (length === 0) { + return 0; + } + if (this.peekQueue.length === 0 && this.endOfStream) { + throw new EndOfFileStream_1.EndOfStreamError(); + } + let remaining = length; + let bytesRead = 0; + // consume peeked data first + while (this.peekQueue.length > 0 && remaining > 0) { + const peekData = this.peekQueue.pop(); // Front of queue + if (!peekData) + throw new Error('peekData should be defined'); + const lenCopy = Math.min(peekData.length, remaining); + buffer.set(peekData.subarray(0, lenCopy), offset + bytesRead); + bytesRead += lenCopy; + remaining -= lenCopy; + if (lenCopy < peekData.length) { + // remainder back to queue + this.peekQueue.push(peekData.subarray(lenCopy)); + } + } + // continue reading from stream if required + while (remaining > 0 && !this.endOfStream) { + const reqLen = Math.min(remaining, maxStreamReadSize); + const chunkLen = await this.readFromStream(buffer, offset + bytesRead, reqLen); + bytesRead += chunkLen; + if (chunkLen < reqLen) + break; + remaining -= chunkLen; + } + return bytesRead; + } + /** + * Read chunk from stream + * @param buffer Target Uint8Array (or Buffer) to store data read from stream in + * @param offset Offset target + * @param length Number of bytes to read + * @returns Number of bytes read + */ + async readFromStream(buffer, offset, length) { + const readBuffer = this.s.read(length); + if (readBuffer) { + buffer.set(readBuffer, offset); + return readBuffer.length; + } + else { + const request = { + buffer, + offset, + length, + deferred: new Deferred_1.Deferred() + }; + this.deferred = request.deferred; + this.s.once('readable', () => { + this.readDeferred(request); + }); + return request.deferred.promise; + } + } + /** + * Process deferred read request + * @param request Deferred read request + */ + readDeferred(request) { + const readBuffer = this.s.read(request.length); + if (readBuffer) { + request.buffer.set(readBuffer, request.offset); + request.deferred.resolve(readBuffer.length); + this.deferred = null; + } + else { + this.s.once('readable', () => { + this.readDeferred(request); + }); + } + } + reject(err) { + this.endOfStream = true; + if (this.deferred) { + this.deferred.reject(err); + this.deferred = null; + } + } +} +exports.StreamReader = StreamReader; + + +/***/ }), + +/***/ 5167: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.StreamReader = exports.EndOfStreamError = void 0; +var EndOfFileStream_1 = __webpack_require__(7279); +Object.defineProperty(exports, "EndOfStreamError", ({ enumerable: true, get: function () { return EndOfFileStream_1.EndOfStreamError; } })); +var StreamReader_1 = __webpack_require__(6654); +Object.defineProperty(exports, "StreamReader", ({ enumerable: true, get: function () { return StreamReader_1.StreamReader; } })); + + +/***/ }), + +/***/ 4155: +/***/ ((module) => { + +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; + +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} + +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} + +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + + +/***/ }), + +/***/ 4281: +/***/ ((module) => { + +"use strict"; + + +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + +var codes = {}; + +function createErrorType(code, message, Base) { + if (!Base) { + Base = Error; + } + + function getMessage(arg1, arg2, arg3) { + if (typeof message === 'string') { + return message; + } else { + return message(arg1, arg2, arg3); + } + } + + var NodeError = + /*#__PURE__*/ + function (_Base) { + _inheritsLoose(NodeError, _Base); + + function NodeError(arg1, arg2, arg3) { + return _Base.call(this, getMessage(arg1, arg2, arg3)) || this; + } + + return NodeError; + }(Base); + + NodeError.prototype.name = Base.name; + NodeError.prototype.code = code; + codes[code] = NodeError; +} // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js + + +function oneOf(expected, thing) { + if (Array.isArray(expected)) { + var len = expected.length; + expected = expected.map(function (i) { + return String(i); + }); + + if (len > 2) { + return "one of ".concat(thing, " ").concat(expected.slice(0, len - 1).join(', '), ", or ") + expected[len - 1]; + } else if (len === 2) { + return "one of ".concat(thing, " ").concat(expected[0], " or ").concat(expected[1]); + } else { + return "of ".concat(thing, " ").concat(expected[0]); + } + } else { + return "of ".concat(thing, " ").concat(String(expected)); + } +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith + + +function startsWith(str, search, pos) { + return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search; +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith + + +function endsWith(str, search, this_len) { + if (this_len === undefined || this_len > str.length) { + this_len = str.length; + } + + return str.substring(this_len - search.length, this_len) === search; +} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes + + +function includes(str, search, start) { + if (typeof start !== 'number') { + start = 0; + } + + if (start + search.length > str.length) { + return false; + } else { + return str.indexOf(search, start) !== -1; + } +} + +createErrorType('ERR_INVALID_OPT_VALUE', function (name, value) { + return 'The value "' + value + '" is invalid for option "' + name + '"'; +}, TypeError); +createErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) { + // determiner: 'must be' or 'must not be' + var determiner; + + if (typeof expected === 'string' && startsWith(expected, 'not ')) { + determiner = 'must not be'; + expected = expected.replace(/^not /, ''); + } else { + determiner = 'must be'; + } + + var msg; + + if (endsWith(name, ' argument')) { + // For cases like 'first argument' + msg = "The ".concat(name, " ").concat(determiner, " ").concat(oneOf(expected, 'type')); + } else { + var type = includes(name, '.') ? 'property' : 'argument'; + msg = "The \"".concat(name, "\" ").concat(type, " ").concat(determiner, " ").concat(oneOf(expected, 'type')); + } + + msg += ". Received type ".concat(typeof actual); + return msg; +}, TypeError); +createErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF'); +createErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) { + return 'The ' + name + ' method is not implemented'; +}); +createErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close'); +createErrorType('ERR_STREAM_DESTROYED', function (name) { + return 'Cannot call ' + name + ' after a stream was destroyed'; +}); +createErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times'); +createErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable'); +createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end'); +createErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError); +createErrorType('ERR_UNKNOWN_ENCODING', function (arg) { + return 'Unknown encoding: ' + arg; +}, TypeError); +createErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event'); +module.exports.q = codes; + + +/***/ }), + +/***/ 6753: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var process = __webpack_require__(4155); +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. + +/**/ + +var objectKeys = Object.keys || function (obj) { + var keys = []; + + for (var key in obj) { + keys.push(key); + } + + return keys; +}; +/**/ + + +module.exports = Duplex; + +var Readable = __webpack_require__(9481); + +var Writable = __webpack_require__(4229); + +__webpack_require__(5717)(Duplex, Readable); + +{ + // Allow the keys array to be GC'ed. + var keys = objectKeys(Writable.prototype); + + for (var v = 0; v < keys.length; v++) { + var method = keys[v]; + if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; + } +} + +function Duplex(options) { + if (!(this instanceof Duplex)) return new Duplex(options); + Readable.call(this, options); + Writable.call(this, options); + this.allowHalfOpen = true; + + if (options) { + if (options.readable === false) this.readable = false; + if (options.writable === false) this.writable = false; + + if (options.allowHalfOpen === false) { + this.allowHalfOpen = false; + this.once('end', onend); + } + } +} + +Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.highWaterMark; + } +}); +Object.defineProperty(Duplex.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState && this._writableState.getBuffer(); + } +}); +Object.defineProperty(Duplex.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.length; + } +}); // the no-half-open enforcer + +function onend() { + // If the writable side ended, then we're ok. + if (this._writableState.ended) return; // no more data can be written. + // But allow more writes to happen in this tick. + + process.nextTick(onEndNT, this); +} + +function onEndNT(self) { + self.end(); +} + +Object.defineProperty(Duplex.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._readableState === undefined || this._writableState === undefined) { + return false; + } + + return this._readableState.destroyed && this._writableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (this._readableState === undefined || this._writableState === undefined) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._readableState.destroyed = value; + this._writableState.destroyed = value; + } +}); + +/***/ }), + +/***/ 2725: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. + + +module.exports = PassThrough; + +var Transform = __webpack_require__(4605); + +__webpack_require__(5717)(PassThrough, Transform); + +function PassThrough(options) { + if (!(this instanceof PassThrough)) return new PassThrough(options); + Transform.call(this, options); +} + +PassThrough.prototype._transform = function (chunk, encoding, cb) { + cb(null, chunk); +}; + +/***/ }), + +/***/ 9481: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var process = __webpack_require__(4155); +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + +module.exports = Readable; +/**/ + +var Duplex; +/**/ + +Readable.ReadableState = ReadableState; +/**/ + +var EE = (__webpack_require__(7187).EventEmitter); + +var EElistenerCount = function EElistenerCount(emitter, type) { + return emitter.listeners(type).length; +}; +/**/ + +/**/ + + +var Stream = __webpack_require__(2503); +/**/ + + +var Buffer = (__webpack_require__(8764).Buffer); + +var OurUint8Array = __webpack_require__.g.Uint8Array || function () {}; + +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} + +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} +/**/ + + +var debugUtil = __webpack_require__(4616); + +var debug; + +if (debugUtil && debugUtil.debuglog) { + debug = debugUtil.debuglog('stream'); +} else { + debug = function debug() {}; +} +/**/ + + +var BufferList = __webpack_require__(7327); + +var destroyImpl = __webpack_require__(1195); + +var _require = __webpack_require__(2457), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = (__webpack_require__(4281)/* .codes */ .q), + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance. + + +var StringDecoder; +var createReadableStreamAsyncIterator; +var from; + +__webpack_require__(5717)(Readable, Stream); + +var errorOrDestroy = destroyImpl.errorOrDestroy; +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + +function prependListener(emitter, event, fn) { + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. + if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); // This is a hack to make sure that our error handler is attached before any + // userland ones. NEVER DO THIS. This is here only because this code needs + // to continue to work with older versions of Node.js that do not include + // the prependListener() method. The goal is to eventually remove this hack. + + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; +} + +function ReadableState(options, stream, isDuplex) { + Duplex = Duplex || __webpack_require__(6753); + options = options || {}; // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + + this.objectMode = !!options.objectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + + this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the + // linked list can remove elements from the beginning faster than + // array.shift() + + this.buffer = new BufferList(); + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; // a flag to be able to tell if the event 'readable'/'data' is emitted + // immediately, or on a later tick. We set this to true at first, because + // any actions that shouldn't happen until "later" should generally also + // not happen before the first read call. + + this.sync = true; // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + this.resumeScheduled = false; + this.paused = true; // Should close be emitted on destroy. Defaults to true. + + this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish') + + this.autoDestroy = !!options.autoDestroy; // has it been destroyed + + this.destroyed = false; // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + + this.defaultEncoding = options.defaultEncoding || 'utf8'; // the number of writers that are awaiting a drain event in .pipe()s + + this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled + + this.readingMore = false; + this.decoder = null; + this.encoding = null; + + if (options.encoding) { + if (!StringDecoder) StringDecoder = (__webpack_require__(2553)/* .StringDecoder */ .s); + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } +} + +function Readable(options) { + Duplex = Duplex || __webpack_require__(6753); + if (!(this instanceof Readable)) return new Readable(options); // Checking for a Stream.Duplex instance is faster here instead of inside + // the ReadableState constructor, at least with V8 6.5 + + var isDuplex = this instanceof Duplex; + this._readableState = new ReadableState(options, this, isDuplex); // legacy + + this.readable = true; + + if (options) { + if (typeof options.read === 'function') this._read = options.read; + if (typeof options.destroy === 'function') this._destroy = options.destroy; + } + + Stream.call(this); +} + +Object.defineProperty(Readable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._readableState === undefined) { + return false; + } + + return this._readableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._readableState) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._readableState.destroyed = value; + } +}); +Readable.prototype.destroy = destroyImpl.destroy; +Readable.prototype._undestroy = destroyImpl.undestroy; + +Readable.prototype._destroy = function (err, cb) { + cb(err); +}; // Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. + + +Readable.prototype.push = function (chunk, encoding) { + var state = this._readableState; + var skipChunkCheck; + + if (!state.objectMode) { + if (typeof chunk === 'string') { + encoding = encoding || state.defaultEncoding; + + if (encoding !== state.encoding) { + chunk = Buffer.from(chunk, encoding); + encoding = ''; + } + + skipChunkCheck = true; + } + } else { + skipChunkCheck = true; + } + + return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); +}; // Unshift should *always* be something directly out of read() + + +Readable.prototype.unshift = function (chunk) { + return readableAddChunk(this, chunk, null, true, false); +}; + +function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + debug('readableAddChunk', chunk); + var state = stream._readableState; + + if (chunk === null) { + state.reading = false; + onEofChunk(stream, state); + } else { + var er; + if (!skipChunkCheck) er = chunkInvalid(state, chunk); + + if (er) { + errorOrDestroy(stream, er); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (addToFront) { + if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true); + } else if (state.ended) { + errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); + } else if (state.destroyed) { + return false; + } else { + state.reading = false; + + if (state.decoder && !encoding) { + chunk = state.decoder.write(chunk); + if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); + } else { + addChunk(stream, state, chunk, false); + } + } + } else if (!addToFront) { + state.reading = false; + maybeReadMore(stream, state); + } + } // We can push more data if we are below the highWaterMark. + // Also, if we have no data yet, we can stand some more bytes. + // This is to work around cases where hwm=0, such as the repl. + + + return !state.ended && (state.length < state.highWaterMark || state.length === 0); +} + +function addChunk(stream, state, chunk, addToFront) { + if (state.flowing && state.length === 0 && !state.sync) { + state.awaitDrain = 0; + stream.emit('data', chunk); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); + if (state.needReadable) emitReadable(stream); + } + + maybeReadMore(stream, state); +} + +function chunkInvalid(state, chunk) { + var er; + + if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk); + } + + return er; +} + +Readable.prototype.isPaused = function () { + return this._readableState.flowing === false; +}; // backwards compatibility. + + +Readable.prototype.setEncoding = function (enc) { + if (!StringDecoder) StringDecoder = (__webpack_require__(2553)/* .StringDecoder */ .s); + var decoder = new StringDecoder(enc); + this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8 + + this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers: + + var p = this._readableState.buffer.head; + var content = ''; + + while (p !== null) { + content += decoder.write(p.data); + p = p.next; + } + + this._readableState.buffer.clear(); + + if (content !== '') this._readableState.buffer.push(content); + this._readableState.length = content.length; + return this; +}; // Don't raise the hwm > 1GB + + +var MAX_HWM = 0x40000000; + +function computeNewHighWaterMark(n) { + if (n >= MAX_HWM) { + // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE. + n = MAX_HWM; + } else { + // Get the next highest power of 2 to prevent increasing hwm excessively in + // tiny amounts + n--; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + n++; + } + + return n; +} // This function is designed to be inlinable, so please take care when making +// changes to the function body. + + +function howMuchToRead(n, state) { + if (n <= 0 || state.length === 0 && state.ended) return 0; + if (state.objectMode) return 1; + + if (n !== n) { + // Only flow one buffer at a time + if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; + } // If we're asking for more than the current hwm, then raise the hwm. + + + if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); + if (n <= state.length) return n; // Don't have enough + + if (!state.ended) { + state.needReadable = true; + return 0; + } + + return state.length; +} // you can override either this method, or the async _read(n) below. + + +Readable.prototype.read = function (n) { + debug('read', n); + n = parseInt(n, 10); + var state = this._readableState; + var nOrig = n; + if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + + if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); + return null; + } + + n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up. + + if (n === 0 && state.ended) { + if (state.length === 0) endReadable(this); + return null; + } // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. + // if we need a readable event, then we need to do some reading. + + + var doRead = state.needReadable; + debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some + + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); + } // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + + + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } else if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; // if the length is currently zero, then we *need* a readable event. + + if (state.length === 0) state.needReadable = true; // call internal read method + + this._read(state.highWaterMark); + + state.sync = false; // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + + if (!state.reading) n = howMuchToRead(nOrig, state); + } + + var ret; + if (n > 0) ret = fromList(n, state);else ret = null; + + if (ret === null) { + state.needReadable = state.length <= state.highWaterMark; + n = 0; + } else { + state.length -= n; + state.awaitDrain = 0; + } + + if (state.length === 0) { + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick. + + if (nOrig !== n && state.ended) endReadable(this); + } + + if (ret !== null) this.emit('data', ret); + return ret; +}; + +function onEofChunk(stream, state) { + debug('onEofChunk'); + if (state.ended) return; + + if (state.decoder) { + var chunk = state.decoder.end(); + + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } + } + + state.ended = true; + + if (state.sync) { + // if we are sync, wait until next tick to emit the data. + // Otherwise we risk emitting data in the flow() + // the readable code triggers during a read() call + emitReadable(stream); + } else { + // emit 'readable' now to make sure it gets picked up. + state.needReadable = false; + + if (!state.emittedReadable) { + state.emittedReadable = true; + emitReadable_(stream); + } + } +} // Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. + + +function emitReadable(stream) { + var state = stream._readableState; + debug('emitReadable', state.needReadable, state.emittedReadable); + state.needReadable = false; + + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + process.nextTick(emitReadable_, stream); + } +} + +function emitReadable_(stream) { + var state = stream._readableState; + debug('emitReadable_', state.destroyed, state.length, state.ended); + + if (!state.destroyed && (state.length || state.ended)) { + stream.emit('readable'); + state.emittedReadable = false; + } // The stream needs another readable event if + // 1. It is not flowing, as the flow mechanism will take + // care of it. + // 2. It is not ended. + // 3. It is below the highWaterMark, so we can schedule + // another readable later. + + + state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark; + flow(stream); +} // at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. + + +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + process.nextTick(maybeReadMore_, stream, state); + } +} + +function maybeReadMore_(stream, state) { + // Attempt to read more data if we should. + // + // The conditions for reading more data are (one of): + // - Not enough data buffered (state.length < state.highWaterMark). The loop + // is responsible for filling the buffer with enough data if such data + // is available. If highWaterMark is 0 and we are not in the flowing mode + // we should _not_ attempt to buffer any extra data. We'll get more data + // when the stream consumer calls read() instead. + // - No data in the buffer, and the stream is in flowing mode. In this mode + // the loop below is responsible for ensuring read() is called. Failing to + // call read here would abort the flow and there's no other mechanism for + // continuing the flow if the stream consumer has just subscribed to the + // 'data' event. + // + // In addition to the above conditions to keep reading data, the following + // conditions prevent the data from being read: + // - The stream has ended (state.ended). + // - There is already a pending 'read' operation (state.reading). This is a + // case where the the stream has called the implementation defined _read() + // method, but they are processing the call asynchronously and have _not_ + // called push() with new data. In this case we skip performing more + // read()s. The execution ends in this method again after the _read() ends + // up calling push() with more data. + while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) { + var len = state.length; + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) // didn't get any data, stop spinning. + break; + } + + state.readingMore = false; +} // abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. + + +Readable.prototype._read = function (n) { + errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()')); +}; + +Readable.prototype.pipe = function (dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + + case 1: + state.pipes = [state.pipes, dest]; + break; + + default: + state.pipes.push(dest); + break; + } + + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); + var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; + var endFn = doEnd ? onend : unpipe; + if (state.endEmitted) process.nextTick(endFn);else src.once('end', endFn); + dest.on('unpipe', onunpipe); + + function onunpipe(readable, unpipeInfo) { + debug('onunpipe'); + + if (readable === src) { + if (unpipeInfo && unpipeInfo.hasUnpiped === false) { + unpipeInfo.hasUnpiped = true; + cleanup(); + } + } + } + + function onend() { + debug('onend'); + dest.end(); + } // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + + + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); + var cleanedUp = false; + + function cleanup() { + debug('cleanup'); // cleanup event handlers once the pipe is broken + + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', unpipe); + src.removeListener('data', ondata); + cleanedUp = true; // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + + if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); + } + + src.on('data', ondata); + + function ondata(chunk) { + debug('ondata'); + var ret = dest.write(chunk); + debug('dest.write', ret); + + if (ret === false) { + // If the user unpiped during `dest.write()`, it is possible + // to get stuck in a permanently paused state if that write + // also returned false. + // => Check whether `dest` is still a piping destination. + if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { + debug('false write response, pause', state.awaitDrain); + state.awaitDrain++; + } + + src.pause(); + } + } // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + + + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er); + } // Make sure our error handler is attached before userland ones. + + + prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once. + + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); + } + + dest.once('close', onclose); + + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); + } + + dest.once('finish', onfinish); + + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } // tell the dest that it's being piped to + + + dest.emit('pipe', src); // start the flow if it hasn't been started already. + + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } + + return dest; +}; + +function pipeOnDrain(src) { + return function pipeOnDrainFunctionResult() { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) state.awaitDrain--; + + if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} + +Readable.prototype.unpipe = function (dest) { + var state = this._readableState; + var unpipeInfo = { + hasUnpiped: false + }; // if we're not piping anywhere, then do nothing. + + if (state.pipesCount === 0) return this; // just one destination. most common case. + + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) return this; + if (!dest) dest = state.pipes; // got a match. + + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) dest.emit('unpipe', this, unpipeInfo); + return this; + } // slow case. multiple pipe destinations. + + + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this, { + hasUnpiped: false + }); + } + + return this; + } // try to find the right one. + + + var index = indexOf(state.pipes, dest); + if (index === -1) return this; + state.pipes.splice(index, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) state.pipes = state.pipes[0]; + dest.emit('unpipe', this, unpipeInfo); + return this; +}; // set up data events if they are asked for +// Ensure readable listeners eventually get something + + +Readable.prototype.on = function (ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); + var state = this._readableState; + + if (ev === 'data') { + // update readableListening so that resume() may be a no-op + // a few lines down. This is needed to support once('readable'). + state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused + + if (state.flowing !== false) this.resume(); + } else if (ev === 'readable') { + if (!state.endEmitted && !state.readableListening) { + state.readableListening = state.needReadable = true; + state.flowing = false; + state.emittedReadable = false; + debug('on readable', state.length, state.reading); + + if (state.length) { + emitReadable(this); + } else if (!state.reading) { + process.nextTick(nReadingNextTick, this); + } + } + } + + return res; +}; + +Readable.prototype.addListener = Readable.prototype.on; + +Readable.prototype.removeListener = function (ev, fn) { + var res = Stream.prototype.removeListener.call(this, ev, fn); + + if (ev === 'readable') { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + process.nextTick(updateReadableListening, this); + } + + return res; +}; + +Readable.prototype.removeAllListeners = function (ev) { + var res = Stream.prototype.removeAllListeners.apply(this, arguments); + + if (ev === 'readable' || ev === undefined) { + // We need to check if there is someone still listening to + // readable and reset the state. However this needs to happen + // after readable has been emitted but before I/O (nextTick) to + // support once('readable', fn) cycles. This means that calling + // resume within the same tick will have no + // effect. + process.nextTick(updateReadableListening, this); + } + + return res; +}; + +function updateReadableListening(self) { + var state = self._readableState; + state.readableListening = self.listenerCount('readable') > 0; + + if (state.resumeScheduled && !state.paused) { + // flowing needs to be set to true now, otherwise + // the upcoming resume will not flow. + state.flowing = true; // crude way to check if we should resume + } else if (self.listenerCount('data') > 0) { + self.resume(); + } +} + +function nReadingNextTick(self) { + debug('readable nexttick read 0'); + self.read(0); +} // pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. + + +Readable.prototype.resume = function () { + var state = this._readableState; + + if (!state.flowing) { + debug('resume'); // we flow only if there is no one listening + // for readable, but we still have to call + // resume() + + state.flowing = !state.readableListening; + resume(this, state); + } + + state.paused = false; + return this; +}; + +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + process.nextTick(resume_, stream, state); + } +} + +function resume_(stream, state) { + debug('resume', state.reading); + + if (!state.reading) { + stream.read(0); + } + + state.resumeScheduled = false; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) stream.read(0); +} + +Readable.prototype.pause = function () { + debug('call pause flowing=%j', this._readableState.flowing); + + if (this._readableState.flowing !== false) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); + } + + this._readableState.paused = true; + return this; +}; + +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + + while (state.flowing && stream.read() !== null) { + ; + } +} // wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. + + +Readable.prototype.wrap = function (stream) { + var _this = this; + + var state = this._readableState; + var paused = false; + stream.on('end', function () { + debug('wrapped end'); + + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) _this.push(chunk); + } + + _this.push(null); + }); + stream.on('data', function (chunk) { + debug('wrapped data'); + if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode + + if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + + var ret = _this.push(chunk); + + if (!ret) { + paused = true; + stream.pause(); + } + }); // proxy all the other methods. + // important when wrapping filters and duplexes. + + for (var i in stream) { + if (this[i] === undefined && typeof stream[i] === 'function') { + this[i] = function methodWrap(method) { + return function methodWrapReturnFunction() { + return stream[method].apply(stream, arguments); + }; + }(i); + } + } // proxy certain important events. + + + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); + } // when we try to consume some more bytes, simply unpause the + // underlying stream. + + + this._read = function (n) { + debug('wrapped _read', n); + + if (paused) { + paused = false; + stream.resume(); + } + }; + + return this; +}; + +if (typeof Symbol === 'function') { + Readable.prototype[Symbol.asyncIterator] = function () { + if (createReadableStreamAsyncIterator === undefined) { + createReadableStreamAsyncIterator = __webpack_require__(5850); + } + + return createReadableStreamAsyncIterator(this); + }; +} + +Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.highWaterMark; + } +}); +Object.defineProperty(Readable.prototype, 'readableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState && this._readableState.buffer; + } +}); +Object.defineProperty(Readable.prototype, 'readableFlowing', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.flowing; + }, + set: function set(state) { + if (this._readableState) { + this._readableState.flowing = state; + } + } +}); // exposed for testing purposes only. + +Readable._fromList = fromList; +Object.defineProperty(Readable.prototype, 'readableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._readableState.length; + } +}); // Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. + +function fromList(n, state) { + // nothing buffered + if (state.length === 0) return null; + var ret; + if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { + // read it all, truncate the list + if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length); + state.buffer.clear(); + } else { + // read part of list + ret = state.buffer.consume(n, state.decoder); + } + return ret; +} + +function endReadable(stream) { + var state = stream._readableState; + debug('endReadable', state.endEmitted); + + if (!state.endEmitted) { + state.ended = true; + process.nextTick(endReadableNT, state, stream); + } +} + +function endReadableNT(state, stream) { + debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift. + + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the writable side is ready for autoDestroy as well + var wState = stream._writableState; + + if (!wState || wState.autoDestroy && wState.finished) { + stream.destroy(); + } + } + } +} + +if (typeof Symbol === 'function') { + Readable.from = function (iterable, opts) { + if (from === undefined) { + from = __webpack_require__(889); + } + + return from(Readable, iterable, opts); + }; +} + +function indexOf(xs, x) { + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) return i; + } + + return -1; +} + +/***/ }), + +/***/ 4605: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. + + +module.exports = Transform; + +var _require$codes = (__webpack_require__(4281)/* .codes */ .q), + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING, + ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0; + +var Duplex = __webpack_require__(6753); + +__webpack_require__(5717)(Transform, Duplex); + +function afterTransform(er, data) { + var ts = this._transformState; + ts.transforming = false; + var cb = ts.writecb; + + if (cb === null) { + return this.emit('error', new ERR_MULTIPLE_CALLBACK()); + } + + ts.writechunk = null; + ts.writecb = null; + if (data != null) // single equals check for both `null` and `undefined` + this.push(data); + cb(er); + var rs = this._readableState; + rs.reading = false; + + if (rs.needReadable || rs.length < rs.highWaterMark) { + this._read(rs.highWaterMark); + } +} + +function Transform(options) { + if (!(this instanceof Transform)) return new Transform(options); + Duplex.call(this, options); + this._transformState = { + afterTransform: afterTransform.bind(this), + needTransform: false, + transforming: false, + writecb: null, + writechunk: null, + writeencoding: null + }; // start out asking for a readable event once data is transformed. + + this._readableState.needReadable = true; // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + + this._readableState.sync = false; + + if (options) { + if (typeof options.transform === 'function') this._transform = options.transform; + if (typeof options.flush === 'function') this._flush = options.flush; + } // When the writable side finishes, then flush out anything remaining. + + + this.on('prefinish', prefinish); +} + +function prefinish() { + var _this = this; + + if (typeof this._flush === 'function' && !this._readableState.destroyed) { + this._flush(function (er, data) { + done(_this, er, data); + }); + } else { + done(this, null, null); + } +} + +Transform.prototype.push = function (chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); +}; // This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. + + +Transform.prototype._transform = function (chunk, encoding, cb) { + cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()')); +}; + +Transform.prototype._write = function (chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); + } +}; // Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. + + +Transform.prototype._read = function (n) { + var ts = this._transformState; + + if (ts.writechunk !== null && !ts.transforming) { + ts.transforming = true; + + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); + } else { + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; + } +}; + +Transform.prototype._destroy = function (err, cb) { + Duplex.prototype._destroy.call(this, err, function (err2) { + cb(err2); + }); +}; + +function done(stream, er, data) { + if (er) return stream.emit('error', er); + if (data != null) // single equals check for both `null` and `undefined` + stream.push(data); // TODO(BridgeAR): Write a test for these two error cases + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + + if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0(); + if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING(); + return stream.push(null); +} + +/***/ }), + +/***/ 4229: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var process = __webpack_require__(4155); +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. +// A bit simpler than readable streams. +// Implement an async ._write(chunk, encoding, cb), and it'll handle all +// the drain event emission and buffering. + + +module.exports = Writable; +/* */ + +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; + this.next = null; +} // It seems a linked list but it is not +// there will be only 2 of these for each stream + + +function CorkedRequest(state) { + var _this = this; + + this.next = null; + this.entry = null; + + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +/* */ + +/**/ + + +var Duplex; +/**/ + +Writable.WritableState = WritableState; +/**/ + +var internalUtil = { + deprecate: __webpack_require__(4927) +}; +/**/ + +/**/ + +var Stream = __webpack_require__(2503); +/**/ + + +var Buffer = (__webpack_require__(8764).Buffer); + +var OurUint8Array = __webpack_require__.g.Uint8Array || function () {}; + +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} + +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + +var destroyImpl = __webpack_require__(1195); + +var _require = __webpack_require__(2457), + getHighWaterMark = _require.getHighWaterMark; + +var _require$codes = (__webpack_require__(4281)/* .codes */ .q), + ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE, + ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED, + ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK, + ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED, + ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES, + ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END, + ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING; + +var errorOrDestroy = destroyImpl.errorOrDestroy; + +__webpack_require__(5717)(Writable, Stream); + +function nop() {} + +function WritableState(options, stream, isDuplex) { + Duplex = Duplex || __webpack_require__(6753); + options = options || {}; // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream, + // e.g. options.readableObjectMode vs. options.writableObjectMode, etc. + + if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream + // contains buffers or objects. + + this.objectMode = !!options.objectMode; + if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + + this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called + + this.finalCalled = false; // drain event flag. + + this.needDrain = false; // at the start of calling end() + + this.ending = false; // when end() has been called, and returned + + this.ended = false; // when 'finish' is emitted + + this.finished = false; // has it been destroyed + + this.destroyed = false; // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + + this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + + this.length = 0; // a flag to see when we're in the middle of a write. + + this.writing = false; // when true all writes will be buffered until .uncork() call + + this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + + this.sync = true; // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + + this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb) + + this.onwrite = function (er) { + onwrite(stream, er); + }; // the callback that the user supplies to write(chunk,encoding,cb) + + + this.writecb = null; // the amount that is being written when _write is called. + + this.writelen = 0; + this.bufferedRequest = null; + this.lastBufferedRequest = null; // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + + this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + + this.prefinished = false; // True if the error was already emitted and should not be thrown again + + this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true. + + this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end') + + this.autoDestroy = !!options.autoDestroy; // count buffered requests + + this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always + // one allocated and free to use, and we maintain at most two + + this.corkedRequestsFree = new CorkedRequest(this); +} + +WritableState.prototype.getBuffer = function getBuffer() { + var current = this.bufferedRequest; + var out = []; + + while (current) { + out.push(current); + current = current.next; + } + + return out; +}; + +(function () { + try { + Object.defineProperty(WritableState.prototype, 'buffer', { + get: internalUtil.deprecate(function writableStateBufferGetter() { + return this.getBuffer(); + }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') + }); + } catch (_) {} +})(); // Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. + + +var realHasInstance; + +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function value(object) { + if (realHasInstance.call(this, object)) return true; + if (this !== Writable) return false; + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function realHasInstance(object) { + return object instanceof this; + }; +} + +function Writable(options) { + Duplex = Duplex || __webpack_require__(6753); // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + // Checking for a Stream.Duplex instance is faster here instead of inside + // the WritableState constructor, at least with V8 6.5 + + var isDuplex = this instanceof Duplex; + if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options); + this._writableState = new WritableState(options, this, isDuplex); // legacy. + + this.writable = true; + + if (options) { + if (typeof options.write === 'function') this._write = options.write; + if (typeof options.writev === 'function') this._writev = options.writev; + if (typeof options.destroy === 'function') this._destroy = options.destroy; + if (typeof options.final === 'function') this._final = options.final; + } + + Stream.call(this); +} // Otherwise people can pipe Writable streams, which is just wrong. + + +Writable.prototype.pipe = function () { + errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); +}; + +function writeAfterEnd(stream, cb) { + var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb + + errorOrDestroy(stream, er); + process.nextTick(cb, er); +} // Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. + + +function validChunk(stream, state, chunk, cb) { + var er; + + if (chunk === null) { + er = new ERR_STREAM_NULL_VALUES(); + } else if (typeof chunk !== 'string' && !state.objectMode) { + er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); + } + + if (er) { + errorOrDestroy(stream, er); + process.nextTick(cb, er); + return false; + } + + return true; +} + +Writable.prototype.write = function (chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + + var isBuf = !state.objectMode && _isUint8Array(chunk); + + if (isBuf && !Buffer.isBuffer(chunk)) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + if (typeof cb !== 'function') cb = nop; + if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); + } + return ret; +}; + +Writable.prototype.cork = function () { + this._writableState.corked++; +}; + +Writable.prototype.uncork = function () { + var state = this._writableState; + + if (state.corked) { + state.corked--; + if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); + } +}; + +Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { + // node::ParseEncoding() requires lower case. + if (typeof encoding === 'string') encoding = encoding.toLowerCase(); + if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding); + this._writableState.defaultEncoding = encoding; + return this; +}; + +Object.defineProperty(Writable.prototype, 'writableBuffer', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState && this._writableState.getBuffer(); + } +}); + +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding); + } + + return chunk; +} + +Object.defineProperty(Writable.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.highWaterMark; + } +}); // if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. + +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + var newChunk = decodeChunk(state, chunk, encoding); + + if (chunk !== newChunk) { + isBuf = true; + encoding = 'buffer'; + chunk = newChunk; + } + } + + var len = state.objectMode ? 1 : chunk.length; + state.length += len; + var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false. + + if (!ret) state.needDrain = true; + + if (state.writing || state.corked) { + var last = state.lastBufferedRequest; + state.lastBufferedRequest = { + chunk: chunk, + encoding: encoding, + isBuf: isBuf, + callback: cb, + next: null + }; + + if (last) { + last.next = state.lastBufferedRequest; + } else { + state.bufferedRequest = state.lastBufferedRequest; + } + + state.bufferedRequestCount += 1; + } else { + doWrite(stream, state, false, len, chunk, encoding, cb); + } + + return ret; +} + +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} + +function onwriteError(stream, state, sync, er, cb) { + --state.pendingcb; + + if (sync) { + // defer the callback if we are being called synchronously + // to avoid piling up things on the stack + process.nextTick(cb, er); // this can emit finish, and it will always happen + // after error + + process.nextTick(finishMaybe, stream, state); + stream._writableState.errorEmitted = true; + errorOrDestroy(stream, er); + } else { + // the caller expect this to happen before if + // it is async + cb(er); + stream._writableState.errorEmitted = true; + errorOrDestroy(stream, er); // this can emit finish, but finish must + // always follow error + + finishMaybe(stream, state); + } +} + +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} + +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; + if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK(); + onwriteStateUpdate(state); + if (er) onwriteError(stream, state, sync, er, cb);else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(state) || stream.destroyed; + + if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { + clearBuffer(stream, state); + } + + if (sync) { + process.nextTick(afterWrite, stream, state, finished, cb); + } else { + afterWrite(stream, state, finished, cb); + } + } +} + +function afterWrite(stream, state, finished, cb) { + if (!finished) onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} // Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. + + +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} // if there's something in the buffer waiting, then process it + + +function clearBuffer(stream, state) { + state.bufferProcessing = true; + var entry = state.bufferedRequest; + + if (stream._writev && entry && entry.next) { + // Fast case, write everything using _writev() + var l = state.bufferedRequestCount; + var buffer = new Array(l); + var holder = state.corkedRequestsFree; + holder.entry = entry; + var count = 0; + var allBuffers = true; + + while (entry) { + buffer[count] = entry; + if (!entry.isBuf) allBuffers = false; + entry = entry.next; + count += 1; + } + + buffer.allBuffers = allBuffers; + doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time + // as the hot path ends with doWrite + + state.pendingcb++; + state.lastBufferedRequest = null; + + if (holder.next) { + state.corkedRequestsFree = holder.next; + holder.next = null; + } else { + state.corkedRequestsFree = new CorkedRequest(state); + } + + state.bufferedRequestCount = 0; + } else { + // Slow case, write chunks one-by-one + while (entry) { + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; + doWrite(stream, state, false, len, chunk, encoding, cb); + entry = entry.next; + state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + + if (state.writing) { + break; + } + } + + if (entry === null) state.lastBufferedRequest = null; + } + + state.bufferedRequest = entry; + state.bufferProcessing = false; +} + +Writable.prototype._write = function (chunk, encoding, cb) { + cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()')); +}; + +Writable.prototype._writev = null; + +Writable.prototype.end = function (chunk, encoding, cb) { + var state = this._writableState; + + if (typeof chunk === 'function') { + cb = chunk; + chunk = null; + encoding = null; + } else if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks + + if (state.corked) { + state.corked = 1; + this.uncork(); + } // ignore unnecessary end() calls. + + + if (!state.ending) endWritable(this, state, cb); + return this; +}; + +Object.defineProperty(Writable.prototype, 'writableLength', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + return this._writableState.length; + } +}); + +function needFinish(state) { + return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; +} + +function callFinal(stream, state) { + stream._final(function (err) { + state.pendingcb--; + + if (err) { + errorOrDestroy(stream, err); + } + + state.prefinished = true; + stream.emit('prefinish'); + finishMaybe(stream, state); + }); +} + +function prefinish(stream, state) { + if (!state.prefinished && !state.finalCalled) { + if (typeof stream._final === 'function' && !state.destroyed) { + state.pendingcb++; + state.finalCalled = true; + process.nextTick(callFinal, stream, state); + } else { + state.prefinished = true; + stream.emit('prefinish'); + } + } +} + +function finishMaybe(stream, state) { + var need = needFinish(state); + + if (need) { + prefinish(stream, state); + + if (state.pendingcb === 0) { + state.finished = true; + stream.emit('finish'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the readable side is ready for autoDestroy as well + var rState = stream._readableState; + + if (!rState || rState.autoDestroy && rState.endEmitted) { + stream.destroy(); + } + } + } + } + + return need; +} + +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + + if (cb) { + if (state.finished) process.nextTick(cb);else stream.once('finish', cb); + } + + state.ended = true; + stream.writable = false; +} + +function onCorkedFinish(corkReq, state, err) { + var entry = corkReq.entry; + corkReq.entry = null; + + while (entry) { + var cb = entry.callback; + state.pendingcb--; + cb(err); + entry = entry.next; + } // reuse the free corkReq. + + + state.corkedRequestsFree.next = corkReq; +} + +Object.defineProperty(Writable.prototype, 'destroyed', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function get() { + if (this._writableState === undefined) { + return false; + } + + return this._writableState.destroyed; + }, + set: function set(value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._writableState) { + return; + } // backward compatibility, the user is explicitly + // managing destroyed + + + this._writableState.destroyed = value; + } +}); +Writable.prototype.destroy = destroyImpl.destroy; +Writable.prototype._undestroy = destroyImpl.undestroy; + +Writable.prototype._destroy = function (err, cb) { + cb(err); +}; + +/***/ }), + +/***/ 5850: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var process = __webpack_require__(4155); + + +var _Object$setPrototypeO; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var finished = __webpack_require__(8610); + +var kLastResolve = Symbol('lastResolve'); +var kLastReject = Symbol('lastReject'); +var kError = Symbol('error'); +var kEnded = Symbol('ended'); +var kLastPromise = Symbol('lastPromise'); +var kHandlePromise = Symbol('handlePromise'); +var kStream = Symbol('stream'); + +function createIterResult(value, done) { + return { + value: value, + done: done + }; +} + +function readAndResolve(iter) { + var resolve = iter[kLastResolve]; + + if (resolve !== null) { + var data = iter[kStream].read(); // we defer if data is null + // we can be expecting either 'end' or + // 'error' + + if (data !== null) { + iter[kLastPromise] = null; + iter[kLastResolve] = null; + iter[kLastReject] = null; + resolve(createIterResult(data, false)); + } + } +} + +function onReadable(iter) { + // we wait for the next tick, because it might + // emit an error with process.nextTick + process.nextTick(readAndResolve, iter); +} + +function wrapForNext(lastPromise, iter) { + return function (resolve, reject) { + lastPromise.then(function () { + if (iter[kEnded]) { + resolve(createIterResult(undefined, true)); + return; + } + + iter[kHandlePromise](resolve, reject); + }, reject); + }; +} + +var AsyncIteratorPrototype = Object.getPrototypeOf(function () {}); +var ReadableStreamAsyncIteratorPrototype = Object.setPrototypeOf((_Object$setPrototypeO = { + get stream() { + return this[kStream]; + }, + + next: function next() { + var _this = this; + + // if we have detected an error in the meanwhile + // reject straight away + var error = this[kError]; + + if (error !== null) { + return Promise.reject(error); + } + + if (this[kEnded]) { + return Promise.resolve(createIterResult(undefined, true)); + } + + if (this[kStream].destroyed) { + // We need to defer via nextTick because if .destroy(err) is + // called, the error will be emitted via nextTick, and + // we cannot guarantee that there is no error lingering around + // waiting to be emitted. + return new Promise(function (resolve, reject) { + process.nextTick(function () { + if (_this[kError]) { + reject(_this[kError]); + } else { + resolve(createIterResult(undefined, true)); + } + }); + }); + } // if we have multiple next() calls + // we will wait for the previous Promise to finish + // this logic is optimized to support for await loops, + // where next() is only called once at a time + + + var lastPromise = this[kLastPromise]; + var promise; + + if (lastPromise) { + promise = new Promise(wrapForNext(lastPromise, this)); + } else { + // fast path needed to support multiple this.push() + // without triggering the next() queue + var data = this[kStream].read(); + + if (data !== null) { + return Promise.resolve(createIterResult(data, false)); + } + + promise = new Promise(this[kHandlePromise]); + } + + this[kLastPromise] = promise; + return promise; + } +}, _defineProperty(_Object$setPrototypeO, Symbol.asyncIterator, function () { + return this; +}), _defineProperty(_Object$setPrototypeO, "return", function _return() { + var _this2 = this; + + // destroy(err, cb) is a private API + // we can guarantee we have that here, because we control the + // Readable class this is attached to + return new Promise(function (resolve, reject) { + _this2[kStream].destroy(null, function (err) { + if (err) { + reject(err); + return; + } + + resolve(createIterResult(undefined, true)); + }); + }); +}), _Object$setPrototypeO), AsyncIteratorPrototype); + +var createReadableStreamAsyncIterator = function createReadableStreamAsyncIterator(stream) { + var _Object$create; + + var iterator = Object.create(ReadableStreamAsyncIteratorPrototype, (_Object$create = {}, _defineProperty(_Object$create, kStream, { + value: stream, + writable: true + }), _defineProperty(_Object$create, kLastResolve, { + value: null, + writable: true + }), _defineProperty(_Object$create, kLastReject, { + value: null, + writable: true + }), _defineProperty(_Object$create, kError, { + value: null, + writable: true + }), _defineProperty(_Object$create, kEnded, { + value: stream._readableState.endEmitted, + writable: true + }), _defineProperty(_Object$create, kHandlePromise, { + value: function value(resolve, reject) { + var data = iterator[kStream].read(); + + if (data) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + resolve(createIterResult(data, false)); + } else { + iterator[kLastResolve] = resolve; + iterator[kLastReject] = reject; + } + }, + writable: true + }), _Object$create)); + iterator[kLastPromise] = null; + finished(stream, function (err) { + if (err && err.code !== 'ERR_STREAM_PREMATURE_CLOSE') { + var reject = iterator[kLastReject]; // reject if we are waiting for data in the Promise + // returned by next() and store the error + + if (reject !== null) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + reject(err); + } + + iterator[kError] = err; + return; + } + + var resolve = iterator[kLastResolve]; + + if (resolve !== null) { + iterator[kLastPromise] = null; + iterator[kLastResolve] = null; + iterator[kLastReject] = null; + resolve(createIterResult(undefined, true)); + } + + iterator[kEnded] = true; + }); + stream.on('readable', onReadable.bind(null, iterator)); + return iterator; +}; + +module.exports = createReadableStreamAsyncIterator; + +/***/ }), + +/***/ 7327: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +var _require = __webpack_require__(8764), + Buffer = _require.Buffer; + +var _require2 = __webpack_require__(2361), + inspect = _require2.inspect; + +var custom = inspect && inspect.custom || 'inspect'; + +function copyBuffer(src, target, offset) { + Buffer.prototype.copy.call(src, target, offset); +} + +module.exports = +/*#__PURE__*/ +function () { + function BufferList() { + _classCallCheck(this, BufferList); + + this.head = null; + this.tail = null; + this.length = 0; + } + + _createClass(BufferList, [{ + key: "push", + value: function push(v) { + var entry = { + data: v, + next: null + }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + } + }, { + key: "unshift", + value: function unshift(v) { + var entry = { + data: v, + next: this.head + }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + } + }, { + key: "shift", + value: function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + } + }, { + key: "clear", + value: function clear() { + this.head = this.tail = null; + this.length = 0; + } + }, { + key: "join", + value: function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + + while (p = p.next) { + ret += s + p.data; + } + + return ret; + } + }, { + key: "concat", + value: function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; + } + + return ret; + } // Consumes a specified amount of bytes or characters from the buffered data. + + }, { + key: "consume", + value: function consume(n, hasStrings) { + var ret; + + if (n < this.head.data.length) { + // `slice` is the same for buffers and strings. + ret = this.head.data.slice(0, n); + this.head.data = this.head.data.slice(n); + } else if (n === this.head.data.length) { + // First chunk is a perfect match. + ret = this.shift(); + } else { + // Result spans more than one buffer. + ret = hasStrings ? this._getString(n) : this._getBuffer(n); + } + + return ret; + } + }, { + key: "first", + value: function first() { + return this.head.data; + } // Consumes a specified amount of characters from the buffered data. + + }, { + key: "_getString", + value: function _getString(n) { + var p = this.head; + var c = 1; + var ret = p.data; + n -= ret.length; + + while (p = p.next) { + var str = p.data; + var nb = n > str.length ? str.length : n; + if (nb === str.length) ret += str;else ret += str.slice(0, n); + n -= nb; + + if (n === 0) { + if (nb === str.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = str.slice(nb); + } + + break; + } + + ++c; + } + + this.length -= c; + return ret; + } // Consumes a specified amount of bytes from the buffered data. + + }, { + key: "_getBuffer", + value: function _getBuffer(n) { + var ret = Buffer.allocUnsafe(n); + var p = this.head; + var c = 1; + p.data.copy(ret); + n -= p.data.length; + + while (p = p.next) { + var buf = p.data; + var nb = n > buf.length ? buf.length : n; + buf.copy(ret, ret.length - n, 0, nb); + n -= nb; + + if (n === 0) { + if (nb === buf.length) { + ++c; + if (p.next) this.head = p.next;else this.head = this.tail = null; + } else { + this.head = p; + p.data = buf.slice(nb); + } + + break; + } + + ++c; + } + + this.length -= c; + return ret; + } // Make sure the linked list only shows the minimal necessary information. + + }, { + key: custom, + value: function value(_, options) { + return inspect(this, _objectSpread({}, options, { + // Only inspect one level. + depth: 0, + // It should not recurse. + customInspect: false + })); + } + }]); + + return BufferList; +}(); + +/***/ }), + +/***/ 1195: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var process = __webpack_require__(4155); + // undocumented cb() API, needed for core, not for public API + +function destroy(err, cb) { + var _this = this; + + var readableDestroyed = this._readableState && this._readableState.destroyed; + var writableDestroyed = this._writableState && this._writableState.destroyed; + + if (readableDestroyed || writableDestroyed) { + if (cb) { + cb(err); + } else if (err) { + if (!this._writableState) { + process.nextTick(emitErrorNT, this, err); + } else if (!this._writableState.errorEmitted) { + this._writableState.errorEmitted = true; + process.nextTick(emitErrorNT, this, err); + } + } + + return this; + } // we set destroyed to true before firing error callbacks in order + // to make it re-entrance safe in case destroy() is called within callbacks + + + if (this._readableState) { + this._readableState.destroyed = true; + } // if this is a duplex stream mark the writable part as destroyed as well + + + if (this._writableState) { + this._writableState.destroyed = true; + } + + this._destroy(err || null, function (err) { + if (!cb && err) { + if (!_this._writableState) { + process.nextTick(emitErrorAndCloseNT, _this, err); + } else if (!_this._writableState.errorEmitted) { + _this._writableState.errorEmitted = true; + process.nextTick(emitErrorAndCloseNT, _this, err); + } else { + process.nextTick(emitCloseNT, _this); + } + } else if (cb) { + process.nextTick(emitCloseNT, _this); + cb(err); + } else { + process.nextTick(emitCloseNT, _this); + } + }); + + return this; +} + +function emitErrorAndCloseNT(self, err) { + emitErrorNT(self, err); + emitCloseNT(self); +} + +function emitCloseNT(self) { + if (self._writableState && !self._writableState.emitClose) return; + if (self._readableState && !self._readableState.emitClose) return; + self.emit('close'); +} + +function undestroy() { + if (this._readableState) { + this._readableState.destroyed = false; + this._readableState.reading = false; + this._readableState.ended = false; + this._readableState.endEmitted = false; + } + + if (this._writableState) { + this._writableState.destroyed = false; + this._writableState.ended = false; + this._writableState.ending = false; + this._writableState.finalCalled = false; + this._writableState.prefinished = false; + this._writableState.finished = false; + this._writableState.errorEmitted = false; + } +} + +function emitErrorNT(self, err) { + self.emit('error', err); +} + +function errorOrDestroy(stream, err) { + // We have tests that rely on errors being emitted + // in the same tick, so changing this is semver major. + // For now when you opt-in to autoDestroy we allow + // the error to be emitted nextTick. In a future + // semver major update we should change the default to this. + var rState = stream._readableState; + var wState = stream._writableState; + if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err); +} + +module.exports = { + destroy: destroy, + undestroy: undestroy, + errorOrDestroy: errorOrDestroy +}; + +/***/ }), + +/***/ 8610: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +// Ported from https://github.com/mafintosh/end-of-stream with +// permission from the author, Mathias Buus (@mafintosh). + + +var ERR_STREAM_PREMATURE_CLOSE = (__webpack_require__(4281)/* .codes.ERR_STREAM_PREMATURE_CLOSE */ .q.ERR_STREAM_PREMATURE_CLOSE); + +function once(callback) { + var called = false; + return function () { + if (called) return; + called = true; + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + callback.apply(this, args); + }; +} + +function noop() {} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function eos(stream, opts, callback) { + if (typeof opts === 'function') return eos(stream, null, opts); + if (!opts) opts = {}; + callback = once(callback || noop); + var readable = opts.readable || opts.readable !== false && stream.readable; + var writable = opts.writable || opts.writable !== false && stream.writable; + + var onlegacyfinish = function onlegacyfinish() { + if (!stream.writable) onfinish(); + }; + + var writableEnded = stream._writableState && stream._writableState.finished; + + var onfinish = function onfinish() { + writable = false; + writableEnded = true; + if (!readable) callback.call(stream); + }; + + var readableEnded = stream._readableState && stream._readableState.endEmitted; + + var onend = function onend() { + readable = false; + readableEnded = true; + if (!writable) callback.call(stream); + }; + + var onerror = function onerror(err) { + callback.call(stream, err); + }; + + var onclose = function onclose() { + var err; + + if (readable && !readableEnded) { + if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); + } + + if (writable && !writableEnded) { + if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE(); + return callback.call(stream, err); + } + }; + + var onrequest = function onrequest() { + stream.req.on('finish', onfinish); + }; + + if (isRequest(stream)) { + stream.on('complete', onfinish); + stream.on('abort', onclose); + if (stream.req) onrequest();else stream.on('request', onrequest); + } else if (writable && !stream._writableState) { + // legacy streams + stream.on('end', onlegacyfinish); + stream.on('close', onlegacyfinish); + } + + stream.on('end', onend); + stream.on('finish', onfinish); + if (opts.error !== false) stream.on('error', onerror); + stream.on('close', onclose); + return function () { + stream.removeListener('complete', onfinish); + stream.removeListener('abort', onclose); + stream.removeListener('request', onrequest); + if (stream.req) stream.req.removeListener('finish', onfinish); + stream.removeListener('end', onlegacyfinish); + stream.removeListener('close', onlegacyfinish); + stream.removeListener('finish', onfinish); + stream.removeListener('end', onend); + stream.removeListener('error', onerror); + stream.removeListener('close', onclose); + }; +} + +module.exports = eos; + +/***/ }), + +/***/ 889: +/***/ ((module) => { + +module.exports = function () { + throw new Error('Readable.from is not available in the browser') +}; + + +/***/ }), + +/***/ 9946: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +// Ported from https://github.com/mafintosh/pump with +// permission from the author, Mathias Buus (@mafintosh). + + +var eos; + +function once(callback) { + var called = false; + return function () { + if (called) return; + called = true; + callback.apply(void 0, arguments); + }; +} + +var _require$codes = (__webpack_require__(4281)/* .codes */ .q), + ERR_MISSING_ARGS = _require$codes.ERR_MISSING_ARGS, + ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED; + +function noop(err) { + // Rethrow the error if it exists to avoid swallowing it + if (err) throw err; +} + +function isRequest(stream) { + return stream.setHeader && typeof stream.abort === 'function'; +} + +function destroyer(stream, reading, writing, callback) { + callback = once(callback); + var closed = false; + stream.on('close', function () { + closed = true; + }); + if (eos === undefined) eos = __webpack_require__(8610); + eos(stream, { + readable: reading, + writable: writing + }, function (err) { + if (err) return callback(err); + closed = true; + callback(); + }); + var destroyed = false; + return function (err) { + if (closed) return; + if (destroyed) return; + destroyed = true; // request.destroy just do .end - .abort is what we want + + if (isRequest(stream)) return stream.abort(); + if (typeof stream.destroy === 'function') return stream.destroy(); + callback(err || new ERR_STREAM_DESTROYED('pipe')); + }; +} + +function call(fn) { + fn(); +} + +function pipe(from, to) { + return from.pipe(to); +} + +function popCallback(streams) { + if (!streams.length) return noop; + if (typeof streams[streams.length - 1] !== 'function') return noop; + return streams.pop(); +} + +function pipeline() { + for (var _len = arguments.length, streams = new Array(_len), _key = 0; _key < _len; _key++) { + streams[_key] = arguments[_key]; + } + + var callback = popCallback(streams); + if (Array.isArray(streams[0])) streams = streams[0]; + + if (streams.length < 2) { + throw new ERR_MISSING_ARGS('streams'); + } + + var error; + var destroys = streams.map(function (stream, i) { + var reading = i < streams.length - 1; + var writing = i > 0; + return destroyer(stream, reading, writing, function (err) { + if (!error) error = err; + if (err) destroys.forEach(call); + if (reading) return; + destroys.forEach(call); + callback(error); + }); + }); + return streams.reduce(pipe); +} + +module.exports = pipeline; + +/***/ }), + +/***/ 2457: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var ERR_INVALID_OPT_VALUE = (__webpack_require__(4281)/* .codes.ERR_INVALID_OPT_VALUE */ .q.ERR_INVALID_OPT_VALUE); + +function highWaterMarkFrom(options, isDuplex, duplexKey) { + return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null; +} + +function getHighWaterMark(state, options, duplexKey, isDuplex) { + var hwm = highWaterMarkFrom(options, isDuplex, duplexKey); + + if (hwm != null) { + if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) { + var name = isDuplex ? duplexKey : 'highWaterMark'; + throw new ERR_INVALID_OPT_VALUE(name, hwm); + } + + return Math.floor(hwm); + } // Default value + + + return state.objectMode ? 16 : 16 * 1024; +} + +module.exports = { + getHighWaterMark: getHighWaterMark +}; + +/***/ }), + +/***/ 2503: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +module.exports = __webpack_require__(7187).EventEmitter; + + +/***/ }), + +/***/ 8473: +/***/ ((module, exports, __webpack_require__) => { + +exports = module.exports = __webpack_require__(9481); +exports.Stream = exports; +exports.Readable = exports; +exports.Writable = __webpack_require__(4229); +exports.Duplex = __webpack_require__(6753); +exports.Transform = __webpack_require__(4605); +exports.PassThrough = __webpack_require__(2725); +exports.finished = __webpack_require__(8610); +exports.pipeline = __webpack_require__(9946); + + +/***/ }), + +/***/ 8090: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ReadableWebToNodeStream = void 0; +const readable_stream_1 = __webpack_require__(8473); +/** + * Converts a Web-API stream into Node stream.Readable class + * Node stream readable: https://nodejs.org/api/stream.html#stream_readable_streams + * Web API readable-stream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream + * Node readable stream: https://nodejs.org/api/stream.html#stream_readable_streams + */ +class ReadableWebToNodeStream extends readable_stream_1.Readable { + /** + * + * @param stream Readable​Stream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream + */ + constructor(stream) { + super(); + this.bytesRead = 0; + this.released = false; + this.reader = stream.getReader(); + } + /** + * Implementation of readable._read(size). + * When readable._read() is called, if data is available from the resource, + * the implementation should begin pushing that data into the read queue + * https://nodejs.org/api/stream.html#stream_readable_read_size_1 + */ + async _read() { + // Should start pushing data into the queue + // Read data from the underlying Web-API-readable-stream + if (this.released) { + this.push(null); // Signal EOF + return; + } + this.pendingRead = this.reader.read(); + const data = await this.pendingRead; + // clear the promise before pushing pushing new data to the queue and allow sequential calls to _read() + delete this.pendingRead; + if (data.done || this.released) { + this.push(null); // Signal EOF + } + else { + this.bytesRead += data.value.length; + this.push(data.value); // Push new data to the queue + } + } + /** + * If there is no unresolved read call to Web-API Readable​Stream immediately returns; + * otherwise will wait until the read is resolved. + */ + async waitForReadToComplete() { + if (this.pendingRead) { + await this.pendingRead; + } + } + /** + * Close wrapper + */ + async close() { + await this.syncAndRelease(); + } + async syncAndRelease() { + this.released = true; + await this.waitForReadToComplete(); + await this.reader.releaseLock(); + } +} +exports.ReadableWebToNodeStream = ReadableWebToNodeStream; +//# sourceMappingURL=index.js.map + +/***/ }), + +/***/ 9509: +/***/ ((module, exports, __webpack_require__) => { + +/* eslint-disable node/no-deprecated-api */ +var buffer = __webpack_require__(8764) +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} + +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} + +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} + + +/***/ }), + +/***/ 2553: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +/**/ + +var Buffer = (__webpack_require__(9509).Buffer); +/**/ + +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; + } +}; + +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; + } + } +}; + +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; +} + +// StringDecoder provides an interface for efficiently splitting a series of +// buffers into a series of JS strings without breaking apart multi-byte +// characters. +exports.s = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; + switch (this.encoding) { + case 'utf16le': + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; + break; + case 'base64': + this.text = base64Text; + this.end = base64End; + nb = 3; + break; + default: + this.write = simpleWrite; + this.end = simpleEnd; + return; + } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} + +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; + } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; +}; + +StringDecoder.prototype.end = utf8End; + +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; + +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; +}; + +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. If an invalid byte is detected, -2 is returned. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return byte >> 6 === 0x02 ? -1 : -2; +} + +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; + } + return nb; + } + return 0; +} + +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'; + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'; + } + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'; + } + } + } +} + +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); + } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} + +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character is added when ending on a partial +// character. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'; + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} + +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); + } + return r; +} + +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} + +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} + +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} + +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; +} + +/***/ }), + +/***/ 842: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AbstractTokenizer = void 0; +const peek_readable_1 = __webpack_require__(5167); +/** + * Core tokenizer + */ +class AbstractTokenizer { + constructor(fileInfo) { + /** + * Tokenizer-stream position + */ + this.position = 0; + this.numBuffer = new Uint8Array(8); + this.fileInfo = fileInfo ? fileInfo : {}; + } + /** + * Read a token from the tokenizer-stream + * @param token - The token to read + * @param position - If provided, the desired position in the tokenizer-stream + * @returns Promise with token data + */ + async readToken(token, position = this.position) { + const uint8Array = Buffer.alloc(token.len); + const len = await this.readBuffer(uint8Array, { position }); + if (len < token.len) + throw new peek_readable_1.EndOfStreamError(); + return token.get(uint8Array, 0); + } + /** + * Peek a token from the tokenizer-stream. + * @param token - Token to peek from the tokenizer-stream. + * @param position - Offset where to begin reading within the file. If position is null, data will be read from the current file position. + * @returns Promise with token data + */ + async peekToken(token, position = this.position) { + const uint8Array = Buffer.alloc(token.len); + const len = await this.peekBuffer(uint8Array, { position }); + if (len < token.len) + throw new peek_readable_1.EndOfStreamError(); + return token.get(uint8Array, 0); + } + /** + * Read a numeric token from the stream + * @param token - Numeric token + * @returns Promise with number + */ + async readNumber(token) { + const len = await this.readBuffer(this.numBuffer, { length: token.len }); + if (len < token.len) + throw new peek_readable_1.EndOfStreamError(); + return token.get(this.numBuffer, 0); + } + /** + * Read a numeric token from the stream + * @param token - Numeric token + * @returns Promise with number + */ + async peekNumber(token) { + const len = await this.peekBuffer(this.numBuffer, { length: token.len }); + if (len < token.len) + throw new peek_readable_1.EndOfStreamError(); + return token.get(this.numBuffer, 0); + } + /** + * Ignore number of bytes, advances the pointer in under tokenizer-stream. + * @param length - Number of bytes to ignore + * @return resolves the number of bytes ignored, equals length if this available, otherwise the number of bytes available + */ + async ignore(length) { + if (this.fileInfo.size !== undefined) { + const bytesLeft = this.fileInfo.size - this.position; + if (length > bytesLeft) { + this.position += bytesLeft; + return bytesLeft; + } + } + this.position += length; + return length; + } + async close() { + // empty + } + normalizeOptions(uint8Array, options) { + if (options && options.position !== undefined && options.position < this.position) { + throw new Error('`options.position` must be equal or greater than `tokenizer.position`'); + } + if (options) { + return { + mayBeLess: options.mayBeLess === true, + offset: options.offset ? options.offset : 0, + length: options.length ? options.length : (uint8Array.length - (options.offset ? options.offset : 0)), + position: options.position ? options.position : this.position + }; + } + return { + mayBeLess: false, + offset: 0, + length: uint8Array.length, + position: this.position + }; + } +} +exports.AbstractTokenizer = AbstractTokenizer; + + +/***/ }), + +/***/ 778: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.BufferTokenizer = void 0; +const peek_readable_1 = __webpack_require__(5167); +const AbstractTokenizer_1 = __webpack_require__(842); +class BufferTokenizer extends AbstractTokenizer_1.AbstractTokenizer { + /** + * Construct BufferTokenizer + * @param uint8Array - Uint8Array to tokenize + * @param fileInfo - Pass additional file information to the tokenizer + */ + constructor(uint8Array, fileInfo) { + super(fileInfo); + this.uint8Array = uint8Array; + this.fileInfo.size = this.fileInfo.size ? this.fileInfo.size : uint8Array.length; + } + /** + * Read buffer from tokenizer + * @param uint8Array - Uint8Array to tokenize + * @param options - Read behaviour options + * @returns {Promise} + */ + async readBuffer(uint8Array, options) { + if (options && options.position) { + if (options.position < this.position) { + throw new Error('`options.position` must be equal or greater than `tokenizer.position`'); + } + this.position = options.position; + } + const bytesRead = await this.peekBuffer(uint8Array, options); + this.position += bytesRead; + return bytesRead; + } + /** + * Peek (read ahead) buffer from tokenizer + * @param uint8Array + * @param options - Read behaviour options + * @returns {Promise} + */ + async peekBuffer(uint8Array, options) { + const normOptions = this.normalizeOptions(uint8Array, options); + const bytes2read = Math.min(this.uint8Array.length - normOptions.position, normOptions.length); + if ((!normOptions.mayBeLess) && bytes2read < normOptions.length) { + throw new peek_readable_1.EndOfStreamError(); + } + else { + uint8Array.set(this.uint8Array.subarray(normOptions.position, normOptions.position + bytes2read), normOptions.offset); + return bytes2read; + } + } + async close() { + // empty + } +} +exports.BufferTokenizer = BufferTokenizer; + + +/***/ }), + +/***/ 599: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.ReadStreamTokenizer = void 0; +const AbstractTokenizer_1 = __webpack_require__(842); +const peek_readable_1 = __webpack_require__(5167); +const maxBufferSize = 256000; +class ReadStreamTokenizer extends AbstractTokenizer_1.AbstractTokenizer { + constructor(stream, fileInfo) { + super(fileInfo); + this.streamReader = new peek_readable_1.StreamReader(stream); + } + /** + * Get file information, an HTTP-client may implement this doing a HEAD request + * @return Promise with file information + */ + async getFileInfo() { + return this.fileInfo; + } + /** + * Read buffer from tokenizer + * @param uint8Array - Target Uint8Array to fill with data read from the tokenizer-stream + * @param options - Read behaviour options + * @returns Promise with number of bytes read + */ + async readBuffer(uint8Array, options) { + const normOptions = this.normalizeOptions(uint8Array, options); + const skipBytes = normOptions.position - this.position; + if (skipBytes > 0) { + await this.ignore(skipBytes); + return this.readBuffer(uint8Array, options); + } + else if (skipBytes < 0) { + throw new Error('`options.position` must be equal or greater than `tokenizer.position`'); + } + if (normOptions.length === 0) { + return 0; + } + const bytesRead = await this.streamReader.read(uint8Array, normOptions.offset, normOptions.length); + this.position += bytesRead; + if ((!options || !options.mayBeLess) && bytesRead < normOptions.length) { + throw new peek_readable_1.EndOfStreamError(); + } + return bytesRead; + } + /** + * Peek (read ahead) buffer from tokenizer + * @param uint8Array - Uint8Array (or Buffer) to write data to + * @param options - Read behaviour options + * @returns Promise with number of bytes peeked + */ + async peekBuffer(uint8Array, options) { + const normOptions = this.normalizeOptions(uint8Array, options); + let bytesRead = 0; + if (normOptions.position) { + const skipBytes = normOptions.position - this.position; + if (skipBytes > 0) { + const skipBuffer = new Uint8Array(normOptions.length + skipBytes); + bytesRead = await this.peekBuffer(skipBuffer, { mayBeLess: normOptions.mayBeLess }); + uint8Array.set(skipBuffer.subarray(skipBytes), normOptions.offset); + return bytesRead - skipBytes; + } + else if (skipBytes < 0) { + throw new Error('Cannot peek from a negative offset in a stream'); + } + } + if (normOptions.length > 0) { + try { + bytesRead = await this.streamReader.peek(uint8Array, normOptions.offset, normOptions.length); + } + catch (err) { + if (options && options.mayBeLess && err instanceof peek_readable_1.EndOfStreamError) { + return 0; + } + throw err; + } + if ((!normOptions.mayBeLess) && bytesRead < normOptions.length) { + throw new peek_readable_1.EndOfStreamError(); + } + } + return bytesRead; + } + async ignore(length) { + // debug(`ignore ${this.position}...${this.position + length - 1}`); + const bufSize = Math.min(maxBufferSize, length); + const buf = new Uint8Array(bufSize); + let totBytesRead = 0; + while (totBytesRead < length) { + const remaining = length - totBytesRead; + const bytesRead = await this.readBuffer(buf, { length: Math.min(bufSize, remaining) }); + if (bytesRead < 0) { + return bytesRead; + } + totBytesRead += bytesRead; + } + return totBytesRead; + } +} +exports.ReadStreamTokenizer = ReadStreamTokenizer; + + +/***/ }), + +/***/ 5849: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.fromBuffer = exports.fromStream = exports.EndOfStreamError = void 0; +const ReadStreamTokenizer_1 = __webpack_require__(599); +const BufferTokenizer_1 = __webpack_require__(778); +var peek_readable_1 = __webpack_require__(5167); +Object.defineProperty(exports, "EndOfStreamError", ({ enumerable: true, get: function () { return peek_readable_1.EndOfStreamError; } })); +/** + * Construct ReadStreamTokenizer from given Stream. + * Will set fileSize, if provided given Stream has set the .path property/ + * @param stream - Read from Node.js Stream.Readable + * @param fileInfo - Pass the file information, like size and MIME-type of the corresponding stream. + * @returns ReadStreamTokenizer + */ +function fromStream(stream, fileInfo) { + fileInfo = fileInfo ? fileInfo : {}; + return new ReadStreamTokenizer_1.ReadStreamTokenizer(stream, fileInfo); +} +exports.fromStream = fromStream; +/** + * Construct ReadStreamTokenizer from given Buffer. + * @param uint8Array - Uint8Array to tokenize + * @param fileInfo - Pass additional file information to the tokenizer + * @returns BufferTokenizer + */ +function fromBuffer(uint8Array, fileInfo) { + return new BufferTokenizer_1.BufferTokenizer(uint8Array, fileInfo); +} +exports.fromBuffer = fromBuffer; + + +/***/ }), + +/***/ 3416: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var Buffer = __webpack_require__(8764)["Buffer"]; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.AnsiStringType = exports.StringType = exports.BufferType = exports.Uint8ArrayType = exports.IgnoreType = exports.Float80_LE = exports.Float80_BE = exports.Float64_LE = exports.Float64_BE = exports.Float32_LE = exports.Float32_BE = exports.Float16_LE = exports.Float16_BE = exports.INT64_BE = exports.UINT64_BE = exports.INT64_LE = exports.UINT64_LE = exports.INT32_LE = exports.INT32_BE = exports.INT24_BE = exports.INT24_LE = exports.INT16_LE = exports.INT16_BE = exports.INT8 = exports.UINT32_BE = exports.UINT32_LE = exports.UINT24_BE = exports.UINT24_LE = exports.UINT16_BE = exports.UINT16_LE = exports.UINT8 = void 0; +const ieee754 = __webpack_require__(645); +// Primitive types +function dv(array) { + return new DataView(array.buffer, array.byteOffset); +} +/** + * 8-bit unsigned integer + */ +exports.UINT8 = { + len: 1, + get(array, offset) { + return dv(array).getUint8(offset); + }, + put(array, offset, value) { + dv(array).setUint8(offset, value); + return offset + 1; + } +}; +/** + * 16-bit unsigned integer, Little Endian byte order + */ +exports.UINT16_LE = { + len: 2, + get(array, offset) { + return dv(array).getUint16(offset, true); + }, + put(array, offset, value) { + dv(array).setUint16(offset, value, true); + return offset + 2; + } +}; +/** + * 16-bit unsigned integer, Big Endian byte order + */ +exports.UINT16_BE = { + len: 2, + get(array, offset) { + return dv(array).getUint16(offset); + }, + put(array, offset, value) { + dv(array).setUint16(offset, value); + return offset + 2; + } +}; +/** + * 24-bit unsigned integer, Little Endian byte order + */ +exports.UINT24_LE = { + len: 3, + get(array, offset) { + const dataView = dv(array); + return dataView.getUint8(offset) + (dataView.getUint16(offset + 1, true) << 8); + }, + put(array, offset, value) { + const dataView = dv(array); + dataView.setUint8(offset, value & 0xff); + dataView.setUint16(offset + 1, value >> 8, true); + return offset + 3; + } +}; +/** + * 24-bit unsigned integer, Big Endian byte order + */ +exports.UINT24_BE = { + len: 3, + get(array, offset) { + const dataView = dv(array); + return (dataView.getUint16(offset) << 8) + dataView.getUint8(offset + 2); + }, + put(array, offset, value) { + const dataView = dv(array); + dataView.setUint16(offset, value >> 8); + dataView.setUint8(offset + 2, value & 0xff); + return offset + 3; + } +}; +/** + * 32-bit unsigned integer, Little Endian byte order + */ +exports.UINT32_LE = { + len: 4, + get(array, offset) { + return dv(array).getUint32(offset, true); + }, + put(array, offset, value) { + dv(array).setUint32(offset, value, true); + return offset + 4; + } +}; +/** + * 32-bit unsigned integer, Big Endian byte order + */ +exports.UINT32_BE = { + len: 4, + get(array, offset) { + return dv(array).getUint32(offset); + }, + put(array, offset, value) { + dv(array).setUint32(offset, value); + return offset + 4; + } +}; +/** + * 8-bit signed integer + */ +exports.INT8 = { + len: 1, + get(array, offset) { + return dv(array).getInt8(offset); + }, + put(array, offset, value) { + dv(array).setInt8(offset, value); + return offset + 2; + } +}; +/** + * 16-bit signed integer, Big Endian byte order + */ +exports.INT16_BE = { + len: 2, + get(array, offset) { + return dv(array).getInt16(offset); + }, + put(array, offset, value) { + dv(array).setInt16(offset, value); + return offset + 2; + } +}; +/** + * 16-bit signed integer, Little Endian byte order + */ +exports.INT16_LE = { + len: 2, + get(array, offset) { + return dv(array).getInt16(offset, true); + }, + put(array, offset, value) { + dv(array).setInt16(offset, value, true); + return offset + 2; + } +}; +/** + * 24-bit signed integer, Little Endian byte order + */ +exports.INT24_LE = { + len: 3, + get(array, offset) { + const unsigned = exports.UINT24_LE.get(array, offset); + return unsigned > 0x7fffff ? unsigned - 0x1000000 : unsigned; + }, + put(array, offset, value) { + const dataView = dv(array); + dataView.setUint8(offset, value & 0xff); + dataView.setUint16(offset + 1, value >> 8, true); + return offset + 3; + } +}; +/** + * 24-bit signed integer, Big Endian byte order + */ +exports.INT24_BE = { + len: 3, + get(array, offset) { + const unsigned = exports.UINT24_BE.get(array, offset); + return unsigned > 0x7fffff ? unsigned - 0x1000000 : unsigned; + }, + put(array, offset, value) { + const dataView = dv(array); + dataView.setUint16(offset, value >> 8); + dataView.setUint8(offset + 2, value & 0xff); + return offset + 3; + } +}; +/** + * 32-bit signed integer, Big Endian byte order + */ +exports.INT32_BE = { + len: 4, + get(array, offset) { + return dv(array).getInt32(offset); + }, + put(array, offset, value) { + dv(array).setInt32(offset, value); + return offset + 4; + } +}; +/** + * 32-bit signed integer, Big Endian byte order + */ +exports.INT32_LE = { + len: 4, + get(array, offset) { + return dv(array).getInt32(offset, true); + }, + put(array, offset, value) { + dv(array).setInt32(offset, value, true); + return offset + 4; + } +}; +/** + * 64-bit unsigned integer, Little Endian byte order + */ +exports.UINT64_LE = { + len: 8, + get(array, offset) { + return dv(array).getBigUint64(offset, true); + }, + put(array, offset, value) { + dv(array).setBigUint64(offset, value, true); + return offset + 8; + } +}; +/** + * 64-bit signed integer, Little Endian byte order + */ +exports.INT64_LE = { + len: 8, + get(array, offset) { + return dv(array).getBigInt64(offset, true); + }, + put(array, offset, value) { + dv(array).setBigInt64(offset, value, true); + return offset + 8; + } +}; +/** + * 64-bit unsigned integer, Big Endian byte order + */ +exports.UINT64_BE = { + len: 8, + get(array, offset) { + return dv(array).getBigUint64(offset); + }, + put(array, offset, value) { + dv(array).setBigUint64(offset, value); + return offset + 8; + } +}; +/** + * 64-bit signed integer, Big Endian byte order + */ +exports.INT64_BE = { + len: 8, + get(array, offset) { + return dv(array).getBigInt64(offset); + }, + put(array, offset, value) { + dv(array).setBigInt64(offset, value); + return offset + 8; + } +}; +/** + * IEEE 754 16-bit (half precision) float, big endian + */ +exports.Float16_BE = { + len: 2, + get(dataView, offset) { + return ieee754.read(dataView, offset, false, 10, this.len); + }, + put(dataView, offset, value) { + ieee754.write(dataView, value, offset, false, 10, this.len); + return offset + this.len; + } +}; +/** + * IEEE 754 16-bit (half precision) float, little endian + */ +exports.Float16_LE = { + len: 2, + get(array, offset) { + return ieee754.read(array, offset, true, 10, this.len); + }, + put(array, offset, value) { + ieee754.write(array, value, offset, true, 10, this.len); + return offset + this.len; + } +}; +/** + * IEEE 754 32-bit (single precision) float, big endian + */ +exports.Float32_BE = { + len: 4, + get(array, offset) { + return dv(array).getFloat32(offset); + }, + put(array, offset, value) { + dv(array).setFloat32(offset, value); + return offset + 4; + } +}; +/** + * IEEE 754 32-bit (single precision) float, little endian + */ +exports.Float32_LE = { + len: 4, + get(array, offset) { + return dv(array).getFloat32(offset, true); + }, + put(array, offset, value) { + dv(array).setFloat32(offset, value, true); + return offset + 4; + } +}; +/** + * IEEE 754 64-bit (double precision) float, big endian + */ +exports.Float64_BE = { + len: 8, + get(array, offset) { + return dv(array).getFloat64(offset); + }, + put(array, offset, value) { + dv(array).setFloat64(offset, value); + return offset + 8; + } +}; +/** + * IEEE 754 64-bit (double precision) float, little endian + */ +exports.Float64_LE = { + len: 8, + get(array, offset) { + return dv(array).getFloat64(offset, true); + }, + put(array, offset, value) { + dv(array).setFloat64(offset, value, true); + return offset + 8; + } +}; +/** + * IEEE 754 80-bit (extended precision) float, big endian + */ +exports.Float80_BE = { + len: 10, + get(array, offset) { + return ieee754.read(array, offset, false, 63, this.len); + }, + put(array, offset, value) { + ieee754.write(array, value, offset, false, 63, this.len); + return offset + this.len; + } +}; +/** + * IEEE 754 80-bit (extended precision) float, little endian + */ +exports.Float80_LE = { + len: 10, + get(array, offset) { + return ieee754.read(array, offset, true, 63, this.len); + }, + put(array, offset, value) { + ieee754.write(array, value, offset, true, 63, this.len); + return offset + this.len; + } +}; +/** + * Ignore a given number of bytes + */ +class IgnoreType { + /** + * @param len number of bytes to ignore + */ + constructor(len) { + this.len = len; + } + // ToDo: don't read, but skip data + get(array, off) { + } +} +exports.IgnoreType = IgnoreType; +class Uint8ArrayType { + constructor(len) { + this.len = len; + } + get(array, offset) { + return array.subarray(offset, offset + this.len); + } +} +exports.Uint8ArrayType = Uint8ArrayType; +class BufferType { + constructor(len) { + this.len = len; + } + get(uint8Array, off) { + return Buffer.from(uint8Array.subarray(off, off + this.len)); + } +} +exports.BufferType = BufferType; +/** + * Consume a fixed number of bytes from the stream and return a string with a specified encoding. + */ +class StringType { + constructor(len, encoding) { + this.len = len; + this.encoding = encoding; + } + get(uint8Array, offset) { + return Buffer.from(uint8Array).toString(this.encoding, offset, offset + this.len); + } +} +exports.StringType = StringType; +/** + * ANSI Latin 1 String + * Using windows-1252 / ISO 8859-1 decoding + */ +class AnsiStringType { + constructor(len) { + this.len = len; + } + static decode(buffer, offset, until) { + let str = ''; + for (let i = offset; i < until; ++i) { + str += AnsiStringType.codePointToString(AnsiStringType.singleByteDecoder(buffer[i])); + } + return str; + } + static inRange(a, min, max) { + return min <= a && a <= max; + } + static codePointToString(cp) { + if (cp <= 0xFFFF) { + return String.fromCharCode(cp); + } + else { + cp -= 0x10000; + return String.fromCharCode((cp >> 10) + 0xD800, (cp & 0x3FF) + 0xDC00); + } + } + static singleByteDecoder(bite) { + if (AnsiStringType.inRange(bite, 0x00, 0x7F)) { + return bite; + } + const codePoint = AnsiStringType.windows1252[bite - 0x80]; + if (codePoint === null) { + throw Error('invaliding encoding'); + } + return codePoint; + } + get(buffer, offset = 0) { + return AnsiStringType.decode(buffer, offset, offset + this.len); + } +} +exports.AnsiStringType = AnsiStringType; +AnsiStringType.windows1252 = [8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, + 8249, 338, 141, 381, 143, 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, + 8482, 353, 8250, 339, 157, 382, 376, 160, 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255]; + + +/***/ }), + +/***/ 9620: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; + +Object.defineProperty(exports, "__esModule", ({ value: true })); +exports.fetchFromUrl = exports.parseBlob = exports.parseReadableStream = exports.parseNodeStream = exports.selectCover = exports.ratingToStars = exports.orderTags = exports.parseFromTokenizer = exports.parseBuffer = void 0; +const initDebug = __webpack_require__(1227); +const mm = __webpack_require__(523); +const readable_web_to_node_stream_1 = __webpack_require__(8090); +const debug = initDebug('music-metadata-browser:main'); +var core_1 = __webpack_require__(523); +Object.defineProperty(exports, "parseBuffer", ({ enumerable: true, get: function () { return core_1.parseBuffer; } })); +Object.defineProperty(exports, "parseFromTokenizer", ({ enumerable: true, get: function () { return core_1.parseFromTokenizer; } })); +Object.defineProperty(exports, "orderTags", ({ enumerable: true, get: function () { return core_1.orderTags; } })); +Object.defineProperty(exports, "ratingToStars", ({ enumerable: true, get: function () { return core_1.ratingToStars; } })); +Object.defineProperty(exports, "selectCover", ({ enumerable: true, get: function () { return core_1.selectCover; } })); +/** + * Parse audio Stream + * @param stream - ReadableStream + * @param contentType - MIME-Type + * @param options - Parsing options + * @returns Metadata + */ +exports.parseNodeStream = mm.parseStream; +/** + * Parse Web API ReadableStream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream + * @param stream - ReadableStream (web stream according WTWG Streams Standard) + * @param fileInfo FileInfo object or MIME-Type + * @param options - Parsing options + * @returns Metadata + */ +async function parseReadableStream(stream, fileInfo, options) { + const ns = new readable_web_to_node_stream_1.ReadableWebToNodeStream(stream); + const res = await (0, exports.parseNodeStream)(ns, typeof fileInfo === 'string' ? { mimeType: fileInfo } : fileInfo, options); + await ns.close(); + return res; +} +exports.parseReadableStream = parseReadableStream; +/** + * Parse Web API File + * @param blob - Blob to parse + * @param options - Parsing options + * @returns Metadata + */ +async function parseBlob(blob, options) { + const fileInfo = { mimeType: blob.type, size: blob.size }; + if (blob instanceof File) { + fileInfo.path = blob.name; + } + const stream = (blob.stream ? blob.stream() : convertBlobToReadableStream(blob)); + return parseReadableStream(stream, { mimeType: blob.type, size: blob.size }, options); +} +exports.parseBlob = parseBlob; +/** + * Convert Blob to ReadableStream + * Fallback for Safari versions < 14.1 + * @param blob + */ +function convertBlobToReadableStream(blob) { + const fileReader = new FileReader(); + return new ReadableStream({ + start(controller) { + // The following function handles each data chunk + fileReader.onloadend = event => { + let data = event.target.result; + if (data instanceof ArrayBuffer) { + data = new Uint8Array(data); + } + controller.enqueue(data); + controller.close(); + }; + fileReader.onerror = error => { + controller.close(); + }; + fileReader.onabort = error => { + controller.close(); + }; + fileReader.readAsArrayBuffer(blob); + } + }); +} +/** + * Parse fetched file, using the Web Fetch API + * @param audioTrackUrl - URL to download the audio track from + * @param options - Parsing options + * @returns Metadata + */ +async function fetchFromUrl(audioTrackUrl, options) { + const response = await fetch(audioTrackUrl); + const fileInfo = { + size: parseInt(response.headers.get('Content-Length'), 10), + mimeType: response.headers.get('Content-Type') + }; + if (response.ok) { + if (response.body) { + const res = await parseReadableStream(response.body, fileInfo, options); + debug('Closing HTTP-readable-stream...'); + if (!response.body.locked) { // Prevent error in Firefox + await response.body.cancel(); + } + debug('HTTP-readable-stream closed.'); + return res; + } + else { + // Fall back on Blob + return parseBlob(await response.blob(), options); + } + } + else { + throw new Error(`HTTP error status=${response.status}: ${response.statusText}`); + } +} +exports.fetchFromUrl = fetchFromUrl; + + +/***/ }), + +/***/ 4927: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + + +/** + * Module exports. + */ + +module.exports = deprecate; + +/** + * Mark that a method should not be used. + * Returns a modified function which warns once by default. + * + * If `localStorage.noDeprecation = true` is set, then it is a no-op. + * + * If `localStorage.throwDeprecation = true` is set, then deprecated functions + * will throw an Error when invoked. + * + * If `localStorage.traceDeprecation = true` is set, then deprecated functions + * will invoke `console.trace()` instead of `console.error()`. + * + * @param {Function} fn - the function to deprecate + * @param {String} msg - the string to print to the console when `fn` is invoked + * @returns {Function} a new "deprecated" version of `fn` + * @api public + */ + +function deprecate (fn, msg) { + if (config('noDeprecation')) { + return fn; + } + + var warned = false; + function deprecated() { + if (!warned) { + if (config('throwDeprecation')) { + throw new Error(msg); + } else if (config('traceDeprecation')) { + console.trace(msg); + } else { + console.warn(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } + + return deprecated; +} + +/** + * Checks `localStorage` for boolean values for the given `name`. + * + * @param {String} name + * @returns {Boolean} + * @api private + */ + +function config (name) { + // accessing global.localStorage can trigger a DOMException in sandboxed iframes + try { + if (!__webpack_require__.g.localStorage) return false; + } catch (_) { + return false; + } + var val = __webpack_require__.g.localStorage[name]; + if (null == val) return false; + return String(val).toLowerCase() === 'true'; +} + + +/***/ }), + +/***/ 2361: +/***/ (() => { + +/* (ignored) */ + +/***/ }), + +/***/ 4616: +/***/ (() => { + +/* (ignored) */ + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module is referenced by other modules so it can't be inlined +/******/ var __webpack_exports__ = __webpack_require__(9620); +/******/ +/******/ return __webpack_exports__; +/******/ })() +; +}); \ No newline at end of file diff --git a/src/util/audio.ts b/src/util/audio.ts index bad44283e..12429f5d3 100644 --- a/src/util/audio.ts +++ b/src/util/audio.ts @@ -6,7 +6,7 @@ type AudioMetadata = { }; export async function parseAudioMetadata(url: string): Promise { - const { fetchFromUrl, selectCover } = await import('music-metadata-browser'); + const { fetchFromUrl, selectCover } = await import('../lib/music-metadata-browser'); const metadata = await fetchFromUrl(url); const { common: { title, artist, picture }, format: { duration } } = metadata; diff --git a/webpack.config.js b/webpack.config.js index 9f2c965a3..07b962764 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -142,7 +142,6 @@ module.exports = (env = {}, argv = {}) => { }), new ProvidePlugin({ Buffer: ['buffer', 'Buffer'], - process: 'process/browser', }), new StatoscopeWebpackPlugin({ statsOptions: {