trackparse 0.1.0 → 0.2.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/dist/index.cjs +46 -27
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +46 -27
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/data.generated.ts
|
|
4
|
-
var SPEC_VERSION = "0.
|
|
4
|
+
var SPEC_VERSION = "0.2.0";
|
|
5
5
|
var descriptorsData = {
|
|
6
6
|
"descriptors": [
|
|
7
7
|
"radio",
|
|
@@ -469,11 +469,11 @@ function isAllDigits(s) {
|
|
|
469
469
|
for (let i = 0; i < s.length; i++) if (!isDigit(s[i])) return false;
|
|
470
470
|
return true;
|
|
471
471
|
}
|
|
472
|
-
var
|
|
472
|
+
var LETTER = /^\p{L}$/u;
|
|
473
473
|
function isLetterAt(s, index) {
|
|
474
474
|
const cp = s.codePointAt(index);
|
|
475
475
|
if (cp === void 0) return false;
|
|
476
|
-
return
|
|
476
|
+
return LETTER.test(String.fromCodePoint(cp));
|
|
477
477
|
}
|
|
478
478
|
function asciiLower(s) {
|
|
479
479
|
let out = "";
|
|
@@ -705,8 +705,15 @@ function byPos(items) {
|
|
|
705
705
|
}
|
|
706
706
|
|
|
707
707
|
// src/tables.ts
|
|
708
|
+
function stringList(value) {
|
|
709
|
+
return Array.isArray(value) ? value.filter((s) => typeof s === "string") : [];
|
|
710
|
+
}
|
|
711
|
+
function stringEntries(value) {
|
|
712
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return [];
|
|
713
|
+
return Object.entries(value).filter((e) => typeof e[1] === "string");
|
|
714
|
+
}
|
|
708
715
|
function lowerKeys(list) {
|
|
709
|
-
return (list
|
|
716
|
+
return stringList(list).map((s) => asciiLower(s).trim()).filter((s) => s.length > 0);
|
|
710
717
|
}
|
|
711
718
|
function buildTables(keywords) {
|
|
712
719
|
const featMarkers = new PhraseTable(
|
|
@@ -722,7 +729,7 @@ function buildTables(keywords) {
|
|
|
722
729
|
);
|
|
723
730
|
const junkEntries = [
|
|
724
731
|
...Object.entries(junkData.phrases),
|
|
725
|
-
...
|
|
732
|
+
...stringEntries(keywords?.junk)
|
|
726
733
|
];
|
|
727
734
|
const genres = [...genresData.genres, ...lowerKeys(keywords?.genres)];
|
|
728
735
|
const junkPhrases = new PhraseTable(junkEntries);
|
|
@@ -732,7 +739,7 @@ function buildTables(keywords) {
|
|
|
732
739
|
]);
|
|
733
740
|
const headEntries = [
|
|
734
741
|
...Object.entries(versionKeywordsData.heads),
|
|
735
|
-
...
|
|
742
|
+
...stringEntries(keywords?.versionHeads)
|
|
736
743
|
];
|
|
737
744
|
const heads = new PhraseTable(headEntries);
|
|
738
745
|
const runInfo = /* @__PURE__ */ new Map();
|
|
@@ -966,7 +973,7 @@ function normalize(input) {
|
|
|
966
973
|
|
|
967
974
|
// src/context.ts
|
|
968
975
|
function makeCtx(t, options) {
|
|
969
|
-
const known = (options?.knownArtists
|
|
976
|
+
const known = stringList(options?.knownArtists);
|
|
970
977
|
const knownKeys = new Set(known.map(dedupKey).filter((k) => k.length > 0));
|
|
971
978
|
const knownMaxLen = known.reduce((m, k) => Math.max(m, k.length), 0);
|
|
972
979
|
const splitAnd = options?.splitAnd ?? "auto";
|
|
@@ -2088,21 +2095,28 @@ function extractUnbracketedCredits(input, out, ctx) {
|
|
|
2088
2095
|
return skel;
|
|
2089
2096
|
}
|
|
2090
2097
|
function stripTrailingJunk(input, out, ctx) {
|
|
2091
|
-
|
|
2098
|
+
const skel = trimSkel(input);
|
|
2099
|
+
const spans = wordSpans(skel.text);
|
|
2100
|
+
const words = spans.map((s) => s.text);
|
|
2101
|
+
let end = spans.length;
|
|
2092
2102
|
for (; ; ) {
|
|
2093
|
-
const
|
|
2094
|
-
if (!
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
if (
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2103
|
+
const m = ctx.t.junkPhrases.matchEnding(words, end);
|
|
2104
|
+
if (!m) break;
|
|
2105
|
+
const first = end - m.length;
|
|
2106
|
+
let keep = first;
|
|
2107
|
+
if (keep > 0 && isLoneEdge(words[keep - 1])) keep--;
|
|
2108
|
+
if (keep === 0) break;
|
|
2109
|
+
const from = spans[first]?.start ?? 0;
|
|
2110
|
+
const to = spans[end - 1]?.end ?? skel.text.length;
|
|
2111
|
+
out.junk.push({
|
|
2112
|
+
raw: collapseSpaces(skel.text.slice(from, to)),
|
|
2113
|
+
kind: m.entry.value,
|
|
2114
|
+
pos: skel.pos[from] ?? 0
|
|
2115
|
+
});
|
|
2116
|
+
end = keep;
|
|
2105
2117
|
}
|
|
2118
|
+
if (end === spans.length) return skel;
|
|
2119
|
+
return trimSkel(sliceSkel(skel, 0, spans[end - 1]?.end ?? 0));
|
|
2106
2120
|
}
|
|
2107
2121
|
function isLoneEdge(word) {
|
|
2108
2122
|
return word === "-" || word === "|";
|
|
@@ -2242,16 +2256,21 @@ function createParser(base = {}) {
|
|
|
2242
2256
|
};
|
|
2243
2257
|
}
|
|
2244
2258
|
function mergeKeywords(a, b) {
|
|
2245
|
-
const x = a.keywords
|
|
2246
|
-
const y = b.keywords
|
|
2259
|
+
const x = isRecord(a.keywords) ? a.keywords : {};
|
|
2260
|
+
const y = isRecord(b.keywords) ? b.keywords : {};
|
|
2261
|
+
const map = (k) => Object.fromEntries([...stringEntries(x[k]), ...stringEntries(y[k])]);
|
|
2262
|
+
const list = (k) => [...stringList(x[k]), ...stringList(y[k])];
|
|
2247
2263
|
return {
|
|
2248
|
-
versionHeads:
|
|
2249
|
-
descriptors:
|
|
2250
|
-
genres:
|
|
2251
|
-
junk:
|
|
2252
|
-
featMarkers:
|
|
2264
|
+
versionHeads: map("versionHeads"),
|
|
2265
|
+
descriptors: list("descriptors"),
|
|
2266
|
+
genres: list("genres"),
|
|
2267
|
+
junk: map("junk"),
|
|
2268
|
+
featMarkers: list("featMarkers")
|
|
2253
2269
|
};
|
|
2254
2270
|
}
|
|
2271
|
+
function isRecord(v) {
|
|
2272
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2273
|
+
}
|
|
2255
2274
|
var defaultParser = createParser();
|
|
2256
2275
|
function parse(input, options) {
|
|
2257
2276
|
return defaultParser.parse(input, options);
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/data.generated.ts
|
|
2
|
-
var SPEC_VERSION = "0.
|
|
2
|
+
var SPEC_VERSION = "0.2.0";
|
|
3
3
|
var descriptorsData = {
|
|
4
4
|
"descriptors": [
|
|
5
5
|
"radio",
|
|
@@ -467,11 +467,11 @@ function isAllDigits(s) {
|
|
|
467
467
|
for (let i = 0; i < s.length; i++) if (!isDigit(s[i])) return false;
|
|
468
468
|
return true;
|
|
469
469
|
}
|
|
470
|
-
var
|
|
470
|
+
var LETTER = /^\p{L}$/u;
|
|
471
471
|
function isLetterAt(s, index) {
|
|
472
472
|
const cp = s.codePointAt(index);
|
|
473
473
|
if (cp === void 0) return false;
|
|
474
|
-
return
|
|
474
|
+
return LETTER.test(String.fromCodePoint(cp));
|
|
475
475
|
}
|
|
476
476
|
function asciiLower(s) {
|
|
477
477
|
let out = "";
|
|
@@ -703,8 +703,15 @@ function byPos(items) {
|
|
|
703
703
|
}
|
|
704
704
|
|
|
705
705
|
// src/tables.ts
|
|
706
|
+
function stringList(value) {
|
|
707
|
+
return Array.isArray(value) ? value.filter((s) => typeof s === "string") : [];
|
|
708
|
+
}
|
|
709
|
+
function stringEntries(value) {
|
|
710
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return [];
|
|
711
|
+
return Object.entries(value).filter((e) => typeof e[1] === "string");
|
|
712
|
+
}
|
|
706
713
|
function lowerKeys(list) {
|
|
707
|
-
return (list
|
|
714
|
+
return stringList(list).map((s) => asciiLower(s).trim()).filter((s) => s.length > 0);
|
|
708
715
|
}
|
|
709
716
|
function buildTables(keywords) {
|
|
710
717
|
const featMarkers = new PhraseTable(
|
|
@@ -720,7 +727,7 @@ function buildTables(keywords) {
|
|
|
720
727
|
);
|
|
721
728
|
const junkEntries = [
|
|
722
729
|
...Object.entries(junkData.phrases),
|
|
723
|
-
...
|
|
730
|
+
...stringEntries(keywords?.junk)
|
|
724
731
|
];
|
|
725
732
|
const genres = [...genresData.genres, ...lowerKeys(keywords?.genres)];
|
|
726
733
|
const junkPhrases = new PhraseTable(junkEntries);
|
|
@@ -730,7 +737,7 @@ function buildTables(keywords) {
|
|
|
730
737
|
]);
|
|
731
738
|
const headEntries = [
|
|
732
739
|
...Object.entries(versionKeywordsData.heads),
|
|
733
|
-
...
|
|
740
|
+
...stringEntries(keywords?.versionHeads)
|
|
734
741
|
];
|
|
735
742
|
const heads = new PhraseTable(headEntries);
|
|
736
743
|
const runInfo = /* @__PURE__ */ new Map();
|
|
@@ -964,7 +971,7 @@ function normalize(input) {
|
|
|
964
971
|
|
|
965
972
|
// src/context.ts
|
|
966
973
|
function makeCtx(t, options) {
|
|
967
|
-
const known = (options?.knownArtists
|
|
974
|
+
const known = stringList(options?.knownArtists);
|
|
968
975
|
const knownKeys = new Set(known.map(dedupKey).filter((k) => k.length > 0));
|
|
969
976
|
const knownMaxLen = known.reduce((m, k) => Math.max(m, k.length), 0);
|
|
970
977
|
const splitAnd = options?.splitAnd ?? "auto";
|
|
@@ -2086,21 +2093,28 @@ function extractUnbracketedCredits(input, out, ctx) {
|
|
|
2086
2093
|
return skel;
|
|
2087
2094
|
}
|
|
2088
2095
|
function stripTrailingJunk(input, out, ctx) {
|
|
2089
|
-
|
|
2096
|
+
const skel = trimSkel(input);
|
|
2097
|
+
const spans = wordSpans(skel.text);
|
|
2098
|
+
const words = spans.map((s) => s.text);
|
|
2099
|
+
let end = spans.length;
|
|
2090
2100
|
for (; ; ) {
|
|
2091
|
-
const
|
|
2092
|
-
if (!
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
if (
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2101
|
+
const m = ctx.t.junkPhrases.matchEnding(words, end);
|
|
2102
|
+
if (!m) break;
|
|
2103
|
+
const first = end - m.length;
|
|
2104
|
+
let keep = first;
|
|
2105
|
+
if (keep > 0 && isLoneEdge(words[keep - 1])) keep--;
|
|
2106
|
+
if (keep === 0) break;
|
|
2107
|
+
const from = spans[first]?.start ?? 0;
|
|
2108
|
+
const to = spans[end - 1]?.end ?? skel.text.length;
|
|
2109
|
+
out.junk.push({
|
|
2110
|
+
raw: collapseSpaces(skel.text.slice(from, to)),
|
|
2111
|
+
kind: m.entry.value,
|
|
2112
|
+
pos: skel.pos[from] ?? 0
|
|
2113
|
+
});
|
|
2114
|
+
end = keep;
|
|
2103
2115
|
}
|
|
2116
|
+
if (end === spans.length) return skel;
|
|
2117
|
+
return trimSkel(sliceSkel(skel, 0, spans[end - 1]?.end ?? 0));
|
|
2104
2118
|
}
|
|
2105
2119
|
function isLoneEdge(word) {
|
|
2106
2120
|
return word === "-" || word === "|";
|
|
@@ -2240,16 +2254,21 @@ function createParser(base = {}) {
|
|
|
2240
2254
|
};
|
|
2241
2255
|
}
|
|
2242
2256
|
function mergeKeywords(a, b) {
|
|
2243
|
-
const x = a.keywords
|
|
2244
|
-
const y = b.keywords
|
|
2257
|
+
const x = isRecord(a.keywords) ? a.keywords : {};
|
|
2258
|
+
const y = isRecord(b.keywords) ? b.keywords : {};
|
|
2259
|
+
const map = (k) => Object.fromEntries([...stringEntries(x[k]), ...stringEntries(y[k])]);
|
|
2260
|
+
const list = (k) => [...stringList(x[k]), ...stringList(y[k])];
|
|
2245
2261
|
return {
|
|
2246
|
-
versionHeads:
|
|
2247
|
-
descriptors:
|
|
2248
|
-
genres:
|
|
2249
|
-
junk:
|
|
2250
|
-
featMarkers:
|
|
2262
|
+
versionHeads: map("versionHeads"),
|
|
2263
|
+
descriptors: list("descriptors"),
|
|
2264
|
+
genres: list("genres"),
|
|
2265
|
+
junk: map("junk"),
|
|
2266
|
+
featMarkers: list("featMarkers")
|
|
2251
2267
|
};
|
|
2252
2268
|
}
|
|
2269
|
+
function isRecord(v) {
|
|
2270
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2271
|
+
}
|
|
2253
2272
|
var defaultParser = createParser();
|
|
2254
2273
|
function parse(input, options) {
|
|
2255
2274
|
return defaultParser.parse(input, options);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trackparse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Spec-driven parser for music track strings: artists, feat credits, remixes/versions, junk and more from single track strings (store titles, YouTube titles, filenames).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Maksim Maksimov",
|