taglib-wasm 2.2.0 → 2.2.2
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/dist/disc-folder.d.ts +3 -1
- package/dist/disc-folder.d.ts.map +1 -1
- package/dist/disc-folder.js +187 -152
- package/dist/index.browser.js +7 -4
- package/dist/simple.browser.js +22 -9
- package/dist/src/folder-api/album-corroborate.d.ts +13 -0
- package/dist/src/folder-api/album-corroborate.d.ts.map +1 -0
- package/dist/src/folder-api/album-corroborate.js +36 -0
- package/dist/src/folder-api/album-discs.d.ts +13 -0
- package/dist/src/folder-api/album-discs.d.ts.map +1 -0
- package/dist/src/folder-api/album-discs.js +122 -0
- package/dist/src/folder-api/album-grouping.d.ts +24 -0
- package/dist/src/folder-api/album-grouping.d.ts.map +1 -0
- package/dist/src/folder-api/album-grouping.js +118 -0
- package/dist/src/folder-api/album-identity.d.ts +27 -0
- package/dist/src/folder-api/album-identity.d.ts.map +1 -0
- package/dist/src/folder-api/album-identity.js +151 -0
- package/dist/src/folder-api/{group-albums.d.ts → album-types.d.ts} +55 -26
- package/dist/src/folder-api/album-types.d.ts.map +1 -0
- package/dist/src/folder-api/album-types.js +0 -0
- package/dist/src/folder-api/folder-disc.d.ts +24 -0
- package/dist/src/folder-api/folder-disc.d.ts.map +1 -0
- package/dist/src/folder-api/folder-disc.js +169 -0
- package/dist/src/folder-api/index.d.ts +3 -1
- package/dist/src/folder-api/index.d.ts.map +1 -1
- package/dist/src/folder-api/index.js +2 -4
- package/dist/src/folder-api/scan-for-albums.d.ts +1 -1
- package/dist/src/folder-api/scan-for-albums.d.ts.map +1 -1
- package/dist/src/folder-api/scan-for-albums.js +1 -3
- package/dist/src/runtime/wasi-adapter/audio-properties.d.ts +20 -0
- package/dist/src/runtime/wasi-adapter/audio-properties.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/audio-properties.js +84 -0
- package/dist/src/runtime/wasi-adapter/file-handle.d.ts +5 -19
- package/dist/src/runtime/wasi-adapter/file-handle.d.ts.map +1 -1
- package/dist/src/runtime/wasi-adapter/file-handle.js +67 -389
- package/dist/src/runtime/wasi-adapter/handle-state.d.ts +28 -0
- package/dist/src/runtime/wasi-adapter/handle-state.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/handle-state.js +58 -0
- package/dist/src/runtime/wasi-adapter/mp4-items.d.ts +34 -0
- package/dist/src/runtime/wasi-adapter/mp4-items.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/mp4-items.js +80 -0
- package/dist/src/runtime/wasi-adapter/property-surface.d.ts +25 -0
- package/dist/src/runtime/wasi-adapter/property-surface.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/property-surface.js +104 -0
- package/dist/src/runtime/wasi-adapter/structured-fields.d.ts +44 -0
- package/dist/src/runtime/wasi-adapter/structured-fields.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/structured-fields.js +139 -0
- package/dist/src/runtime/wasi-adapter/tag-keys.d.ts +28 -0
- package/dist/src/runtime/wasi-adapter/tag-keys.d.ts.map +1 -0
- package/dist/src/runtime/wasi-adapter/tag-keys.js +46 -0
- package/dist/src/simple/batch-operations.d.ts +28 -11
- package/dist/src/simple/batch-operations.d.ts.map +1 -1
- package/dist/src/simple/batch-operations.js +17 -7
- package/dist/src/utils/tag-mapping.d.ts +8 -0
- package/dist/src/utils/tag-mapping.d.ts.map +1 -1
- package/dist/src/utils/tag-mapping.js +6 -3
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +2 -1
- package/dist/src/folder-api/group-albums.d.ts.map +0 -1
- package/dist/src/folder-api/group-albums.js +0 -544
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
function dirname(path) {
|
|
2
|
+
const i = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
3
|
+
return i === -1 ? path : path.slice(0, i);
|
|
4
|
+
}
|
|
5
|
+
const UNCONDITIONAL_MARKERS = [
|
|
6
|
+
"cd",
|
|
7
|
+
"disc",
|
|
8
|
+
"disk",
|
|
9
|
+
"dvd",
|
|
10
|
+
"sacd",
|
|
11
|
+
"blu-ray",
|
|
12
|
+
"bd",
|
|
13
|
+
"digital media"
|
|
14
|
+
];
|
|
15
|
+
const GATED_MARKERS = ["tape", "vinyl", "cassette", "lp", "record"];
|
|
16
|
+
const MARKERS = [...UNCONDITIONAL_MARKERS, ...GATED_MARKERS];
|
|
17
|
+
const GATED_MARKER_SET = new Set(GATED_MARKERS);
|
|
18
|
+
const WORD_NUMBERS = {
|
|
19
|
+
one: 1,
|
|
20
|
+
two: 2,
|
|
21
|
+
three: 3,
|
|
22
|
+
four: 4,
|
|
23
|
+
five: 5,
|
|
24
|
+
six: 6,
|
|
25
|
+
seven: 7,
|
|
26
|
+
eight: 8,
|
|
27
|
+
nine: 9,
|
|
28
|
+
ten: 10,
|
|
29
|
+
eleven: 11,
|
|
30
|
+
twelve: 12
|
|
31
|
+
};
|
|
32
|
+
function romanToInt(s) {
|
|
33
|
+
const values = {
|
|
34
|
+
i: 1,
|
|
35
|
+
v: 5,
|
|
36
|
+
x: 10,
|
|
37
|
+
l: 50,
|
|
38
|
+
c: 100,
|
|
39
|
+
d: 500,
|
|
40
|
+
m: 1e3
|
|
41
|
+
};
|
|
42
|
+
let total = 0;
|
|
43
|
+
let prev = 0;
|
|
44
|
+
for (let i = s.length - 1; i >= 0; i--) {
|
|
45
|
+
const v = values[s[i]];
|
|
46
|
+
if (v === void 0) return NaN;
|
|
47
|
+
total += v < prev ? -v : v;
|
|
48
|
+
prev = v;
|
|
49
|
+
}
|
|
50
|
+
return total;
|
|
51
|
+
}
|
|
52
|
+
function parseNumberToken(token) {
|
|
53
|
+
if (/^\d+$/.test(token)) return parseInt(token, 10);
|
|
54
|
+
const word = WORD_NUMBERS[token.toLowerCase()];
|
|
55
|
+
if (word) return word;
|
|
56
|
+
const roman = romanToInt(token.toLowerCase());
|
|
57
|
+
return Number.isFinite(roman) ? roman : void 0;
|
|
58
|
+
}
|
|
59
|
+
const SEP = String.raw`[\s._#-]*`;
|
|
60
|
+
const NUM = String.raw`(?:\d+|(?:[ivxlcdm]+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|[a-z])(?![a-z]))`;
|
|
61
|
+
function parseDiscName(name) {
|
|
62
|
+
const trimmed = name.trim();
|
|
63
|
+
if (/^(?:extras?|bonus)$/i.test(trimmed)) return void 0;
|
|
64
|
+
for (const marker of MARKERS) {
|
|
65
|
+
const left = String.raw`(?:^|[^a-z0-9])`;
|
|
66
|
+
const esc = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
67
|
+
const re = new RegExp(
|
|
68
|
+
left + String.raw`(${esc})(?![a-z])${SEP}(${NUM})`,
|
|
69
|
+
"i"
|
|
70
|
+
);
|
|
71
|
+
const m = trimmed.match(re);
|
|
72
|
+
if (!m) continue;
|
|
73
|
+
const sideLetter = /^[a-z]$/i.test(m[2]);
|
|
74
|
+
const number = sideLetter ? void 0 : parseNumberToken(m[2]);
|
|
75
|
+
if (number === void 0 && !sideLetter) continue;
|
|
76
|
+
if (!sideLetter && /^[ivxlcdm]{2,}$/i.test(m[2]) && (number ?? 0) > 100) continue;
|
|
77
|
+
const isGated = GATED_MARKER_SET.has(marker.toLowerCase()) || sideLetter;
|
|
78
|
+
const markerStart = m.index + m[1].length - marker.length;
|
|
79
|
+
const rawPrefix = trimmed.slice(0, markerStart).trim();
|
|
80
|
+
const title = rawPrefix.replace(/[()[\]]/g, "").replace(/[\s._#-]+$/, "") || void 0;
|
|
81
|
+
const isExact = title === void 0;
|
|
82
|
+
const after = trimmed.slice(m.index + m[0].length).trim();
|
|
83
|
+
const discTitle = after.replace(/^[()[\],:;\-–—\s]+/, "").replace(/[)\]\[,:;\-–—\s]+$/, "").trim() || void 0;
|
|
84
|
+
const ofMatch = after.trim().match(/^of\s+(\d+)\b/i);
|
|
85
|
+
const total = ofMatch ? parseInt(ofMatch[1], 10) : void 0;
|
|
86
|
+
return {
|
|
87
|
+
kind: isExact ? "exact" : "embedded",
|
|
88
|
+
number: sideLetter ? void 0 : number,
|
|
89
|
+
total,
|
|
90
|
+
title,
|
|
91
|
+
discTitle,
|
|
92
|
+
gated: isGated,
|
|
93
|
+
sideLetter,
|
|
94
|
+
digit: /^\d+$/.test(m[2])
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const volume = trimmed.match(
|
|
98
|
+
/^(?:volume|vol\.?|part|pt\.?)\s*(\d+)(?:\s*of\s*(\d+))?$/i
|
|
99
|
+
);
|
|
100
|
+
if (volume) {
|
|
101
|
+
return {
|
|
102
|
+
kind: "volume",
|
|
103
|
+
number: parseInt(volume[1], 10),
|
|
104
|
+
total: volume[2] ? parseInt(volume[2], 10) : void 0,
|
|
105
|
+
title: void 0,
|
|
106
|
+
discTitle: void 0,
|
|
107
|
+
gated: false,
|
|
108
|
+
sideLetter: false,
|
|
109
|
+
digit: true
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
if (/^bonus\s+disc$/i.test(trimmed)) {
|
|
113
|
+
return {
|
|
114
|
+
kind: "bonus",
|
|
115
|
+
number: void 0,
|
|
116
|
+
total: void 0,
|
|
117
|
+
title: void 0,
|
|
118
|
+
discTitle: void 0,
|
|
119
|
+
gated: true,
|
|
120
|
+
sideLetter: false,
|
|
121
|
+
digit: false
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
if (/^(?:\d+|v\d+|p\d+|[ab])$/i.test(trimmed)) {
|
|
125
|
+
return {
|
|
126
|
+
kind: "bare",
|
|
127
|
+
number: /^\d+$/i.test(trimmed) ? parseInt(trimmed, 10) : void 0,
|
|
128
|
+
total: void 0,
|
|
129
|
+
title: void 0,
|
|
130
|
+
discTitle: void 0,
|
|
131
|
+
gated: true,
|
|
132
|
+
sideLetter: false,
|
|
133
|
+
digit: false
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return void 0;
|
|
137
|
+
}
|
|
138
|
+
function baseConfidence(parse) {
|
|
139
|
+
switch (parse.kind) {
|
|
140
|
+
case "exact":
|
|
141
|
+
return parse.digit ? "high" : "low";
|
|
142
|
+
case "embedded":
|
|
143
|
+
return "medium";
|
|
144
|
+
case "volume":
|
|
145
|
+
return "medium";
|
|
146
|
+
case "bonus":
|
|
147
|
+
case "bare":
|
|
148
|
+
return "low";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function discFolderInfo(name) {
|
|
152
|
+
const parse = parseDiscName(name);
|
|
153
|
+
if (!parse) return void 0;
|
|
154
|
+
return {
|
|
155
|
+
kind: parse.kind,
|
|
156
|
+
gated: parse.gated,
|
|
157
|
+
number: parse.number,
|
|
158
|
+
total: parse.total,
|
|
159
|
+
title: parse.title,
|
|
160
|
+
discTitle: parse.discTitle,
|
|
161
|
+
confidence: parse.gated ? "low" : baseConfidence(parse)
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export {
|
|
165
|
+
baseConfidence,
|
|
166
|
+
dirname,
|
|
167
|
+
discFolderInfo,
|
|
168
|
+
parseDiscName
|
|
169
|
+
};
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
export type { AudioDynamics, AudioFileMetadata, DuplicateGroup, FolderScanItem, FolderScanOptions, FolderScanResult, } from "./types.js";
|
|
6
6
|
export { scanFolder } from "./scan-operations.js";
|
|
7
7
|
export { exportFolderMetadata, findDuplicates } from "./folder-operations.js";
|
|
8
|
-
export { type AlbumDisc, type AlbumGroup, type AlbumGroupingResult, type AlbumGroupItem, type AlbumGroupKey, type DiscConfidence, type DiscFolderInfo,
|
|
8
|
+
export { type AlbumDisc, type AlbumGroup, type AlbumGroupingResult, type AlbumGroupItem, type AlbumGroupKey, type DiscConfidence, type DiscFolderInfo, type GroupAlbumsOptions, } from "./album-types.js";
|
|
9
|
+
export { discFolderInfo } from "./folder-disc.js";
|
|
10
|
+
export { groupAlbums } from "./album-grouping.js";
|
|
9
11
|
export { scanForAlbums, type ScanForAlbumsOptions } from "./scan-for-albums.js";
|
|
10
12
|
//# 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,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE9E,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,
|
|
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,GACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE9E,OAAO,EACL,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { scanFolder } from "./scan-operations.js";
|
|
2
2
|
import { exportFolderMetadata, findDuplicates } from "./folder-operations.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
groupAlbums
|
|
6
|
-
} from "./group-albums.js";
|
|
3
|
+
import { discFolderInfo } from "./folder-disc.js";
|
|
4
|
+
import { groupAlbums } from "./album-grouping.js";
|
|
7
5
|
import { scanForAlbums } from "./scan-for-albums.js";
|
|
8
6
|
export {
|
|
9
7
|
discFolderInfo,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and runtime-agnostic.
|
|
5
5
|
*/
|
|
6
6
|
import type { FolderScanOptions } from "./types.js";
|
|
7
|
-
import {
|
|
7
|
+
import type { AlbumGroupingResult, GroupAlbumsOptions } from "./album-types.js";
|
|
8
8
|
export type ScanForAlbumsOptions = FolderScanOptions & GroupAlbumsOptions;
|
|
9
9
|
/**
|
|
10
10
|
* Scan a folder and group the result into albums with disc subdivisions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan-for-albums.d.ts","sourceRoot":"","sources":["../../../src/folder-api/scan-for-albums.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,
|
|
1
|
+
{"version":3,"file":"scan-for-albums.d.ts","sourceRoot":"","sources":["../../../src/folder-api/scan-for-albums.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAGhF,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAE1E;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAc9B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio metrics and format detection over the WASI tag-data snapshot.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions over (tagData, fileData): the WasiFileHandle wrappers add
|
|
5
|
+
* destruction guards and pass their fields. Extracted from file-handle.ts in
|
|
6
|
+
* the taglib-1dfc split.
|
|
7
|
+
*/
|
|
8
|
+
import type { AudioProperties } from "../../types.js";
|
|
9
|
+
/** The audio-properties block of the C++ snapshot, null when absent. */
|
|
10
|
+
export declare function getAudioProperties(tagData: Record<string, unknown> | null): AudioProperties | null;
|
|
11
|
+
/** OGG codec sniffing: "OpusHead" in the first page payload, else OGG. */
|
|
12
|
+
export declare function detectOggCodec(fileData: Uint8Array): string;
|
|
13
|
+
/**
|
|
14
|
+
* Format detection: container-based first (works for path and buffer modes),
|
|
15
|
+
* magic-byte fallback for buffers.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getFormat(tagData: Record<string, unknown> | null, fileData: Uint8Array | null): string;
|
|
18
|
+
/** MP4 detection: containerFormat (path mode) or ftyp box (buffer mode). */
|
|
19
|
+
export declare function isMP4(tagData: Record<string, unknown> | null, fileData: Uint8Array | null): boolean;
|
|
20
|
+
//# sourceMappingURL=audio-properties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audio-properties.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/audio-properties.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AAexB,wEAAwE;AACxE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACtC,eAAe,GAAG,IAAI,CA4BxB;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,CAe3D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,MAAM,CAuDR;AAED,4EAA4E;AAC5E,wBAAgB,KAAK,CACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACvC,QAAQ,EAAE,UAAU,GAAG,IAAI,GAC1B,OAAO,CAYT"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
const CONTAINER_TO_FORMAT = {
|
|
2
|
+
MP3: "MP3",
|
|
3
|
+
MP4: "MP4",
|
|
4
|
+
FLAC: "FLAC",
|
|
5
|
+
OGG: "OGG",
|
|
6
|
+
WAV: "WAV",
|
|
7
|
+
AIFF: "AIFF",
|
|
8
|
+
WavPack: "WV",
|
|
9
|
+
TTA: "TTA",
|
|
10
|
+
ASF: "ASF",
|
|
11
|
+
Matroska: "MATROSKA"
|
|
12
|
+
};
|
|
13
|
+
function getAudioProperties(tagData) {
|
|
14
|
+
if (!tagData || !("sampleRate" in tagData)) return null;
|
|
15
|
+
const d = tagData;
|
|
16
|
+
const containerFormat = d.containerFormat || "unknown";
|
|
17
|
+
const mpegVersion = d.mpegVersion ?? 0;
|
|
18
|
+
const formatVersion = d.formatVersion ?? 0;
|
|
19
|
+
return {
|
|
20
|
+
duration: d.length ?? 0,
|
|
21
|
+
durationMs: d.lengthMs ?? 0,
|
|
22
|
+
bitrate: d.bitrate ?? 0,
|
|
23
|
+
sampleRate: d.sampleRate ?? 0,
|
|
24
|
+
channels: d.channels ?? 0,
|
|
25
|
+
bitsPerSample: d.bitsPerSample ?? 0,
|
|
26
|
+
codec: d.codec || "unknown",
|
|
27
|
+
containerFormat,
|
|
28
|
+
isLossless: d.isLossless ?? false,
|
|
29
|
+
...mpegVersion > 0 ? { mpegVersion, mpegLayer: d.mpegLayer ?? 0 } : {},
|
|
30
|
+
...containerFormat === "MP4" || containerFormat === "ASF" ? { isEncrypted: d.isEncrypted ?? false } : {},
|
|
31
|
+
...formatVersion > 0 ? { formatVersion } : {},
|
|
32
|
+
...d.outputGainDb !== void 0 ? { outputGainDb: d.outputGainDb } : {}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function detectOggCodec(fileData) {
|
|
36
|
+
if (fileData.length < 37) return "OGG";
|
|
37
|
+
const segCount = fileData[26];
|
|
38
|
+
if (segCount === void 0) return "OGG";
|
|
39
|
+
const payloadStart = 27 + segCount;
|
|
40
|
+
if (fileData.length < payloadStart + 8) return "OGG";
|
|
41
|
+
const sig = String.fromCharCode(
|
|
42
|
+
...fileData.slice(payloadStart, payloadStart + 8)
|
|
43
|
+
);
|
|
44
|
+
if (sig === "OpusHead") return "OPUS";
|
|
45
|
+
return "OGG";
|
|
46
|
+
}
|
|
47
|
+
function getFormat(tagData, fileData) {
|
|
48
|
+
const container = tagData?.containerFormat;
|
|
49
|
+
if (container) {
|
|
50
|
+
const codec = tagData?.codec;
|
|
51
|
+
if (container === "OGG" && codec === "Opus") return "OPUS";
|
|
52
|
+
if (CONTAINER_TO_FORMAT[container]) return CONTAINER_TO_FORMAT[container];
|
|
53
|
+
}
|
|
54
|
+
if (!fileData || fileData.length < 8) return "unknown";
|
|
55
|
+
const magic = fileData.slice(0, 4);
|
|
56
|
+
if (magic[0] === 255 && (magic[1] & 224) === 224) return "MP3";
|
|
57
|
+
if (magic[0] === 73 && magic[1] === 68 && magic[2] === 51) {
|
|
58
|
+
return "MP3";
|
|
59
|
+
}
|
|
60
|
+
if (magic[0] === 102 && magic[1] === 76 && magic[2] === 97 && magic[3] === 67) return "FLAC";
|
|
61
|
+
if (magic[0] === 79 && magic[1] === 103 && magic[2] === 103 && magic[3] === 83) return detectOggCodec(fileData);
|
|
62
|
+
if (magic[0] === 82 && magic[1] === 73 && magic[2] === 70 && magic[3] === 70) return "WAV";
|
|
63
|
+
if (magic[0] === 119 && magic[1] === 118 && magic[2] === 112 && magic[3] === 107) return "WV";
|
|
64
|
+
if (magic[0] === 84 && magic[1] === 84 && magic[2] === 65 && magic[3] === 49) return "TTA";
|
|
65
|
+
if (fileData.length >= 16 && magic[0] === 48 && magic[1] === 38 && magic[2] === 178 && magic[3] === 117) return "ASF";
|
|
66
|
+
if (magic[0] === 26 && magic[1] === 69 && magic[2] === 223 && magic[3] === 163) return "MATROSKA";
|
|
67
|
+
const ftyp = fileData.slice(4, 8);
|
|
68
|
+
if (ftyp[0] === 102 && ftyp[1] === 116 && ftyp[2] === 121 && ftyp[3] === 112) return "MP4";
|
|
69
|
+
return "unknown";
|
|
70
|
+
}
|
|
71
|
+
function isMP4(tagData, fileData) {
|
|
72
|
+
if (!fileData) {
|
|
73
|
+
return tagData?.containerFormat === "MP4";
|
|
74
|
+
}
|
|
75
|
+
if (fileData.length < 8) return false;
|
|
76
|
+
const magic = fileData.slice(4, 8);
|
|
77
|
+
return magic[0] === 102 && magic[1] === 116 && magic[2] === 121 && magic[3] === 112;
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
detectOggCodec,
|
|
81
|
+
getAudioProperties,
|
|
82
|
+
getFormat,
|
|
83
|
+
isMP4
|
|
84
|
+
};
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview WASI-based FileHandle implementation
|
|
3
|
-
*/
|
|
1
|
+
/** WASI-based FileHandle implementation (taglib-1dfc split). */
|
|
4
2
|
import type { FileHandle, RawChapter, RawId3v2Frame, RawLyrics, RawPicture } from "../../wasm.js";
|
|
5
3
|
import type { BasicTagData } from "../../types/tags.js";
|
|
6
4
|
import type { AudioProperties } from "../../types.js";
|
|
7
5
|
import type { WasiModule } from "../wasmer-sdk-loader/types.js";
|
|
8
6
|
export declare class WasiFileHandle implements FileHandle {
|
|
9
|
-
private readonly
|
|
10
|
-
private fileData;
|
|
11
|
-
private filePath;
|
|
12
|
-
private tagData;
|
|
7
|
+
private readonly state;
|
|
13
8
|
private destroyed;
|
|
14
9
|
constructor(wasiModule: WasiModule);
|
|
15
10
|
private checkNotDestroyed;
|
|
@@ -17,27 +12,18 @@ export declare class WasiFileHandle implements FileHandle {
|
|
|
17
12
|
loadFromPath(path: string): boolean;
|
|
18
13
|
isValid(): boolean;
|
|
19
14
|
save(): boolean;
|
|
15
|
+
getBuffer(): Uint8Array;
|
|
20
16
|
getTagData(): BasicTagData;
|
|
21
17
|
setTagData(data: Partial<BasicTagData>): void;
|
|
22
18
|
getAudioProperties(): AudioProperties | null;
|
|
23
19
|
getFormat(): string;
|
|
24
|
-
|
|
25
|
-
getBuffer(): Uint8Array;
|
|
20
|
+
isMP4(): boolean;
|
|
26
21
|
getProperties(): Record<string, string[]>;
|
|
27
|
-
setProperties(
|
|
22
|
+
setProperties(properties: Record<string, string[]>): void;
|
|
28
23
|
getProperty(key: string): string;
|
|
29
24
|
setProperty(key: string, value: string): void;
|
|
30
|
-
isMP4(): boolean;
|
|
31
25
|
getMP4Item(key: string): string;
|
|
32
26
|
setMP4Item(key: string, value: string): void;
|
|
33
|
-
/** Record an exact atom name to be repaired after the PropertyMap write. */
|
|
34
|
-
private registerMp4ItemName;
|
|
35
|
-
/**
|
|
36
|
-
* Record a foreign-mean freeform atom for deletion at save (taglib-65nm).
|
|
37
|
-
* The PropertyMap erase pass cannot express foreign atoms, so the C++ shim
|
|
38
|
-
* consumes this list and calls removeItem on each exact atom name.
|
|
39
|
-
*/
|
|
40
|
-
private registerMp4ItemRemoval;
|
|
41
27
|
getMp4ItemRemovals(): string[] | undefined;
|
|
42
28
|
setMp4ItemRemovals(removals: string[]): void;
|
|
43
29
|
removeMP4Item(key: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-handle.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/file-handle.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"file-handle.d.ts","sourceRoot":"","sources":["../../../../src/runtime/wasi-adapter/file-handle.ts"],"names":[],"mappings":"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"}
|