taglib-wasm 1.7.0 → 1.7.1

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.
@@ -2730,7 +2730,7 @@ var VERSION;
2730
2730
  var init_version = __esm({
2731
2731
  "src/version.ts"() {
2732
2732
  "use strict";
2733
- VERSION = "1.7.0";
2733
+ VERSION = "1.7.1";
2734
2734
  }
2735
2735
  });
2736
2736
 
@@ -2662,7 +2662,7 @@ var VERSION;
2662
2662
  var init_version = __esm({
2663
2663
  "src/version.ts"() {
2664
2664
  "use strict";
2665
- VERSION = "1.7.0";
2665
+ VERSION = "1.7.1";
2666
2666
  }
2667
2667
  });
2668
2668
 
@@ -92,5 +92,31 @@ export interface GroupAlbumsOptions {
92
92
  * scanned root). scanForAlbums always passes the folder path it scanned. */
93
93
  scanRoot?: string;
94
94
  }
95
+ /** The standalone disc-folder recognizer result. */
96
+ export interface DiscFolderInfo {
97
+ /** Which grammar form matched. */
98
+ kind: "exact" | "embedded" | "volume" | "bonus" | "bare";
99
+ /** True when corroboration is required (title-word markers like "Tape 4",
100
+ * side letters like "CD D", bonus, bare). */
101
+ gated: boolean;
102
+ /** Disc number; undefined for side letters, bonus, and bare letters. */
103
+ number: number | undefined;
104
+ /** "of N" total from "CD 1 of 2". */
105
+ total: number | undefined;
106
+ /** Title text before an embedded marker ("Album (Disc 1)" -> "Album"). */
107
+ title: string | undefined;
108
+ /** Trailing text after the number ("Bonus Tracks" from "Disc 2 (Bonus Tracks)"). */
109
+ discTitle: string | undefined;
110
+ /** Base confidence tier; sibling corroboration may upgrade embedded to
111
+ * "high" inside groupAlbums. Gated names stay "low" even corroborated. */
112
+ confidence: DiscConfidence;
113
+ }
114
+ /**
115
+ * Recognize a directory name as a disc folder. Standalone — it only
116
+ * classifies the name; it does not resolve the folder to its parent (use
117
+ * the album result's per-file `albumDir` for that). Returns undefined for
118
+ * non-disc names. Plain "Bonus" and "Extras" are never discs by name.
119
+ */
120
+ export declare function discFolderInfo(name: string): DiscFolderInfo | undefined;
95
121
  export declare function groupAlbums(result: FolderScanResult, options?: GroupAlbumsOptions): AlbumGroupingResult;
96
122
  //# sourceMappingURL=group-albums.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"group-albums.d.ts","sourceRoot":"","sources":["../../../src/folder-api/group-albums.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAOtE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,eAAe,CAAA;CAAE,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEvD,2DAA2D;AAC3D,MAAM,WAAW,cAAe,SAAQ,iBAAiB;IACvD;kEAC8D;IAC9D,QAAQ,EAAE,MAAM,CAAC;IACjB;qDACiD;IACjD,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IACxB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4FAA4F;IAC5F,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,+EAA+E;IAC/E,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,mFAAmF;IACnF,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,4FAA4F;IAC5F,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4EAA4E;IAC5E,UAAU,EAAE,cAAc,CAAC;IAC3B,2EAA2E;IAC3E,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,8EAA8E;IAC9E,GAAG,EAAE,aAAa,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B;;sEAEkE;IAClE,WAAW,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC;sEACkE;IAClE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,6EAA6E;IAC7E,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,uEAAuE;IACvE,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB;yDACqD;IACrD,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,mFAAmF;IACnF,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,wEAAwE;IACxE,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,6EAA6E;IAC7E,mBAAmB,CAAC,EAAE,cAAc,CAAC;IACrC,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;gFAI4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA4SD,wBAAgB,WAAW,CACzB,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,kBAAuB,GAC/B,mBAAmB,CAwcrB"}
1
+ {"version":3,"file":"group-albums.d.ts","sourceRoot":"","sources":["../../../src/folder-api/group-albums.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,22 @@
1
1
  import { basename } from "../utils/path.js";
2
+ function discFolderInfo(name) {
3
+ const parse = parseDiscName(name);
4
+ if (!parse) return void 0;
5
+ return {
6
+ kind: parse.kind,
7
+ gated: parse.gated,
8
+ number: parse.number,
9
+ total: parse.total,
10
+ title: parse.title,
11
+ discTitle: parse.discTitle,
12
+ confidence: parse.gated ? "low" : baseConfidence(parse)
13
+ };
14
+ }
2
15
  function dirname(path) {
3
16
  const i = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
4
17
  return i === -1 ? path : path.slice(0, i);
5
18
  }
6
- const MARKERS = [
19
+ const UNCONDITIONAL_MARKERS = [
7
20
  "cd",
8
21
  "disc",
9
22
  "disk",
@@ -11,13 +24,11 @@ const MARKERS = [
11
24
  "sacd",
12
25
  "blu-ray",
13
26
  "bd",
14
- "vinyl",
15
- "lp",
16
- "record",
17
- "cassette",
18
- "tape",
19
27
  "digital media"
20
28
  ];
29
+ const GATED_MARKERS = ["tape", "vinyl", "cassette", "lp", "record"];
30
+ const MARKERS = [...UNCONDITIONAL_MARKERS, ...GATED_MARKERS];
31
+ const GATED_MARKER_SET = new Set(GATED_MARKERS);
21
32
  const WORD_NUMBERS = {
22
33
  one: 1,
23
34
  two: 2,
@@ -60,7 +71,7 @@ function parseNumberToken(token) {
60
71
  return Number.isFinite(roman) ? roman : void 0;
61
72
  }
62
73
  const SEP = String.raw`[\s._#-]*`;
63
- const NUM = String.raw`(?:\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve)`;
74
+ const NUM = String.raw`(?:\d+|[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|[a-z])`;
64
75
  function parseDiscName(name) {
65
76
  const trimmed = name.trim();
66
77
  if (/^(?:extras?|bonus)$/i.test(trimmed)) return void 0;
@@ -70,8 +81,10 @@ function parseDiscName(name) {
70
81
  const re = new RegExp(left + String.raw`(${esc})${SEP}(${NUM})`, "i");
71
82
  const m = trimmed.match(re);
72
83
  if (!m) continue;
73
- const number = parseNumberToken(m[2]);
74
- if (number === void 0) continue;
84
+ const sideLetter = /^[a-z]$/i.test(m[2]);
85
+ const number = sideLetter ? void 0 : parseNumberToken(m[2]);
86
+ if (number === void 0 && !sideLetter) continue;
87
+ const isGated = GATED_MARKER_SET.has(marker.toLowerCase()) || sideLetter;
75
88
  const markerStart = m.index + m[1].length - marker.length;
76
89
  const rawPrefix = trimmed.slice(0, markerStart).trim();
77
90
  const title = rawPrefix.replace(/[()[\]]/g, "").replace(/[\s._#-]+$/, "") || void 0;
@@ -82,10 +95,13 @@ function parseDiscName(name) {
82
95
  const total = ofMatch ? parseInt(ofMatch[1], 10) : void 0;
83
96
  return {
84
97
  kind: isExact ? "exact" : "embedded",
85
- number,
98
+ number: sideLetter ? void 0 : number,
86
99
  total,
87
100
  title,
88
- discTitle
101
+ discTitle,
102
+ gated: isGated,
103
+ sideLetter,
104
+ digit: /^\d+$/.test(m[2])
89
105
  };
90
106
  }
91
107
  const volume = trimmed.match(
@@ -97,7 +113,10 @@ function parseDiscName(name) {
97
113
  number: parseInt(volume[1], 10),
98
114
  total: volume[2] ? parseInt(volume[2], 10) : void 0,
99
115
  title: void 0,
100
- discTitle: void 0
116
+ discTitle: void 0,
117
+ gated: false,
118
+ sideLetter: false,
119
+ digit: true
101
120
  };
102
121
  }
103
122
  if (/^bonus\s+disc$/i.test(trimmed)) {
@@ -106,7 +125,10 @@ function parseDiscName(name) {
106
125
  number: void 0,
107
126
  total: void 0,
108
127
  title: void 0,
109
- discTitle: void 0
128
+ discTitle: void 0,
129
+ gated: true,
130
+ sideLetter: false,
131
+ digit: false
110
132
  };
111
133
  }
112
134
  if (/^(?:\d+|v\d+|p\d+|[ab])$/i.test(trimmed)) {
@@ -115,7 +137,10 @@ function parseDiscName(name) {
115
137
  number: /^\d+$/i.test(trimmed) ? parseInt(trimmed, 10) : void 0,
116
138
  total: void 0,
117
139
  title: void 0,
118
- discTitle: void 0
140
+ discTitle: void 0,
141
+ gated: true,
142
+ sideLetter: false,
143
+ digit: false
119
144
  };
120
145
  }
121
146
  return void 0;
@@ -123,7 +148,7 @@ function parseDiscName(name) {
123
148
  function baseConfidence(parse) {
124
149
  switch (parse.kind) {
125
150
  case "exact":
126
- return typeof parse.number === "number" && /^\d+$/.test(String(parse.number)) ? "high" : "low";
151
+ return parse.digit ? "high" : "low";
127
152
  case "embedded":
128
153
  return "medium";
129
154
  case "volume":
@@ -134,16 +159,23 @@ function baseConfidence(parse) {
134
159
  }
135
160
  }
136
161
  function corroborated(parse, siblings) {
137
- if (parse.kind === "exact") return true;
162
+ if (!parse.gated && parse.kind === "exact") return true;
138
163
  if (siblings.length === 0) return false;
139
164
  const siblingParses = siblings.map((s) => parseDiscName(basename(s))).filter((p) => p !== void 0);
140
- const hasExactSibling = siblingParses.some((p) => p.kind === "exact");
165
+ const hasExactSibling = siblingParses.some(
166
+ (p) => !p.gated && p.kind === "exact"
167
+ );
141
168
  const hasNumberedSibling = siblingParses.some(
142
169
  (p) => p.number !== void 0
143
170
  );
144
171
  if (parse.number !== void 0 && hasNumberedSibling) return true;
145
- if (parse.kind === "embedded" && hasExactSibling) return true;
146
- if (parse.kind === "volume" && hasNumberedSibling) return true;
172
+ if (!parse.gated && parse.kind === "embedded" && hasExactSibling) return true;
173
+ if (!parse.gated && parse.kind === "volume" && hasNumberedSibling) {
174
+ return true;
175
+ }
176
+ if (parse.sideLetter) {
177
+ return siblingParses.some((p) => p.sideLetter);
178
+ }
147
179
  if (parse.kind === "bonus" || parse.kind === "bare") {
148
180
  const numberedCount = siblingParses.filter((p) => p.number !== void 0).length;
149
181
  if (numberedCount >= 2) return true;
@@ -207,8 +239,10 @@ function groupAlbums(result, options = {}) {
207
239
  (d) => d !== dir && dirname(d) === dirname(dir)
208
240
  );
209
241
  const corroboratedBySiblings = corroborated(parse, siblings);
210
- let confidence = baseConfidence(parse);
211
- if (parse.kind === "bonus" || parse.kind === "bare") {
242
+ let confidence = parse.gated ? "low" : baseConfidence(parse);
243
+ if (parse.gated) {
244
+ if (!corroboratedBySiblings) continue;
245
+ } else if (parse.kind === "bonus" || parse.kind === "bare") {
212
246
  if (!corroboratedBySiblings) continue;
213
247
  } else if (corroboratedBySiblings) {
214
248
  confidence = "high";
@@ -501,5 +535,6 @@ function groupAlbums(result, options = {}) {
501
535
  return { albums: albumsOut, singles, unmatched, errors };
502
536
  }
503
537
  export {
538
+ discFolderInfo,
504
539
  groupAlbums
505
540
  };
@@ -5,6 +5,6 @@
5
5
  export type { AudioDynamics, AudioFileMetadata, DuplicateGroup, FolderScanItem, FolderScanOptions, FolderScanResult, FolderUpdateItem, FolderUpdateResult, } from "./types.js";
6
6
  export { scanFolder } from "./scan-operations.js";
7
7
  export { exportFolderMetadata, findDuplicates, updateFolderTags, } from "./folder-operations.js";
8
- export { type AlbumDisc, type AlbumGroup, type AlbumGroupingResult, type AlbumGroupItem, type AlbumGroupKey, type DiscConfidence, groupAlbums, type GroupAlbumsOptions, } from "./group-albums.js";
8
+ export { type AlbumDisc, type AlbumGroup, type AlbumGroupingResult, type AlbumGroupItem, type AlbumGroupKey, type DiscConfidence, type DiscFolderInfo, discFolderInfo, groupAlbums, type GroupAlbumsOptions, } from "./group-albums.js";
9
9
  export { scanForAlbums, type ScanForAlbumsOptions } from "./scan-for-albums.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/folder-api/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/folder-api/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EACV,aAAa,EACb,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,gBAAgB,GACjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,cAAc,EACd,WAAW,EACX,KAAK,kBAAkB,GACxB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -5,10 +5,12 @@ import {
5
5
  updateFolderTags
6
6
  } from "./folder-operations.js";
7
7
  import {
8
+ discFolderInfo,
8
9
  groupAlbums
9
10
  } from "./group-albums.js";
10
11
  import { scanForAlbums } from "./scan-for-albums.js";
11
12
  export {
13
+ discFolderInfo,
12
14
  exportFolderMetadata,
13
15
  findDuplicates,
14
16
  groupAlbums,
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "1.7.0";
1
+ export declare const VERSION = "1.7.1";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,4 +1,4 @@
1
- const VERSION = "1.7.0";
1
+ const VERSION = "1.7.1";
2
2
  export {
3
3
  VERSION
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taglib-wasm",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "TagLib-Wasm is the universal tagging library for TypeScript/JavaScript platforms: Browsers, Node.js, Deno, Bun, Cloudflare Workers, and Electron apps",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",