PageSourceSearch

https://tabletopy.com/jukebox/js/app/lib/jsmediatags-3.9.7.js

js tabletopy.com collected 2026-09-25 21:05:31 UTC 127,670 bytes, 3,329 lines download raw bytes

vendor: 4,111 bytes, lines 1-60
1/**
2
3Downloaded from: https://github.com/aadsm/jsmediatags/blob/master/dist/jsmediatags.js
4
5[BSD License](http://opensource.org/licenses/BSD-3-Clause)
6
7Copyright (c) 2009 Opera Software ASA
8
9Copyright (c) 2015 António Afonso
10
11Copyright (c) 2008 Jacob Seidelin, http://blog.nihilogic.dk/
12
13Copyright (c) 2010 Joshua Kifer
14
15All rights reserved.
16
17Redistribution and use in source and binary forms, with or without modification,
18are permitted provided that the following conditions are met:
19
20 * Redistributions of source code must retain the above copyright notice, this
21   list of conditions and the following disclaimer.
22
23 * Redistributions in binary form must reproduce the above copyright notice,
24   this list of conditions and the following disclaimer in the documentation
25   and/or other materials provided with the distribution.
26
27 * Neither the name Facebook nor the names of its contributors may be used to
28   endorse or promote products derived from this software without specific
29   prior written permission.
30
31THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
35ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
38ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41
42**/
43
44(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jsmediatags = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
45
46},{}],2:[function(require,module,exports){
47module.exports = XMLHttpRequest;
48
49},{}],3:[function(require,module,exports){
50'use strict';
51
52function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
53
54function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
55
56function _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); } }
57
58function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
59
60function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { c
60onstructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
61
62function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
63
64function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
65
66function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
67
68function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
69
70function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
71
72function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
73
74function _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; }
75
76var MediaFileReader = require('./MediaFileReader');
77
78var ArrayFileReader = /*#__PURE__*/function (_MediaFileReader) {
79  _inherits(ArrayFileReader, _MediaFileReader);
80
81  var _super = _createSuper(ArrayFileReader);
82
83  function ArrayFileReader(array) {
84    var _this;
85
86    _classCallCheck(this, ArrayFileReader);
87
88    _this = _super.call(this);
89
90    _defineProperty(_assertThisInitialized(_this), "_array", void 0);
91
92    _defineProperty(_assertThisInitialized(_this), "_size", void 0);
93
94    _this._array = array;
95    _this._size = array.length;
96    _this._isInitialized = true;
97    return _this;
98  }
99
100  _createClass(ArrayFileReader, [{
101    key: "init",
102    value: function init(callbacks) {
103      setTimeout(callbacks.onSuccess, 0);
104    }
105  }, {
106    key: "loadRange",
107    value: function loadRange(range, callbacks) {
108      setTimeout(callbacks.onSuccess, 0);
109    }
110  }, {
111    key: "getByteAt",
112    value: function getByteAt(offset) {
113      if (offset >= this._array.length) {
114        throw new Error("Offset " + offset + " hasn't been loaded yet.");
115      }
116
117      return this._array[offset];
118    }
119  }], [{
120    key: "canReadFile",
121    value: function canReadFile(file) {
122      return Array.isArray(file) || typeof Buffer === 'function' && Buffer.isBuffer(file);
123    }
124  }]);
125
126  return ArrayFileReader;
127}(MediaFileReader);
128
129module.exports = ArrayFileReader;
130
131},{"./MediaFileReader":11}],4:[function(require,module,exports){
132'use strict';
133
134function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
135
136function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
137
138function _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); } }
139
140function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
141
142function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { c
142onstructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
143
144function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
145
146function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
147
148function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
149
150function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
151
152function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
153
154function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
155
156function _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; }
157
158var ChunkedFileData = require('./ChunkedFileData');
159
160var MediaFileReader = require('./MediaFileReader');
161
162var BlobFileReader = /*#__PURE__*/function (_MediaFileReader) {
163  _inherits(BlobFileReader, _MediaFileReader);
164
165  var _super = _createSuper(BlobFileReader);
166
167  function BlobFileReader(blob) {
168    var _this;
169
170    _classCallCheck(this, BlobFileReader);
171
172    _this = _super.call(this);
173
174    _defineProperty(_assertThisInitialized(_this), "_blob", void 0);
175
176    _defineProperty(_assertThisInitialized(_this), "_fileData", void 0);
177
178    _this._blob = blob;
179    _this._fileData = new ChunkedFileData();
180    return _this;
181  }
182
183  _createClass(BlobFileReader, [{
184    key: "_init",
185    value: function _init(callbacks) {
186      this._size = this._blob.size;
187      setTimeout(callbacks.onSuccess, 1);
188    }
189  }, {
190    key: "loadRange",
191    value: function loadRange(range, callbacks) {
192      var self = this; // $FlowIssue - flow isn't aware of mozSlice or webkitSlice
193
194      var blobSlice = this._blob.slice || this._blob.mozSlice || this._blob.webkitSlice;
195      var blob = blobSlice.call(this._blob, range[0], range[1] + 1);
196      var browserFileReader = new FileReader();
197
198      browserFileReader.onloadend = function (event) {
199        var intArray = new Uint8Array(browserFileReader.result);
200
201        self._fileData.addData(range[0], intArray);
202
203        callbacks.onSuccess();
204      };
205
206      browserFileReader.onerror = browserFileReader.onabort = function (event) {
207        if (callbacks.onError) {
208          callbacks.onError({
209            "type": "blob",
210            "info": browserFileReader.error
211          });
212        }
213      };
214
215      browserFileReader.readAsArrayBuffer(blob);
216    }
217  }, {
218    key: "getByteAt",
219    value: function getByteAt(offset) {
220      return this._fileData.getByteAt(offset);
221    }
222  }], [{
223    key: "canReadFile",
224    value: function canReadFile(file) {
225      return typeof Blob !== "undefined" && file instanceof Blob || // File extends Blob but it seems that File instanceof Blob doesn't
226      // quite work as expected in Cordova/PhoneGap.
227      typeof File !== "undefined" && file instanceof File;
228    }
229  }]);
230
231  return BlobFileReader;
232}(MediaFileReader);
233
234module.exports = BlobFileReader;
235
236},{"./ChunkedFileData":5,"./MediaFileReader":11}],5:[function(require,module,exports){
237/**
238 * This class represents a file that might not have all its data loaded yet.
239 * It is used when loading the entire file is not an option because it's too
240 * expensive. Instead, parts of the file are loaded and added only when needed.
241 * From a reading point of view is as if the entire file is loaded. The
242 * exception is when the data is not available yet, an error will be thrown.
243 * This class does not load the data, it just manages it. It provides operations
244 * to add and read data from the file.
245 *
246 * 
247 */
248'use strict';
249
250function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
251
252function _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); } }
253
254function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
255
256function _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; }
257
258var NOT_FOUND = -1;
259
260var ChunkedFileData = /*#__PURE__*/function () {
261  function ChunkedFileData() {
262    _classCallCheck(this, ChunkedFileData);
263
264    _defineProperty(this, "_fileData", void 0);
265
266    this._fileData = [];
267  }
268  /**
269   * Adds data to the file storage at a specific offset.
270   */
271
272
273  _createClass(ChunkedFileData, [{
274    key: "addData",
275    value: function addData(offset, data) {
276      var offsetEnd = offset + data.length - 1;
277
278      var chunkRange = this._getChunkRange(offset, offsetEnd);
279
280      if (chunkRange.startIx === NOT_FOUND) {
281        this._fileData.splice(chunkRange.insertIx || 0, 0, {
282          offset: offset,
283          data: data
284        });
285      } else {
286        // If the data to add collides with existing chunks we prepend and
287        // append data from the half colliding chunks to make the collision at
288        // 100%. The new data can then replace all the colliding chunkes.
289        var firstChunk = this._fileData[chunkRange.startIx];
290        var lastChunk = this._fileData[chunkRange.endIx];
291        var needsPrepend = offset > firstChunk.offset;
292        var needsAppend = offsetEnd < lastChunk.offset + lastChunk.data.length - 1;
293        var chunk = {
294          offset: Math.min(offset, firstChunk.offset),
295          data: data
296        };
297
298        if (needsPrepend) {
299          var slicedData = this._sliceData(firstChunk.data, 0, offset - firstChunk.offset);
300
301          chunk.data = this._concatData(slicedData, data);
302        }
303
304        if (needsAppend) {
305          // Use the lastChunk because the slice logic is easier to handle.
306          var slicedData = this._sliceData(chunk.data, 0, lastChunk.offset - chunk.offset);
307
308          chunk.data = this._concatData(slicedData, lastChunk.data);
309        }
310
311        this._fileData.splice(chunkRange.startIx, chunkRange.endIx - chunkRange.startIx + 1, chunk);
312      }
313    }
314  }, {
315    key: "_concatData",
316    value: function _concatData(dataA, dataB) {
317      // TypedArrays don't support concat.
318      if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView && ArrayBuffer.isView(dataA)) {
319        // $FlowIssue - flow thinks dataAandB is a string but it's not
320        var dataAandB = new dataA.constructor(dataA.length + dataB.length); // $FlowIssue - flow thinks dataAandB is a string but it's not
321
322        dataAandB.set(dataA, 0); // $FlowIssue - flow thinks dataAandB is a string but it's not
323
324        dataAandB.set(dataB, dataA.length);
325        return dataAandB;
326      } else {
327        // $FlowIssue - flow thinks dataAandB is a TypedArray but it's not
328        return dataA.concat(dataB);
329      }
330    }
331  }, {
332    key: "_sliceData",
333    value: function _sliceData(data, begin, end) {
334      // Some TypeArray implementations do not support slice yet.
335      if (data.slice) {
336        return data.slice(begin, end);
337      } else {
338        // $FlowIssue - flow thinks data is a string but it's not
339        return data.subarray(begin, end);
340      }
341    }
342    /**
343     * Finds the chunk range that overlaps the [offsetStart-1,offsetEnd+1] range.
344     * When a chunk is adjacent to the offset we still consider it part of the
345     * range (this is the situation of offsetStart-1 or offsetEnd+1).
346     * When no chunks are found `insertIx` denotes the index where the data
347     * should be inserted in the data list (startIx == NOT_FOUND and endIX ==
348     * NOT_FOUND).
349     */
350
351  }, {
352    key: "_getChunkRange",
353    value: function _getChunkRange(offsetStart, offsetEnd) {
354      var startChunkIx = NOT_FOUND;
355      var endChunkIx = NOT_FOUND;
356      var insertIx = 0; // Could use binary search but not expecting that many blocks to exist.
357
358      for (var i = 0; i < this._fileData.length; i++, insertIx = i) {
359        var chunkOffsetStart = this._fileData[i].offset;
360        var chunkOffsetEnd = chunkOffsetStart + this._fileData[i].data.length;
361
362        if (offsetEnd < chunkOffsetStart - 1) {
363          // This offset range doesn't overlap with any chunks.
364          break;
365        } // If it is adjacent we still consider it part of the range because
366        // we're going end up with a single block with all contiguous data.
367
368
369        if (offsetStart <= chunkOffsetEnd + 1 && offsetEnd >= chunkOffsetStart - 1) {
370          startChunkIx = i;
371          break;
372        }
373      } // No starting chunk was found, meaning that the offset is either before
374      // or after the current stored chunks.
375
376
377      if (startChunkIx === NOT_FOUND) {
378        return {
379          startIx: NOT_FOUND,
380          endIx: NOT_FOUND,
381          insertIx: insertIx
382        };
383      } // Find the ending chunk.
384
385
386      for (var i = startChunkIx; i < this._fileData.length; i++) {
387        var chunkOffsetStart = this._fileData[i].offset;
388        var chunkOffsetEnd = chunkOffsetStart + this._fileData[i].data.length;
389
390        if (offsetEnd >= chunkOffsetStart - 1) {
391          // Candidate for the end chunk, it doesn't mean it is yet.
392          endChunkIx = i;
393        }
394
395        if (offsetEnd <= chunkOffsetEnd + 1) {
396          break;
397        }
398      }
399
400      if (endChunkIx === NOT_FOUND) {
401        endChunkIx = startChunkIx;
402      }
403
404      return {
405        startIx: startChunkIx,
406        endIx: endChunkIx
407      };
408    }
409  }, {
410    key: "hasDataRange",
411    value: function hasDataRange(offsetStart, offsetEnd) {
412      for (var i = 0; i < this._fileData.length; i++) {
413        var chunk = this._fileData[i];
414
415        if (offsetEnd < chunk.offset) {
416          return false;
417        }
418
419        if (offsetStart >= chunk.offset && offsetEnd < chunk.offset + chunk.data.length) {
420          return true;
421        }
422      }
423
424      return false;
425    }
426  }, {
427    key: "getByteAt",
428    value: function getByteAt(offset) {
429      var dataChunk;
430
431      for (var i = 0; i < this._fileData.length; i++) {
432        var dataChunkStart = this._fileData[i].offset;
433        var dataChunkEnd = dataChunkStart + this._fileData[i].data.length - 1;
434
435        if (offset >= dataChunkStart && offset <= dataChunkEnd) {
436          dataChunk = this._fileData[i];
437          break;
438        }
439      }
440
441      if (dataChunk) {
442        return dataChunk.data[offset - dataChunk.offset];
443      }
444
445      throw new Error("Offset " + offset + " hasn't been loaded yet.");
446    }
447  }], [{
448    key: "NOT_FOUND",
449    get: // $FlowIssue - get/set properties not yet supported
450    function get() {
451      return NOT_FOUND;
452    }
453  }]);
454
455  return ChunkedFileData;
456}();
457
458module.exports = ChunkedFileData;
459
460},{}],6:[function(require,module,exports){
461"use strict";
462
463function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
464
465function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
466
467function _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); } }
468
469function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
470
471function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
472
473function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
474
475function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
476
477function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
478
479function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
480
481function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
482
483function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
484
485function _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; }
486
487var MediaTagReader = require('./MediaTagReader');
488/* The first 4 bytes of a FLAC file describes the header for the file. If these
489 * bytes respectively read "fLaC", we can determine it is a FLAC file.
490 */
491
492
493var FLAC_HEADER_SIZE = 4;
494/* FLAC metadata is stored in blocks containing data ranging from STREAMINFO to
495 * VORBIS_COMMENT, which is what we want to work with.
496 *
497 * Each metadata header is 4 bytes long, with the first byte determining whether
498 * it is the last metadata block before the audio data and what the block type is.
499 * This first byte can further be split into 8 bits, with the first bit being the
500 * last-metadata-block flag, and the last three bits being the block type.
501 *
502 * Since the specification states that the decimal value for a VORBIS_COMMENT block
503 * type is 4, the two possibilities for the comment block header values are:
504 * - 00000100 (Not a last metadata comment block, value of 4)
505 * - 10000100 (A last metadata comment block, value of 132)
506 *
507 * Similarly, the picture block header values are 6 and 128.
508 *
509 * All values for METADATA_BLOCK_HEADER can be found here.
510 * https://xiph.org/flac/format.html#metadata_block_header
511 */
512
513var COMMENT_HEADERS = [4, 132];
514var PICTURE_HEADERS = [6, 134]; // These are the possible image types as defined by the FLAC specification.
515
516var IMAGE_TYPES = ["Other", "32x32 pixels 'file icon' (PNG only)", "Other file icon", "Cover (front)", "Cover (back)", "Leaflet page", "Media (e.g. label side of CD)", "Lead artist/lead performer/soloist", "Artist/performer", "Conductor", "Band/Orchestra", "Composer", "Lyricist/text writer", "Recording Location", "During recording", "During performance", "Movie/video screen capture", "A bright coloured fish", "Illustration", "Band/artist logotype", "Publisher/Studio logotype"];
517
518/**
519 * Class representing a MediaTagReader that parses FLAC tags.
520 */
521var FLACTagReader = /*#__PURE__*/function (_MediaTagReader) {
522  _inherits(FLACTagReader, _MediaTagReader);
523
524  var _super = _createSuper(FLACTagReader);
525
526  function FLACTagReader() {
527    var _this;
528
529    _classCallCheck(this, FLACTagReader);
530
531    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
532      args[_key] = arguments[_key];
533    }
534
535    _this = _super.call.apply(_super, [this].concat(args));
536
537    _defineProperty(_assertThisInitialized(_this), "_commentOffset", void 0);
538
539    _defineProperty(_assertThisInitialized(_this), "_pictureOffset", void 0);
540
541    return _this;
542  }
543
544  _createClass(FLACTagReader, [{
545    key: "_loadData",
546    value:
547    /**
548     * Function called to load the data from the file.
549     *
550     * To begin processing the blocks, the next 4 bytes after the initial 4 bytes
551     * (bytes 4 through 7) are loaded. From there, the rest of the loading process
552     * is passed on to the _loadBlock function, which will handle the rest of the
553     * parsing for the metadata blocks.
554     *
555     * @param {MediaFileReader} mediaFileReader - The MediaFileReader used to parse the file.
556     * @param {LoadCallbackType} callbacks - The callback to call once _loadData is completed.
557     */
558    function _loadData(mediaFileReader, callbacks) {
559      var self = this;
560      mediaFileReader.loadRange([4, 7], {
561        onSuccess: function onSuccess() {
562          self._loadBlock(mediaFileReader, 4, callbacks);
563        }
564      });
565    }
566    /**
567     * Special internal function used to parse the different FLAC blocks.
568     *
569     * The FLAC specification doesn't specify a specific location for metadata to resign, but
570     * dictates that it may be in one of various blocks located throughout the file. To load the
571     * metadata, we must locate the header first. This can be done by reading the first byte of
572     * each block to determine the block type. After the block type comes a 24 bit integer that stores
573     * the length of the block as big endian. Using this, we locate the block and store the offset for
574     * parsing later.
575     *
576     * After each block has been parsed, the _nextBlock function is called in order
577     * to parse the information of the next block. All blocks need to be parsed in order to find
578     * all of the picture and comment blocks.
579     *
580     * More info on the FLAC specification may be found here:
581     * https://xiph.org/flac/format.html
582     * @param {MediaFileReader} mediaFileReader - The MediaFileReader used to parse the file.
583     * @param {number} offset - The offset to start checking the header from.
584     * @param {LoadCallbackType} callbacks - The callback to call once the header has been found.
585     */
586
587  }, {
588    key: "_loadBlock",
589    value: function _loadBlock(mediaFileReader, offset, callbacks) {
590      var self = this;
591      /* As mentioned above, this first byte is loaded to see what metadata type
592       * this block represents.
593       */
594
595      var blockHeader = mediaFileReader.getByteAt(offset);
596      /* The last three bytes (integer 24) contain a value representing the length
597       * of the following metadata block. The 1 is added in order to shift the offset
598       * by one to get the last three bytes in the block header.
599       */
600
601      var blockSize = mediaFileReader.getInteger24At(offset + 1, true);
602      /* This conditional checks if blockHeader (the byte retrieved representing the
603       * type of the header) is one the headers we are looking for.
604       *
605       * If that is not true, the block is skipped over and the next range is loaded:
606       * - offset + 4 + blockSize adds 4 to skip over the initial metadata header and
607       * blockSize to skip over the block overall, placing it at the head of the next
608       * metadata header.
609       * - offset + 4 + 4 + blockSize does the same thing as the previous block with
610       * the exception of adding another 4 bytes to move it to the end of the new metadata
611       * header.
612       */
613
614      if (COMMENT_HEADERS.indexOf(blockHeader) !== -1) {
615        /* 4 is added to offset to move it to the head of the actual metadata.
616         * The range starting from offsetMatadata (the beginning of the block)
617         * and offsetMetadata + blockSize (the end of the block) is loaded.
618         */
619        var offsetMetadata = offset + 4;
620        mediaFileReader.loadRange([offsetMetadata, offsetMetadata + blockSize], {
621          onSuccess: function onSuccess() {
622            self._commentOffset = offsetMetadata;
623
624            self._nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks);
625          }
626        });
627      } else if (PICTURE_HEADERS.indexOf(blockHeader) !== -1) {
628        var offsetMetadata = offset + 4;
629        mediaFileReader.loadRange([offsetMetadata, offsetMetadata + blockSize], {
630          onSuccess: function onSuccess() {
631            self._pictureOffset = offsetMetadata;
632
633            self._nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks);
634          }
635        });
636      } else {
637        self._nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks);
638      }
639    }
640    /**
641     * Internal function used to load the next range and respective block.
642     *
643     * If the metadata block that was identified is not the last block before the
644     * audio blocks, the function will continue loading the next blocks. If it is
645     * the last block (identified by any values greater than 127, see FLAC spec.),
646     * the function will determine whether a comment block had been identified.
647     *
648     * If the block does not exist, the error callback is called. Otherwise, the function
649     * will call the success callback, allowing data parsing to begin.
650     * @param {MediaFileReader} mediaFileReader - The MediaFileReader used to parse the file.
651     * @param {number} offset - The offset that the existing header was located at.
652     * @param {number} blockHeader - An integer reflecting the header type of the block.
653     * @param {number} blockSize - The size of the previously processed header.
654     * @param {LoadCallbackType} callbacks - The callback functions to be called.
655     */
656
657  }, {
658    key: "_nextBlock",
659    value: function _nextBlock(mediaFileReader, offset, blockHeader, blockSize, callbacks) {
660      var self = this;
661
662      if (blockHeader > 127) {
663        if (!self._commentOffset) {
664          callbacks.onError({
665            "type": "loadData",
666            "info": "Comment block could not be found."
667          });
668        } else {
669          callbacks.onSuccess();
670        }
671      } else {
672        mediaFileReader.loadRange([offset + 4 + blockSize, offset + 4 + 4 + blockSize], {
673          onSuccess: function onSuccess() {
674            self._loadBlock(mediaFileReader, offset + 4 + blockSize, callbacks);
675          }
676        });
677      }
678    }
679    /**
680     * Parses the data and returns the tags.
681     *
682     * This is an overview of the VorbisComment format and what this function attempts to
683     * retrieve:
684     * - First 4 bytes: a long that contains the length of the vendor string.
685     * - Next n bytes: the vendor string encoded in UTF-8.
686     * - Next 4 bytes: a long representing how many comments are in this block
687     * For each comment that exists:
688     * - First 4 bytes: a long representing the length of the comment
689     * - Next n bytes: the comment encoded in UTF-8.
690     * The comment string will usually appear in a format similar to:
691     * ARTIST=me
692     *
693     * Note that the longs and integers in this block are encoded in little endian
694     * as opposed to big endian for the rest of the FLAC spec.
695     * @param {MediaFileReader} data - The MediaFileReader to parse the file with.
696     * @param {Array<string>} [tags] - Optional tags to also be retrieved from the file.
697     * @return {TagType}
697 - An object containing the tag information for the file.
698     */
699
700  }, {
701    key: "_parseData",
702    value: function _parseData(data, tags) {
703      var vendorLength = data.getLongAt(this._commentOffset, false);
704      var offsetVendor = this._commentOffset + 4;
705      /* This line is able to retrieve the vendor string that the VorbisComment block
706       * contains. However, it is not part of the tags that JSMediaTags normally retrieves,
707       * and is therefore commented out.
708       */
709      // var vendor = data.getStringWithCharsetAt(offsetVendor, vendorLength, "utf-8").toString();
710
711      var offsetList = vendorLength + offsetVendor;
712      /* To get the metadata from the block, we first get the long that contains the
713       * number of actual comment values that are existent within the block.
714       *
715       * As we loop through all of the comment blocks, we get the data length in order to
716       * get the right size string, and then determine which category that string falls under.
717       * The dataOffset variable is constantly updated so that it is at the beginning of the
718       * comment that is currently being parsed.
719       *
720       * Additions of 4 here are used to move the offset past the first 4 bytes which only contain
721       * the length of the comment.
722       */
723
724      var numComments = data.getLongAt(offsetList, false);
725      var dataOffset = offsetList + 4;
726      var title, artist, album, track, genre, picture;
727
728      for (var i = 0; i < numComments; i++) {
729        var _dataLength = data.getLongAt(dataOffset, false);
730
731        var s = data.getStringWithCharsetAt(dataOffset + 4, _dataLength, "utf-8").toString();
732        var d = s.indexOf("=");
733        var split = [s.slice(0, d), s.slice(d + 1)];
734
735        switch (split[0].toUpperCase()) {
736          case "TITLE":
737            title = split[1];
738            break;
739
740          case "ARTIST":
741            artist = split[1];
742            break;
743
744          case "ALBUM":
745            album = split[1];
746            break;
747
748          case "TRACKNUMBER":
749            track = split[1];
750            break;
751
752          case "GENRE":
753            genre = split[1];
754            break;
755        }
756
757        dataOffset += 4 + _dataLength;
758      }
759      /* If a picture offset was found and assigned, then the reader will start processing
760       * the picture block from that point.
761       *
762       * All the lengths for the picture data can be found online here:
763       * https://xiph.org/flac/format.html#metadata_block_picture
764       */
765
766
767      if (this._pictureOffset) {
768        var imageType = data.getLongAt(this._pictureOffset, true);
769        var offsetMimeLength = this._pictureOffset + 4;
770        var mimeLength = data.getLongAt(offsetMimeLength, true);
771        var offsetMime = offsetMimeLength + 4;
772        var mime = data.getStringAt(offsetMime, mimeLength);
773        var offsetDescriptionLength = offsetMime + mimeLength;
774        var descriptionLength = data.getLongAt(offsetDescriptionLength, true);
775        var offsetDescription = offsetDescriptionLength + 4;
776        var description = data.getStringWithCharsetAt(offsetDescription, descriptionLength, "utf-8").toString();
777        var offsetDataLength = offsetDescription + descriptionLength + 16;
778        var dataLength = data.getLongAt(offsetDataLength, true);
779        var offsetData = offsetDataLength + 4;
780        var imageData = data.getBytesAt(offsetData, dataLength, true);
781        picture = {
782          format: mime,
783          type: IMAGE_TYPES[imageType],
784          description: description,
785          data: imageData
786        };
787      }
788
789      var tag = {
790        type: "FLAC",
791        version: "1",
792        tags: {
793          "title": title,
794          "artist": artist,
795          "album": album,
796          "track": track,
797          "genre": genre,
798          "picture": picture
799        }
800      };
801      return tag;
802    }
803  }], [{
804    key: "getTagIdentifierByteRange",
805    value:
806    /**
807     * Gets the byte range for the tag identifier.
808     *
809     * Because the Vorbis comment block is not guaranteed to be in a specified
810     * location, we can only load the first 4 bytes of the file to confirm it
811     * is a FLAC first.
812     *
813     * @return {ByteRange} The byte range that identifies the tag for a FLAC.
814     */
815    function getTagIdentifierByteRange() {
816      return {
817        offset: 0,
818        length: FLAC_HEADER_SIZE
819      };
820    }
821    /**
822     * Determines whether or not this reader can read a certain tag format.
823     *
824     * This checks that the first 4 characters in the file are fLaC, which
825     * according to the FLAC file specification should be the characters that
826     * indicate a FLAC file.
827     *
828     * @return {boolean} True if the header is fLaC, false otherwise.
829     */
830
831  }, {
832    key: "canReadTagFormat",
833    value: function canReadTagFormat(tagIdentifier) {
834      var id = String.fromCharCode.apply(String, tagIdentifier.slice(0, 4));
835      return id === 'fLaC';
836    }
837  }]);
838
839  return FLACTagReader;
840}(MediaTagReader);
841
842module.exports = FLACTagReader;
843
844},{"./MediaTagReader":12}],7:[function(require,module,exports){
845'use strict';
846
847function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
848
849function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
850
851function _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); } }
852
853function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
854
855function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
856
857function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
858
859function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
860
861function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
862
863function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
864
865function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
866
867function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
868
869var MediaTagReader = require('./MediaTagReader');
870
871var MediaFileReader = require('./MediaFileReader');
872
873var ID3v1TagReader = /*#__PURE__*/function (_MediaTagReader) {
874  _inherits(ID3v1TagReader, _MediaTagReader);
875
876  var _super = _createSuper(ID3v1TagReader);
877
878  function ID3v1TagReader() {
879    _classCallCheck(this, ID3v1TagReader);
880
881    return _super.apply(this, arguments);
882  }
883
884  _createClass(ID3v1TagReader, [{
885    key: "_loadData",
886    value: function _loadData(mediaFileReader, callbacks) {
887      var fileSize = mediaFileReader.getSize();
888      mediaFileReader.loadRange([fileSize - 128, fileSize - 1], callbacks);
889    }
890  }, {
891    key: "_parseData",
892    value: function _parseData(data, tags) {
893      var offset = data.getSize() - 128;
894      var title = data.getStringWithCharsetAt(offset + 3, 30).toString();
895      var artist = data.getStringWithCharsetAt(offset + 33, 30).toString();
896      var album = data.getStringWithCharsetAt(offset + 63, 30).toString();
897      var year = data.getStringWithCharsetAt(offset + 93, 4).toString();
898      var trackFlag = data.getByteAt(offset + 97 + 28);
899      var track = data.getByteAt(offset + 97 + 29);
900
901      if (trackFlag == 0 && track != 0) {
902        var version = "1.1";
903        var comment = data.getStringWithCharsetAt(offset + 97, 28).toString();
904      } else {
905        var version = "1.0";
906        var comment = data.getStringWithCharsetAt(offset + 97, 30).toString();
907        track = 0;
908      }
909
910      var genreIdx = data.getByteAt(offset + 97 + 30);
911
912      if (genreIdx < 255) {
913        var genre = GENRES[genreIdx];
914      } else {
915        var genre = "";
916      }
917
918      var tag = {
919        "type": "ID3",
920        "version": version,
921        "tags": {
922          "title": title,
923          "artist": artist,
924          "album": album,
925          "year": year,
926          "comment": comment,
927          "genre": genre
928        }
929      };
930
931      if (track) {
932        // $FlowIssue - flow is not happy with adding properties
933        tag.tags.track = track;
934      }
935
936      return tag;
937    }
938  }], [{
939    key: "getTagIdentifierByteRange",
940    value: function getTagIdentifierByteRange() {
941      // The identifier is TAG and is at offset: -128. However, to avoid a
942      // fetch for the tag identifier and another for the data, we load the
943      // entire data since it's so small.
944      return {
945        offset: -128,
946        length: 128
947      };
948    }
949  }, {
950    key: "canReadTagFormat",
951    value: function canReadTagFormat(tagIdentifier) {
952      var id = String.fromCharCode.apply(String, tagIdentifier.slice(0, 3));
953      return id === "TAG";
954    }
955  }]);
956
957  return ID3v1TagReader;
958}(MediaTagReader);
959
960var 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", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", "New Wave", "Psychadelic", "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", "Acapella", "Euro-House", "Dance Hall"];
961module.exports = ID3v1TagReader;
962
963},{"./MediaFileReader":11,"./MediaTagReader":12}],8:[function(require,module,exports){
964'use strict';
965
966function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
967
968function _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); } }
969
970function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
971
972var MediaFileReader = require('./MediaFileReader');
973
974var StringUtils = require('./StringUtils');
975
976var ArrayFileReader = require('./ArrayFileReader');
977
978var FRAME_DESCRIPTIONS = {
979  // v2.2
980  "BUF": "Recommended buffer size",
981  "CNT": "Play counter",
982  "COM": "Comments",
983  "CRA": "Audio encryption",
984  "CRM": "Encrypted meta frame",
985  "ETC": "Event timing codes",
986  "EQU": "Equalization",
987  "GEO": "General encapsulated object",
988  "IPL": "Involved people list",
989  "LNK": "Linked information",
990  "MCI": "Music CD Identifier",
991  "MLL": "MPEG location lookup table",
992  "PIC": "Attached picture",
993  "POP": "Popularimeter",
994  "REV": "Reverb",
995  "RVA": "Relative volume adjustment",
996  "SLT": "Synchronized lyric/text",
997  "STC": "Synced tempo codes",
998  "TAL": "Album/Movie/Show title",
999  "TBP": "BPM (Beats Per Minute)",
1000  "TCM": "Composer",
1001  "TCO": "Content type",
1002  "TCR": "Copyright message",
1003  "TDA": "Date",
1004  "TDY": "Playlist delay",
1005  "TEN": "Encoded by",
1006  "TFT": "File type",
1007  "TIM": "Time",
1008  "TKE": "Initial key",
1009  "TLA": "Language(s)",
1010  "TLE": "Length",
1011  "TMT": "Media type",
1012  "TOA": "Original artist(s)/performer(s)",
1013  "TOF": "Original filename",
1014  "TOL": "Original Lyricist(s)/text writer(s)",
1015  "TOR": "Original release year",
1016  "TOT": "Original album/Movie/Show title",
1017  "TP1": "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group",
1018  "TP2": "Band/Orchestra/Accompaniment",
1019  "TP3": "Conductor/Performer refinement",
1020  "TP4": "Interpreted, remixed, or otherwise modified by",
1021  "TPA": "Part of a set",
1022  "TPB": "Publisher",
1023  "TRC": "ISRC (International Standard Recording Code)",
1024  "TRD": "Recording dates",
1025  "TRK": "Track number/Position in set",
1026  "TSI": "Size",
1027  "TSS": "Software/hardware and settings used for encoding",
1028  "TT1": "Content group description",
1029  "TT2": "Title/Songname/Content description",
1030  "TT3": "Subtitle/Description refinement",
1031  "TXT": "Lyricist/text writer",
1032  "TXX": "User defined text information frame",
1033  "TYE": "Year",
1034  "UFI": "Unique file identifier",
1035  "ULT": "Unsychronized lyric/text transcription",
1036  "WAF": "Official audio file webpage",
1037  "WAR": "Official artist/performer webpage",
1038  "WAS": "Official audio source webpage",
1039  "WCM": "Commercial information",
1040  "WCP": "Copyright/Legal information",
1041  "WPB": "Publishers official webpage",
1042  "WXX": "User defined URL link frame",
1043  // v2.3
1044  "AENC": "Audio encryption",
1045  "APIC": "Attached picture",
1046  "ASPI": "Audio seek point index",
1047  "CHAP": "Chapter",
1048  "CTOC": "Table of contents",
1049  "COMM": "Comments",
1050  "COMR": "Commercial frame",
1051  "ENCR": "Encryption method registration",
1052  "EQU2": "Equalisation (2)",
1053  "EQUA": "Equalization",
1054  "ETCO": "Event timing codes",
1055  "GEOB": "General encapsulated object",
1056  "GRID": "Group identification registration",
1057  "IPLS": "Involved people list",
1058  "LINK": "Linked information",
1059  "MCDI": "Music CD identifier",
1060  "MLLT": "MPEG location lookup table",
1061  "OWNE": "Ownership frame",
1062  "PRIV": "Private frame",
1063  "PCNT": "Play counter",
1064  "POPM": "Popularimeter",
1065  "POSS": "Position synchronisation frame",
1066  "RBUF": "Recommended buffer size",
1067  "RVA2": "Relative volume adjustment (2)",
1068  "RVAD": "Relative volume adjustment",
1069  "RVRB": "Reverb",
1070  "SEEK": "Seek frame",
1071  "SYLT": "Synchronized lyric/text",
1072  "SYTC": "Synchronized tempo codes",
1073  "TALB": "Album/Movie/Show title",
1074  "TBPM": "BPM (beats per minute)",
1075  "TCOM": "Composer",
1076  "TCON": "Content type",
1077  "TCOP": "Copyright message",
1078  "TDAT": "Date",
1079  "TDLY": "Playlist delay",
1080  "TDRC": "Recording time",
1081  "TDRL": "Release time",
1082  "TDTG": "Tagging time",
1083  "TENC": "Encoded by",
1084  "TEXT": "Lyricist/Text writer",
1085  "TFLT": "File type",
1086  "TIME": "Time",
1087  "TIPL": "Involved people list",
1088  "TIT1": "Content group description",
1089  "TIT2": "Title/songname/content description",
1090  "TIT3": "Subtitle/Description refinement",
1091  "TKEY": "Initial key",
1092  "TLAN": "Language(s)",
1093  "TLEN": "Length",
1094  "TMCL": "Musician credits list",
1095  "TMED": "Media type",
1096  "TMOO": "Mood",
1097  "TOAL": "Original album/movie/show title",
1098  "TOFN": "Original filename",
1099  "TOLY": "Original lyricist(s)/text writer(s)",
1100  "TOPE": "Original artist(s)/performer(s)",
1101  "TORY": "Original release year",
1102  "TOWN": "File owner/licensee",
1103  "TPE1": "Lead performer(s)/Soloist(s)",
1104  "TPE2": "Band/orchestra/accompaniment",
1105  "TPE3": "Conductor/performer refinement",
1106  "TPE4": "Interpreted, remixed, or otherwise modified by",
1107  "TPOS": "Part of a set",
1108  "TPRO": "Produced notice",
1109  "TPUB": "Publisher",
1110  "TRCK": "Track number/Position in set",
1111  "TRDA": "Recording dates",
1112  "TRSN": "Internet radio station name",
1113  "TRSO": "Internet radio station owner",
1114  "TSOA": "Album sort order",
1115  "TSOP": "Performer sort order",
1116  "TSOT": "Title sort order",
1117  "TSIZ": "Size",
1118  "TSRC": "ISRC (international standard recording code)",
1119  "TSSE": "Software/Hardware and settings used for encoding",
1120  "TSST": "Set subtitle",
1121  "TYER": "Year",
1122  "TXXX": "User defined text information frame",
1123  "UFID": "Unique file identifier",
1124  "USER": "Terms of use",
1125  "USLT": "Unsychronized lyric/text transcription",
1126  "WCOM": "Commercial information",
1127  "WCOP": "Copyright/Legal information",
1128  "WOAF": "Official audio file webpage",
1129  "WOAR": "Official artist/performer webpage",
1130  "WOAS": "Official audio source webpage",
1131  "WORS": "Official internet radio station homepage",
1132  "WPAY": "Payment",
1133  "WPUB": "Publishers official webpage",
1134  "WXXX": "User defined URL link frame"
1135};
1136
1137var ID3v2FrameReader = /*#__PURE__*/function () {
1138  function ID3v2FrameReader() {
1139    _classCallCheck(this, ID3v2FrameReader);
1140  }
1141
1142  _createClass(ID3v2FrameReader, null, [{
1143    key: "getFrameReaderFunction",
1144    value: function getFrameReaderFunction(frameId) {
1145      if (frameId in frameReaderFunctions) {
1146        return frameReaderFunctions[frameId];
1147      } else if (frameId[0] === "T") {
1148        // All frame ids starting with T are text tags.
1149        return frameReaderFunctions["T*"];
1150      } else if (frameId[0] === "W") {
1151        // All frame ids starting with W are url tags.
1152        return frameReaderFunctions["W*"];
1153      } else {
1154        return null;
1155      }
1156    }
1157    /**
1158     * All the frames consists of a frame header followed by one or more fields
1159     * containing the actual information.
1160     * The frame ID made out of the characters capital A-Z and 0-9. Identifiers
1161     * beginning with "X", "Y" and "Z" are for experimental use and free for
1162     * everyone to use, without the need to set the experimental bit in the tag
1163     * header. Have in mind that someone else might have used the same identifier
1164     * as you. All other identifiers are either used or reserved for future use.
1165     * The frame ID is followed by a size descriptor, making a total header size
1166     * of ten bytes in every frame. The size is calculated as frame size excluding
1167     * frame header (frame size - 10).
1168     */
1169
1170  }, {
1171    key: "readFrames",
1172    value: function readFrames(offset, end, data, id3header, tags) {
1173      var frames = {};
1174
1175      var frameHeaderSize = this._getFrameHeaderSize(id3header); // console.log('header', id3header);
1176
1177
1178      while ( // we should be able to read at least the frame header
1179      offset < end - frameHeaderSize) {
1180        var header = this._readFrameHeader(data, offset, id3header);
1181
1182        var frameId = header.id; // No frame ID sometimes means it's the last frame (GTFO).
1183
1184        if (!frameId) {
1185          break;
1186        }
1187
1188        var flags = header.flags;
1189        var frameSize = header.size;
1190        var frameDataOffset = offset + header.headerSize;
1191        var frameData = data; // console.log(offset, frameId, header.size + header.headerSize, flags && flags.format.unsynchronisation);
1192        // advance data offset to the next frame data
1193
1194        offset += header.headerSize + header.size; // skip unwanted tags
1195
1196        if (tags && tags.indexOf(frameId) === -1) {
1197          continue;
1198        } // Workaround: MP3ext V3.3.17 places a non-compliant padding string at
1199        // the end of the ID3v2 header. A string like "MP3ext V3.3.19(ansi)"
1200        // is added multiple times at the end of the ID3 tag. More information
1201        // about this issue can be found at
1202        // https://github.com/aadsm/jsmediatags/issues/58#issuecomment-313865336
1203
1204
1205        if (frameId === 'MP3e' || frameId === '\x00MP3' || frameId === '\x00\x00MP' || frameId === ' MP3') {
1206          break;
1207        }
1208
1209        var unsyncData;
1210
1211        if (flags && flags.format.unsynchronisation && !id3header.flags.unsynchronisation) {
1212          frameData = this.getUnsyncFileReader(frameData, frameDataOffset, frameSize);
1213          frameDataOffset = 0;
1214          frameSize = frameData.getSize();
1215        } // the first 4 bytes are the real data size
1216        // (after unsynchronisation && encryption)
1217
1218
1219        if (flags && flags.format.data_length_indicator) {
1220          // var frameDataSize = frameData.getSynchsafeInteger32At(frameDataOffset);
1221          frameDataOffset += 4;
1222          frameSize -= 4;
1223        }
1224
1225        var readFrameFunc = ID3v2FrameReader.getFrameReaderFunction(frameId);
1226        var parsedData = readFrameFunc ? readFrameFunc.apply(this, [frameDataOffset, frameSize, frameData, flags, id3header]) : null;
1227
1228        var desc = this._getFrameDescription(frameId);
1229
1230        var frame = {
1231          id: frameId,
1232          size: frameSize,
1233          description: desc,
1234          data: parsedData
1235        };
1236
1237        if (frameId in frames) {
1238          if (frames[frameId].id) {
1239            frames[frameId] = [frames[frameId]];
1240          }
1241
1242          frames[frameId].push(frame);
1243        } else {
1244          frames[frameId] = frame;
1245        }
1246      }
1247
1248      return frames;
1249    }
1250  }, {
1251    key: "_getFrameHeaderSize",
1252    value: function _getFrameHeaderSize(id3header) {
1253      var major = id3header.major;
1254
1255      if (major == 2) {
1256        return 6;
1257      } else if (major == 3 || major == 4) {
1258        return 10;
1259      } else {
1260        return 0;
1261      }
1262    }
1263  }, {
1264    key: "_readFrameHeader",
1265    value: function _readFrameHeader(data, offset, id3header) {
1266      var major = id3header.major;
1267      var flags = null;
1268
1269      var frameHeaderSize = this._getFrameHeaderSize(id3header);
1270
1271      switch (major) {
1272        case 2:
1273          var frameId = data.getStringAt(offset, 3);
1274          var frameSize = data.getInteger24At(offset + 3, true);
1275          break;
1276
1277        case 3:
1278          var frameId = data.getStringAt(offset, 4);
1279          var frameSize = data.getLongAt(offset + 4, true);
1280          break;
1281
1282        case 4:
1283          var frameId = data.getStringAt(offset, 4);
1284          var frameSize = data.getSynchsafeInteger32At(offset + 4);
1285          break;
1286      }
1287
1288      if (frameId == String.fromCharCode(0, 0, 0) || frameId == String.fromCharCode(0, 0, 0, 0)) {
1289        frameId = "";
1290      } // if frameId is empty then it's the last frame
1291
1292
1293      if (frameId) {
1294        // read frame message and format flags
1295        if (major > 2) {
1296          flags = this._readFrameFlags(data, offset + 8);
1297        }
1298      }
1299
1300      return {
1301        "id": frameId || "",
1302        "size": frameSize || 0,
1303        "headerSize": frameHeaderSize || 0,
1304        "flags": flags
1305      };
1306    }
1307  }, {
1308    key: "_readFrameFlags",
1309    value: function _readFrameFlags(data, offset) {
1310      return {
1311        message: {
1312          tag_alter_preservation: data.isBitSetAt(offset, 6),
1313          file_alter_preservation: data.isBitSetAt(offset, 5),
1314          read_only: data.isBitSetAt(offset, 4)
1315        },
1316        format: {
1317          grouping_identity: data.isBitSetAt(offset + 1, 7),
1318          compression: data.isBitSetAt(offset + 1, 3),
1319          encryption: data.isBitSetAt(offset + 1, 2),
1320          unsynchronisation: data.isBitSetAt(offset + 1, 1),
1321          data_length_indicator: data.isBitSetAt(offset + 1, 0)
1322        }
1323      };
1324    }
1325  }, {
1326    key: "_getFrameDescription",
1327    value: function _getFrameDescription(frameId) {
1328      if (frameId in FRAME_DESCRIPTIONS) {
1329        return FRAME_DESCRIPTIONS[frameId];
1330      } else {
1331        return 'Unknown';
1332      }
1333    }
1334  }, {
1335    key: "getUnsyncFileReader",
1336    value: function getUnsyncFileReader(data, offset, size) {
1337      var frameData = data.getBytesAt(offset, size);
1338
1339      for (var i = 0; i < frameData.length - 1; i++) {
1340        if (frameData[i] === 0xff && frameData[i + 1] === 0x00) {
1341          frameData.splice(i + 1, 1);
1342        }
1343      }
1344
1345      return new ArrayFileReader(frameData);
1346    }
1347  }]);
1348
1349  return ID3v2FrameReader;
1350}();
1351
1352;
1353var frameReaderFunctions = {};
1354
1355frameReaderFunctions['APIC'] = function readPictureFrame(offset, length, data, flags, id3header) {
1356  var start = offset;
1357  var charset = getTextEncoding(data.getByteAt(offset));
1358
1359  switch (id3header && id3header.major) {
1360    case 2:
1361      var format = data.getStringAt(offset + 1, 3);
1362      offset += 4;
1363      break;
1364
1365    case 3:
1366    case 4:
1367      var format = data.getStringWithCharsetAt(offset + 1, length - 1);
1368      offset += 1 + format.bytesReadCount;
1369      break;
1370
1371    default:
1372      throw new Error("Couldn't read ID3v2 major version.");
1373  }
1374
1375  var bite = data.getByteAt(offset);
1376  var type = PICTURE_TYPE[bite];
1377  var desc = data.getStringWithCharsetAt(offset + 1, length - (offset - start) - 1, charset);
1378  offset += 1 + desc.bytesReadCount;
1379  return {
1380    "format": format.toString(),
1381    "type": type,
1382    "description": desc.toString(),
1383    "data": data.getBytesAt(offset, start + length - offset)
1384  };
1385};
1385 // ID3v2 chapters according to http://id3.org/id3v2-chapters-1.0
1386
1387
1388frameReaderFunctions['CHAP'] = function readChapterFrame(offset, length, data, flags, id3header) {
1389  var originalOffset = offset;
1390  var result = {};
1391  var id = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length));
1392  result.id = id.toString();
1393  offset += id.bytesReadCount;
1394  result.startTime = data.getLongAt(offset, true);
1395  offset += 4;
1396  result.endTime = data.getLongAt(offset, true);
1397  offset += 4;
1398  result.startOffset = data.getLongAt(offset, true);
1399  offset += 4;
1400  result.endOffset = data.getLongAt(offset, true);
1401  offset += 4;
1402  var remainingLength = length - (offset - originalOffset);
1403  result.subFrames = this.readFrames(offset, offset + remainingLength, data, id3header);
1404  return result;
1405}; // ID3v2 table of contents according to http://id3.org/id3v2-chapters-1.0
1406
1407
1408frameReaderFunctions['CTOC'] = function readTableOfContentsFrame(offset, length, data, flags, id3header) {
1409  var originalOffset = offset;
1410  var result = {
1411    childElementIds: [],
1412    id: undefined,
1413    topLevel: undefined,
1414    ordered: undefined,
1415    entryCount: undefined,
1416    subFrames: undefined
1417  };
1418  var id = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length));
1419  result.id = id.toString();
1420  offset += id.bytesReadCount;
1421  result.topLevel = data.isBitSetAt(offset, 1);
1422  result.ordered = data.isBitSetAt(offset, 0);
1423  offset++;
1424  result.entryCount = data.getByteAt(offset);
1425  offset++;
1426
1427  for (var i = 0; i < result.entryCount; i++) {
1428    var childId = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length - (offset - originalOffset)));
1429    result.childElementIds.push(childId.toString());
1430    offset += childId.bytesReadCount;
1431  }
1432
1433  var remainingLength = length - (offset - originalOffset);
1434  result.subFrames = this.readFrames(offset, offset + remainingLength, data, id3header);
1435  return result;
1436};
1437
1438frameReaderFunctions['COMM'] = function readCommentsFrame(offset, length, data, flags, id3header) {
1439  var start = offset;
1440  var charset = getTextEncoding(data.getByteAt(offset));
1441  var language = data.getStringAt(offset + 1, 3);
1442  var shortdesc = data.getStringWithCharsetAt(offset + 4, length - 4, charset);
1443  offset += 4 + shortdesc.bytesReadCount;
1444  var text = data.getStringWithCharsetAt(offset, start + length - offset, charset);
1445  return {
1446    language: language,
1447    short_description: shortdesc.toString(),
1448    text: text.toString()
1449  };
1450};
1451
1452frameReaderFunctions['COM'] = frameReaderFunctions['COMM'];
1453
1454frameReaderFunctions['PIC'] = function (offset, length, data, flags, id3header) {
1455  return frameReaderFunctions['APIC'](offset, length, data, flags, id3header);
1456};
1457
1458frameReaderFunctions['PCNT'] = function readCounterFrame(offset, length, data, flags, id3header) {
1459  // FIXME: implement the rest of the spec
1460  return data.getLongAt(offset, false);
1461};
1462
1463frameReaderFunctions['CNT'] = frameReaderFunctions['PCNT'];
1464
1465frameReaderFunctions['T*'] = function readTextFrame(offset, length, data, flags, id3header) {
1466  var charset = getTextEncoding(data.getByteAt(offset));
1467  return data.getStringWithCharsetAt(offset + 1, length - 1, charset).toString();
1468};
1469
1470frameReaderFunctions['TXXX'] = function readTextFrame(offset, length, data, flags, id3header) {
1471  var charset = getTextEncoding(data.getByteAt(offset));
1472  return getUserDefinedFields(offset, length, data, charset);
1473};
1474
1475frameReaderFunctions['WXXX'] = function readUrlFrame(offset, length, data, flags, id3header) {
1476  if (length === 0) {
1477    return null;
1478  }
1479
1480  var charset = getTextEncoding(data.getByteAt(offset));
1481  return getUserDefinedFields(offset, length, data, charset);
1482};
1483
1484frameReaderFunctions['W*'] = function readUrlFrame(offset, length, data, flags, id3header) {
1485  if (length === 0) {
1486    return null;
1487  }
1488
1489  return data.getStringWithCharsetAt(offset, length, 'iso-8859-1').toString();
1490};
1491
1492frameReaderFunctions['TCON'] = function readGenreFrame(offset, length, data, flags) {
1493  var text = frameReaderFunctions['T*'].apply(this, arguments);
1494  return text.replace(/^\(\d+\)/, '');
1495};
1496
1497frameReaderFunctions['TCO'] = frameReaderFunctions['TCON'];
1498
1499frameReaderFunctions['USLT'] = function readLyricsFrame(offset, length, data, flags, id3header) {
1500  var start = offset;
1501  var charset = getTextEncoding(data.getByteAt(offset));
1502  var language = data.getStringAt(offset + 1, 3);
1503  var descriptor = data.getStringWithCharsetAt(offset + 4, length - 4, charset);
1504  offset += 4 + descriptor.bytesReadCount;
1505  var lyrics = data.getStringWithCharsetAt(offset, start + length - offset, charset);
1506  return {
1507    language: language,
1508    descriptor: descriptor.toString(),
1509    lyrics: lyrics.toString()
1510  };
1511};
1512
1513frameReaderFunctions['ULT'] = frameReaderFunctions['USLT'];
1514
1515frameReaderFunctions['UFID'] = function readLyricsFrame(offset, length, data, flags, id3header) {
1516  var ownerIdentifier = StringUtils.readNullTerminatedString(data.getBytesAt(offset, length));
1517  offset += ownerIdentifier.bytesReadCount;
1518  var identifier = data.getBytesAt(offset, length - ownerIdentifier.bytesReadCount);
1519  return {
1520    ownerIdentifier: ownerIdentifier.toString(),
1521    identifier: identifier
1522  };
1523};
1524
1525function getTextEncoding(bite) {
1526  var charset;
1527
1528  switch (bite) {
1529    case 0x00:
1530      charset = 'iso-8859-1';
1531      break;
1532
1533    case 0x01:
1534      charset = 'utf-16';
1535      break;
1536
1537    case 0x02:
1538      charset = 'utf-16be';
1539      break;
1540
1541    case 0x03:
1542      charset = 'utf-8';
1543      break;
1544
1545    default:
1546      charset = 'iso-8859-1';
1547  }
1548
1549  return charset;
1550}
1550 // Handles reading description/data from either http://id3.org/id3v2.3.0#User_defined_text_information_frame
1551// and http://id3.org/id3v2.3.0#User_defined_URL_link_frame
1552
1553
1554function getUserDefinedFields(offset, length, data, charset) {
1555  var userDesc = data.getStringWithCharsetAt(offset + 1, length - 1, charset);
1556  var userDefinedData = data.getStringWithCharsetAt(offset + 1 + userDesc.bytesReadCount, length - 1 - userDesc.bytesReadCount, charset);
1557  return {
1558    user_description: userDesc.toString(),
1559    data: userDefinedData.toString()
1560  };
1561}
1562
1563var PICTURE_TYPE = ["Other", "32x32 pixels 'file icon' (PNG only)", "Other file icon", "Cover (front)", "Cover (back)", "Leaflet page", "Media (e.g. label side of CD)", "Lead artist/lead performer/soloist", "Artist/performer", "Conductor", "Band/Orchestra", "Composer", "Lyricist/text writer", "Recording Location", "During recording", "During performance", "Movie/video screen capture", "A bright coloured fish", "Illustration", "Band/artist logotype", "Publisher/Studio logotype"];
1564module.exports = ID3v2FrameReader;
1565
1566},{"./ArrayFileReader":3,"./MediaFileReader":11,"./StringUtils":13}],9:[function(require,module,exports){
1567'use strict';
1568
1569function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
1570
1571function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
1572
1573function _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); } }
1574
1575function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
1576
1577function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
1578
1579function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
1580
1581function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
1582
1583function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
1584
1585function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
1586
1587function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
1588
1589function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o
1589); }; return _getPrototypeOf(o); }
1590
1591var MediaTagReader = require('./MediaTagReader');
1592
1593var MediaFileReader = require('./MediaFileReader');
1594
1595var ID3v2FrameReader = require('./ID3v2FrameReader');
1596
1597var ID3_HEADER_SIZE = 10;
1598
1599var ID3v2TagReader = /*#__PURE__*/function (_MediaTagReader) {
1600  _inherits(ID3v2TagReader, _MediaTagReader);
1601
1602  var _super = _createSuper(ID3v2TagReader);
1603
1604  function ID3v2TagReader() {
1605    _classCallCheck(this, ID3v2TagReader);
1606
1607    return _super.apply(this, arguments);
1608  }
1609
1610  _createClass(ID3v2TagReader, [{
1611    key: "_loadData",
1612    value: function _loadData(mediaFileReader, callbacks) {
1613      mediaFileReader.loadRange([6, 9], {
1614        onSuccess: function onSuccess() {
1615          mediaFileReader.loadRange( // The tag size does not include the header size.
1616          [0, ID3_HEADER_SIZE + mediaFileReader.getSynchsafeInteger32At(6) - 1], callbacks);
1617        },
1618        onError: callbacks.onError
1619      });
1620    }
1621  }, {
1622    key: "_parseData",
1623    value: function _parseData(data, tags) {
1624      var offset = 0;
1625      var major = data.getByteAt(offset + 3);
1626
1627      if (major > 4) {
1628        return {
1629          "type": "ID3",
1630          "version": ">2.4",
1631          "tags": {}
1632        };
1633      }
1634
1635      var revision = data.getByteAt(offset + 4);
1636      var unsynch = data.isBitSetAt(offset + 5, 7);
1637      var xheader = data.isBitSetAt(offset + 5, 6);
1638      var xindicator = data.isBitSetAt(offset + 5, 5);
1639      var size = data.getSynchsafeInteger32At(offset + 6);
1640      offset += 10;
1641
1642      if (xheader) {
1643        // We skip the extended header and don't offer support for it right now.
1644        if (major === 4) {
1645          var xheadersize = data.getSynchsafeInteger32At(offset);
1646          offset += xheadersize;
1647        } else {
1648          var xheadersize = data.getLongAt(offset, true); // The 'Extended header size', currently 6 or 10 bytes, excludes itself.
1649
1650          offset += xheadersize + 4;
1651        }
1652      }
1653
1654      var id3 = {
1655        "type": "ID3",
1656        "version": '2.' + major + '.' + revision,
1657        "major": major,
1658        "revision": revision,
1659        "flags": {
1660          "unsynchronisation": unsynch,
1661          "extended_header": xheader,
1662          "experimental_indicator": xindicator,
1663          // TODO: footer_present
1664          "footer_present": false
1665        },
1666        "size": size,
1667        "tags": {}
1668      };
1669
1670      if (tags) {
1671        var expandedTags = this._expandShortcutTags(tags);
1672      }
1673
1674      var offsetEnd = size + 10
1675      /*header size*/
1676      ; // When this flag is set the entire tag needs to be un-unsynchronised
1677      // before parsing each individual frame. Individual frame sizes might not
1678      // take unsynchronisation into consideration when it's set on the tag
1679      // header.
1680
1681      if (id3.flags.unsynchronisation) {
1682        data = ID3v2FrameReader.getUnsyncFileReader(data, offset, size);
1683        offset = 0;
1684        offsetEnd = data.getSize();
1685      }
1686
1687      var frames = ID3v2FrameReader.readFrames(offset, offsetEnd, data, id3, expandedTags); // create shortcuts for most common data.
1688
1689      for (var name in SHORTCUTS) {
1690        if (SHORTCUTS.hasOwnProperty(name)) {
1691          var frameData = this._getFrameData(frames, SHORTCUTS[name]);
1692
1693          if (frameData) {
1694            id3.tags[name] = frameData;
1695          }
1696        }
1697      }
1698
1699      for (var frame in frames) {
1700        if (frames.hasOwnProperty(frame)) {
1701          id3.tags[frame] = frames[frame];
1702        }
1703      }
1704
1705      return id3;
1706    }
1707  }, {
1708    key: "_getFrameData",
1709    value: function _getFrameData(frames, ids) {
1710      var frame;
1711
1712      for (var i = 0, id; id = ids[i]; i++) {
1713        if (id in frames) {
1714          if (frames[id] instanceof Array) {
1715            frame = frames[id][0];
1716          } else {
1717            frame = frames[id];
1718          }
1719
1720          return frame.data;
1721        }
1722      }
1723    }
1724  }, {
1725    key: "getShortcuts",
1726    value: function getShortcuts() {
1727      return SHORTCUTS;
1728    }
1729  }], [{
1730    key: "getTagIdentifierByteRange",
1731    value: function getTagIdentifierByteRange() {
1732      // ID3 header
1733      return {
1734        offset: 0,
1735        length: ID3_HEADER_SIZE
1736      };
1737    }
1738  }, {
1739    key: "canReadTagFormat",
1740    value: function canReadTagFormat(tagIdentifier) {
1741      var id = String.fromCharCode.apply(String, tagIdentifier.slice(0, 3));
1742      return id === 'ID3';
1743    }
1744  }]);
1745
1746  return ID3v2TagReader;
1747}(MediaTagReader);
1748
1749var SHORTCUTS = {
1750  "title": ["TIT2", "TT2"],
1751  "artist": ["TPE1", "TP1"],
1752  "album": ["TALB", "TAL"],
1753  "year": ["TYER", "TYE"],
1754  "comment": ["COMM", "COM"],
1755  "track": ["TRCK", "TRK"],
1756  "genre": ["TCON", "TCO"],
1757  "picture": ["APIC", "PIC"],
1758  "lyrics": ["USLT", "ULT"]
1759};
1760module.exports = ID3v2TagReader;
1761
1762},{"./ID3v2FrameReader":8,"./MediaFileReader":11,"./MediaTagReader":12}],10:[function(require,module,exports){
1763/**
1764 * Support for iTunes-style m4a tags
1765 * See:
1766 *   http://atomicparsley.sourceforge.net/mpeg-4files.html
1767 *   http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/Metadata/Metadata.html
1768 * Authored by Joshua Kifer <joshua.kifer gmail.com>
1769 * 
1770 */
1771'use strict';
1772
1773function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
1774
1775function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
1776
1777function _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); } }
1778
1779function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
1780
1781function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { c
1781onstructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
1782
1783function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
1784
1785function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
1786
1787function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
1788
1789function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
1790
1791function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
1792
1793function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
1794
1795var MediaTagReader = require('./MediaTagReader');
1796
1797var MediaFileReader = require('./MediaFileReader');
1798
1799var MP4TagReader = /*#__PURE__*/function (_MediaTagReader) {
1800  _inherits(MP4TagReader, _MediaTagReader);
1801
1802  var _super = _createSuper(MP4TagReader);
1803
1804  function MP4TagReader() {
1805    _classCallCheck(this, MP4TagReader);
1806
1807    return _super.apply(this, arguments);
1808  }
1809
1810  _createClass(MP4TagReader, [{
1811    key: "_loadData",
1812    value: function _loadData(mediaFileReader, callbacks) {
1813      // MP4 metadata isn't located in a specific location of the file. Roughly
1814      // speaking, it's composed of blocks chained together like a linked list.
1815      // These blocks are called atoms (or boxes).
1816      // Each atom of the list can have its own child linked list. Atoms in this
1817      // situation do not possess any data and are called "container" as they only
1818      // contain other atoms.
1819      // Other atoms represent a particular set of data, like audio, video or
1820      // metadata. In order to find and load all the interesting atoms we need
1821      // to traverse the entire linked list of atoms and only load the ones
1822      // associated with metadata.
1823      // The metadata atoms can be find under the "moov.udta.meta.ilst" hierarchy.
1824      var self = this; // Load the header of the first atom
1825
1826      mediaFileReader.loadRange([0, 16], {
1827        onSuccess: function onSuccess() {
1828          self._loadAtom(mediaFileReader, 0, "", callbacks);
1829        },
1830        onError: callbacks.onError
1831      });
1832    }
1833  }, {
1834    key: "_loadAtom",
1835    value: function _loadAtom(mediaFileReader, offset, parentAtomFullName, callbacks) {
1836      if (offset >= mediaFileReader.getSize()) {
1837        callbacks.onSuccess();
1838        return;
1839      }
1840
1841      var self = this; // 8 is the size of the atomSize and atomName fields.
1842      // When reading the current block we always read 8 more bytes in order
1843      // to also read the header of the next block.
1844
1845      var atomSize = mediaFileReader.getLongAt(offset, true);
1846
1847      if (atomSize == 0 || isNaN(atomSize)) {
1848        callbacks.onSuccess();
1849        return;
1850      }
1851
1852      var atomName = mediaFileReader.getStringAt(offset + 4, 4); // console.log(parentAtomFullName, atomName, atomSize);
1853      // Container atoms (no actual data)
1854
1855      if (this._isContainerAtom(atomName)) {
1856        if (atomName == "meta") {
1857          // The "meta" atom breaks convention and is a container with data.
1858          offset += 4; // next_item_id (uint32)
1859        }
1860
1861        var atomFullName = (parentAtomFullName ? parentAtomFullName + "." : "") + atomName;
1862
1863        if (atomFullName === "moov.udta.meta.ilst") {
1864          mediaFileReader.loadRange([offset, offset + atomSize], callbacks);
1865        } else {
1866          mediaFileReader.loadRange([offset + 8, offset + 8 + 8], {
1867            onSuccess: function onSuccess() {
1868              self._loadAtom(mediaFileReader, offset + 8, atomFullName, callbacks);
1869            },
1870            onError: callbacks.onError
1871          });
1872        }
1873      } else {
1874        mediaFileReader.loadRange([offset + atomSize, offset + atomSize + 8], {
1875          onSuccess: function onSuccess() {
1876            self._loadAtom(mediaFileReader, offset + atomSize, parentAtomFullName, callbacks);
1877          },
1878          onError: callbacks.onError
1879        });
1880      }
1881    }
1882  }, {
1883    key: "_isContainerAtom",
1884    value: function _isContainerAtom(atomName) {
1885      return ["moov", "udta", "meta", "ilst"].indexOf(atomName) >= 0;
1886    }
1887  }, {
1888    key: "_canReadAtom",
1889    value: function _canReadAtom(atomName) {
1890      return atomName !== "----";
1891    }
1892  }, {
1893    key: "_parseData",
1894    value: function _parseData(data, tagsToRead) {
1895      var tags = {};
1896      tagsToRead = this._expandShortcutTags(tagsToRead);
1897
1898      this._readAtom(tags, data, 0, data.getSize(), tagsToRead); // create shortcuts for most common data.
1899
1900
1901      for (var name in SHORTCUTS) {
1902        if (SHORTCUTS.hasOwnProperty(name)) {
1903          var tag = tags[SHORTCUTS[name]];
1904
1905          if (tag) {
1906            if (name === "track") {
1907              tags[name] = tag.data.track;
1908            } else {
1909              tags[name] = tag.data;
1910            }
1911          }
1912        }
1913      }
1914
1915      return {
1916        "type": "MP4",
1917        "ftyp": data.getStringAt(8, 4),
1918        "version": data.getLongAt(12, true),
1919        "tags": tags
1920      };
1921    }
1922  }, {
1923    key: "_readAtom",
1924    value: function _readAtom(tags, data, offset, length, tagsToRead, parentAtomFullName, indent) {
1925      indent = indent === undefined ? "" : indent + "  ";
1926      var seek = offset;
1927
1928      while (seek < offset + length) {
1929        var atomSize = data.getLongAt(seek, true);
1930
1931        if (atomSize == 0) {
1932          return;
1933        }
1934
1935        var atomName = data.getStringAt(seek + 4, 4); // console.log(seek, parentAtomFullName, atomName, atomSize);
1936
1937        if (this._isContainerAtom(atomName)) {
1938          if (atomName == "meta") {
1939            seek += 4; // next_item_id (uint32)
1940          }
1941
1942          var atomFullName = (parentAtomFullName ? parentAtomFullName + "." : "") + atomName;
1943
1944          this._readAtom(tags, data, seek + 8, atomSize - 8, tagsToRead, atomFullName, indent);
1945
1946          return;
1947        } // Value atoms
1948
1949
1950        if ((!tagsToRead || tagsToRead.indexOf(atomName) >= 0) && parentAtomFullName === "moov.udta.meta.ilst" && this._canReadAtom(atomName)) {
1951          tags[atomName] = this._readMetadataAtom(data, seek);
1952        }
1953
1954        seek += atomSize;
1955      }
1956    }
1957  }, {
1958    key: "_readMetadataAtom",
1959    value: function _readMetadataAtom(data, offset) {
1960      // 16: size + name + size + "data" (4 bytes each)
1961      // 8: 1 byte atom version & 3 bytes atom flags + 4 bytes NULL space
1962      // 8: 4 bytes track + 4 bytes total
1963      var METADATA_HEADER = 16;
1964      var atomSize = data.getLongAt(offset, true);
1965      var atomName = data.getStringAt(offset + 4, 4);
1966      var klass = data.getInteger24At(offset + METADATA_HEADER + 1, true);
1967      var type = TYPES[klass];
1968      var atomData;
1969      var bigEndian = true;
1970
1971      if (atomName == "trkn") {
1972        atomData = {
1973          "track": data.getShortAt(offset + METADATA_HEADER + 10, bigEndian),
1974          "total": data.getShortAt(offset + METADATA_HEADER + 14, bigEndian)
1975        };
1976      } else if (atomName == "disk") {
1977        atomData = {
1978          "disk": data.getShortAt(offset + METADATA_HEADER + 10, bigEndian),
1979          "total": data.getShortAt(offset + METADATA_HEADER + 14, bigEndian)
1980        };
1981      } else {
1982        // 4: atom version (1 byte) + atom flags (3 bytes)
1983        // 4: NULL (usually locale indicator)
1984        var atomHeader = METADATA_HEADER + 4 + 4;
1985        var dataStart = offset + atomHeader;
1986        var dataLength = atomSize - atomHeader;
1987        var atomData; // Workaround for covers being parsed as 'uint8' type despite being an 'covr' atom
1988
1989        if (atomName === 'covr' && type === 'uint8') {
1990          type = 'jpeg';
1991        }
1992
1993        switch (type) {
1994          case "text":
1995            atomData = data.getStringWithCharsetAt(dataStart, dataLength, "utf-8").toString();
1996            break;
1997
1998          case "uint8":
1999            atomData = data.getShortAt(dataStart, false);
2000            break;
2001
2002          case "int":
2003          case "uint":
2004            // Though the QuickTime spec doesn't state it, there are 64-bit values
2005            // such as plID (Playlist/Collection ID). With its single 64-bit floating
2006            // point number type, these are hard to parse and pass in JavaScript.
2007            // The high word of plID seems to always be zero, so, as this is the
2008            // only current 64-bit atom handled, it is parsed from its 32-bit
2009            // low word as an unsigned long.
2010            //
2011            var intReader = type == 'int' ? dataLength == 1 ? data.getSByteAt : dataLength == 2 ? data.getSShortAt : dataLength == 4 ? data.getSLongAt : data.getL
2011ongAt : dataLength == 1 ? data.getByteAt : dataLength == 2 ? data.getShortAt : data.getLongAt; // $FlowFixMe - getByteAt doesn't receive a second argument
2012
2013            atomData = intReader.call(data, dataStart + (dataLength == 8 ? 4 : 0), true);
2014            break;
2015
2016          case "jpeg":
2017          case "png":
2018            atomData = {
2019              "format": "image/" + type,
2020              "data": data.getBytesAt(dataStart, dataLength)
2021            };
2022            break;
2023        }
2024      }
2025
2026      return {
2027        id: atomName,
2028        size: atomSize,
2029        description: ATOM_DESCRIPTIONS[atomName] || "Unknown",
2030        data: atomData
2031      };
2032    }
2033  }, {
2034    key: "getShortcuts",
2035    value: function getShortcuts() {
2036      return SHORTCUTS;
2037    }
2038  }], [{
2039    key: "getTagIdentifierByteRange",
2040    value: function getTagIdentifierByteRange() {
2041      // The tag identifier is located in [4, 8] but since we'll need to reader
2042      // the header of the first block anyway, we load it instead to avoid
2043      // making two requests.
2044      return {
2045        offset: 0,
2046        length: 16
2047      };
2048    }
2049  }, {
2050    key: "canReadTagFormat",
2051    value: function canReadTagFormat(tagIdentifier) {
2052      var id = String.fromCharCode.apply(String, tagIdentifier.slice(4, 8));
2053      return id === "ftyp";
2054    }
2055  }]);
2056
2057  return MP4TagReader;
2058}(MediaTagReader);
2059/*
2060 * https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35
2061*/
2062
2063
2064var TYPES = {
2065  "0": "uint8",
2066  "1": "text",
2067  "13": "jpeg",
2068  "14": "png",
2069  "21": "int",
2070  "22": "uint"
2071};
2072var ATOM_DESCRIPTIONS = {
2073  "©alb": "Album",
2074  "©ART": "Artist",
2075  "aART": "Album Artist",
2076  "©day": "Release Date",
2077  "©nam": "Title",
2078  "©gen": "Genre",
2079  "gnre": "Genre",
2080  "trkn": "Track Number",
2081  "©wrt": "Composer",
2082  "©too": "Encoding Tool",
2083  "©enc": "Encoded By",
2084  "cprt": "Copyright",
2085  "covr": "Cover Art",
2086  "©grp": "Grouping",
2087  "keyw": "Keywords",
2088  "©lyr": "Lyrics",
2089  "©cmt": "Comment",
2090  "tmpo": "Tempo",
2091  "cpil": "Compilation",
2092  "disk": "Disc Number",
2093  "tvsh": "TV Show Name",
2094  "tven": "TV Episode ID",
2095  "tvsn": "TV Season",
2096  "tves": "TV Episode",
2097  "tvnn": "TV Network",
2098  "desc": "Description",
2099  "ldes": "Long Description",
2100  "sonm": "Sort Name",
2101  "soar": "Sort Artist",
2102  "soaa": "Sort Album",
2103  "soco": "Sort Composer",
2104  "sosn": "Sort Show",
2105  "purd": "Purchase Date",
2106  "pcst": "Podcast",
2107  "purl": "Podcast URL",
2108  "catg": "Category",
2109  "hdvd": "HD Video",
2110  "stik": "Media Type",
2111  "rtng": "Content Rating",
2112  "pgap": "Gapless Playback",
2113  "apID": "Purchase Account",
2114  "sfID": "Country Code",
2115  "atID": "Artist ID",
2116  "cnID": "Catalog ID",
2117  "plID": "Collection ID",
2118  "geID": "Genre ID",
2119  "xid ": "Vendor Information",
2120  "flvr": "Codec Flavor"
2121};
2122var UNSUPPORTED_ATOMS = {
2123  "----": 1
2124};
2125var SHORTCUTS = {
2126  "title": "©nam",
2127  "artist": "©ART",
2128  "album": "©alb",
2129  "year": "©day",
2130  "comment": "©cmt",
2131  "track": "trkn",
2132  "genre": "©gen",
2133  "picture": "covr",
2134  "lyrics": "©lyr"
2135};
2136module.exports = MP4TagReader;
2137
2138},{"./MediaFileReader":11,"./MediaTagReader":12}],11:[function(require,module,exports){
2139'use strict';
2140
2141function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2142
2143function _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); } }
2144
2145function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
2146
2147function _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; }
2148
2149var StringUtils = require('./StringUtils');
2150
2151var MediaFileReader = /*#__PURE__*/function () {
2152  function MediaFileReader(path) {
2153    _classCallCheck(this, MediaFileReader);
2154
2155    _defineProperty(this, "_isInitialized", void 0);
2156
2157    _defineProperty(this, "_size", void 0);
2158
2159    this._isInitialized = false;
2160    this._size = 0;
2161  }
2162  /**
2163   * Decides if this media file reader is able to read the given file.
2164   */
2165
2166
2167  _createClass(MediaFileReader, [{
2168    key: "init",
2169    value:
2170    /**
2171     * This function needs to be called before any other function.
2172     * Loads the necessary initial information from the file.
2173     */
2174    function init(callbacks) {
2175      var self = this;
2176
2177      if (this._isInitialized) {
2178        setTimeout(callbacks.onSuccess, 1);
2179      } else {
2180        return this._init({
2181          onSuccess: function onSuccess() {
2182            self._isInitialized = true;
2183            callbacks.onSuccess();
2184          },
2185          onError: callbacks.onError
2186        });
2187      }
2188    }
2189  }, {
2190    key: "_init",
2191    value: function _init(callbacks) {
2192      throw new Error("Must implement init function");
2193    }
2194    /**
2195     * @param range The start and end indexes of the range to load.
2196     *        Ex: [0, 7] load bytes 0 to 7 inclusive.
2197     */
2198
2199  }, {
2200    key: "loadRange",
2201    value: function loadRange(range, callbacks) {
2202      throw new Error("Must implement loadRange function");
2203    }
2204    /**
2205     * @return The size of the file in bytes.
2206     */
2207
2208  }, {
2209    key: "getSize",
2210    value: function getSize() {
2211      if (!this._isInitialized) {
2212        throw new Error("init() must be called first.");
2213      }
2214
2215      return this._size;
2216    }
2217  }, {
2218    key: "getByteAt",
2219    value: function getByteAt(offset) {
2220      throw new Error("Must implement getByteAt function");
2221    }
2222  }, {
2223    key: "getBytesAt",
2224    value: function getBytesAt(offset, length) {
2225      var bytes = new Array(length);
2226
2227      for (var i = 0; i < length; i++) {
2228        bytes[i] = this.getByteAt(offset + i);
2229      }
2230
2231      return bytes;
2232    }
2233  }, {
2234    key: "isBitSetAt",
2235    value: function isBitSetAt(offset, bit) {
2236      var iByte = this.getByteAt(offset);
2237      return (iByte & 1 << bit) != 0;
2238    }
2239  }, {
2240    key: "getSByteAt",
2241    value: function getSByteAt(offset) {
2242      var iByte = this.getByteAt(offset);
2243
2244      if (iByte > 127) {
2245        return iByte - 256;
2246      } else {
2247        return iByte;
2248      }
2249    }
2250  }, {
2251    key: "getShortAt",
2252    value: function getShortAt(offset, isBigEndian) {
2253      var iShort = isBigEndian ? (this.getByteAt(offset) << 8) + this.getByteAt(offset + 1) : (this.getByteAt(offset + 1) << 8) + this.getByteAt(offset);
2254
2255      if (iShort < 0) {
2256        iShort += 65536;
2257      }
2258
2259      return iShort;
2260    }
2261  }, {
2262    key: "getSShortAt",
2263    value: function getSShortAt(offset, isBigEndian) {
2264      var iUShort = this.getShortAt(offset, isBigEndian);
2265
2266      if (iUShort > 32767) {
2267        return iUShort - 65536;
2268      } else {
2269        return iUShort;
2270      }
2271    }
2272  }, {
2273    key: "getLongAt",
2274    value: function getLongAt(offset, isBigEndian) {
2275      var iByte1 = this.getByteAt(offset),
2276          iByte2 = this.getByteAt(offset + 1),
2277          iByte3 = this.getByteAt(offset + 2),
2278          iByte4 = this.getByteAt(offset + 3);
2279      var iLong = isBigEndian ? (((iByte1 << 8) + iByte2 << 8) + iByte3 << 8) + iByte4 : (((iByte4 << 8) + iByte3 << 8) + iByte2 << 8) + iByte1;
2280
2281      if (iLong < 0) {
2282        iLong += 4294967296;
2283      }
2284
2285      return iLong;
2286    }
2287  }, {
2288    key: "getSLongAt",
2289    value: function getSLongAt(offset, isBigEndian) {
2290      var iULong = this.getLongAt(offset, isBigEndian);
2291
2292      if (iULong > 2147483647) {
2293        return iULong - 4294967296;
2294      } else {
2295        return iULong;
2296      }
2297    }
2298  }, {
2299    key: "getInteger24At",
2300    value: function getInteger24At(offset, isBigEndian) {
2301      var iByte1 = this.getByteAt(offset),
2302          iByte2 = this.getByteAt(offset + 1),
2303          iByte3 = this.getByteAt(offset + 2);
2304      var iInteger = isBigEndian ? ((iByte1 << 8) + iByte2 << 8) + iByte3 : ((iByte3 << 8) + iByte2 << 8) + iByte1;
2305
2306      if (iInteger < 0) {
2307        iInteger += 16777216;
2308      }
2309
2310      return iInteger;
2311    }
2312  }, {
2313    key: "getStringAt",
2314    value: function getStringAt(offset, length) {
2315      var string = [];
2316
2317      for (var i = offset, j = 0; i < offset + length; i++, j++) {
2318        string[j] = String.fromCharCode(this.getByteAt(i));
2319      }
2320
2321      return string.join("");
2322    }
2323  }, {
2324    key: "getStringWithCharsetAt",
2325    value: function getStringWithCharsetAt(offset, length, charset) {
2326      var bytes = this.getBytesAt(offset, length);
2327      var string;
2328
2329      switch ((charset || '').toLowerCase()) {
2330        case "utf-16":
2331        case "utf-16le":
2332        case "utf-16be":
2333          string = StringUtils.readUTF16String(bytes, charset === "utf-16be");
2334          break;
2335
2336        case "utf-8":
2337          string = StringUtils.readUTF8String(bytes);
2338          break;
2339
2340        default:
2341          string = StringUtils.readNullTerminatedString(bytes);
2342          break;
2343      }
2344
2345      return string;
2346    }
2347  }, {
2348    key: "getCharAt",
2349    value: function getCharAt(offset) {
2350      return String.fromCharCode(this.getByteAt(offset));
2351    }
2352    /**
2353     * The ID3v2 tag/frame size is encoded with four bytes where the most
2354     * significant bit (bit 7) is set to zero in every byte, making a total of 28
2355     * bits. The zeroed bits are ignored, so a 257 bytes long tag is represented
2356     * as $00 00 02 01.
2357     */
2358
2359  }, {
2360    key: "getSynchsafeInteger32At",
2361    value: function getSynchsafeInteger32At(offset) {
2362      var size1 = this.getByteAt(offset);
2363      var size2 = this.getByteAt(offset + 1);
2364      var size3 = this.getByteAt(offset + 2);
2365      var size4 = this.getByteAt(offset + 3); // 0x7f = 0b01111111
2366
2367      var size = size4 & 0x7f | (size3 & 0x7f) << 7 | (size2 & 0x7f) << 14 | (size1 & 0x7f) << 21;
2368      return size;
2369    }
2370  }], [{
2371    key: "canReadFile",
2372    value: function canReadFile(file) {
2373      throw new Error("Must implement canReadFile function");
2374    }
2375  }]);
2376
2377  return MediaFileReader;
2378}();
2379
2380module.exports = MediaFileReader;
2381
2382},{"./StringUtils":13}],12:[function(require,module,exports){
2383'use strict';
2384
2385function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2386
2387function _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); } }
2388
2389function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
2390
2391function _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; }
2392
2393var MediaFileReader = require('./MediaFileReader');
2394
2395var MediaTagReader = /*#__PURE__*/function () {
2396  function MediaTagReader(mediaFileReader) {
2397    _classCallCheck(this, MediaTagReader);
2398
2399    _defineProperty(this, "_mediaFileReader", void 0);
2400
2401    _defineProperty(this, "_tags", void 0);
2402
2403    this._mediaFileReader = mediaFileReader;
2404    this._tags = null;
2405  }
2406  /**
2407   * Returns the byte range that needs to be loaded and fed to
2408   * _canReadTagFormat in order to identify if the file contains tag
2409   * information that can be read.
2410   */
2411
2412
2413  _createClass(MediaTagReader, [{
2414    key: "setTagsToRead",
2415    value: function setTagsToRead(tags) {
2416      this._tags = tags;
2417      return this;
2418    }
2419  }, {
2420    key: "read",
2421    value: function read(callbacks) {
2422      var self = this;
2423
2424      this._mediaFileReader.init({
2425        onSuccess: function onSuccess() {
2426          self._loadData(self._mediaFileReader, {
2427            onSuccess: function onSuccess() {
2428              try {
2429                var tags = self._parseData(self._mediaFileReader, self._tags);
2430              } catch (ex) {
2431                if (callbacks.onError) {
2432                  callbacks.onError({
2433                    "type": "parseData",
2434                    "info": ex.message
2435                  });
2436                  return;
2437                }
2438              } // TODO: destroy mediaFileReader
2439
2440
2441              callbacks.onSuccess(tags);
2442            },
2443            onError: callbacks.onError
2444          });
2445        },
2446        onError: callbacks.onError
2447      });
2448    }
2449  }, {
2450    key: "getShortcuts",
2451    value: function getShortcuts() {
2452      return {};
2453    }
2454    /**
2455     * Load the necessary bytes from the media file.
2456     */
2457
2458  }, {
2459    key: "_loadData",
2460    value: function _loadData(mediaFileReader, callbacks) {
2461      throw new Error("Must implement _loadData function");
2462    }
2463    /**
2464     * Parse the loaded data to read the media tags.
2465     */
2466
2467  }, {
2468    key: "_parseData",
2469    value: function _parseData(mediaFileReader, tags) {
2470      throw new Error("Must implement _parseData function");
2471    }
2472  }, {
2473    key: "_expandShortcutTags",
2474    value: function _expandShortcutTags(tagsWithShortcuts) {
2475      if (!tagsWithShortcuts) {
2476        return null;
2477      }
2478
2479      var tags = [];
2480      var shortcuts = this.getShortcuts();
2481
2482      for (var i = 0, tagOrShortcut; tagOrShortcut = tagsWithShortcuts[i]; i++) {
2483        tags = tags.concat(shortcuts[tagOrShortcut] || [tagOrShortcut]);
2484      }
2485
2486      return tags;
2487    }
2488  }], [{
2489    key: "getTagIdentifierByteRange",
2490    value: function getTagIdentifierByteRange() {
2491      throw new Error("Must implement");
2492    }
2493    /**
2494     * Given a tag identifier (read from the file byte positions speficied by
2495     * getTagIdentifierByteRange) this function checks if it can read the tag
2496     * format or not.
2497     */
2498
2499  }, {
2500    key: "canReadTagFormat",
2501    value: function canReadTagFormat(tagIdentifier) {
2502      throw new Error("Must implement");
2503    }
2504  }]);
2505
2506  return MediaTagReader;
2507}();
2508
2509module.exports = MediaTagReader;
2510
2511},{"./MediaFileReader":11}],13:[function(require,module,exports){
2512'use strict';
2513
2514function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2515
2516function _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); } }
2517
2518function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
2519
2520function _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; }
2521
2522var InternalDecodedString = /*#__PURE__*/function () {
2523  function InternalDecodedString(value, bytesReadCount) {
2524    _classCallCheck(this, InternalDecodedString);
2525
2526    _defineProperty(this, "_value", void 0);
2527
2528    _defineProperty(this, "bytesReadCount", void 0);
2529
2530    _defineProperty(this, "length", void 0);
2531
2532    this._value = value;
2533    this.bytesReadCount = bytesReadCount;
2534    this.length = value.length;
2535  }
2536
2537  _createClass(InternalDecodedString, [{
2538    key: "toString",
2539    value: function toString() {
2540      return this._value;
2541    }
2542  }]);
2543
2544  return InternalDecodedString;
2545}();
2546
2547var StringUtils = {
2548  readUTF16String: function readUTF16String(bytes, bigEndian, maxBytes) {
2549    var ix = 0;
2550    var offset1 = 1,
2551        offset2 = 0;
2552    maxBytes = Math.min(maxBytes || bytes.length, bytes.length);
2553
2554    if (bytes[0] == 0xFE && bytes[1] == 0xFF) {
2555      bigEndian = true;
2556      ix = 2;
2557    } else if (bytes[0] == 0xFF && bytes[1] == 0xFE) {
2558      bigEndian = false;
2559      ix = 2;
2560    }
2561
2562    if (bigEndian) {
2563      offset1 = 0;
2564      offset2 = 1;
2565    }
2566
2567    var arr = [];
2568
2569    for (var j = 0; ix < maxBytes; j++) {
2570      var byte1 = bytes[ix + offset1];
2571      var byte2 = bytes[ix + offset2];
2572      var word1 = (byte1 << 8) + byte2;
2573      ix += 2;
2574
2575      if (word1 == 0x0000) {
2576        break;
2577      } else if (byte1 < 0xD8 || byte1 >= 0xE0) {
2578        arr[j] = String.fromCharCode(word1);
2579      } else {
2580        var byte3 = bytes[ix + offset1];
2581        var byte4 = bytes[ix + offset2];
2582        var word2 = (byte3 << 8) + byte4;
2583        ix += 2;
2584        arr[j] = String.fromCharCode(word1, word2);
2585      }
2586    }
2587
2588    return new InternalDecodedString(arr.join(""), ix);
2589  },
2590  readUTF8String: function readUTF8String(bytes, maxBytes) {
2591    var ix = 0;
2592    maxBytes = Math.min(maxBytes || bytes.length, bytes.length);
2593
2594    if (bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) {
2595      ix = 3;
2596    }
2597
2598    var arr = [];
2599
2600    for (var j = 0; ix < maxBytes; j++) {
2601      var byte1 = bytes[ix++];
2602
2603      if (byte1 == 0x00) {
2604        break;
2605      } else if (byte1 < 0x80) {
2606        arr[j] = String.fromCharCode(byte1);
2607      } else if (byte1 >= 0xC2 && byte1 < 0xE0) {
2608        var byte2 = bytes[ix++];
2609        arr[j] = String.fromCharCode(((byte1 & 0x1F) << 6) + (byte2 & 0x3F));
2610      } else if (byte1 >= 0xE0 && byte1 < 0xF0) {
2611        var byte2 = bytes[ix++];
2612        var byte3 = bytes[ix++];
2613        arr[j] = String.fromCharCode(((byte1 & 0xFF) << 12) + ((byte2 & 0x3F) << 6) + (byte3 & 0x3F));
2614      } else if (byte1 >= 0xF0 && byte1 < 0xF5) {
2615        var byte2 = bytes[ix++];
2616        var byte3 = bytes[ix++];
2617        var byte4 = bytes[ix++];
2618        var codepoint = ((byte1 & 0x07) << 18) + ((byte2 & 0x3F) << 12) + ((byte3 & 0x3F) << 6) + (byte4 & 0x3F) - 0x10000;
2619        arr[j] = String.fromCharCode((codepoint >> 10) + 0xD800, (codepoint & 0x3FF) + 0xDC00);
2620      }
2621    }
2622
2623    return new InternalDecodedString(arr.join(""), ix);
2624  },
2625  readNullTerminatedString: function readNullTerminatedString(bytes, maxBytes) {
2626    var arr = [];
2627    maxBytes = maxBytes || bytes.length;
2628
2629    for (var i = 0; i < maxBytes;) {
2630      var byte1 = bytes[i++];
2631
2632      if (byte1 == 0x00) {
2633        break;
2634      }
2635
2636      arr[i - 1] = String.fromCharCode(byte1);
2637    }
2638
2639    return new InternalDecodedString(arr.join(""), i);
2640  }
2641};
2642module.exports = StringUtils;
2643
2644},{}],14:[function(require,module,exports){
2645'use strict';
2646
2647function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
2648
2649function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
2650
2651function _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); } }
2652
2653function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
2654
2655function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { c
vendor: 2,556 bytes, lines 2655-2700
2655onstructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
2656
2657function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
2658
2659function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
2660
2661function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
2662
2663function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
2664
2665function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
2666
2667function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
2668
2669function _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; }
2670
2671var ChunkedFileData = require('./ChunkedFileData');
2672
2673var MediaFileReader = require('./MediaFileReader');
2674
2675var CHUNK_SIZE = 1024;
2676
2677var XhrFileReader = /*#__PURE__*/function (_MediaFileReader) {
2678  _inherits(XhrFileReader, _MediaFileReader);
2679
2680  var _super = _createSuper(XhrFileReader);
2681
2682  function XhrFileReader(url) {
2683    var _this;
2684
2685    _classCallCheck(this, XhrFileReader);
2686
2687    _this = _super.call(this);
2688
2689    _defineProperty(_assertThisInitialized(_this), "_url", void 0);
2690
2691    _defineProperty(_assertThisInitialized(_this), "_fileData", void 0);
2692
2693    _this._url = url;
2694    _this._fileData = new ChunkedFileData();
2695    return _this;
2696  }
2697
2698  _createClass(XhrFileReader, [{
2699    key: "_init",
2700    value: function _init(callbacks) {
2701      if (XhrFileReader._config.avoidHeadRequests) {
2702        this._fetchSizeWithGetRequest(callbacks);
2703      } else {
2704        this._fetchSizeWithHeadRequest(callbacks);
2705      }
2706    }
2707  }, {
2708    key: "_fetchSizeWithHeadRequest",
2709    value: function _fetchSizeWithHeadRequest(callbacks) {
2710      var self = this;
2711
2712      this._makeXHRRequest("HEAD", null, {
2713        onSuccess: function onSuccess(xhr) {
2714          var contentLength = self._parseContentLength(xhr);
2715
2716          if (contentLength) {
2717            self._size = contentLength;
2718            callbacks.onSuccess();
2719          } else {
2720            // Content-Length not provided by the server, fallback to
2721            // GET requests.
2722            self._fetchSizeWithGetRequest(callbacks);
2723          }
2724        },
2725        onError: callbacks.onError
2726      });
2727    }
2728  }, {
2729    key: "_fetchSizeWithGetRequest",
2730    value: function _fetchSizeWithGetRequest(callbacks) {
2731      var self = this;
2732
2733      var range = this._roundRangeToChunkMultiple([0, 0]);
2734
2735      this._makeXHRRequest("GET", range, {
2736        onSuccess: function onSuccess(xhr) {
2737          var contentRange = self._parseContentRange(xhr);
2738
2739          var data = self._getXhrResponseContent(xhr);
2740
2741          if (contentRange) {
2742            if (contentRange.instanceLength == null) {
2743              // Last resort, server is not able to tell us the content length,
2744              // need to fetch entire file then.
2745              self._fetchEntireFile(callbacks);
2746
2747              return;
2748            }
2749
2750            self._size = contentRange.instanceLength;
2751          } else {
2752            // Range request not supported, we got the entire file
2753            self._size = data.length;
2754          }
2755
2756          self._fileData.addData(0, data);
2757
2758          callbacks.onSuccess();
2759        },
2760        onError: callbacks.onError
2761      });
2762    }
2763  }, {
2764    key: "_fetchEntireFile",
2765    value: function _fetchEntireFile(callbacks) {
2766      var self = this;
2767
2768      this._makeXHRRequest("GET", null, {
2769        onSuccess: function onSuccess(xhr) {
2770          var data = self._getXhrResponseContent(xhr);
2771
2772          self._size = data.length;
2773
2774          self._fileData.addData(0, data);
2775
2776          callbacks.onSuccess();
2777        },
2778        onError: callbacks.onError
2779      });
2780    }
2781  }, {
2782    key: "_getXhrResponseContent",
2783    value: function _getXhrResponseContent(xhr) {
2784      return xhr.responseBody || xhr.responseText || "";
2785    }
2786  }, {
2787    key: "_parseContentLength",
2788    value: function _parseContentLength(xhr) {
2789      var contentLength = this._getResponseHeader(xhr, "Content-Length");
2790
2791      if (contentLength == null) {
2792        return contentLength;
2793      } else {
2794        return parseInt(contentLength, 10);
2795      }
2796    }
2797  }, {
2798    key: "_parseContentRange",
2799    value: function _parseContentRange(xhr) {
2800      var contentRange = this._getResponseHeader(xhr, "Content-Range");
2801
2802      if (contentRange) {
2803        var parsedContentRange = contentRange.match(/bytes (\d+)-(\d+)\/(?:(\d+)|\*)/i);
2804
2805        if (!parsedContentRange) {
2806          throw new Error("FIXME: Unknown Content-Range syntax: " + contentRange);
2807        }
2808
2809        return {
2810          firstBytePosition: parseInt(parsedContentRange[1], 10),
2811          lastBytePosition: parseInt(parsedContentRange[2], 10),
2812          instanceLength: parsedContentRange[3] ? parseInt(parsedContentRange[3], 10) : null
2813        };
2814      } else {
2815        return null;
2816      }
2817    }
2818  }, {
2819    key: "loadRange",
2820    value: function loadRange(range, callbacks) {
2821      var self = this;
2822
2823      if (self._fileData.hasDataRange(range[0], Math.min(self._size, range[1]))) {
2824        setTimeout(callbacks.onSuccess, 1);
2825        return;
2826      } // Always download in multiples of CHUNK_SIZE. If we're going to make a
2827      // request might as well get a chunk that makes sense. The big cost is
2828      // establishing the connection so getting 10bytes or 1K doesn't really
2829      // make a difference.
2830
2831
2832      range = this._roundRangeToChunkMultiple(range); // Upper range should not be greater than max file size
2833
2834      range[1] = Math.min(self._size, range[1]);
2835
2836      this._makeXHRRequest("GET", range, {
2837        onSuccess: function onSuccess(xhr) {
2838          var data = self._getXhrResponseContent(xhr);
2839
2840          self._fileData.addData(range[0], data);
2841
2842          callbacks.onSuccess();
2843        },
2844        onError: callbacks.onError
2845      });
2846    }
2847  }, {
2848    key: "_roundRangeToChunkMultiple",
2849    value: function _roundRangeToChunkMultiple(range) {
2850      var length = range[1] - range[0] + 1;
2851      var newLength = Math.ceil(length / CHUNK_SIZE) * CHUNK_SIZE;
2852      return [range[0], range[0] + newLength - 1];
2853    }
2854  }, {
2855    key: "_makeXHRRequest",
2856    value: function _makeXHRRequest(method, range, callbacks) {
2857      var xhr = this._createXHRObject();
2858
2859      xhr.open(method, this._url);
2860
2861      var onXHRLoad = function onXHRLoad() {
2862        // 200 - OK
2863        // 206 - Partial Content
2864        // $FlowIssue - xhr will not be null here
2865        if (xhr.status === 200 || xhr.status === 206) {
2866          callbacks.onSuccess(xhr);
2867        } else if (callbacks.onError) {
2868          callbacks.onError({
2869            "type": "xhr",
2870            "info": "Unexpected HTTP status " + xhr.status + ".",
2871            "xhr": xhr
2872          });
2873        }
2874
2875        xhr = null;
2876      };
2877
2878      if (typeof xhr.onload !== 'undefined') {
2879        xhr.onload = onXHRLoad;
2880
2881        xhr.onerror = function () {
2882          if (callbacks.onError) {
2883            callbacks.onError({
2884              "type": "xhr",
2885              "info": "Generic XHR error, check xhr object.",
2886              "xhr": xhr
2887            });
2888          }
2889        };
2890      } else {
2891        xhr.onreadystatechange = function () {
2892          // $FlowIssue - xhr will not be null here
2893          if (xhr.readyState === 4) {
2894            onXHRLoad();
2895          }
2896        };
2897      }
2898
2899      if (XhrFileReader._config.timeoutInSec) {
2900        xhr.timeout = XhrFileReader._config.timeoutInSec * 1000;
2901
2902        xhr.ontimeout = function () {
2903          if (callbacks.onError) {
2904            callbacks.onError({
2905              "type": "xhr",
2906              // $FlowIssue - xhr.timeout will not be null
2907              "info": "Timeout after " + xhr.timeout / 1000 + "s. Use jsmediatags.Config.setXhrTimeout to override.",
2908              "xhr": xhr
2909            });
2910          }
2911        };
2912      }
2913
2914      xhr.overrideMimeType("text/plain; charset=x-user-defined");
2915
2916      if (range) {
2917        this._setRequestHeader(xhr, "Range", "bytes=" + range[0] + "-" + range[1]);
2918      }
2919
2920      this._setRequestHeader(xhr, "If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
2921
2922      xhr.send(null);
2923    }
2924  }, {
2925    key: "_setRequestHeader",
2926    value: function _setRequestHeader(xhr, headerName, headerValue) {
2927      if (XhrFileReader._config.disallowedXhrHeaders.indexOf(headerName.toLowerCase()) < 0) {
2928        xhr.setRequestHeader(headerName, headerValue);
2929      }
2930    }
2931  }, {
2932    key: "_hasResponseHeader",
2933    value: function _hasResponseHeader(xhr, headerName) {
2934      var allResponseHeaders = xhr.getAllResponseHeaders();
2935
2936      if (!allResponseHeaders) {
2937        return false;
2938      }
2939
2940      var headers = allResponseHeaders.split("\r\n");
2941      var headerNames = [];
2942
2943      for (var i = 0; i < headers.length; i++) {
2944        headerNames[i] = headers[i].split(":")[0].toLowerCase();
2945      }
2946
2947      return headerNames.indexOf(headerName.toLowerCase()) >= 0;
2948    }
2949  }, {
2950    key: "_getResponseHeader",
2951    value: function _getResponseHeader(xhr, headerName) {
2952      if (!this._hasResponseHeader(xhr, headerName)) {
2953        return null;
2954      }
2955
2956      return xhr.getResponseHeader(headerName);
2957    }
2958  }, {
2959    key: "getByteAt",
2960    value: function getByteAt(offset) {
2961      var character = this._fileData.getByteAt(offset);
2962
2963      return character.charCodeAt(0) & 0xff;
2964    }
2965  }, {
2966    key: "_isWebWorker",
2967    value: function _isWebWorker() {
2968      return typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
2969    }
2970  }, {
2971    key: "_createXHRObject",
2972    value: function _createXHRObject() {
2973      if (typeof window === "undefined" && !this._isWebWorker()) {
2974        // $FlowIssue - flow is not able to recognize this module.
2975        return new (require("xhr2").XMLHttpRequest)();
2976      }
2977
2978      if (typeof XMLHttpRequest !== "undefined") {
2979        return new XMLHttpRequest();
2980      }
2981
2982      throw new Error("XMLHttpRequest is not supported");
2983    }
2984  }], [{
2985    key: "canReadFile",
2986    value: function canReadFile(file) {
2987      return typeof file === 'string' && /^[a-z]+:\/\//i.test(file);
2988    }
2989  }, {
2990    key: "setConfig",
2991    value: function setConfig(config) {
2992      for (var key in config) {
2993        if (config.hasOwnProperty(key)) {
2994          this._config[key] = config[key];
2995        }
2996      }
2997
2998      var disallowedXhrHeaders = this._config.disallowedXhrHeaders;
2999
3000      for (var i = 0; i < disallowedXhrHeaders.length; i++) {
3001        disallowedXhrHeaders[i] = disallowedXhrHeaders[i].toLowerCase();
3002      }
3003    }
3004  }]);
3005
3006  return XhrFileReader;
3007}(MediaFileReader);
3008
3009_defineProperty(XhrFileReader, "_config", void 0);
3010
3011XhrFileReader._config = {
3012  avoidHeadRequests: false,
3013  disallowedXhrHeaders: [],
3014  timeoutInSec: 30
3015};
3016module.exports = XhrFileReader;
3017
3018},{"./ChunkedFileData":5,"./MediaFileReader":11,"xhr2":2}],15:[function(require,module,exports){
3019'use strict';
3020
3021function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
3022
3023function _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); } }
3024
3025function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
3026
3027function _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; }
3028
3029var MediaFileReader = require("./MediaFileReader");
3030
3031var XhrFileReader = require("./XhrFileReader");
3032
3033var BlobFileReader = require("./BlobFileReader");
3034
3035var ArrayFileReader = require("./ArrayFileReader");
3036
3037var MediaTagReader = require("./MediaTagReader");
3038
3039var ID3v1TagReader = require("./ID3v1TagReader");
3040
3041var ID3v2TagReader = require("./ID3v2TagReader");
3042
3043var MP4TagReader = require("./MP4TagReader");
3044
3045var FLACTagReader = require("./FLACTagReader");
3046
3047var mediaFileReaders = [];
3048var mediaTagReaders = [];
3049
3050function read(location, callbacks) {
3051  new Reader(location).read(callbacks);
3052}
3053
3054function isRangeValid(range, fileSize) {
3055  var invalidPositiveRange = range.offset >= 0 && range.offset + range.length >= fileSize;
3056  var invalidNegativeRange = range.offset < 0 && (-range.offset > fileSize || range.offset + range.length > 0);
3057  return !(invalidPositiveRange || invalidNegativeRange);
3058}
3059
3060var Reader = /*#__PURE__*/function () {
3061  function Reader(file) {
3062    _classCallCheck(this, Reader);
3063
3064    _defineProperty(this, "_file", void 0);
3065
3066    _defineProperty(this, "_tagsToRead", void 0);
3067
3068    _defineProperty(this, "_fileReader", void 0);
3069
3070    _defineProperty(this, "_tagReader", void 0);
3071
3072    this._file = file;
3073  }
3074
3075  _createClass(Reader, [{
3076    key: "setTagsToRead",
3077    value: function setTagsToRead(tagsToRead) {
3078      this._tagsToRead = tagsToRead;
3079      return this;
3080    }
3081  }, {
3082    key: "setFileReader",
3083    value: function setFileReader(fileReader) {
3084      this._fileReader = fileReader;
3085      return this;
3086    }
3087  }, {
3088    key: "setTagReader",
3089    value: function setTagReader(tagReader) {
3090      this._tagReader = tagReader;
3091      return this;
3092    }
3093  }, {
3094    key: "read",
3095    value: function read(callbacks) {
3096      var FileReader = this._getFileReader();
3097
3098      var fileReader = new FileReader(this._file);
3099      var self = this;
3100      fileReader.init({
3101        onSuccess: function onSuccess() {
3102          self._getTagReader(fileReader, {
3103            onSuccess: function onSuccess(TagReader) {
3104              new TagReader(fileReader).setTagsToRead(self._tagsToRead).read(callbacks);
3105            },
3106            onError: callbacks.onError
3107          });
3108        },
3109        onError: callbacks.onError
3110      });
3111    }
3112  }, {
3113    key: "_getFileReader",
3114    value: function _getFileReader() {
3115      if (this._fileReader) {
3116        return this._fileReader;
3117      } else {
3118        return this._findFileReader();
3119      }
3120    }
3121  }, {
3122    key: "_findFileReader",
3123    value: function _findFileReader() {
3124      for (var i = 0; i < mediaFileReaders.length; i++) {
3125        if (mediaFileReaders[i].canReadFile(this._file)) {
3126          return mediaFileReaders[i];
3127        }
3128      }
3129
3130      throw new Error("No suitable file reader found for " + this._file);
3131    }
3132  }, {
3133    key: "_getTagReader",
3134    value: function _getTagReader(fileReader, callbacks) {
3135      if (this._tagReader) {
3136        var tagReader = this._tagReader;
3137        setTimeout(function () {
3138          callbacks.onSuccess(tagReader);
3139        }, 1);
3140      } else {
3141        this._findTagReader(fileReader, callbacks);
3142      }
3143    }
3144  }, {
3145    key: "_findTagReader",
3146    value: function _findTagReader(fileReader, callbacks) {
3147      // We don't want to make multiple fetches per tag reader to get the tag
3148      // identifier. The strategy here is to combine all the tag identifier
3149      // ranges into one and make a single fetch. This is particularly important
3150      // in file readers that have expensive loads like the XHR one.
3151      // However, with this strategy we run into the problem of loading the
3152      // entire file because tag identifiers might be at the start or end of
3153      // the file.
3154      // To get around this we divide the tag readers into two categories, the
3155      // ones that read their tag identifiers from the start of the file and the
3156      // ones that read from the end of the file.
3157      var tagReadersAtFileStart = [];
3158      var tagReadersAtFileEnd = [];
3159      var fileSize = fileReader.getSize();
3160
3161      for (var i = 0; i < mediaTagReaders.length; i++) {
3162        var range = mediaTagReaders[i].getTagIdentifierByteRange();
3163
3164        if (!isRangeValid(range, fileSize)) {
3165          continue;
3166        }
3167
3168        if (range.offset >= 0 && range.offset < fileSize / 2 || range.offset < 0 && range.offset < -fileSize / 2) {
3169          tagReadersAtFileStart.push(mediaTagReaders[i]);
3170        } else {
3171          tagReadersAtFileEnd.push(mediaTagReaders[i]);
3172        }
3173      }
3174
3175      var tagsLoaded = false;
3176      var loadTagIdentifiersCallbacks = {
3177        onSuccess: function onSuccess() {
3178          if (!tagsLoaded) {
3179            // We're expecting to load two sets of tag identifiers. This flag
3180            // indicates when the first one has been loaded.
3181            tagsLoaded = true;
3182            return;
3183          }
3184
3185          for (var i = 0; i < mediaTagReaders.length; i++) {
3186            var range = mediaTagReaders[i].getTagIdentifierByteRange();
3187
3188            if (!isRangeValid(range, fileSize)) {
3189              continue;
3190            }
3191
3192            try {
3193              var tagIndentifier = fileReader.getBytesAt(range.offset >= 0 ? range.offset : range.offset + fileSize, range.length);
3194            } catch (ex) {
3195              if (callbacks.onError) {
3196                callbacks.onError({
3197                  "type": "fileReader",
3198                  "info": ex.message
3199                });
3200              }
3201
3202              return;
3203            }
3204
3205            if (mediaTagReaders[i].canReadTagFormat(tagIndentifier)) {
3206              callbacks.onSuccess(mediaTagReaders[i]);
3207              return;
3208            }
3209          }
3210
3211          if (callbacks.onError) {
3212            callbacks.onError({
3213              "type": "tagFormat",
3214              "info": "No suitable tag reader found"
3215            });
3216          }
3217        },
3218        onError: callbacks.onError
3219      };
3220
3221      this._loadTagIdentifierRanges(fileReader, tagReadersAtFileStart, loadTagIdentifiersCallbacks);
3222
3223      this._loadTagIdentifierRanges(fileReader, tagReadersAtFileEnd, loadTagIdentifiersCallbacks);
3224    }
3225  }, {
3226    key: "_loadTagIdentifierRanges",
3227    value: function _loadTagIdentifierRanges(fileReader, tagReaders, callbacks) {
3228      if (tagReaders.length === 0) {
3229        // Force async
3230        setTimeout(callbacks.onSuccess, 1);
3231        return;
3232      }
3233
3234      var tagIdentifierRange = [Number.MAX_VALUE, 0];
3235      var fileSize = fileReader.getSize(); // Create a super set of all ranges so we can load them all at once.
3236      // Might need to rethink this approach if there are tag ranges too far
3237      // a part from each other. We're good for now though.
3238
3239      for (var i = 0; i < tagReaders.length; i++) {
3240        var range = tagReaders[i].getTagIdentifierByteRange();
3241        var start = range.offset >= 0 ? range.offset : range.offset + fileSize;
3242        var end = start + range.length - 1;
3243        tagIdentifierRange[0] = Math.min(start, tagIdentifierRange[0]);
3244        tagIdentifierRange[1] = Math.max(end, tagIdentifierRange[1]);
3245      }
3246
3247      fileReader.loadRange(tagIdentifierRange, callbacks);
3248    }
3249  }]);
3250
3251  return Reader;
3252}();
3253
3254var Config = /*#__PURE__*/function () {
3255  function Config() {
3256    _classCallCheck(this, Config);
3257  }
3258
3259  _createClass(Config, null, [{
3260    key: "addFileReader",
3261    value: function addFileReader(fileReader) {
3262      mediaFileReaders.push(fileReader);
3263      return Config;
3264    }
3265  }, {
3266    key: "addTagReader",
3267    value: function addTagReader(tagReader) {
3268      mediaTagReaders.push(tagReader);
3269      return Config;
3270    }
3271  }, {
3272    key: "removeTagReader",
3273    value: function removeTagReader(tagReader) {
3274      var tagReaderIx = mediaTagReaders.indexOf(tagReader);
3275
3276      if (tagReaderIx >= 0) {
3277        mediaTagReaders.splice(tagReaderIx, 1);
3278      }
3279
3280      return Config;
3281    }
3282  }, {
3283    key: "EXPERIMENTAL_avoidHeadRequests",
3284    value: function EXPERIMENTAL_avoidHeadRequests() {
3285      XhrFileReader.setConfig({
3286        avoidHeadRequests: true
3287      });
3288    }
3289  }, {
3290    key: "setDisallowedXhrHeaders",
3291    value: function setDisallowedXhrHeaders(disallowedXhrHeaders) {
3292      XhrFileReader.setConfig({
3293        disallowedXhrHeaders: disallowedXhrHeaders
3294      });
3295    }
3296  }, {
3297    key: "setXhrTimeoutInSec",
3298    value: function setXhrTimeoutInSec(timeoutInSec) {
3299      XhrFileReader.setConfig({
3300        timeoutInSec: timeoutInSec
3301      });
3302    }
3303  }]);
3304
3305  return Config;
3306}();
3307
3308Config.addFileReader(XhrFileReader).addFileReader(BlobFileReader).addFileReader(ArrayFileReader).addTagReader(ID3v2TagReader).addTagReader(ID3v1TagReader).addTagReader(MP4TagReader).addTagReader(FLACTagReader);
3309
3310if (typeof process !== "undefined" && !process.browser) {
3311  if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
3312    var ReactNativeFileReader = require('./ReactNativeFileReader');
3313
3314    Config.addFileReader(ReactNativeFileReader);
3315  } else {
3316    var NodeFileReader = require('./NodeFileReader');
3317
3318    Config.addFileReader(NodeFileReader);
3319  }
3320}
3321
3322module.exports = {
3323  "read": read,
3324  "Reader": Reader,
3325  "Config": Config
3326};
3327
3328},{"./ArrayFileReader":3,"./BlobFileReader":4,"./FLACTagReader":6,"./ID3v1TagReader":7,"./ID3v2TagReader":9,"./MP4TagReader":10,"./MediaFileReader":11,"./MediaTagReader":12,"./NodeFileReader":1,"./ReactNativeFileReader":1,"./XhrFileReader":14}]},{},[15])(15)
3329});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.