music-metadata 7.12.5 → 7.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,6 +55,7 @@ Following tag header formats are supported:
55
55
  * [iTunes](https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata)
56
56
  * [RIFF](https://wikipedia.org/wiki/Resource_Interchange_File_Format)/INFO
57
57
  * [Vorbis comment](https://wikipedia.org/wiki/Vorbis_comment)
58
+ * [AIFF](https://wikipedia.org/wiki/Audio_Interchange_File_Format)
58
59
 
59
60
  It allows many tags to be accessed in audio format, and tag format independent way.
60
61
 
@@ -90,8 +91,8 @@ import * as mm from 'music-metadata/lib/core';
90
91
  ```
91
92
 
92
93
  | function | `music-metadata` | `music-metadata/lib/core` |
93
- | -----------------------------------------------------| ---------------------------|----------------------------|
94
- | [`parseBuffer`](#parsefile-function) | ✓ | ✓ |
94
+ |------------------------------------------------------| ---------------------------|----------------------------|
95
+ | [`parseBuffer`](#parsebuffer-function) | ✓ | ✓ |
95
96
  | [`parseStream`](#parsestream-function) * | ✓ | ✓ |
96
97
  | [`parseFromTokenizer`](#parsefromtokenizer-function) | ✓ | ✓ |
97
98
  | [`parseFile`](#parsefile-function) | ✓ | |
@@ -11,4 +11,5 @@ export declare class AIFFParser extends BasicParser {
11
11
  private isCompressed;
12
12
  parse(): Promise<void>;
13
13
  readData(header: iff.IChunkHeader): Promise<number>;
14
+ readTextChunk(header: iff.IChunkHeader): Promise<number>;
14
15
  }
@@ -10,6 +10,17 @@ const BasicParser_1 = require("../common/BasicParser");
10
10
  const AiffToken = require("./AiffToken");
11
11
  const iff = require("../iff");
12
12
  const debug = (0, debug_1.default)('music-metadata:parser:aiff');
13
+ const compressionTypes = {
14
+ NONE: 'not compressed PCM Apple Computer',
15
+ sowt: 'PCM (byte swapped)',
16
+ fl32: '32-bit floating point IEEE 32-bit float',
17
+ fl64: '64-bit floating point IEEE 64-bit float Apple Computer',
18
+ alaw: 'ALaw 2:1 8-bit ITU-T G.711 A-law',
19
+ ulaw: 'µLaw 2:1 8-bit ITU-T G.711 µ-law Apple Computer',
20
+ ULAW: 'CCITT G.711 u-law 8-bit ITU-T G.711 µ-law',
21
+ ALAW: 'CCITT G.711 A-law 8-bit ITU-T G.711 A-law',
22
+ FL32: 'Float 32 IEEE 32-bit float '
23
+ };
13
24
  /**
14
25
  * AIFF - Audio Interchange File Format
15
26
  *
@@ -40,7 +51,6 @@ class AIFFParser extends BasicParser_1.BasicParser {
40
51
  while (!this.tokenizer.fileInfo.size || this.tokenizer.fileInfo.size - this.tokenizer.position >= iff.Header.len) {
41
52
  debug('Reading AIFF chunk at offset=' + this.tokenizer.position);
42
53
  const chunkHeader = await this.tokenizer.readToken(iff.Header);
43
- debug(`Chunk id=${chunkHeader.chunkID}`);
44
54
  const nextChunk = 2 * Math.round(chunkHeader.chunkSize / 2);
45
55
  const bytesRead = await this.readData(chunkHeader);
46
56
  await this.tokenizer.ignore(nextChunk - bytesRead);
@@ -56,6 +66,7 @@ class AIFFParser extends BasicParser_1.BasicParser {
56
66
  }
57
67
  }
58
68
  async readData(header) {
69
+ var _a;
59
70
  switch (header.chunkID) {
60
71
  case 'COMM': // The Common Chunk
61
72
  const common = await this.tokenizer.readToken(new AiffToken.Common(header, this.isCompressed));
@@ -64,7 +75,7 @@ class AIFFParser extends BasicParser_1.BasicParser {
64
75
  this.metadata.setFormat('numberOfChannels', common.numChannels);
65
76
  this.metadata.setFormat('numberOfSamples', common.numSampleFrames);
66
77
  this.metadata.setFormat('duration', common.numSampleFrames / common.sampleRate);
67
- this.metadata.setFormat('codec', common.compressionName);
78
+ this.metadata.setFormat('codec', (_a = common.compressionName) !== null && _a !== void 0 ? _a : compressionTypes[common.compressionType]);
68
79
  return header.chunkSize;
69
80
  case 'ID3 ': // ID3-meta-data
70
81
  const id3_data = await this.tokenizer.readToken(new Token.Uint8ArrayType(header.chunkSize));
@@ -76,9 +87,22 @@ class AIFFParser extends BasicParser_1.BasicParser {
76
87
  this.metadata.setFormat('bitrate', 8 * header.chunkSize / this.metadata.format.duration);
77
88
  }
78
89
  return 0;
90
+ case 'NAME': // Sample name chunk
91
+ case 'AUTH': // Author chunk
92
+ case '(c) ': // Copyright chunk
93
+ case 'ANNO': // Annotation chunk
94
+ return this.readTextChunk(header);
79
95
  default:
96
+ debug(`Ignore chunk id=${header.chunkID}, size=${header.chunkSize}`);
80
97
  return 0;
81
98
  }
82
99
  }
100
+ async readTextChunk(header) {
101
+ const value = await this.tokenizer.readToken(new Token.StringType(header.chunkSize, 'ascii'));
102
+ value.split('\0').map(v => v.trim()).filter(v => v && v.length > 0).forEach(v => {
103
+ this.metadata.addTag('AIFF', header.chunkID, v.trim());
104
+ });
105
+ return header.chunkSize;
106
+ }
83
107
  }
84
108
  exports.AIFFParser = AIFFParser;
@@ -0,0 +1,4 @@
1
+ import { CommonTagMapper } from '../common/GenericTagMapper.js';
2
+ export declare class AiffTagMapper extends CommonTagMapper {
3
+ constructor();
4
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AiffTagMapper = void 0;
4
+ const GenericTagMapper_js_1 = require("../common/GenericTagMapper.js");
5
+ /**
6
+ * ID3v1 tag mappings
7
+ */
8
+ const tagMap = {
9
+ NAME: 'title',
10
+ AUTH: 'artist',
11
+ '(c) ': 'copyright',
12
+ ANNO: 'comment'
13
+ };
14
+ class AiffTagMapper extends GenericTagMapper_js_1.CommonTagMapper {
15
+ constructor() {
16
+ super(['AIFF'], tagMap);
17
+ }
18
+ }
19
+ exports.AiffTagMapper = AiffTagMapper;
20
+ //# sourceMappingURL=AiffTagMap.js.map
@@ -25,12 +25,17 @@ class Common {
25
25
  res.compressionType = FourCC_1.FourCcToken.get(buf, off + 18);
26
26
  if (this.len > 22) {
27
27
  const strLen = buf.readInt8(off + 22);
28
- const padding = (strLen + 1) % 2;
29
- if (23 + strLen + padding === this.len) {
30
- res.compressionName = new Token.StringType(strLen, 'binary').get(buf, off + 23);
28
+ if (strLen > 0) {
29
+ const padding = (strLen + 1) % 2;
30
+ if (23 + strLen + padding === this.len) {
31
+ res.compressionName = new Token.StringType(strLen, 'binary').get(buf, off + 23);
32
+ }
33
+ else {
34
+ throw new Error('Illegal pstring length');
35
+ }
31
36
  }
32
37
  else {
33
- throw new Error('Illegal pstring length');
38
+ res.compressionName = undefined;
34
39
  }
35
40
  }
36
41
  }
@@ -10,6 +10,7 @@ const MP4TagMapper_1 = require("../mp4/MP4TagMapper");
10
10
  const VorbisTagMapper_1 = require("../ogg/vorbis/VorbisTagMapper");
11
11
  const RiffInfoTagMap_1 = require("../riff/RiffInfoTagMap");
12
12
  const MatroskaTagMapper_1 = require("../matroska/MatroskaTagMapper");
13
+ const AiffTagMap_1 = require("../aiff/AiffTagMap");
13
14
  class CombinedTagMapper {
14
15
  constructor() {
15
16
  this.tagMappers = {};
@@ -23,7 +24,8 @@ class CombinedTagMapper {
23
24
  new APEv2TagMapper_1.APEv2TagMapper(),
24
25
  new AsfTagMapper_1.AsfTagMapper(),
25
26
  new RiffInfoTagMap_1.RiffInfoTagMapper(),
26
- new MatroskaTagMapper_1.MatroskaTagMapper()
27
+ new MatroskaTagMapper_1.MatroskaTagMapper(),
28
+ new AiffTagMap_1.AiffTagMapper()
27
29
  ].forEach(mapper => {
28
30
  this.registerTagMapper(mapper);
29
31
  });
@@ -11,11 +11,8 @@ exports.FourCcToken = {
11
11
  len: 4,
12
12
  get: (buf, off) => {
13
13
  const id = buf.toString('binary', off, off + exports.FourCcToken.len);
14
- switch (id) {
15
- default:
16
- if (!id.match(validFourCC)) {
17
- throw new Error(`FourCC contains invalid characters: ${util.a2hex(id)} "${id}"`);
18
- }
14
+ if (!id.match(validFourCC)) {
15
+ throw new Error(`FourCC contains invalid characters: ${util.a2hex(id)} "${id}"`);
19
16
  }
20
17
  return id;
21
18
  },
@@ -1,4 +1,4 @@
1
- export declare type TagType = 'vorbis' | 'ID3v1' | 'ID3v2.2' | 'ID3v2.3' | 'ID3v2.4' | 'APEv2' | 'asf' | 'iTunes' | 'exif' | 'matroska';
1
+ export declare type TagType = 'vorbis' | 'ID3v1' | 'ID3v2.2' | 'ID3v2.3' | 'ID3v2.4' | 'APEv2' | 'asf' | 'iTunes' | 'exif' | 'matroska' | 'AIFF';
2
2
  export interface IGenericTag {
3
3
  id: GenericTagId;
4
4
  value: any;
@@ -9,7 +9,7 @@ const GenericTagMapper_1 = require("./GenericTagMapper");
9
9
  const Util_1 = require("./Util");
10
10
  const FileType = require("file-type/core");
11
11
  const debug = (0, debug_1.default)('music-metadata:collector');
12
- const TagPriority = ['matroska', 'APEv2', 'vorbis', 'ID3v2.4', 'ID3v2.3', 'ID3v2.2', 'exif', 'asf', 'iTunes', 'ID3v1'];
12
+ const TagPriority = ['matroska', 'APEv2', 'vorbis', 'ID3v2.4', 'ID3v2.3', 'ID3v2.2', 'exif', 'asf', 'iTunes', 'AIFF', 'ID3v1'];
13
13
  /**
14
14
  * Provided to the parser to uodate the metadata result.
15
15
  * Responsible for triggering async updates
@@ -44,7 +44,7 @@ class MetadataCollector {
44
44
  this.originPriority[tagType] = priority++;
45
45
  }
46
46
  this.originPriority.artificial = 500; // Filled using alternative tags
47
- this.originPriority.id3v1 = 600; // Consider worst due to field length limit
47
+ this.originPriority.id3v1 = 600; // Consider as the worst because of the field length limit
48
48
  }
49
49
  /**
50
50
  * @returns {boolean} true if one or more tags have been found
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "music-metadata",
3
3
  "description": "Music metadata parser for Node.js, supporting virtual any audio and tag format.",
4
- "version": "7.12.5",
4
+ "version": "7.13.0",
5
5
  "author": {
6
6
  "name": "Borewit",
7
7
  "url": "https://github.com/Borewit"
@@ -79,7 +79,6 @@
79
79
  "build": "npm run clean && npm run compile && npm run doc-gen",
80
80
  "start": "npm-run-all compile lint cover-test",
81
81
  "test-coverage": "nyc npm run test",
82
- "send-coveralls": "nyc report --reporter=text-lcov | coveralls",
83
82
  "send-codacy": "nyc report --reporter=text-lcov | codacy-coverage",
84
83
  "doc-gen": "node doc-gen/gen.js"
85
84
  },
@@ -90,26 +89,25 @@
90
89
  "file-type": "^16.5.4",
91
90
  "media-typer": "^1.1.0",
92
91
  "strtok3": "^6.3.0",
93
- "token-types": "^4.2.0"
92
+ "token-types": "^4.2.1"
94
93
  },
95
94
  "devDependencies": {
96
- "@types/chai": "^4.3.1",
95
+ "@types/chai": "^4.3.3",
97
96
  "@types/chai-as-promised": "^7.1.5",
98
97
  "@types/debug": "^4.1.7",
99
98
  "@types/file-type": "^10.9.1",
100
99
  "@types/mocha": "^9.1.0",
101
- "@types/node": "^18.0.6",
102
- "@typescript-eslint/eslint-plugin": "^5.30.7",
103
- "@typescript-eslint/parser": "^5.30.7",
100
+ "@types/node": "^18.7.14",
101
+ "@typescript-eslint/eslint-plugin": "^5.37.0",
102
+ "@typescript-eslint/parser": "^5.37.0",
104
103
  "chai": "^4.3.6",
105
104
  "chai-as-promised": "^7.1.1",
106
- "coveralls": "^3.1.1",
107
105
  "del-cli": "5.0.0",
108
- "eslint": "^8.20.0",
106
+ "eslint": "^8.23.1",
109
107
  "eslint-config-prettier": "^8.5.0",
110
- "eslint-import-resolver-typescript": "^3.3.0",
108
+ "eslint-import-resolver-typescript": "^3.5.1",
111
109
  "eslint-plugin-import": "^2.26.0",
112
- "eslint-plugin-jsdoc": "^39.3.3",
110
+ "eslint-plugin-jsdoc": "^39.3.6",
113
111
  "eslint-plugin-node": "^11.1.0",
114
112
  "eslint-plugin-unicorn": "^43.0.2",
115
113
  "mime": "^3.0.0",
@@ -120,7 +118,7 @@
120
118
  "remark-preset-lint-recommended": "^6.1.2",
121
119
  "source-map-support": "^0.5.21",
122
120
  "ts-node": "^10.9.1",
123
- "typescript": "^4.7.4"
121
+ "typescript": "^4.8.3"
124
122
  },
125
123
  "engines": {
126
124
  "node": ">=10"