@utilix-tech/sdk 0.25.0 → 0.27.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/CHANGELOG.md +8 -0
- package/README.md +27 -8
- package/dist/{api-Xl7OzIgq.d.cts → api-DmTNE4c1.d.cts} +29 -2
- package/dist/{api-Xl7OzIgq.d.ts → api-DmTNE4c1.d.ts} +29 -2
- package/dist/{chunk-Q3B3YWOA.js → chunk-52ZDKSIX.js} +45 -2
- package/dist/{chunk-FVKNR3PV.js → chunk-I63BCOAG.js} +88 -1
- package/dist/{chunk-XMKJYVKB.js → chunk-Q3M23WNJ.js} +97 -1
- package/dist/index.cjs +226 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/{media-9HEpTPGA.d.cts → media-CN17a3MM.d.cts} +34 -2
- package/dist/{media-9HEpTPGA.d.ts → media-CN17a3MM.d.ts} +34 -2
- package/dist/tools/api.cjs +43 -0
- package/dist/tools/api.d.cts +1 -1
- package/dist/tools/api.d.ts +1 -1
- package/dist/tools/api.js +1 -1
- package/dist/tools/media.cjs +96 -0
- package/dist/tools/media.d.cts +1 -1
- package/dist/tools/media.d.ts +1 -1
- package/dist/tools/media.js +1 -1
- package/dist/tools/units.cjs +87 -0
- package/dist/tools/units.d.cts +1 -1
- package/dist/tools/units.d.ts +1 -1
- package/dist/tools/units.js +1 -1
- package/dist/{units-DUqjk24x.d.ts → units-COt5uI20.d.cts} +64 -2
- package/dist/{units-DUqjk24x.d.cts → units-COt5uI20.d.ts} +64 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -7154,10 +7154,12 @@ __export(units_exports, {
|
|
|
7154
7154
|
calculateLoan: () => calculateLoan,
|
|
7155
7155
|
calculateMarginMarkup: () => calculateMarginMarkup,
|
|
7156
7156
|
calculatePercentageChange: () => calculatePercentageChange,
|
|
7157
|
+
calculateRuleOf72: () => calculateRuleOf72,
|
|
7157
7158
|
calculateSimpleInterest: () => calculateSimpleInterest,
|
|
7158
7159
|
calculateTax: () => calculateTax,
|
|
7159
7160
|
calculateTimeValue: () => calculateTimeValue,
|
|
7160
7161
|
calculateTipSplit: () => calculateTipSplit,
|
|
7162
|
+
calculateVideoBitrate: () => calculateVideoBitrate,
|
|
7161
7163
|
compareSemver: () => compareSemver,
|
|
7162
7164
|
convert: () => convert,
|
|
7163
7165
|
convertAprApy: () => convertAprApy,
|
|
@@ -8718,6 +8720,91 @@ function calculateBreakEven(input) {
|
|
|
8718
8720
|
}
|
|
8719
8721
|
return result;
|
|
8720
8722
|
}
|
|
8723
|
+
function calculateVideoBitrate(input) {
|
|
8724
|
+
const { mode, durationSeconds, videoBitrateKbps, targetSizeMB } = input;
|
|
8725
|
+
const audioBitrateKbps = input.audioBitrateKbps ?? 0;
|
|
8726
|
+
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
|
|
8727
|
+
return { error: "durationSeconds must be a positive number" };
|
|
8728
|
+
}
|
|
8729
|
+
if (!Number.isFinite(audioBitrateKbps) || audioBitrateKbps < 0) {
|
|
8730
|
+
return { error: "audioBitrateKbps must be zero or a positive number" };
|
|
8731
|
+
}
|
|
8732
|
+
const round23 = (n) => Math.round(n * 100) / 100;
|
|
8733
|
+
if (mode === "size-from-bitrate") {
|
|
8734
|
+
if (typeof videoBitrateKbps !== "number" || !Number.isFinite(videoBitrateKbps) || videoBitrateKbps <= 0) {
|
|
8735
|
+
return { error: 'videoBitrateKbps must be a positive number for mode "size-from-bitrate"' };
|
|
8736
|
+
}
|
|
8737
|
+
const totalBitrateKbps = videoBitrateKbps + audioBitrateKbps;
|
|
8738
|
+
const fileSizeBytes = totalBitrateKbps * 1e3 * durationSeconds / 8;
|
|
8739
|
+
return {
|
|
8740
|
+
mode,
|
|
8741
|
+
durationSeconds,
|
|
8742
|
+
videoBitrateKbps: round23(videoBitrateKbps),
|
|
8743
|
+
audioBitrateKbps: round23(audioBitrateKbps),
|
|
8744
|
+
totalBitrateKbps: round23(totalBitrateKbps),
|
|
8745
|
+
fileSizeBytes: Math.round(fileSizeBytes),
|
|
8746
|
+
fileSizeMB: round23(fileSizeBytes / 1e6),
|
|
8747
|
+
fileSizeMiB: round23(fileSizeBytes / 1048576)
|
|
8748
|
+
};
|
|
8749
|
+
}
|
|
8750
|
+
if (mode === "bitrate-from-size") {
|
|
8751
|
+
if (typeof targetSizeMB !== "number" || !Number.isFinite(targetSizeMB) || targetSizeMB <= 0) {
|
|
8752
|
+
return { error: 'targetSizeMB must be a positive number for mode "bitrate-from-size"' };
|
|
8753
|
+
}
|
|
8754
|
+
const fileSizeBytes = targetSizeMB * 1e6;
|
|
8755
|
+
const totalBitrateKbps = fileSizeBytes * 8 / (1e3 * durationSeconds);
|
|
8756
|
+
const videoKbps = totalBitrateKbps - audioBitrateKbps;
|
|
8757
|
+
if (videoKbps <= 0) {
|
|
8758
|
+
return {
|
|
8759
|
+
error: "audioBitrateKbps exceeds the total bitrate available at this target size and duration; lower the audio bitrate or raise the target size"
|
|
8760
|
+
};
|
|
8761
|
+
}
|
|
8762
|
+
return {
|
|
8763
|
+
mode,
|
|
8764
|
+
durationSeconds,
|
|
8765
|
+
videoBitrateKbps: round23(videoKbps),
|
|
8766
|
+
audioBitrateKbps: round23(audioBitrateKbps),
|
|
8767
|
+
totalBitrateKbps: round23(totalBitrateKbps),
|
|
8768
|
+
fileSizeBytes: Math.round(fileSizeBytes),
|
|
8769
|
+
fileSizeMB: round23(targetSizeMB),
|
|
8770
|
+
fileSizeMiB: round23(fileSizeBytes / 1048576)
|
|
8771
|
+
};
|
|
8772
|
+
}
|
|
8773
|
+
return { error: 'mode must be "size-from-bitrate" or "bitrate-from-size"' };
|
|
8774
|
+
}
|
|
8775
|
+
function calculateRuleOf72(value, direction) {
|
|
8776
|
+
if (!Number.isFinite(value) || value <= 0) return { error: "Value must be a positive number" };
|
|
8777
|
+
if (direction !== "rate-to-years" && direction !== "years-to-rate") {
|
|
8778
|
+
return { error: 'Direction must be "rate-to-years" or "years-to-rate"' };
|
|
8779
|
+
}
|
|
8780
|
+
const round4 = (n) => Math.round(n * 1e4) / 1e4;
|
|
8781
|
+
if (direction === "rate-to-years") {
|
|
8782
|
+
const ratePercent = value;
|
|
8783
|
+
const ruleOf72Estimate2 = 72 / ratePercent;
|
|
8784
|
+
const exactValue2 = Math.log(2) / Math.log(1 + ratePercent / 100);
|
|
8785
|
+
const errorPercent2 = (ruleOf72Estimate2 - exactValue2) / exactValue2 * 100;
|
|
8786
|
+
return {
|
|
8787
|
+
direction,
|
|
8788
|
+
ratePercent: round4(ratePercent),
|
|
8789
|
+
years: round4(exactValue2),
|
|
8790
|
+
ruleOf72Estimate: round4(ruleOf72Estimate2),
|
|
8791
|
+
exactValue: round4(exactValue2),
|
|
8792
|
+
errorPercent: round4(errorPercent2)
|
|
8793
|
+
};
|
|
8794
|
+
}
|
|
8795
|
+
const years = value;
|
|
8796
|
+
const ruleOf72Estimate = 72 / years;
|
|
8797
|
+
const exactValue = (Math.pow(2, 1 / years) - 1) * 100;
|
|
8798
|
+
const errorPercent = (ruleOf72Estimate - exactValue) / exactValue * 100;
|
|
8799
|
+
return {
|
|
8800
|
+
direction,
|
|
8801
|
+
ratePercent: round4(exactValue),
|
|
8802
|
+
years: round4(years),
|
|
8803
|
+
ruleOf72Estimate: round4(ruleOf72Estimate),
|
|
8804
|
+
exactValue: round4(exactValue),
|
|
8805
|
+
errorPercent: round4(errorPercent)
|
|
8806
|
+
};
|
|
8807
|
+
}
|
|
8721
8808
|
|
|
8722
8809
|
// src/tools/network.ts
|
|
8723
8810
|
var network_exports = {};
|
|
@@ -10550,6 +10637,7 @@ __export(api_exports, {
|
|
|
10550
10637
|
buildCurl: () => buildCurl,
|
|
10551
10638
|
buildCurlMultiline: () => buildCurlMultiline,
|
|
10552
10639
|
buildUrl: () => buildUrl,
|
|
10640
|
+
computeJwkThumbprint: () => computeJwkThumbprint,
|
|
10553
10641
|
convertToCode: () => convertToCode,
|
|
10554
10642
|
decodeJwt: () => decodeJwt,
|
|
10555
10643
|
decodeUrlComponent: () => decodeUrlComponent,
|
|
@@ -11068,6 +11156,48 @@ function parseJwks(input) {
|
|
|
11068
11156
|
const duplicateKids = [...kidCounts.entries()].filter(([, c]) => c > 1).map(([kid]) => kid);
|
|
11069
11157
|
return { ok: true, keys, count: keys.length, duplicateKids };
|
|
11070
11158
|
}
|
|
11159
|
+
var JWK_THUMBPRINT_MEMBERS = {
|
|
11160
|
+
oct: ["k", "kty"],
|
|
11161
|
+
RSA: ["e", "kty", "n"],
|
|
11162
|
+
EC: ["crv", "kty", "x", "y"],
|
|
11163
|
+
OKP: ["crv", "kty", "x"]
|
|
11164
|
+
};
|
|
11165
|
+
var JWK_THUMBPRINT_NODE_HASH = {
|
|
11166
|
+
"SHA-256": "sha256",
|
|
11167
|
+
"SHA-384": "sha384",
|
|
11168
|
+
"SHA-512": "sha512"
|
|
11169
|
+
};
|
|
11170
|
+
function computeJwkThumbprint(input, hashAlg = "SHA-256") {
|
|
11171
|
+
const trimmed = input.trim();
|
|
11172
|
+
if (!trimmed) return { ok: false, error: "No input provided" };
|
|
11173
|
+
const nodeHash = JWK_THUMBPRINT_NODE_HASH[hashAlg];
|
|
11174
|
+
if (!nodeHash) return { ok: false, error: 'hashAlg must be one of "SHA-256", "SHA-384", "SHA-512"' };
|
|
11175
|
+
let jwk;
|
|
11176
|
+
try {
|
|
11177
|
+
jwk = JSON.parse(trimmed);
|
|
11178
|
+
} catch (e) {
|
|
11179
|
+
return { ok: false, error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` };
|
|
11180
|
+
}
|
|
11181
|
+
if (jwk === null || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
11182
|
+
return { ok: false, error: "Input must be a single JWK object, not a JWKS set or array" };
|
|
11183
|
+
}
|
|
11184
|
+
const obj = jwk;
|
|
11185
|
+
const kty = obj.kty;
|
|
11186
|
+
if (typeof kty !== "string") return { ok: false, error: 'JWK must have a "kty" (key type) member' };
|
|
11187
|
+
const members = JWK_THUMBPRINT_MEMBERS[kty];
|
|
11188
|
+
if (!members) return { ok: false, error: `Unsupported key type "${kty}": supported types are RSA, EC, oct, OKP` };
|
|
11189
|
+
const canonical = {};
|
|
11190
|
+
for (const m of members) {
|
|
11191
|
+
const v = obj[m];
|
|
11192
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
11193
|
+
return { ok: false, error: `JWK is missing required member "${m}" for key type "${kty}"` };
|
|
11194
|
+
}
|
|
11195
|
+
canonical[m] = v;
|
|
11196
|
+
}
|
|
11197
|
+
const canonicalJson = "{" + members.map((m) => `${JSON.stringify(m)}:${JSON.stringify(canonical[m])}`).join(",") + "}";
|
|
11198
|
+
const thumbprint = crypto.createHash(nodeHash).update(canonicalJson, "utf8").digest("base64url");
|
|
11199
|
+
return { ok: true, kty, hashAlg, members, canonicalJson, thumbprint };
|
|
11200
|
+
}
|
|
11071
11201
|
var ALG_TO_NODE_HASH = {
|
|
11072
11202
|
HS256: "sha256",
|
|
11073
11203
|
HS384: "sha384",
|
|
@@ -19102,6 +19232,7 @@ function vectorSimilarity(a, b) {
|
|
|
19102
19232
|
var media_exports = {};
|
|
19103
19233
|
__export(media_exports, {
|
|
19104
19234
|
readExifData: () => readExifData,
|
|
19235
|
+
readFlacInfo: () => readFlacInfo,
|
|
19105
19236
|
readIcoInfo: () => readIcoInfo,
|
|
19106
19237
|
readId3Tags: () => readId3Tags,
|
|
19107
19238
|
readImageInfo: () => readImageInfo,
|
|
@@ -19862,6 +19993,101 @@ function readIcoInfo(bytes) {
|
|
|
19862
19993
|
}
|
|
19863
19994
|
return { imageCount: count, images };
|
|
19864
19995
|
}
|
|
19996
|
+
var FLAC_TAG_FIELDS = {
|
|
19997
|
+
TITLE: "title",
|
|
19998
|
+
ARTIST: "artist",
|
|
19999
|
+
ALBUM: "album",
|
|
20000
|
+
DATE: "date",
|
|
20001
|
+
GENRE: "genre",
|
|
20002
|
+
TRACKNUMBER: "trackNumber"
|
|
20003
|
+
};
|
|
20004
|
+
function readU24BE(bytes, offset) {
|
|
20005
|
+
return bytes[offset] << 16 | bytes[offset + 1] << 8 | bytes[offset + 2];
|
|
20006
|
+
}
|
|
20007
|
+
function readVorbisComment(bytes, start, end) {
|
|
20008
|
+
let offset = start;
|
|
20009
|
+
if (offset + 4 > end) return null;
|
|
20010
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
20011
|
+
const vendorLength = view.getUint32(offset, true);
|
|
20012
|
+
offset += 4;
|
|
20013
|
+
if (offset + vendorLength > end) return null;
|
|
20014
|
+
const vendor = Buffer.from(bytes.subarray(offset, offset + vendorLength)).toString("utf8");
|
|
20015
|
+
offset += vendorLength;
|
|
20016
|
+
if (offset + 4 > end) return null;
|
|
20017
|
+
const commentCount = view.getUint32(offset, true);
|
|
20018
|
+
offset += 4;
|
|
20019
|
+
const tags = {};
|
|
20020
|
+
for (let i = 0; i < commentCount; i++) {
|
|
20021
|
+
if (offset + 4 > end) break;
|
|
20022
|
+
const commentLength = view.getUint32(offset, true);
|
|
20023
|
+
offset += 4;
|
|
20024
|
+
if (offset + commentLength > end) break;
|
|
20025
|
+
const comment = Buffer.from(bytes.subarray(offset, offset + commentLength)).toString("utf8");
|
|
20026
|
+
offset += commentLength;
|
|
20027
|
+
const eq = comment.indexOf("=");
|
|
20028
|
+
if (eq > 0) {
|
|
20029
|
+
const key = comment.slice(0, eq).toUpperCase();
|
|
20030
|
+
const value = comment.slice(eq + 1);
|
|
20031
|
+
tags[key] = value;
|
|
20032
|
+
}
|
|
20033
|
+
}
|
|
20034
|
+
return { vendor, tags };
|
|
20035
|
+
}
|
|
20036
|
+
function readFlacInfo(bytes) {
|
|
20037
|
+
if (bytes.length < 4) return { error: "File is too small to be a valid FLAC file" };
|
|
20038
|
+
if (readAscii4(bytes, 0) !== "fLaC") return { error: 'Not a FLAC file (missing "fLaC" marker)' };
|
|
20039
|
+
let offset = 4;
|
|
20040
|
+
let streamInfo = null;
|
|
20041
|
+
let vorbisComment = null;
|
|
20042
|
+
while (offset + 4 <= bytes.length) {
|
|
20043
|
+
const header = bytes[offset];
|
|
20044
|
+
const isLast = (header & 128) !== 0;
|
|
20045
|
+
const blockType = header & 127;
|
|
20046
|
+
const length = readU24BE(bytes, offset + 1);
|
|
20047
|
+
const dataStart = offset + 4;
|
|
20048
|
+
const dataEnd = dataStart + length;
|
|
20049
|
+
if (dataEnd > bytes.length) return { error: "Truncated metadata block" };
|
|
20050
|
+
if (blockType === 0) {
|
|
20051
|
+
if (length < 34) return { error: "Truncated STREAMINFO block" };
|
|
20052
|
+
const minBlockSize = bytes[dataStart] << 8 | bytes[dataStart + 1];
|
|
20053
|
+
const maxBlockSize = bytes[dataStart + 2] << 8 | bytes[dataStart + 3];
|
|
20054
|
+
const minFrameSize = readU24BE(bytes, dataStart + 4);
|
|
20055
|
+
const maxFrameSize = readU24BE(bytes, dataStart + 7);
|
|
20056
|
+
let packed = 0n;
|
|
20057
|
+
for (let i = 0; i < 8; i++) packed = packed << 8n | BigInt(bytes[dataStart + 10 + i]);
|
|
20058
|
+
const sampleRate = Number(packed >> 44n & 0xfffffn);
|
|
20059
|
+
const channels = Number(packed >> 41n & 0x7n) + 1;
|
|
20060
|
+
const bitsPerSample = Number(packed >> 36n & 0x1fn) + 1;
|
|
20061
|
+
const totalSamples = Number(packed & 0xfffffffffn);
|
|
20062
|
+
if (sampleRate <= 0) return { error: "Invalid sample rate in STREAMINFO block" };
|
|
20063
|
+
streamInfo = {
|
|
20064
|
+
sampleRate,
|
|
20065
|
+
channels,
|
|
20066
|
+
bitsPerSample,
|
|
20067
|
+
totalSamples,
|
|
20068
|
+
durationSeconds: Math.round(totalSamples / sampleRate * 1e3) / 1e3,
|
|
20069
|
+
minBlockSize,
|
|
20070
|
+
maxBlockSize,
|
|
20071
|
+
minFrameSize,
|
|
20072
|
+
maxFrameSize
|
|
20073
|
+
};
|
|
20074
|
+
} else if (blockType === 4) {
|
|
20075
|
+
vorbisComment = readVorbisComment(bytes, dataStart, dataEnd);
|
|
20076
|
+
}
|
|
20077
|
+
offset = dataEnd;
|
|
20078
|
+
if (isLast) break;
|
|
20079
|
+
}
|
|
20080
|
+
if (!streamInfo) return { error: "No STREAMINFO block found in this FLAC file" };
|
|
20081
|
+
const result = { ...streamInfo };
|
|
20082
|
+
if (vorbisComment) {
|
|
20083
|
+
result.vendor = vorbisComment.vendor;
|
|
20084
|
+
result.tags = vorbisComment.tags;
|
|
20085
|
+
for (const [key, field] of Object.entries(FLAC_TAG_FIELDS)) {
|
|
20086
|
+
if (vorbisComment.tags[key] !== void 0) result[field] = vorbisComment.tags[key];
|
|
20087
|
+
}
|
|
20088
|
+
}
|
|
20089
|
+
return result;
|
|
20090
|
+
}
|
|
19865
20091
|
|
|
19866
20092
|
// src/index.ts
|
|
19867
20093
|
var version = "0.1.0";
|
package/dist/index.d.cts
CHANGED
|
@@ -5,15 +5,15 @@ export { t as text } from './text-D1fySkCB.cjs';
|
|
|
5
5
|
export { d as data } from './data-XRb0D7Zn.cjs';
|
|
6
6
|
export { g as generators } from './generators-BGtRGpJZ.cjs';
|
|
7
7
|
export { t as time } from './time-KqJjdqII.cjs';
|
|
8
|
-
export { u as units } from './units-
|
|
8
|
+
export { u as units } from './units-COt5uI20.cjs';
|
|
9
9
|
export { n as network } from './network-BJOjJnmY.cjs';
|
|
10
|
-
export { a as api } from './api-
|
|
10
|
+
export { a as api } from './api-DmTNE4c1.cjs';
|
|
11
11
|
export { c as code } from './code-DaRvff2v.cjs';
|
|
12
12
|
export { c as color } from './color-tPwZCr9H.cjs';
|
|
13
13
|
export { c as css } from './css-Cf7AMGM-.cjs';
|
|
14
14
|
export { m as misc } from './misc-CA3N198T.cjs';
|
|
15
15
|
export { a as ai_agent } from './ai_agent-B-c59NXD.cjs';
|
|
16
|
-
export { m as media } from './media-
|
|
16
|
+
export { m as media } from './media-CN17a3MM.cjs';
|
|
17
17
|
|
|
18
18
|
declare const version = "0.1.0";
|
|
19
19
|
|
package/dist/index.d.ts
CHANGED
|
@@ -5,15 +5,15 @@ export { t as text } from './text-D1fySkCB.js';
|
|
|
5
5
|
export { d as data } from './data-XRb0D7Zn.js';
|
|
6
6
|
export { g as generators } from './generators-BGtRGpJZ.js';
|
|
7
7
|
export { t as time } from './time-KqJjdqII.js';
|
|
8
|
-
export { u as units } from './units-
|
|
8
|
+
export { u as units } from './units-COt5uI20.js';
|
|
9
9
|
export { n as network } from './network-BJOjJnmY.js';
|
|
10
|
-
export { a as api } from './api-
|
|
10
|
+
export { a as api } from './api-DmTNE4c1.js';
|
|
11
11
|
export { c as code } from './code-DaRvff2v.js';
|
|
12
12
|
export { c as color } from './color-tPwZCr9H.js';
|
|
13
13
|
export { c as css } from './css-Cf7AMGM-.js';
|
|
14
14
|
export { m as misc } from './misc-CA3N198T.js';
|
|
15
15
|
export { a as ai_agent } from './ai_agent-B-c59NXD.js';
|
|
16
|
-
export { m as media } from './media-
|
|
16
|
+
export { m as media } from './media-CN17a3MM.js';
|
|
17
17
|
|
|
18
18
|
declare const version = "0.1.0";
|
|
19
19
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export { media_exports as media } from './chunk-
|
|
2
|
-
export { units_exports as units } from './chunk-
|
|
1
|
+
export { media_exports as media } from './chunk-Q3M23WNJ.js';
|
|
2
|
+
export { units_exports as units } from './chunk-I63BCOAG.js';
|
|
3
3
|
export { network_exports as network } from './chunk-Y5OOP6WN.js';
|
|
4
|
-
export { api_exports as api } from './chunk-
|
|
4
|
+
export { api_exports as api } from './chunk-52ZDKSIX.js';
|
|
5
5
|
export { code_exports as code } from './chunk-LXKIPPDG.js';
|
|
6
6
|
export { color_exports as color } from './chunk-BPVAB4P2.js';
|
|
7
7
|
export { css_exports as css } from './chunk-6YPV2AB5.js';
|
|
@@ -131,9 +131,40 @@ interface IcoInfoError {
|
|
|
131
131
|
* the same container format but a different type flag.
|
|
132
132
|
*/
|
|
133
133
|
declare function readIcoInfo(bytes: Uint8Array): IcoInfo | IcoInfoError;
|
|
134
|
+
interface FlacInfo {
|
|
135
|
+
sampleRate: number;
|
|
136
|
+
channels: number;
|
|
137
|
+
bitsPerSample: number;
|
|
138
|
+
totalSamples: number;
|
|
139
|
+
durationSeconds: number;
|
|
140
|
+
minBlockSize: number;
|
|
141
|
+
maxBlockSize: number;
|
|
142
|
+
minFrameSize: number;
|
|
143
|
+
maxFrameSize: number;
|
|
144
|
+
vendor?: string;
|
|
145
|
+
title?: string;
|
|
146
|
+
artist?: string;
|
|
147
|
+
album?: string;
|
|
148
|
+
date?: string;
|
|
149
|
+
genre?: string;
|
|
150
|
+
trackNumber?: string;
|
|
151
|
+
tags?: Record<string, string>;
|
|
152
|
+
}
|
|
153
|
+
interface FlacInfoError {
|
|
154
|
+
error: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Read a FLAC file's STREAMINFO metadata block (sample rate, channels, bit
|
|
158
|
+
* depth, total samples, duration) and, if present, its VORBIS_COMMENT block
|
|
159
|
+
* (vendor string and tags like ARTIST/TITLE/ALBUM), directly from the file's
|
|
160
|
+
* metadata-block headers. No audio frame decoding is performed.
|
|
161
|
+
*/
|
|
162
|
+
declare function readFlacInfo(bytes: Uint8Array): FlacInfo | FlacInfoError;
|
|
134
163
|
|
|
135
164
|
type media_ExifData = ExifData;
|
|
136
165
|
type media_ExifError = ExifError;
|
|
166
|
+
type media_FlacInfo = FlacInfo;
|
|
167
|
+
type media_FlacInfoError = FlacInfoError;
|
|
137
168
|
type media_IcoImageEntry = IcoImageEntry;
|
|
138
169
|
type media_IcoInfo = IcoInfo;
|
|
139
170
|
type media_IcoInfoError = IcoInfoError;
|
|
@@ -147,13 +178,14 @@ type media_PdfMetadataError = PdfMetadataError;
|
|
|
147
178
|
type media_WavInfo = WavInfo;
|
|
148
179
|
type media_WavInfoError = WavInfoError;
|
|
149
180
|
declare const media_readExifData: typeof readExifData;
|
|
181
|
+
declare const media_readFlacInfo: typeof readFlacInfo;
|
|
150
182
|
declare const media_readIcoInfo: typeof readIcoInfo;
|
|
151
183
|
declare const media_readId3Tags: typeof readId3Tags;
|
|
152
184
|
declare const media_readImageInfo: typeof readImageInfo;
|
|
153
185
|
declare const media_readPdfMetadata: typeof readPdfMetadata;
|
|
154
186
|
declare const media_readWavInfo: typeof readWavInfo;
|
|
155
187
|
declare namespace media {
|
|
156
|
-
export { type media_ExifData as ExifData, type media_ExifError as ExifError, type media_IcoImageEntry as IcoImageEntry, type media_IcoInfo as IcoInfo, type media_IcoInfoError as IcoInfoError, type media_Id3Tags as Id3Tags, type media_Id3TagsError as Id3TagsError, type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, type media_PdfMetadata as PdfMetadata, type media_PdfMetadataError as PdfMetadataError, type media_WavInfo as WavInfo, type media_WavInfoError as WavInfoError, media_readExifData as readExifData, media_readIcoInfo as readIcoInfo, media_readId3Tags as readId3Tags, media_readImageInfo as readImageInfo, media_readPdfMetadata as readPdfMetadata, media_readWavInfo as readWavInfo };
|
|
188
|
+
export { type media_ExifData as ExifData, type media_ExifError as ExifError, type media_FlacInfo as FlacInfo, type media_FlacInfoError as FlacInfoError, type media_IcoImageEntry as IcoImageEntry, type media_IcoInfo as IcoInfo, type media_IcoInfoError as IcoInfoError, type media_Id3Tags as Id3Tags, type media_Id3TagsError as Id3TagsError, type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, type media_PdfMetadata as PdfMetadata, type media_PdfMetadataError as PdfMetadataError, type media_WavInfo as WavInfo, type media_WavInfoError as WavInfoError, media_readExifData as readExifData, media_readFlacInfo as readFlacInfo, media_readIcoInfo as readIcoInfo, media_readId3Tags as readId3Tags, media_readImageInfo as readImageInfo, media_readPdfMetadata as readPdfMetadata, media_readWavInfo as readWavInfo };
|
|
157
189
|
}
|
|
158
190
|
|
|
159
|
-
export { type ExifData as E, type IcoImageEntry as I, type PdfMetadata as P, type WavInfo as W, type ExifError as a, type
|
|
191
|
+
export { type ExifData as E, type FlacInfo as F, type IcoImageEntry as I, type PdfMetadata as P, type WavInfo as W, type ExifError as a, type FlacInfoError as b, type IcoInfo as c, type IcoInfoError as d, type Id3Tags as e, type Id3TagsError as f, type ImageFormat as g, type ImageInfo as h, type ImageInfoError as i, type PdfMetadataError as j, type WavInfoError as k, readFlacInfo as l, media as m, readIcoInfo as n, readId3Tags as o, readImageInfo as p, readPdfMetadata as q, readExifData as r, readWavInfo as s };
|
|
@@ -131,9 +131,40 @@ interface IcoInfoError {
|
|
|
131
131
|
* the same container format but a different type flag.
|
|
132
132
|
*/
|
|
133
133
|
declare function readIcoInfo(bytes: Uint8Array): IcoInfo | IcoInfoError;
|
|
134
|
+
interface FlacInfo {
|
|
135
|
+
sampleRate: number;
|
|
136
|
+
channels: number;
|
|
137
|
+
bitsPerSample: number;
|
|
138
|
+
totalSamples: number;
|
|
139
|
+
durationSeconds: number;
|
|
140
|
+
minBlockSize: number;
|
|
141
|
+
maxBlockSize: number;
|
|
142
|
+
minFrameSize: number;
|
|
143
|
+
maxFrameSize: number;
|
|
144
|
+
vendor?: string;
|
|
145
|
+
title?: string;
|
|
146
|
+
artist?: string;
|
|
147
|
+
album?: string;
|
|
148
|
+
date?: string;
|
|
149
|
+
genre?: string;
|
|
150
|
+
trackNumber?: string;
|
|
151
|
+
tags?: Record<string, string>;
|
|
152
|
+
}
|
|
153
|
+
interface FlacInfoError {
|
|
154
|
+
error: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Read a FLAC file's STREAMINFO metadata block (sample rate, channels, bit
|
|
158
|
+
* depth, total samples, duration) and, if present, its VORBIS_COMMENT block
|
|
159
|
+
* (vendor string and tags like ARTIST/TITLE/ALBUM), directly from the file's
|
|
160
|
+
* metadata-block headers. No audio frame decoding is performed.
|
|
161
|
+
*/
|
|
162
|
+
declare function readFlacInfo(bytes: Uint8Array): FlacInfo | FlacInfoError;
|
|
134
163
|
|
|
135
164
|
type media_ExifData = ExifData;
|
|
136
165
|
type media_ExifError = ExifError;
|
|
166
|
+
type media_FlacInfo = FlacInfo;
|
|
167
|
+
type media_FlacInfoError = FlacInfoError;
|
|
137
168
|
type media_IcoImageEntry = IcoImageEntry;
|
|
138
169
|
type media_IcoInfo = IcoInfo;
|
|
139
170
|
type media_IcoInfoError = IcoInfoError;
|
|
@@ -147,13 +178,14 @@ type media_PdfMetadataError = PdfMetadataError;
|
|
|
147
178
|
type media_WavInfo = WavInfo;
|
|
148
179
|
type media_WavInfoError = WavInfoError;
|
|
149
180
|
declare const media_readExifData: typeof readExifData;
|
|
181
|
+
declare const media_readFlacInfo: typeof readFlacInfo;
|
|
150
182
|
declare const media_readIcoInfo: typeof readIcoInfo;
|
|
151
183
|
declare const media_readId3Tags: typeof readId3Tags;
|
|
152
184
|
declare const media_readImageInfo: typeof readImageInfo;
|
|
153
185
|
declare const media_readPdfMetadata: typeof readPdfMetadata;
|
|
154
186
|
declare const media_readWavInfo: typeof readWavInfo;
|
|
155
187
|
declare namespace media {
|
|
156
|
-
export { type media_ExifData as ExifData, type media_ExifError as ExifError, type media_IcoImageEntry as IcoImageEntry, type media_IcoInfo as IcoInfo, type media_IcoInfoError as IcoInfoError, type media_Id3Tags as Id3Tags, type media_Id3TagsError as Id3TagsError, type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, type media_PdfMetadata as PdfMetadata, type media_PdfMetadataError as PdfMetadataError, type media_WavInfo as WavInfo, type media_WavInfoError as WavInfoError, media_readExifData as readExifData, media_readIcoInfo as readIcoInfo, media_readId3Tags as readId3Tags, media_readImageInfo as readImageInfo, media_readPdfMetadata as readPdfMetadata, media_readWavInfo as readWavInfo };
|
|
188
|
+
export { type media_ExifData as ExifData, type media_ExifError as ExifError, type media_FlacInfo as FlacInfo, type media_FlacInfoError as FlacInfoError, type media_IcoImageEntry as IcoImageEntry, type media_IcoInfo as IcoInfo, type media_IcoInfoError as IcoInfoError, type media_Id3Tags as Id3Tags, type media_Id3TagsError as Id3TagsError, type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, type media_PdfMetadata as PdfMetadata, type media_PdfMetadataError as PdfMetadataError, type media_WavInfo as WavInfo, type media_WavInfoError as WavInfoError, media_readExifData as readExifData, media_readFlacInfo as readFlacInfo, media_readIcoInfo as readIcoInfo, media_readId3Tags as readId3Tags, media_readImageInfo as readImageInfo, media_readPdfMetadata as readPdfMetadata, media_readWavInfo as readWavInfo };
|
|
157
189
|
}
|
|
158
190
|
|
|
159
|
-
export { type ExifData as E, type IcoImageEntry as I, type PdfMetadata as P, type WavInfo as W, type ExifError as a, type
|
|
191
|
+
export { type ExifData as E, type FlacInfo as F, type IcoImageEntry as I, type PdfMetadata as P, type WavInfo as W, type ExifError as a, type FlacInfoError as b, type IcoInfo as c, type IcoInfoError as d, type Id3Tags as e, type Id3TagsError as f, type ImageFormat as g, type ImageInfo as h, type ImageInfoError as i, type PdfMetadataError as j, type WavInfoError as k, readFlacInfo as l, media as m, readIcoInfo as n, readId3Tags as o, readImageInfo as p, readPdfMetadata as q, readExifData as r, readWavInfo as s };
|
package/dist/tools/api.cjs
CHANGED
|
@@ -493,6 +493,48 @@ function parseJwks(input) {
|
|
|
493
493
|
const duplicateKids = [...kidCounts.entries()].filter(([, c]) => c > 1).map(([kid]) => kid);
|
|
494
494
|
return { ok: true, keys, count: keys.length, duplicateKids };
|
|
495
495
|
}
|
|
496
|
+
var JWK_THUMBPRINT_MEMBERS = {
|
|
497
|
+
oct: ["k", "kty"],
|
|
498
|
+
RSA: ["e", "kty", "n"],
|
|
499
|
+
EC: ["crv", "kty", "x", "y"],
|
|
500
|
+
OKP: ["crv", "kty", "x"]
|
|
501
|
+
};
|
|
502
|
+
var JWK_THUMBPRINT_NODE_HASH = {
|
|
503
|
+
"SHA-256": "sha256",
|
|
504
|
+
"SHA-384": "sha384",
|
|
505
|
+
"SHA-512": "sha512"
|
|
506
|
+
};
|
|
507
|
+
function computeJwkThumbprint(input, hashAlg = "SHA-256") {
|
|
508
|
+
const trimmed = input.trim();
|
|
509
|
+
if (!trimmed) return { ok: false, error: "No input provided" };
|
|
510
|
+
const nodeHash = JWK_THUMBPRINT_NODE_HASH[hashAlg];
|
|
511
|
+
if (!nodeHash) return { ok: false, error: 'hashAlg must be one of "SHA-256", "SHA-384", "SHA-512"' };
|
|
512
|
+
let jwk;
|
|
513
|
+
try {
|
|
514
|
+
jwk = JSON.parse(trimmed);
|
|
515
|
+
} catch (e) {
|
|
516
|
+
return { ok: false, error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` };
|
|
517
|
+
}
|
|
518
|
+
if (jwk === null || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
519
|
+
return { ok: false, error: "Input must be a single JWK object, not a JWKS set or array" };
|
|
520
|
+
}
|
|
521
|
+
const obj = jwk;
|
|
522
|
+
const kty = obj.kty;
|
|
523
|
+
if (typeof kty !== "string") return { ok: false, error: 'JWK must have a "kty" (key type) member' };
|
|
524
|
+
const members = JWK_THUMBPRINT_MEMBERS[kty];
|
|
525
|
+
if (!members) return { ok: false, error: `Unsupported key type "${kty}": supported types are RSA, EC, oct, OKP` };
|
|
526
|
+
const canonical = {};
|
|
527
|
+
for (const m of members) {
|
|
528
|
+
const v = obj[m];
|
|
529
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
530
|
+
return { ok: false, error: `JWK is missing required member "${m}" for key type "${kty}"` };
|
|
531
|
+
}
|
|
532
|
+
canonical[m] = v;
|
|
533
|
+
}
|
|
534
|
+
const canonicalJson = "{" + members.map((m) => `${JSON.stringify(m)}:${JSON.stringify(canonical[m])}`).join(",") + "}";
|
|
535
|
+
const thumbprint = crypto.createHash(nodeHash).update(canonicalJson, "utf8").digest("base64url");
|
|
536
|
+
return { ok: true, kty, hashAlg, members, canonicalJson, thumbprint };
|
|
537
|
+
}
|
|
496
538
|
var ALG_TO_NODE_HASH = {
|
|
497
539
|
HS256: "sha256",
|
|
498
540
|
HS384: "sha384",
|
|
@@ -1237,6 +1279,7 @@ exports.base64urlEncode = base64urlEncode;
|
|
|
1237
1279
|
exports.buildCurl = buildCurl;
|
|
1238
1280
|
exports.buildCurlMultiline = buildCurlMultiline;
|
|
1239
1281
|
exports.buildUrl = buildUrl;
|
|
1282
|
+
exports.computeJwkThumbprint = computeJwkThumbprint;
|
|
1240
1283
|
exports.convertToCode = convertToCode;
|
|
1241
1284
|
exports.decodeJwt = decodeJwt;
|
|
1242
1285
|
exports.decodeUrlComponent = decodeUrlComponent;
|
package/dist/tools/api.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as JwkSummary, o as
|
|
1
|
+
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as JwkSummary, o as JwkThumbprintErrorResult, p as JwkThumbprintHash, q as JwkThumbprintOutcome, r as JwkThumbprintResult, s as JwksError, t as JwksParseResult, u as JwksResult, v as JwtAlgorithm, w as JwtDecodeError, x as JwtDecodeResult, y as JwtExpiry, z as JwtPart, A as JwtResult, B as JwtSignOptions, M as MetaTags, O as OgTags, P as ParsedUrl, R as ResponseFormat, S as SUPPORTED_LANGUAGES, T as TargetLanguage, E as TwitterTags, G as addParam, I as base64urlDecode, K as base64urlEncode, L as buildCurl, N as buildCurlMultiline, Q as buildUrl, U as computeJwkThumbprint, V as convertToCode, W as decodeJwt, X as decodeUrlComponent, Y as detectFormat, Z as encodeUrlComponent, _ as extractJsonPaths, $ as formatJwtJson, a0 as formatResponse, a1 as generateCors, a2 as generateCspHeader, a3 as generateFullHeader, a4 as generateMetaHtml, a5 as getParam, a6 as getStats, a7 as isValidUrl, a8 as normalizeUrl, a9 as parseCspHeader, aa as parseCurl, ab as parseCurlCommand, ac as parseJwks, ad as parseMetaTags, ae as parseUrl, af as removeParam, ag as signJwt, ah as validateCorsConfig, ai as validateCspConfig, aj as validateOgTags } from '../api-DmTNE4c1.cjs';
|
package/dist/tools/api.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as JwkSummary, o as
|
|
1
|
+
export { C as COMMON_HEADERS, b as COMMON_PRESETS, c as CORS_COMMON_HEADERS, d as CorsConfig, e as CorsOutput, f as CspConfig, g as CspDirective, h as CspSource, i as CurlCommand, j as CurlConfig, D as DEFAULT_CORS_CONFIG, k as DIRECTIVE_DESCRIPTIONS, l as DirectiveConfig, F as FormatResult, H as HTTP_METHODS, m as Header, n as HttpMethod, J as JwkSummary, o as JwkThumbprintErrorResult, p as JwkThumbprintHash, q as JwkThumbprintOutcome, r as JwkThumbprintResult, s as JwksError, t as JwksParseResult, u as JwksResult, v as JwtAlgorithm, w as JwtDecodeError, x as JwtDecodeResult, y as JwtExpiry, z as JwtPart, A as JwtResult, B as JwtSignOptions, M as MetaTags, O as OgTags, P as ParsedUrl, R as ResponseFormat, S as SUPPORTED_LANGUAGES, T as TargetLanguage, E as TwitterTags, G as addParam, I as base64urlDecode, K as base64urlEncode, L as buildCurl, N as buildCurlMultiline, Q as buildUrl, U as computeJwkThumbprint, V as convertToCode, W as decodeJwt, X as decodeUrlComponent, Y as detectFormat, Z as encodeUrlComponent, _ as extractJsonPaths, $ as formatJwtJson, a0 as formatResponse, a1 as generateCors, a2 as generateCspHeader, a3 as generateFullHeader, a4 as generateMetaHtml, a5 as getParam, a6 as getStats, a7 as isValidUrl, a8 as normalizeUrl, a9 as parseCspHeader, aa as parseCurl, ab as parseCurlCommand, ac as parseJwks, ad as parseMetaTags, ae as parseUrl, af as removeParam, ag as signJwt, ah as validateCorsConfig, ai as validateCspConfig, aj as validateOgTags } from '../api-DmTNE4c1.js';
|
package/dist/tools/api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags } from '../chunk-
|
|
1
|
+
export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, computeJwkThumbprint, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags } from '../chunk-52ZDKSIX.js';
|
|
2
2
|
import '../chunk-MLKGABMK.js';
|
package/dist/tools/media.cjs
CHANGED
|
@@ -755,8 +755,104 @@ function readIcoInfo(bytes) {
|
|
|
755
755
|
}
|
|
756
756
|
return { imageCount: count, images };
|
|
757
757
|
}
|
|
758
|
+
var FLAC_TAG_FIELDS = {
|
|
759
|
+
TITLE: "title",
|
|
760
|
+
ARTIST: "artist",
|
|
761
|
+
ALBUM: "album",
|
|
762
|
+
DATE: "date",
|
|
763
|
+
GENRE: "genre",
|
|
764
|
+
TRACKNUMBER: "trackNumber"
|
|
765
|
+
};
|
|
766
|
+
function readU24BE(bytes, offset) {
|
|
767
|
+
return bytes[offset] << 16 | bytes[offset + 1] << 8 | bytes[offset + 2];
|
|
768
|
+
}
|
|
769
|
+
function readVorbisComment(bytes, start, end) {
|
|
770
|
+
let offset = start;
|
|
771
|
+
if (offset + 4 > end) return null;
|
|
772
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
773
|
+
const vendorLength = view.getUint32(offset, true);
|
|
774
|
+
offset += 4;
|
|
775
|
+
if (offset + vendorLength > end) return null;
|
|
776
|
+
const vendor = Buffer.from(bytes.subarray(offset, offset + vendorLength)).toString("utf8");
|
|
777
|
+
offset += vendorLength;
|
|
778
|
+
if (offset + 4 > end) return null;
|
|
779
|
+
const commentCount = view.getUint32(offset, true);
|
|
780
|
+
offset += 4;
|
|
781
|
+
const tags = {};
|
|
782
|
+
for (let i = 0; i < commentCount; i++) {
|
|
783
|
+
if (offset + 4 > end) break;
|
|
784
|
+
const commentLength = view.getUint32(offset, true);
|
|
785
|
+
offset += 4;
|
|
786
|
+
if (offset + commentLength > end) break;
|
|
787
|
+
const comment = Buffer.from(bytes.subarray(offset, offset + commentLength)).toString("utf8");
|
|
788
|
+
offset += commentLength;
|
|
789
|
+
const eq = comment.indexOf("=");
|
|
790
|
+
if (eq > 0) {
|
|
791
|
+
const key = comment.slice(0, eq).toUpperCase();
|
|
792
|
+
const value = comment.slice(eq + 1);
|
|
793
|
+
tags[key] = value;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return { vendor, tags };
|
|
797
|
+
}
|
|
798
|
+
function readFlacInfo(bytes) {
|
|
799
|
+
if (bytes.length < 4) return { error: "File is too small to be a valid FLAC file" };
|
|
800
|
+
if (readAscii4(bytes, 0) !== "fLaC") return { error: 'Not a FLAC file (missing "fLaC" marker)' };
|
|
801
|
+
let offset = 4;
|
|
802
|
+
let streamInfo = null;
|
|
803
|
+
let vorbisComment = null;
|
|
804
|
+
while (offset + 4 <= bytes.length) {
|
|
805
|
+
const header = bytes[offset];
|
|
806
|
+
const isLast = (header & 128) !== 0;
|
|
807
|
+
const blockType = header & 127;
|
|
808
|
+
const length = readU24BE(bytes, offset + 1);
|
|
809
|
+
const dataStart = offset + 4;
|
|
810
|
+
const dataEnd = dataStart + length;
|
|
811
|
+
if (dataEnd > bytes.length) return { error: "Truncated metadata block" };
|
|
812
|
+
if (blockType === 0) {
|
|
813
|
+
if (length < 34) return { error: "Truncated STREAMINFO block" };
|
|
814
|
+
const minBlockSize = bytes[dataStart] << 8 | bytes[dataStart + 1];
|
|
815
|
+
const maxBlockSize = bytes[dataStart + 2] << 8 | bytes[dataStart + 3];
|
|
816
|
+
const minFrameSize = readU24BE(bytes, dataStart + 4);
|
|
817
|
+
const maxFrameSize = readU24BE(bytes, dataStart + 7);
|
|
818
|
+
let packed = 0n;
|
|
819
|
+
for (let i = 0; i < 8; i++) packed = packed << 8n | BigInt(bytes[dataStart + 10 + i]);
|
|
820
|
+
const sampleRate = Number(packed >> 44n & 0xfffffn);
|
|
821
|
+
const channels = Number(packed >> 41n & 0x7n) + 1;
|
|
822
|
+
const bitsPerSample = Number(packed >> 36n & 0x1fn) + 1;
|
|
823
|
+
const totalSamples = Number(packed & 0xfffffffffn);
|
|
824
|
+
if (sampleRate <= 0) return { error: "Invalid sample rate in STREAMINFO block" };
|
|
825
|
+
streamInfo = {
|
|
826
|
+
sampleRate,
|
|
827
|
+
channels,
|
|
828
|
+
bitsPerSample,
|
|
829
|
+
totalSamples,
|
|
830
|
+
durationSeconds: Math.round(totalSamples / sampleRate * 1e3) / 1e3,
|
|
831
|
+
minBlockSize,
|
|
832
|
+
maxBlockSize,
|
|
833
|
+
minFrameSize,
|
|
834
|
+
maxFrameSize
|
|
835
|
+
};
|
|
836
|
+
} else if (blockType === 4) {
|
|
837
|
+
vorbisComment = readVorbisComment(bytes, dataStart, dataEnd);
|
|
838
|
+
}
|
|
839
|
+
offset = dataEnd;
|
|
840
|
+
if (isLast) break;
|
|
841
|
+
}
|
|
842
|
+
if (!streamInfo) return { error: "No STREAMINFO block found in this FLAC file" };
|
|
843
|
+
const result = { ...streamInfo };
|
|
844
|
+
if (vorbisComment) {
|
|
845
|
+
result.vendor = vorbisComment.vendor;
|
|
846
|
+
result.tags = vorbisComment.tags;
|
|
847
|
+
for (const [key, field] of Object.entries(FLAC_TAG_FIELDS)) {
|
|
848
|
+
if (vorbisComment.tags[key] !== void 0) result[field] = vorbisComment.tags[key];
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
return result;
|
|
852
|
+
}
|
|
758
853
|
|
|
759
854
|
exports.readExifData = readExifData;
|
|
855
|
+
exports.readFlacInfo = readFlacInfo;
|
|
760
856
|
exports.readIcoInfo = readIcoInfo;
|
|
761
857
|
exports.readId3Tags = readId3Tags;
|
|
762
858
|
exports.readImageInfo = readImageInfo;
|
package/dist/tools/media.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { E as ExifData, a as ExifError, I as IcoImageEntry,
|
|
1
|
+
export { E as ExifData, a as ExifError, F as FlacInfo, b as FlacInfoError, I as IcoImageEntry, c as IcoInfo, d as IcoInfoError, e as Id3Tags, f as Id3TagsError, g as ImageFormat, h as ImageInfo, i as ImageInfoError, P as PdfMetadata, j as PdfMetadataError, W as WavInfo, k as WavInfoError, r as readExifData, l as readFlacInfo, n as readIcoInfo, o as readId3Tags, p as readImageInfo, q as readPdfMetadata, s as readWavInfo } from '../media-CN17a3MM.cjs';
|
package/dist/tools/media.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { E as ExifData, a as ExifError, I as IcoImageEntry,
|
|
1
|
+
export { E as ExifData, a as ExifError, F as FlacInfo, b as FlacInfoError, I as IcoImageEntry, c as IcoInfo, d as IcoInfoError, e as Id3Tags, f as Id3TagsError, g as ImageFormat, h as ImageInfo, i as ImageInfoError, P as PdfMetadata, j as PdfMetadataError, W as WavInfo, k as WavInfoError, r as readExifData, l as readFlacInfo, n as readIcoInfo, o as readId3Tags, p as readImageInfo, q as readPdfMetadata, s as readWavInfo } from '../media-CN17a3MM.js';
|
package/dist/tools/media.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { readExifData, readIcoInfo, readId3Tags, readImageInfo, readPdfMetadata, readWavInfo } from '../chunk-
|
|
1
|
+
export { readExifData, readFlacInfo, readIcoInfo, readId3Tags, readImageInfo, readPdfMetadata, readWavInfo } from '../chunk-Q3M23WNJ.js';
|
|
2
2
|
import '../chunk-MLKGABMK.js';
|