@gondola-lyrics/kit 0.4.0 → 0.5.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/formats.d.ts +109 -4
- package/dist/formats.js +1180 -264
- package/dist/formats.js.map +1 -1
- package/dist/generator.d.ts +7 -3
- package/dist/index.d.ts +154 -4
- package/dist/index.js +3 -3
- package/dist/language.js +117 -0
- package/dist/language.js.map +1 -0
- package/dist/parser.d.ts +148 -2
- package/dist/parser.js +3 -3
- package/dist/transforms.d.ts +87 -0
- package/dist/transforms.js +2291 -32
- package/dist/transforms.js.map +1 -1
- package/package.json +1 -1
package/dist/transforms.js
CHANGED
|
@@ -1,20 +1,219 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { i as mapShared, t as findScriptRunEnd } from "./language.js";
|
|
2
|
+
import { AgentType, CreditRole, LineType, Timing, WordType, deriveLanguageUsages, getContentText, isWordLevelLine, makeAgent, makeLineAnnotation, makeLineAnnotationRoman, makeLineAnnotationTranslation, makeLineBackground, makeLineContentText, makeLineContentWords, makeLineInstrumental, makeMeta, makeMetaCredit, makeText, makeTimeRange, makeWordEmphasis, makeWordSpace, validateTimeRange } from "@gondola-lyrics/model/runtime";
|
|
3
|
+
//#region src/utils/rules.ts
|
|
4
|
+
var RULE_WHITESPACE = /[\u0009-\u000D\u0020\u0085\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]/g;
|
|
5
|
+
var RULE_EDGE_WHITESPACE = /^[\u0009-\u000D\u0020\u0085\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+|[\u0009-\u000D\u0020\u0085\u00A0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+$/g;
|
|
3
6
|
/**
|
|
4
|
-
*
|
|
7
|
+
* Uses the shared whitespace set and ASCII case folding to keep matching consistent across language kits.
|
|
8
|
+
*/
|
|
9
|
+
var toRuleMatchKey = (text) => {
|
|
10
|
+
return text.replace(RULE_WHITESPACE, "").replace(/[A-Z]+/g, (run) => run.toLowerCase());
|
|
11
|
+
};
|
|
12
|
+
var RULE_WHITESPACE_CHARACTER = new RegExp(RULE_WHITESPACE.source);
|
|
13
|
+
/**
|
|
14
|
+
* Finds the offsets in toRuleMatchKey(text) where the source allows a cut.
|
|
15
|
+
* A cut sits before the first kept character of a script run and after configured whitespace, so neutral punctuation never splits aliases such as A&R or Co-Producer.
|
|
5
16
|
*
|
|
6
|
-
*
|
|
17
|
+
* @param text A source label with its original spelling.
|
|
18
|
+
*
|
|
19
|
+
* @returns Ascending offsets from 0 to the key length, or undefined when the source has no inner cut.
|
|
7
20
|
*/
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
var findRuleMatchCuts = (text) => {
|
|
22
|
+
if (!RULE_WHITESPACE_CHARACTER.test(text) && findScriptRunEnd(text) === text.length) return;
|
|
23
|
+
const cuts = [0];
|
|
24
|
+
let length = 0;
|
|
25
|
+
let pendingCut = false;
|
|
26
|
+
let runStart = 0;
|
|
27
|
+
while (runStart < text.length) {
|
|
28
|
+
const runEnd = findScriptRunEnd(text, runStart);
|
|
29
|
+
if (runStart > 0) pendingCut = true;
|
|
30
|
+
for (const character of text.slice(runStart, runEnd)) {
|
|
31
|
+
if (RULE_WHITESPACE_CHARACTER.test(character)) {
|
|
32
|
+
pendingCut = true;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (pendingCut) {
|
|
36
|
+
if (length > 0) cuts.push(length);
|
|
37
|
+
pendingCut = false;
|
|
38
|
+
}
|
|
39
|
+
length += character.length;
|
|
15
40
|
}
|
|
41
|
+
runStart = runEnd;
|
|
16
42
|
}
|
|
17
|
-
return
|
|
43
|
+
if (cuts.length === 1) return;
|
|
44
|
+
cuts.push(length);
|
|
45
|
+
return cuts;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Preserves internal whitespace so source labels and credited names retain their spelling.
|
|
49
|
+
*/
|
|
50
|
+
var trimRuleWhitespace = (text) => text.replace(RULE_EDGE_WHITESPACE, "");
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/transforms/agent/extract.ts
|
|
53
|
+
var hashName = (name) => {
|
|
54
|
+
let hash = 0;
|
|
55
|
+
for (let index = 0; index < name.length; index += 1) hash = (hash << 5) - hash + name.charCodeAt(index) | 0;
|
|
56
|
+
return (hash >>> 0).toString(16).padStart(8, "0").toUpperCase();
|
|
57
|
+
};
|
|
58
|
+
var haveSameAgents = (first, second) => {
|
|
59
|
+
return first.length === second.length && first.every((id, index) => id === second[index]);
|
|
60
|
+
};
|
|
61
|
+
var prepareBindings = (bindings, agents) => {
|
|
62
|
+
if (!bindings) return;
|
|
63
|
+
const knownIds = new Set(agents.map((agent) => agent.id));
|
|
64
|
+
return new Map(Object.entries(bindings).map(([prefix, target]) => {
|
|
65
|
+
const ids = [...new Set(typeof target === "string" ? [target] : target)];
|
|
66
|
+
const missingId = ids.find((id) => !knownIds.has(id));
|
|
67
|
+
if (missingId !== void 0) throw new TypeError(`binding for ${JSON.stringify(prefix)} references unknown agent id ${JSON.stringify(missingId)}`);
|
|
68
|
+
return [prefix.trim(), ids];
|
|
69
|
+
}));
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Retains the legacy clock exclusion, including its accepted hour and minute bounds.
|
|
73
|
+
*/
|
|
74
|
+
var isClockTimeColon = (before, after) => {
|
|
75
|
+
const hour = /(\d+)$/.exec(before)?.[1];
|
|
76
|
+
const minute = /^(\d+)/.exec(after)?.[1];
|
|
77
|
+
if (!hour || !minute) return false;
|
|
78
|
+
return hour.length <= 2 && Number(hour) <= 24 && minute.length <= 2 && Number(minute) <= 60;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Cuts only source text, so retained word ranges and annotations do not need fabricated character timings.
|
|
82
|
+
*/
|
|
83
|
+
var removePrefix = (content, length) => {
|
|
84
|
+
if (!content) return;
|
|
85
|
+
if (content.text !== void 0) {
|
|
86
|
+
const text = content.text.slice(length).trim();
|
|
87
|
+
return text ? makeLineContentText(text) : void 0;
|
|
88
|
+
}
|
|
89
|
+
const words = [];
|
|
90
|
+
let remaining = length;
|
|
91
|
+
for (const word of content.words) {
|
|
92
|
+
if (remaining >= word.text.length) {
|
|
93
|
+
remaining -= word.text.length;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (remaining > 0) {
|
|
97
|
+
const text = word.text.slice(remaining).trim();
|
|
98
|
+
remaining = 0;
|
|
99
|
+
if (text) words.push({
|
|
100
|
+
...word,
|
|
101
|
+
text
|
|
102
|
+
});
|
|
103
|
+
} else words.push(word);
|
|
104
|
+
}
|
|
105
|
+
return words.some((word) => !!word.text.trim()) ? makeLineContentWords(words) : void 0;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Extracts colon-prefixed performers and carries them across nonempty normal lines, replacing their existing agent lists.
|
|
109
|
+
* Missing bindings enables legacy name inference; supplied bindings accept exact prefixes and reset propagation on unmatched prefixes.
|
|
110
|
+
* Removing prefixes preserves retained line and word times, but drops prefix-only lines with their attached content.
|
|
111
|
+
*
|
|
112
|
+
* @returns The input when unchanged, or a new lyric sharing all unchanged nodes.
|
|
113
|
+
*
|
|
114
|
+
* @throws {TypeError} If bindings reference an agent id absent from lyric.agents.
|
|
115
|
+
*/
|
|
116
|
+
var extractAgents = (lyric, options = {}) => {
|
|
117
|
+
const bindings = prepareBindings(options.bindings, lyric.agents);
|
|
118
|
+
if (bindings?.size === 0 || !lyric.lines.length) return lyric;
|
|
119
|
+
const removePrefixes = options.removePrefixes ?? true;
|
|
120
|
+
const usedIds = new Set(lyric.agents.map((agent) => agent.id));
|
|
121
|
+
const names = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const agent of lyric.agents) {
|
|
123
|
+
if (!agent.id) continue;
|
|
124
|
+
for (const item of agent.names) {
|
|
125
|
+
const name = item.text.trim();
|
|
126
|
+
if (!name) continue;
|
|
127
|
+
if (!names.has(name)) names.set(name, agent.id);
|
|
128
|
+
else if (names.get(name) !== agent.id) names.set(name, null);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
let agents = lyric.agents;
|
|
132
|
+
const resolveName = (name) => {
|
|
133
|
+
const existing = names.get(name);
|
|
134
|
+
if (existing) return [existing];
|
|
135
|
+
const base = hashName(name);
|
|
136
|
+
let id = base;
|
|
137
|
+
for (let suffix = 1; usedIds.has(id); suffix += 1) id = `${base}-${suffix}`;
|
|
138
|
+
const agent = makeAgent({
|
|
139
|
+
id,
|
|
140
|
+
type: AgentType.PERSON,
|
|
141
|
+
names: [makeText({ text: name })]
|
|
142
|
+
});
|
|
143
|
+
if (agents === lyric.agents) agents = [...agents];
|
|
144
|
+
agents.push(agent);
|
|
145
|
+
usedIds.add(id);
|
|
146
|
+
names.set(name, id);
|
|
147
|
+
return [id];
|
|
148
|
+
};
|
|
149
|
+
const originalLines = lyric.lines;
|
|
150
|
+
let lines;
|
|
151
|
+
let current;
|
|
152
|
+
let contentChanged = false;
|
|
153
|
+
for (const [index, line] of originalLines.entries()) {
|
|
154
|
+
const text = line.type === LineType.NORMAL ? getContentText(line.content) : "";
|
|
155
|
+
if (line.type !== LineType.NORMAL || !text.trim()) {
|
|
156
|
+
current = void 0;
|
|
157
|
+
lines?.push(line);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const colon = text.search(/[::]/u);
|
|
161
|
+
let matched = false;
|
|
162
|
+
if (colon !== -1) {
|
|
163
|
+
const name = text.slice(0, colon).trim();
|
|
164
|
+
if (bindings) {
|
|
165
|
+
const target = bindings.get(name);
|
|
166
|
+
if (!target) {
|
|
167
|
+
current = void 0;
|
|
168
|
+
lines?.push(line);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
current = target;
|
|
172
|
+
matched = true;
|
|
173
|
+
} else if (!isClockTimeColon(text.slice(0, colon), text.slice(colon + 1))) {
|
|
174
|
+
if (!name) {
|
|
175
|
+
current = void 0;
|
|
176
|
+
lines?.push(line);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
current = resolveName(name);
|
|
180
|
+
matched = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
let content = line.content;
|
|
184
|
+
if (matched && removePrefixes) {
|
|
185
|
+
content = removePrefix(content, colon + 1);
|
|
186
|
+
contentChanged = true;
|
|
187
|
+
if (!content) {
|
|
188
|
+
lines ??= originalLines.slice(0, index);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const nextAgents = current && !haveSameAgents(line.agents, current) ? [...current] : line.agents;
|
|
193
|
+
if (content !== line.content || nextAgents !== line.agents) {
|
|
194
|
+
lines ??= originalLines.slice(0, index);
|
|
195
|
+
lines.push({
|
|
196
|
+
...line,
|
|
197
|
+
content,
|
|
198
|
+
agents: nextAgents
|
|
199
|
+
});
|
|
200
|
+
} else lines?.push(line);
|
|
201
|
+
}
|
|
202
|
+
if (!lines && agents === lyric.agents) return lyric;
|
|
203
|
+
const remainingLines = lines ?? originalLines;
|
|
204
|
+
let timing = lyric.timing;
|
|
205
|
+
if (contentChanged && timing === Timing.WORD) {
|
|
206
|
+
if (!remainingLines.some((line) => {
|
|
207
|
+
return isWordLevelLine(line) || line.backgrounds.some(isWordLevelLine);
|
|
208
|
+
})) timing = Timing.LINE;
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
...lyric,
|
|
212
|
+
agents,
|
|
213
|
+
lines: remainingLines,
|
|
214
|
+
timing,
|
|
215
|
+
languages: contentChanged ? deriveLanguageUsages(remainingLines) : lyric.languages
|
|
216
|
+
};
|
|
18
217
|
};
|
|
19
218
|
//#endregion
|
|
20
219
|
//#region src/transforms/background/utils.ts
|
|
@@ -175,7 +374,7 @@ var splitText = (text) => {
|
|
|
175
374
|
return {
|
|
176
375
|
main: main.trim().replaceAll(/\s{2,}/gu, " "),
|
|
177
376
|
runs: runs.filter((run) => {
|
|
178
|
-
return run.text.trim()
|
|
377
|
+
return !!run.text.trim();
|
|
179
378
|
}),
|
|
180
379
|
length: chars.length
|
|
181
380
|
};
|
|
@@ -247,13 +446,13 @@ var splitWords = (words) => {
|
|
|
247
446
|
main,
|
|
248
447
|
runs: runs.filter((run) => {
|
|
249
448
|
return run.some((word) => {
|
|
250
|
-
return word.text.trim()
|
|
449
|
+
return !!word.text.trim();
|
|
251
450
|
});
|
|
252
451
|
})
|
|
253
452
|
};
|
|
254
453
|
};
|
|
255
454
|
var mapSpan = (range, length, run) => {
|
|
256
|
-
if (range.end === void 0 || length
|
|
455
|
+
if (range.end === void 0 || !length) return makeTimeRange({
|
|
257
456
|
start: range.start,
|
|
258
457
|
end: range.end
|
|
259
458
|
});
|
|
@@ -270,7 +469,7 @@ var mapSpan = (range, length, run) => {
|
|
|
270
469
|
*/
|
|
271
470
|
var readWordRange = (words, fallback) => {
|
|
272
471
|
const timed = words.filter((word) => {
|
|
273
|
-
return isNormalWord(word) && word.time
|
|
472
|
+
return isNormalWord(word) && !!word.time;
|
|
274
473
|
});
|
|
275
474
|
const first = timed[0]?.time;
|
|
276
475
|
const last = timed.at(-1)?.time;
|
|
@@ -316,7 +515,7 @@ var boundOpenBackgrounds = (lines) => {
|
|
|
316
515
|
const last = lines.length - 1;
|
|
317
516
|
return lines.map((line, index) => {
|
|
318
517
|
if (!line.backgrounds.filter((background) => {
|
|
319
|
-
return background.time
|
|
518
|
+
return !!background.time && background.time.end === void 0;
|
|
320
519
|
}).length) return line;
|
|
321
520
|
if (index === last) return line.time ? {
|
|
322
521
|
...line,
|
|
@@ -428,7 +627,7 @@ var toBackground = (line, time, wordLevel) => {
|
|
|
428
627
|
var isBracketOnlyLine = (line) => {
|
|
429
628
|
if (!line || line.type !== LineType.NORMAL) return false;
|
|
430
629
|
const { main, runs } = splitText(readLineText(line));
|
|
431
|
-
return runs.length
|
|
630
|
+
return !!runs.length && !main;
|
|
432
631
|
};
|
|
433
632
|
/**
|
|
434
633
|
* A line that held nothing but brackets has no text of its own to sing, so it cannot be the one a background accompanies.
|
|
@@ -457,8 +656,8 @@ var joinCrossLine = (lines, wordLevel) => {
|
|
|
457
656
|
if (line.type === LineType.NORMAL && next?.type === LineType.NORMAL && parentIndex !== -1) {
|
|
458
657
|
const opened = splitText(readLineText(line));
|
|
459
658
|
const closed = splitText(readLineText(next));
|
|
460
|
-
const opens = opened.runs.length
|
|
461
|
-
const closes = closed.runs.length
|
|
659
|
+
const opens = !opened.runs.length && isOpenBracket(opened.main.charAt(0));
|
|
660
|
+
const closes = !closed.runs.length && isCloseBracket(closed.main.charAt(closed.main.length - 1));
|
|
462
661
|
if (opens && closes) {
|
|
463
662
|
const start = line.time?.start;
|
|
464
663
|
const end = next.time?.end ?? next.time?.start;
|
|
@@ -556,15 +755,1823 @@ var extractBackgroundLines = (lyric, options = {}) => {
|
|
|
556
755
|
languages: deriveLanguageUsages(lines)
|
|
557
756
|
};
|
|
558
757
|
};
|
|
758
|
+
var en_default$1 = {
|
|
759
|
+
$schema: "../schema.json",
|
|
760
|
+
version: 1,
|
|
761
|
+
language: "en",
|
|
762
|
+
normalization: {
|
|
763
|
+
"whitespace": "remove",
|
|
764
|
+
"case": "asciiLower"
|
|
765
|
+
},
|
|
766
|
+
groups: [
|
|
767
|
+
{
|
|
768
|
+
"id": "lyricist",
|
|
769
|
+
"kind": "role",
|
|
770
|
+
"roles": ["LYRICIST"],
|
|
771
|
+
"words": [
|
|
772
|
+
"Lyrics",
|
|
773
|
+
"Lyricsby",
|
|
774
|
+
"Lyricist",
|
|
775
|
+
"Words",
|
|
776
|
+
"Wordsby",
|
|
777
|
+
"Lyric",
|
|
778
|
+
"Lyr",
|
|
779
|
+
"Lyricists",
|
|
780
|
+
"Lyricwriting"
|
|
781
|
+
]
|
|
782
|
+
},
|
|
783
|
+
{
|
|
784
|
+
"id": "composer",
|
|
785
|
+
"kind": "role",
|
|
786
|
+
"roles": ["COMPOSER"],
|
|
787
|
+
"words": [
|
|
788
|
+
"Music",
|
|
789
|
+
"Musicby",
|
|
790
|
+
"Composer",
|
|
791
|
+
"Composedby",
|
|
792
|
+
"Compose",
|
|
793
|
+
"Composition",
|
|
794
|
+
"Melody",
|
|
795
|
+
"Melodyby",
|
|
796
|
+
"Comp",
|
|
797
|
+
"Composers",
|
|
798
|
+
"Score",
|
|
799
|
+
"Scoredby",
|
|
800
|
+
"Composed"
|
|
801
|
+
]
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
"id": "arranger",
|
|
805
|
+
"kind": "role",
|
|
806
|
+
"roles": ["ARRANGER"],
|
|
807
|
+
"words": [
|
|
808
|
+
"Arrangement",
|
|
809
|
+
"Arranger",
|
|
810
|
+
"Arrangedby",
|
|
811
|
+
"Arranged",
|
|
812
|
+
"Arrange",
|
|
813
|
+
"Arr",
|
|
814
|
+
"Orchestration",
|
|
815
|
+
"StringArrangement",
|
|
816
|
+
"VocalArrangement",
|
|
817
|
+
"ChoirArrangement",
|
|
818
|
+
"Orchestrator",
|
|
819
|
+
"Orchestratedby",
|
|
820
|
+
"Orch",
|
|
821
|
+
"AdditionalArrangement",
|
|
822
|
+
"BGVsArranger",
|
|
823
|
+
"BVArranger",
|
|
824
|
+
"BackgroundVocalArrangement",
|
|
825
|
+
"BackgroundVocalsArrangement",
|
|
826
|
+
"BackingVocalsArranger",
|
|
827
|
+
"BackingVocalArrangement",
|
|
828
|
+
"BackingVocalsArrangement",
|
|
829
|
+
"BrassArrangement",
|
|
830
|
+
"HornArrangement",
|
|
831
|
+
"OrchestralArrangement",
|
|
832
|
+
"RhythmArrangement",
|
|
833
|
+
"StringArrangedby",
|
|
834
|
+
"StringArranger",
|
|
835
|
+
"VocalArrangedby",
|
|
836
|
+
"VocalArranger"
|
|
837
|
+
]
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
"id": "producer",
|
|
841
|
+
"kind": "role",
|
|
842
|
+
"roles": ["PRODUCER"],
|
|
843
|
+
"words": [
|
|
844
|
+
"Producer",
|
|
845
|
+
"Producedby",
|
|
846
|
+
"Produced",
|
|
847
|
+
"Production",
|
|
848
|
+
"Prod",
|
|
849
|
+
"Prodby",
|
|
850
|
+
"Producers",
|
|
851
|
+
"Produce",
|
|
852
|
+
"CoProducer",
|
|
853
|
+
"Co-Producer",
|
|
854
|
+
"ExecutiveProducer",
|
|
855
|
+
"AdditionalProducer",
|
|
856
|
+
"AdditionalProduction",
|
|
857
|
+
"VocalProducer",
|
|
858
|
+
"MusicProducer",
|
|
859
|
+
"AssociateProducer",
|
|
860
|
+
"Co-Produced",
|
|
861
|
+
"Co-Producedby",
|
|
862
|
+
"Co-Production",
|
|
863
|
+
"Co-Productionby",
|
|
864
|
+
"CoProd",
|
|
865
|
+
"Coproduction",
|
|
866
|
+
"CreativeProducer",
|
|
867
|
+
"ExProd",
|
|
868
|
+
"ExecProducer",
|
|
869
|
+
"ExecutiveProducers",
|
|
870
|
+
"Productionby",
|
|
871
|
+
"VocalProduction",
|
|
872
|
+
"MusicSupervisor",
|
|
873
|
+
"Supervisor",
|
|
874
|
+
"Presentedby",
|
|
875
|
+
"Presenter"
|
|
876
|
+
]
|
|
877
|
+
},
|
|
878
|
+
{
|
|
879
|
+
"id": "performer",
|
|
880
|
+
"kind": "role",
|
|
881
|
+
"roles": ["PERFORMER"],
|
|
882
|
+
"words": [
|
|
883
|
+
"Vocals",
|
|
884
|
+
"Vocal",
|
|
885
|
+
"Vocalist",
|
|
886
|
+
"Singer",
|
|
887
|
+
"Voice",
|
|
888
|
+
"Performer",
|
|
889
|
+
"Featuring",
|
|
890
|
+
"Feat",
|
|
891
|
+
"Ft",
|
|
892
|
+
"Artist",
|
|
893
|
+
"Vocalsby",
|
|
894
|
+
"Sungby",
|
|
895
|
+
"Performedby",
|
|
896
|
+
"Performed",
|
|
897
|
+
"LeadVocal",
|
|
898
|
+
"LeadVocals",
|
|
899
|
+
"BackgroundVocals",
|
|
900
|
+
"BackingVocals",
|
|
901
|
+
"Harmony",
|
|
902
|
+
"Choir",
|
|
903
|
+
"Band",
|
|
904
|
+
"Rap",
|
|
905
|
+
"Rapper",
|
|
906
|
+
"Soloist",
|
|
907
|
+
"Musician",
|
|
908
|
+
"Player",
|
|
909
|
+
"GuestVocals",
|
|
910
|
+
"FeaturedArtist",
|
|
911
|
+
"Narrator",
|
|
912
|
+
"Guitarist",
|
|
913
|
+
"Bassist",
|
|
914
|
+
"Pianist",
|
|
915
|
+
"Drummer",
|
|
916
|
+
"Keyboardist",
|
|
917
|
+
"Violinist",
|
|
918
|
+
"Cellist",
|
|
919
|
+
"Accompaniment",
|
|
920
|
+
"Accompanist",
|
|
921
|
+
"Accordionist",
|
|
922
|
+
"Ad-lib",
|
|
923
|
+
"Ad-libs",
|
|
924
|
+
"AdditionalVocals",
|
|
925
|
+
"Adlib",
|
|
926
|
+
"Adlibs",
|
|
927
|
+
"Allvocals",
|
|
928
|
+
"Allvocalsby",
|
|
929
|
+
"BGV",
|
|
930
|
+
"BGVs",
|
|
931
|
+
"BGs",
|
|
932
|
+
"BV",
|
|
933
|
+
"BackgroundVocal",
|
|
934
|
+
"BackingVocal",
|
|
935
|
+
"Banjoist",
|
|
936
|
+
"Beatbox",
|
|
937
|
+
"Beatboxer",
|
|
938
|
+
"Bvox",
|
|
939
|
+
"CV",
|
|
940
|
+
"ChildrenVoice",
|
|
941
|
+
"Clarinetist",
|
|
942
|
+
"Contrabassist",
|
|
943
|
+
"CoverSong",
|
|
944
|
+
"Dialogue",
|
|
945
|
+
"Ensemble",
|
|
946
|
+
"FemaleVoice",
|
|
947
|
+
"Flutist",
|
|
948
|
+
"GuestArtist",
|
|
949
|
+
"GuestSinger",
|
|
950
|
+
"Harmonies",
|
|
951
|
+
"Harpist",
|
|
952
|
+
"Hornist",
|
|
953
|
+
"HumanBeatbox",
|
|
954
|
+
"HumanVoice",
|
|
955
|
+
"LeadSinger",
|
|
956
|
+
"LeadVocalist",
|
|
957
|
+
"LiveBand",
|
|
958
|
+
"MainVocal",
|
|
959
|
+
"MainVocals",
|
|
960
|
+
"MaleVoice",
|
|
961
|
+
"Mandolinist",
|
|
962
|
+
"Narration",
|
|
963
|
+
"Orchestra",
|
|
964
|
+
"Organist",
|
|
965
|
+
"OriginalSinger",
|
|
966
|
+
"Percussionist",
|
|
967
|
+
"Recitation",
|
|
968
|
+
"Saxophonist",
|
|
969
|
+
"SessionMusician",
|
|
970
|
+
"SessionPlayer",
|
|
971
|
+
"Singers",
|
|
972
|
+
"Singing",
|
|
973
|
+
"Sitarist",
|
|
974
|
+
"Trombonist",
|
|
975
|
+
"Trumpeter",
|
|
976
|
+
"Tubist",
|
|
977
|
+
"Ukuleleist",
|
|
978
|
+
"Violist",
|
|
979
|
+
"VocalPerformance",
|
|
980
|
+
"Vocalists",
|
|
981
|
+
"VoiceActor",
|
|
982
|
+
"VoiceActress",
|
|
983
|
+
"Vox",
|
|
984
|
+
"Chorus",
|
|
985
|
+
"Solo"
|
|
986
|
+
]
|
|
987
|
+
},
|
|
988
|
+
{
|
|
989
|
+
"id": "instruments",
|
|
990
|
+
"kind": "instrument",
|
|
991
|
+
"roles": ["PERFORMER"],
|
|
992
|
+
"words": [
|
|
993
|
+
"Guitar",
|
|
994
|
+
"Piano",
|
|
995
|
+
"Bass",
|
|
996
|
+
"Drums",
|
|
997
|
+
"Keyboard",
|
|
998
|
+
"Strings",
|
|
999
|
+
"Synth",
|
|
1000
|
+
"Violin",
|
|
1001
|
+
"Cello",
|
|
1002
|
+
"Saxophone",
|
|
1003
|
+
"Trumpet",
|
|
1004
|
+
"Flute",
|
|
1005
|
+
"Clarinet",
|
|
1006
|
+
"Trombone",
|
|
1007
|
+
"Horn",
|
|
1008
|
+
"Organ",
|
|
1009
|
+
"Percussion",
|
|
1010
|
+
"Ukulele",
|
|
1011
|
+
"Banjo",
|
|
1012
|
+
"Mandolin",
|
|
1013
|
+
"Harp",
|
|
1014
|
+
"Viola",
|
|
1015
|
+
"AcousticGuitar",
|
|
1016
|
+
"ElectricGuitar",
|
|
1017
|
+
"BassGuitar",
|
|
1018
|
+
"ElectricBass",
|
|
1019
|
+
"Keyboards",
|
|
1020
|
+
"Keys",
|
|
1021
|
+
"Synthesizer",
|
|
1022
|
+
"Perc",
|
|
1023
|
+
"12-StringGuitar",
|
|
1024
|
+
"A.Gtr",
|
|
1025
|
+
"A.Sax",
|
|
1026
|
+
"Accordion",
|
|
1027
|
+
"AcousticBass",
|
|
1028
|
+
"AcousticElectricGuitar",
|
|
1029
|
+
"Allinstrumental",
|
|
1030
|
+
"Allinstrumentalby",
|
|
1031
|
+
"Allinstruments",
|
|
1032
|
+
"AltoSax",
|
|
1033
|
+
"AltoSaxophone",
|
|
1034
|
+
"AppalachianDulcimer",
|
|
1035
|
+
"Autoharp",
|
|
1036
|
+
"B.Cl",
|
|
1037
|
+
"B.Sax",
|
|
1038
|
+
"B3",
|
|
1039
|
+
"BANDONEÓN",
|
|
1040
|
+
"BODHRÁN",
|
|
1041
|
+
"Bagpipe",
|
|
1042
|
+
"Bagpipes",
|
|
1043
|
+
"Balalaika",
|
|
1044
|
+
"Bandoneon",
|
|
1045
|
+
"Bandoneón",
|
|
1046
|
+
"Banhu",
|
|
1047
|
+
"Bansuri",
|
|
1048
|
+
"BaritoneSax",
|
|
1049
|
+
"BaritoneSaxophone",
|
|
1050
|
+
"BassClarinet",
|
|
1051
|
+
"BassSynth",
|
|
1052
|
+
"Bassoon",
|
|
1053
|
+
"Bawu",
|
|
1054
|
+
"Bodhran",
|
|
1055
|
+
"Bodhrán",
|
|
1056
|
+
"Bongo",
|
|
1057
|
+
"Bouzouki",
|
|
1058
|
+
"Brass",
|
|
1059
|
+
"Bsn",
|
|
1060
|
+
"Bss",
|
|
1061
|
+
"CAJÓN",
|
|
1062
|
+
"Cajon",
|
|
1063
|
+
"Cajón",
|
|
1064
|
+
"Castanets",
|
|
1065
|
+
"Cb",
|
|
1066
|
+
"Celesta",
|
|
1067
|
+
"Charango",
|
|
1068
|
+
"Chimes",
|
|
1069
|
+
"Cl",
|
|
1070
|
+
"ClassicalGuitar",
|
|
1071
|
+
"Clav",
|
|
1072
|
+
"Claves",
|
|
1073
|
+
"Clavinet",
|
|
1074
|
+
"Cnt",
|
|
1075
|
+
"Concertina",
|
|
1076
|
+
"Conga",
|
|
1077
|
+
"Contrabass",
|
|
1078
|
+
"Cornet",
|
|
1079
|
+
"Cowbell",
|
|
1080
|
+
"Cymbal",
|
|
1081
|
+
"Cymbals",
|
|
1082
|
+
"DJ",
|
|
1083
|
+
"Daegeum",
|
|
1084
|
+
"Darbuka",
|
|
1085
|
+
"Daruan",
|
|
1086
|
+
"Didgeridoo",
|
|
1087
|
+
"Dizi",
|
|
1088
|
+
"Djembe",
|
|
1089
|
+
"Dobro",
|
|
1090
|
+
"DoubleBass",
|
|
1091
|
+
"Doumbek",
|
|
1092
|
+
"Dr",
|
|
1093
|
+
"Drum",
|
|
1094
|
+
"DrumMachine",
|
|
1095
|
+
"DrumPad",
|
|
1096
|
+
"DrumSet",
|
|
1097
|
+
"Duduk",
|
|
1098
|
+
"Dulcimer",
|
|
1099
|
+
"E.Bss",
|
|
1100
|
+
"E.Gtr",
|
|
1101
|
+
"E.Hn",
|
|
1102
|
+
"EP",
|
|
1103
|
+
"ElectricPiano",
|
|
1104
|
+
"ElectronicKeyboard",
|
|
1105
|
+
"EnglishHorn",
|
|
1106
|
+
"Erhu",
|
|
1107
|
+
"Euph",
|
|
1108
|
+
"Euphonium",
|
|
1109
|
+
"FingerDrumming",
|
|
1110
|
+
"Fingerpicking",
|
|
1111
|
+
"FingerstyleGuitar",
|
|
1112
|
+
"Fl",
|
|
1113
|
+
"Flageolet",
|
|
1114
|
+
"Flt",
|
|
1115
|
+
"Flugelhorn",
|
|
1116
|
+
"FrameDrum",
|
|
1117
|
+
"FrenchHorn",
|
|
1118
|
+
"Gaohu",
|
|
1119
|
+
"Gayageum",
|
|
1120
|
+
"Glockenspiel",
|
|
1121
|
+
"Gong",
|
|
1122
|
+
"Gtr",
|
|
1123
|
+
"Guiro",
|
|
1124
|
+
"Guitars",
|
|
1125
|
+
"Guqin",
|
|
1126
|
+
"Guzheng",
|
|
1127
|
+
"GÜIRO",
|
|
1128
|
+
"Güiro",
|
|
1129
|
+
"Haegeum",
|
|
1130
|
+
"HammeredDulcimer",
|
|
1131
|
+
"Hammond",
|
|
1132
|
+
"HammondOrgan",
|
|
1133
|
+
"HandDrum",
|
|
1134
|
+
"Handpan",
|
|
1135
|
+
"HangDrum",
|
|
1136
|
+
"Harmonica",
|
|
1137
|
+
"Harmonium",
|
|
1138
|
+
"Harpsichord",
|
|
1139
|
+
"Hn",
|
|
1140
|
+
"HornSection",
|
|
1141
|
+
"Horns",
|
|
1142
|
+
"Hpschd",
|
|
1143
|
+
"Hrp",
|
|
1144
|
+
"Hulusi",
|
|
1145
|
+
"Hurdy-Gurdy",
|
|
1146
|
+
"HurdyGurdy",
|
|
1147
|
+
"Janggu",
|
|
1148
|
+
"Jinghu",
|
|
1149
|
+
"Kalimba",
|
|
1150
|
+
"Keytar",
|
|
1151
|
+
"Konghou",
|
|
1152
|
+
"Kora",
|
|
1153
|
+
"Koto",
|
|
1154
|
+
"Kybd",
|
|
1155
|
+
"LapSteel",
|
|
1156
|
+
"LapSteelGuitar",
|
|
1157
|
+
"LeadGuitar",
|
|
1158
|
+
"Liuqin",
|
|
1159
|
+
"Lute",
|
|
1160
|
+
"MPC",
|
|
1161
|
+
"Marimba",
|
|
1162
|
+
"Matouqin",
|
|
1163
|
+
"Mbira",
|
|
1164
|
+
"Mellotron",
|
|
1165
|
+
"Melodica",
|
|
1166
|
+
"MorinKhuur",
|
|
1167
|
+
"MusicalInstruments",
|
|
1168
|
+
"Nyckelharpa",
|
|
1169
|
+
"NylonGuitar",
|
|
1170
|
+
"Ob",
|
|
1171
|
+
"Oboe",
|
|
1172
|
+
"Ocarina",
|
|
1173
|
+
"Org",
|
|
1174
|
+
"Oud",
|
|
1175
|
+
"PanFlute",
|
|
1176
|
+
"Panpipes",
|
|
1177
|
+
"PedalSteel",
|
|
1178
|
+
"PedalSteelGuitar",
|
|
1179
|
+
"PennyWhistle",
|
|
1180
|
+
"Picc",
|
|
1181
|
+
"Piccolo",
|
|
1182
|
+
"Pipa",
|
|
1183
|
+
"Pno",
|
|
1184
|
+
"Rebab",
|
|
1185
|
+
"Recorder",
|
|
1186
|
+
"Resonator",
|
|
1187
|
+
"ResonatorGuitar",
|
|
1188
|
+
"Rhodes",
|
|
1189
|
+
"RhythmGuitar",
|
|
1190
|
+
"Ruan",
|
|
1191
|
+
"S.Sax",
|
|
1192
|
+
"Sampler",
|
|
1193
|
+
"Sanxian",
|
|
1194
|
+
"Sax",
|
|
1195
|
+
"Scratching",
|
|
1196
|
+
"Sequencer",
|
|
1197
|
+
"Shaker",
|
|
1198
|
+
"Shakuhachi",
|
|
1199
|
+
"Shamisen",
|
|
1200
|
+
"Sheng",
|
|
1201
|
+
"Sitar",
|
|
1202
|
+
"SlideGuitar",
|
|
1203
|
+
"Snare",
|
|
1204
|
+
"SnareDrum",
|
|
1205
|
+
"SopranoSax",
|
|
1206
|
+
"SteelDrum",
|
|
1207
|
+
"SteelGuitar",
|
|
1208
|
+
"SteelPan",
|
|
1209
|
+
"Str",
|
|
1210
|
+
"String",
|
|
1211
|
+
"StringQuartet",
|
|
1212
|
+
"StringSection",
|
|
1213
|
+
"SubBass",
|
|
1214
|
+
"Suona",
|
|
1215
|
+
"SynthBass",
|
|
1216
|
+
"Synthesizers",
|
|
1217
|
+
"Synths",
|
|
1218
|
+
"T.Sax",
|
|
1219
|
+
"Tabla",
|
|
1220
|
+
"Taiko",
|
|
1221
|
+
"TalkingDrum",
|
|
1222
|
+
"Tamb",
|
|
1223
|
+
"Tambourine",
|
|
1224
|
+
"Tba",
|
|
1225
|
+
"Tbn",
|
|
1226
|
+
"TenorSax",
|
|
1227
|
+
"TenorSaxophone",
|
|
1228
|
+
"Theremin",
|
|
1229
|
+
"Timbales",
|
|
1230
|
+
"Timp",
|
|
1231
|
+
"Timpani",
|
|
1232
|
+
"TinWhistle",
|
|
1233
|
+
"Tpt",
|
|
1234
|
+
"Triangle",
|
|
1235
|
+
"Tuba",
|
|
1236
|
+
"TubularBells",
|
|
1237
|
+
"Turntable",
|
|
1238
|
+
"Turntables",
|
|
1239
|
+
"Uke",
|
|
1240
|
+
"UprightBass",
|
|
1241
|
+
"Vc",
|
|
1242
|
+
"Vib",
|
|
1243
|
+
"Vibes",
|
|
1244
|
+
"Vibraphone",
|
|
1245
|
+
"Vla",
|
|
1246
|
+
"Vln",
|
|
1247
|
+
"Vocoder",
|
|
1248
|
+
"Whistle",
|
|
1249
|
+
"Winds",
|
|
1250
|
+
"Woodblock",
|
|
1251
|
+
"Woodwinds",
|
|
1252
|
+
"Wurlitzer",
|
|
1253
|
+
"Xiao",
|
|
1254
|
+
"Xiaoruan",
|
|
1255
|
+
"Xun",
|
|
1256
|
+
"Xylo",
|
|
1257
|
+
"Xylophone",
|
|
1258
|
+
"Yangqin",
|
|
1259
|
+
"Yueqin",
|
|
1260
|
+
"Zhonghu",
|
|
1261
|
+
"Zither"
|
|
1262
|
+
]
|
|
1263
|
+
},
|
|
1264
|
+
{
|
|
1265
|
+
"id": "mixer",
|
|
1266
|
+
"kind": "role",
|
|
1267
|
+
"roles": ["MIXER"],
|
|
1268
|
+
"words": [
|
|
1269
|
+
"Mix",
|
|
1270
|
+
"Mixedby",
|
|
1271
|
+
"Mixing",
|
|
1272
|
+
"Mixer",
|
|
1273
|
+
"MixingEngineer",
|
|
1274
|
+
"MixEngineer",
|
|
1275
|
+
"Remix",
|
|
1276
|
+
"Remixedby",
|
|
1277
|
+
"Remixer",
|
|
1278
|
+
"Mixdown",
|
|
1279
|
+
"Mixdownby",
|
|
1280
|
+
"Mixed",
|
|
1281
|
+
"Remixby"
|
|
1282
|
+
]
|
|
1283
|
+
},
|
|
1284
|
+
{
|
|
1285
|
+
"id": "mastering",
|
|
1286
|
+
"kind": "role",
|
|
1287
|
+
"roles": ["MASTERING"],
|
|
1288
|
+
"words": [
|
|
1289
|
+
"Mastering",
|
|
1290
|
+
"Masteredby",
|
|
1291
|
+
"Master",
|
|
1292
|
+
"MasteringEngineer",
|
|
1293
|
+
"MasterEngineer",
|
|
1294
|
+
"Mst",
|
|
1295
|
+
"Mastered",
|
|
1296
|
+
"MasteringEngineerby",
|
|
1297
|
+
"Masteringby"
|
|
1298
|
+
]
|
|
1299
|
+
},
|
|
1300
|
+
{
|
|
1301
|
+
"id": "lyrics-and-composition",
|
|
1302
|
+
"kind": "role",
|
|
1303
|
+
"roles": ["LYRICIST", "COMPOSER"],
|
|
1304
|
+
"words": [
|
|
1305
|
+
"Lyrics&Music",
|
|
1306
|
+
"Music&Lyrics",
|
|
1307
|
+
"Words&Music",
|
|
1308
|
+
"Lyrics&Musicby",
|
|
1309
|
+
"Music&Lyricsby",
|
|
1310
|
+
"Words&Musicby",
|
|
1311
|
+
"Composed&Writtenby",
|
|
1312
|
+
"ComposedandWrittenby",
|
|
1313
|
+
"Composer&Lyricist",
|
|
1314
|
+
"Composer/Lyricist",
|
|
1315
|
+
"Lyricist&Composer",
|
|
1316
|
+
"Lyricist/Composer",
|
|
1317
|
+
"Lyrics&Melody",
|
|
1318
|
+
"Lyrics/Music",
|
|
1319
|
+
"LyricsandMusic",
|
|
1320
|
+
"LyricsandMusicby",
|
|
1321
|
+
"Melody&Lyrics",
|
|
1322
|
+
"Melody&Words",
|
|
1323
|
+
"Music&Words",
|
|
1324
|
+
"Music/Lyrics",
|
|
1325
|
+
"MusicandLyrics",
|
|
1326
|
+
"MusicandLyricsby",
|
|
1327
|
+
"Words&Melody",
|
|
1328
|
+
"Words/Music",
|
|
1329
|
+
"WordsandMusic",
|
|
1330
|
+
"WordsandMusicby",
|
|
1331
|
+
"Written&Composedby",
|
|
1332
|
+
"WrittenandComposedby"
|
|
1333
|
+
]
|
|
1334
|
+
},
|
|
1335
|
+
{
|
|
1336
|
+
"id": "composition-and-arrangement",
|
|
1337
|
+
"kind": "role",
|
|
1338
|
+
"roles": ["COMPOSER", "ARRANGER"],
|
|
1339
|
+
"words": [
|
|
1340
|
+
"Composer&Arranger",
|
|
1341
|
+
"Composer/Arranger",
|
|
1342
|
+
"Composed&Arrangedby",
|
|
1343
|
+
"Music&Arrangement",
|
|
1344
|
+
"Composed&Arranged",
|
|
1345
|
+
"ComposedandArrangedby",
|
|
1346
|
+
"ComposerandArranger",
|
|
1347
|
+
"Composition&Arrangement",
|
|
1348
|
+
"MusicandArrangement"
|
|
1349
|
+
]
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
"id": "mixing-and-mastering",
|
|
1353
|
+
"kind": "role",
|
|
1354
|
+
"roles": ["MIXER", "MASTERING"],
|
|
1355
|
+
"words": [
|
|
1356
|
+
"Mix&Master",
|
|
1357
|
+
"Mix/Master",
|
|
1358
|
+
"Mixed&Masteredby",
|
|
1359
|
+
"Mixing&Mastering",
|
|
1360
|
+
"Mixing/Mastering",
|
|
1361
|
+
"Mix&Mastering",
|
|
1362
|
+
"MixandMaster",
|
|
1363
|
+
"MixandMastering",
|
|
1364
|
+
"MixedandMasteredby",
|
|
1365
|
+
"Mixing&Master",
|
|
1366
|
+
"MixingandMaster",
|
|
1367
|
+
"MixingandMastering"
|
|
1368
|
+
]
|
|
1369
|
+
},
|
|
1370
|
+
{
|
|
1371
|
+
"id": "lyrics-and-arrangement",
|
|
1372
|
+
"kind": "role",
|
|
1373
|
+
"roles": ["LYRICIST", "ARRANGER"],
|
|
1374
|
+
"words": [
|
|
1375
|
+
"Lyrics&Arrangement",
|
|
1376
|
+
"LyricsArrangement",
|
|
1377
|
+
"LyricsandArrangement",
|
|
1378
|
+
"Words&Arrangement",
|
|
1379
|
+
"WordsArrangement"
|
|
1380
|
+
]
|
|
1381
|
+
},
|
|
1382
|
+
{
|
|
1383
|
+
"id": "lyrics-composition-and-arrangement",
|
|
1384
|
+
"kind": "role",
|
|
1385
|
+
"roles": [
|
|
1386
|
+
"LYRICIST",
|
|
1387
|
+
"COMPOSER",
|
|
1388
|
+
"ARRANGER"
|
|
1389
|
+
],
|
|
1390
|
+
"words": [
|
|
1391
|
+
"ComposedWritten&Arrangedby",
|
|
1392
|
+
"ComposedWrittenandArrangedby",
|
|
1393
|
+
"LyricsMusic&Arrangement",
|
|
1394
|
+
"LyricsMusicArrangement",
|
|
1395
|
+
"LyricsMusicandArrangement",
|
|
1396
|
+
"MusicLyrics&Arrangement",
|
|
1397
|
+
"WordsMusic&Arrangement",
|
|
1398
|
+
"WrittenComposed&Arrangedby",
|
|
1399
|
+
"WrittenComposedandArrangedby"
|
|
1400
|
+
]
|
|
1401
|
+
},
|
|
1402
|
+
{
|
|
1403
|
+
"id": "singer-songwriter",
|
|
1404
|
+
"kind": "role",
|
|
1405
|
+
"roles": [
|
|
1406
|
+
"LYRICIST",
|
|
1407
|
+
"COMPOSER",
|
|
1408
|
+
"PERFORMER"
|
|
1409
|
+
],
|
|
1410
|
+
"words": [
|
|
1411
|
+
"Singer-Songwriter",
|
|
1412
|
+
"SingerSongwriter",
|
|
1413
|
+
"SingerSongwriterby"
|
|
1414
|
+
]
|
|
1415
|
+
},
|
|
1416
|
+
{
|
|
1417
|
+
"id": "other",
|
|
1418
|
+
"kind": "role",
|
|
1419
|
+
"roles": ["OTHER"],
|
|
1420
|
+
"words": [
|
|
1421
|
+
"Engineer",
|
|
1422
|
+
"RecordingEngineer",
|
|
1423
|
+
"SoundEngineer",
|
|
1424
|
+
"MixAssistant",
|
|
1425
|
+
"MixingAssistant",
|
|
1426
|
+
"MasteringAssistant",
|
|
1427
|
+
"A&R",
|
|
1428
|
+
"ArtDirection",
|
|
1429
|
+
"ArtDirector",
|
|
1430
|
+
"Design",
|
|
1431
|
+
"Designer",
|
|
1432
|
+
"Photographer",
|
|
1433
|
+
"Photography",
|
|
1434
|
+
"Photo",
|
|
1435
|
+
"Director",
|
|
1436
|
+
"Video",
|
|
1437
|
+
"Manager",
|
|
1438
|
+
"Management",
|
|
1439
|
+
"Coordinator",
|
|
1440
|
+
"Consultant",
|
|
1441
|
+
"Translator",
|
|
1442
|
+
"Translation",
|
|
1443
|
+
"Transcription",
|
|
1444
|
+
"Editor",
|
|
1445
|
+
"Edit",
|
|
1446
|
+
"Programmer",
|
|
1447
|
+
"Programming",
|
|
1448
|
+
"Conductor",
|
|
1449
|
+
"Choreographer",
|
|
1450
|
+
"A.Eng",
|
|
1451
|
+
"Acknowledgments",
|
|
1452
|
+
"AdditionalEngineering",
|
|
1453
|
+
"Adjustment",
|
|
1454
|
+
"AlbumArt",
|
|
1455
|
+
"Animatedby",
|
|
1456
|
+
"Animation",
|
|
1457
|
+
"Animator",
|
|
1458
|
+
"Animatorby",
|
|
1459
|
+
"ArtConsultant",
|
|
1460
|
+
"ArtistManagement",
|
|
1461
|
+
"Artistassistant",
|
|
1462
|
+
"ArtistsandRepertoire",
|
|
1463
|
+
"Artwork",
|
|
1464
|
+
"AssetManagement",
|
|
1465
|
+
"Assistance",
|
|
1466
|
+
"Assistant",
|
|
1467
|
+
"AssistantEngineer",
|
|
1468
|
+
"AssistantMixEngineer",
|
|
1469
|
+
"AsstEng",
|
|
1470
|
+
"AudioEditing",
|
|
1471
|
+
"AudioEditor",
|
|
1472
|
+
"AudioEngineer",
|
|
1473
|
+
"Auto-Tune",
|
|
1474
|
+
"BTS",
|
|
1475
|
+
"Beatby",
|
|
1476
|
+
"Beatmaker",
|
|
1477
|
+
"Beats",
|
|
1478
|
+
"Behind-the-Scenes",
|
|
1479
|
+
"Behind-theScenes",
|
|
1480
|
+
"Behindthe-Scenes",
|
|
1481
|
+
"BehindtheScenes",
|
|
1482
|
+
"CG",
|
|
1483
|
+
"COO",
|
|
1484
|
+
"ChiefOperatingOfficer",
|
|
1485
|
+
"Choreography",
|
|
1486
|
+
"Clothing",
|
|
1487
|
+
"ComputerEngineer",
|
|
1488
|
+
"Cond",
|
|
1489
|
+
"Conductedby",
|
|
1490
|
+
"Contractor",
|
|
1491
|
+
"Copyist",
|
|
1492
|
+
"Copywriter",
|
|
1493
|
+
"Copywriting",
|
|
1494
|
+
"Costume",
|
|
1495
|
+
"CoverArt",
|
|
1496
|
+
"CoverDesign",
|
|
1497
|
+
"CreativeDirection",
|
|
1498
|
+
"CreativeDirector",
|
|
1499
|
+
"Designedby",
|
|
1500
|
+
"Digitaledit",
|
|
1501
|
+
"Digitalediting",
|
|
1502
|
+
"Directedby",
|
|
1503
|
+
"Distributedby",
|
|
1504
|
+
"DolbyAtmos",
|
|
1505
|
+
"Drawing",
|
|
1506
|
+
"DrumProgramming",
|
|
1507
|
+
"DrumTech",
|
|
1508
|
+
"Editedby",
|
|
1509
|
+
"Eng",
|
|
1510
|
+
"Engineeredby",
|
|
1511
|
+
"FOHEngineer",
|
|
1512
|
+
"Fashion",
|
|
1513
|
+
"Film",
|
|
1514
|
+
"Filmedby",
|
|
1515
|
+
"FineArts",
|
|
1516
|
+
"Flatdesign",
|
|
1517
|
+
"Foley",
|
|
1518
|
+
"FoleyArtist",
|
|
1519
|
+
"FrontofHouse",
|
|
1520
|
+
"FrontofHouseEngineer",
|
|
1521
|
+
"GraphicDesign",
|
|
1522
|
+
"Graphics",
|
|
1523
|
+
"Graphicvisual",
|
|
1524
|
+
"GuitarTech",
|
|
1525
|
+
"Hair",
|
|
1526
|
+
"Hair-Stylist",
|
|
1527
|
+
"HairStylist",
|
|
1528
|
+
"Illustratedby",
|
|
1529
|
+
"Illustration",
|
|
1530
|
+
"Illustrator",
|
|
1531
|
+
"Inscription",
|
|
1532
|
+
"InstrumentTech",
|
|
1533
|
+
"Librarian",
|
|
1534
|
+
"LightTech",
|
|
1535
|
+
"LightingDesigner",
|
|
1536
|
+
"LiveSoundEngineer",
|
|
1537
|
+
"Loops",
|
|
1538
|
+
"LyricVideo",
|
|
1539
|
+
"MD",
|
|
1540
|
+
"MIDI",
|
|
1541
|
+
"MIDIProgramming",
|
|
1542
|
+
"MV",
|
|
1543
|
+
"MVDirector",
|
|
1544
|
+
"MainCreators",
|
|
1545
|
+
"Make-up",
|
|
1546
|
+
"Makeup",
|
|
1547
|
+
"MakeupArtist",
|
|
1548
|
+
"Making",
|
|
1549
|
+
"Making-of",
|
|
1550
|
+
"Makingof",
|
|
1551
|
+
"Marketing",
|
|
1552
|
+
"Marketing&promotion",
|
|
1553
|
+
"MonitorEngineer",
|
|
1554
|
+
"MusicConcept",
|
|
1555
|
+
"MusicDirector",
|
|
1556
|
+
"MusicVideo",
|
|
1557
|
+
"MusicVideoDirector",
|
|
1558
|
+
"Musicproductionassistant",
|
|
1559
|
+
"OP",
|
|
1560
|
+
"PGM",
|
|
1561
|
+
"PRpromotion",
|
|
1562
|
+
"PV",
|
|
1563
|
+
"Photoby",
|
|
1564
|
+
"PitchCorrection",
|
|
1565
|
+
"PitchEditing",
|
|
1566
|
+
"Planner",
|
|
1567
|
+
"Planning",
|
|
1568
|
+
"Post-production",
|
|
1569
|
+
"PostMastering",
|
|
1570
|
+
"PostProd",
|
|
1571
|
+
"Pre-production",
|
|
1572
|
+
"Printvisual",
|
|
1573
|
+
"Productionassistant",
|
|
1574
|
+
"Prog",
|
|
1575
|
+
"Program",
|
|
1576
|
+
"Programmedby",
|
|
1577
|
+
"ProjectCoordinator",
|
|
1578
|
+
"ProjectPlanning",
|
|
1579
|
+
"Promo-Material",
|
|
1580
|
+
"PromoMaterial",
|
|
1581
|
+
"Promotion",
|
|
1582
|
+
"Proofreading",
|
|
1583
|
+
"Publicity",
|
|
1584
|
+
"Publishedby",
|
|
1585
|
+
"Publisher",
|
|
1586
|
+
"Rec",
|
|
1587
|
+
"Recordedby",
|
|
1588
|
+
"Recording",
|
|
1589
|
+
"RecordingAssistant",
|
|
1590
|
+
"Recordist",
|
|
1591
|
+
"SFX",
|
|
1592
|
+
"SFXDesigner",
|
|
1593
|
+
"SP",
|
|
1594
|
+
"Samples",
|
|
1595
|
+
"Sampling",
|
|
1596
|
+
"Scoring",
|
|
1597
|
+
"Short-Form",
|
|
1598
|
+
"Short-Video",
|
|
1599
|
+
"ShortForm",
|
|
1600
|
+
"ShortVideo",
|
|
1601
|
+
"Songby",
|
|
1602
|
+
"Songwriter",
|
|
1603
|
+
"Songwriting",
|
|
1604
|
+
"SoundDes",
|
|
1605
|
+
"SoundDesign",
|
|
1606
|
+
"SoundDesigner",
|
|
1607
|
+
"SoundEffects",
|
|
1608
|
+
"SoundEffectsDesigner",
|
|
1609
|
+
"SoundMixer",
|
|
1610
|
+
"SpecialThanks",
|
|
1611
|
+
"SpecialThanksto",
|
|
1612
|
+
"StageManager",
|
|
1613
|
+
"Styling",
|
|
1614
|
+
"Stylist",
|
|
1615
|
+
"Sub-publisher",
|
|
1616
|
+
"Subpublisher",
|
|
1617
|
+
"Subtitles",
|
|
1618
|
+
"Supervisedby",
|
|
1619
|
+
"Tech",
|
|
1620
|
+
"Thanks",
|
|
1621
|
+
"Thanksto",
|
|
1622
|
+
"Timing",
|
|
1623
|
+
"Topliner",
|
|
1624
|
+
"TrackingEng",
|
|
1625
|
+
"TrackingEngineer",
|
|
1626
|
+
"Training",
|
|
1627
|
+
"Trans",
|
|
1628
|
+
"Transcriber",
|
|
1629
|
+
"Translatedby",
|
|
1630
|
+
"Tunedby",
|
|
1631
|
+
"Tuning",
|
|
1632
|
+
"Videoby",
|
|
1633
|
+
"Visual",
|
|
1634
|
+
"VisualDesign",
|
|
1635
|
+
"VocalCoach",
|
|
1636
|
+
"VocalDirectedby",
|
|
1637
|
+
"VocalDirection",
|
|
1638
|
+
"VocalDirector",
|
|
1639
|
+
"VocalEdit",
|
|
1640
|
+
"VocalEditing",
|
|
1641
|
+
"VocalEditor",
|
|
1642
|
+
"VocalTuning",
|
|
1643
|
+
"Wardrobe",
|
|
1644
|
+
"Writer",
|
|
1645
|
+
"Written",
|
|
1646
|
+
"Writtenby",
|
|
1647
|
+
"Art",
|
|
1648
|
+
"Image",
|
|
1649
|
+
"Material",
|
|
1650
|
+
"Marketing-Material",
|
|
1651
|
+
"MarketingMaterial",
|
|
1652
|
+
"Copyrightmanagement",
|
|
1653
|
+
"Copyrightoperation",
|
|
1654
|
+
"StudioManager",
|
|
1655
|
+
"Beat",
|
|
1656
|
+
"Cut",
|
|
1657
|
+
"Guest",
|
|
1658
|
+
"Stage"
|
|
1659
|
+
]
|
|
1660
|
+
}
|
|
1661
|
+
]
|
|
1662
|
+
};
|
|
1663
|
+
var zh_hans_default$1 = {
|
|
1664
|
+
$schema: "../schema.json",
|
|
1665
|
+
version: 1,
|
|
1666
|
+
language: "zh-hans",
|
|
1667
|
+
normalization: {
|
|
1668
|
+
"whitespace": "remove",
|
|
1669
|
+
"case": "asciiLower"
|
|
1670
|
+
},
|
|
1671
|
+
groups: [
|
|
1672
|
+
{
|
|
1673
|
+
"id": "lyricist",
|
|
1674
|
+
"kind": "role",
|
|
1675
|
+
"roles": ["LYRICIST"],
|
|
1676
|
+
"words": [
|
|
1677
|
+
"作词",
|
|
1678
|
+
"填词",
|
|
1679
|
+
"词",
|
|
1680
|
+
"歌词",
|
|
1681
|
+
"作词人",
|
|
1682
|
+
"词作者",
|
|
1683
|
+
"作词者",
|
|
1684
|
+
"填词人",
|
|
1685
|
+
"词作",
|
|
1686
|
+
"中文词",
|
|
1687
|
+
"英文词",
|
|
1688
|
+
"粤语词",
|
|
1689
|
+
"韩文词",
|
|
1690
|
+
"日文词",
|
|
1691
|
+
"RAP词"
|
|
1692
|
+
]
|
|
1693
|
+
},
|
|
1694
|
+
{
|
|
1695
|
+
"id": "composer",
|
|
1696
|
+
"kind": "role",
|
|
1697
|
+
"roles": ["COMPOSER"],
|
|
1698
|
+
"words": [
|
|
1699
|
+
"作曲",
|
|
1700
|
+
"曲",
|
|
1701
|
+
"谱曲",
|
|
1702
|
+
"作曲人",
|
|
1703
|
+
"曲作者",
|
|
1704
|
+
"作曲者"
|
|
1705
|
+
]
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
"id": "arranger",
|
|
1709
|
+
"kind": "role",
|
|
1710
|
+
"roles": ["ARRANGER"],
|
|
1711
|
+
"words": [
|
|
1712
|
+
"编曲",
|
|
1713
|
+
"配器",
|
|
1714
|
+
"和声编写",
|
|
1715
|
+
"弦乐编写",
|
|
1716
|
+
"管乐编写",
|
|
1717
|
+
"节奏编写",
|
|
1718
|
+
"合唱编写",
|
|
1719
|
+
"和声编排",
|
|
1720
|
+
"弦乐编排",
|
|
1721
|
+
"管弦乐编排",
|
|
1722
|
+
"编曲人",
|
|
1723
|
+
"编曲者",
|
|
1724
|
+
"编曲师",
|
|
1725
|
+
"和声编配",
|
|
1726
|
+
"弦乐编配",
|
|
1727
|
+
"和音编写"
|
|
1728
|
+
]
|
|
1729
|
+
},
|
|
1730
|
+
{
|
|
1731
|
+
"id": "producer",
|
|
1732
|
+
"kind": "role",
|
|
1733
|
+
"roles": ["PRODUCER"],
|
|
1734
|
+
"words": [
|
|
1735
|
+
"制作人",
|
|
1736
|
+
"制作",
|
|
1737
|
+
"监制",
|
|
1738
|
+
"出品人",
|
|
1739
|
+
"出品",
|
|
1740
|
+
"音乐制作人",
|
|
1741
|
+
"执行制作人",
|
|
1742
|
+
"制作总监",
|
|
1743
|
+
"总制作人",
|
|
1744
|
+
"人声制作",
|
|
1745
|
+
"人声制作人",
|
|
1746
|
+
"配唱制作人",
|
|
1747
|
+
"共同制作",
|
|
1748
|
+
"共同制作人",
|
|
1749
|
+
"协力制作人",
|
|
1750
|
+
"制作协力",
|
|
1751
|
+
"单曲制作",
|
|
1752
|
+
"创意制作人",
|
|
1753
|
+
"出品方",
|
|
1754
|
+
"联合出品",
|
|
1755
|
+
"联合出品方",
|
|
1756
|
+
"执制",
|
|
1757
|
+
"执行监制",
|
|
1758
|
+
"总监制",
|
|
1759
|
+
"音乐监制"
|
|
1760
|
+
]
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
"id": "performer",
|
|
1764
|
+
"kind": "role",
|
|
1765
|
+
"roles": ["PERFORMER"],
|
|
1766
|
+
"words": [
|
|
1767
|
+
"演唱",
|
|
1768
|
+
"主唱",
|
|
1769
|
+
"歌手",
|
|
1770
|
+
"唱",
|
|
1771
|
+
"和声",
|
|
1772
|
+
"和音",
|
|
1773
|
+
"伴唱",
|
|
1774
|
+
"合唱",
|
|
1775
|
+
"原唱",
|
|
1776
|
+
"翻唱",
|
|
1777
|
+
"配唱",
|
|
1778
|
+
"女声",
|
|
1779
|
+
"男声",
|
|
1780
|
+
"童声",
|
|
1781
|
+
"人声",
|
|
1782
|
+
"合声",
|
|
1783
|
+
"合音",
|
|
1784
|
+
"领唱",
|
|
1785
|
+
"独奏",
|
|
1786
|
+
"演奏",
|
|
1787
|
+
"演奏者",
|
|
1788
|
+
"说唱",
|
|
1789
|
+
"配音",
|
|
1790
|
+
"旁白",
|
|
1791
|
+
"念白",
|
|
1792
|
+
"对白",
|
|
1793
|
+
"口技",
|
|
1794
|
+
"人声打击",
|
|
1795
|
+
"乐队",
|
|
1796
|
+
"乐团",
|
|
1797
|
+
"交响乐团",
|
|
1798
|
+
"管弦乐团",
|
|
1799
|
+
"弦乐团",
|
|
1800
|
+
"现场乐队",
|
|
1801
|
+
"乐手",
|
|
1802
|
+
"乐师",
|
|
1803
|
+
"伴奏",
|
|
1804
|
+
"演唱者",
|
|
1805
|
+
"演唱人",
|
|
1806
|
+
"和声者",
|
|
1807
|
+
"伴唱者",
|
|
1808
|
+
"领唱者",
|
|
1809
|
+
"吉他手",
|
|
1810
|
+
"贝斯手",
|
|
1811
|
+
"鼓手",
|
|
1812
|
+
"键盘手",
|
|
1813
|
+
"钢琴家",
|
|
1814
|
+
"小提琴手",
|
|
1815
|
+
"大提琴手",
|
|
1816
|
+
"中提琴手",
|
|
1817
|
+
"长笛手",
|
|
1818
|
+
"萨克斯手",
|
|
1819
|
+
"小号手",
|
|
1820
|
+
"长号手",
|
|
1821
|
+
"圆号手",
|
|
1822
|
+
"打击乐手",
|
|
1823
|
+
"单簧管手",
|
|
1824
|
+
"口琴手",
|
|
1825
|
+
"合唱团",
|
|
1826
|
+
"手风琴手",
|
|
1827
|
+
"竖琴手",
|
|
1828
|
+
"艺人"
|
|
1829
|
+
]
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
"id": "instruments",
|
|
1833
|
+
"kind": "instrument",
|
|
1834
|
+
"roles": ["PERFORMER"],
|
|
1835
|
+
"words": [
|
|
1836
|
+
"吉他",
|
|
1837
|
+
"钢琴",
|
|
1838
|
+
"贝斯",
|
|
1839
|
+
"贝司",
|
|
1840
|
+
"鼓",
|
|
1841
|
+
"键盘",
|
|
1842
|
+
"弦乐",
|
|
1843
|
+
"小提琴",
|
|
1844
|
+
"大提琴",
|
|
1845
|
+
"中提琴",
|
|
1846
|
+
"长笛",
|
|
1847
|
+
"萨克斯",
|
|
1848
|
+
"小号",
|
|
1849
|
+
"长号",
|
|
1850
|
+
"圆号",
|
|
1851
|
+
"单簧管",
|
|
1852
|
+
"双簧管",
|
|
1853
|
+
"手风琴",
|
|
1854
|
+
"口琴",
|
|
1855
|
+
"二胡",
|
|
1856
|
+
"古筝",
|
|
1857
|
+
"琵琶",
|
|
1858
|
+
"架子鼓",
|
|
1859
|
+
"电子琴",
|
|
1860
|
+
"合成器",
|
|
1861
|
+
"打击乐",
|
|
1862
|
+
"打击乐器",
|
|
1863
|
+
"管乐",
|
|
1864
|
+
"木管",
|
|
1865
|
+
"铜管",
|
|
1866
|
+
"三味线",
|
|
1867
|
+
"三弦",
|
|
1868
|
+
"三角铁",
|
|
1869
|
+
"中国笛",
|
|
1870
|
+
"中提",
|
|
1871
|
+
"中胡",
|
|
1872
|
+
"中阮",
|
|
1873
|
+
"乌德琴",
|
|
1874
|
+
"乐器",
|
|
1875
|
+
"乐器独奏",
|
|
1876
|
+
"京胡",
|
|
1877
|
+
"伽倻琴",
|
|
1878
|
+
"低音单簧管",
|
|
1879
|
+
"低音吉他",
|
|
1880
|
+
"低音提琴",
|
|
1881
|
+
"克拉维奈",
|
|
1882
|
+
"全部乐器",
|
|
1883
|
+
"六角手风琴",
|
|
1884
|
+
"军鼓",
|
|
1885
|
+
"刮壶",
|
|
1886
|
+
"十二弦吉他",
|
|
1887
|
+
"卡洪",
|
|
1888
|
+
"口风琴",
|
|
1889
|
+
"古琴",
|
|
1890
|
+
"合成贝斯",
|
|
1891
|
+
"哈蒙德风琴",
|
|
1892
|
+
"响板",
|
|
1893
|
+
"哨笛",
|
|
1894
|
+
"唢呐",
|
|
1895
|
+
"埙",
|
|
1896
|
+
"塔布拉",
|
|
1897
|
+
"声码器",
|
|
1898
|
+
"大号",
|
|
1899
|
+
"大提",
|
|
1900
|
+
"大笒",
|
|
1901
|
+
"大管",
|
|
1902
|
+
"大键琴",
|
|
1903
|
+
"大阮",
|
|
1904
|
+
"太鼓",
|
|
1905
|
+
"奚琴",
|
|
1906
|
+
"定音鼓",
|
|
1907
|
+
"富鲁格",
|
|
1908
|
+
"富鲁格号",
|
|
1909
|
+
"小提",
|
|
1910
|
+
"小阮",
|
|
1911
|
+
"小鼓",
|
|
1912
|
+
"尤克里里",
|
|
1913
|
+
"尺八",
|
|
1914
|
+
"巴乌",
|
|
1915
|
+
"巴拉莱卡",
|
|
1916
|
+
"巴松",
|
|
1917
|
+
"布祖基",
|
|
1918
|
+
"序列器",
|
|
1919
|
+
"康加鼓",
|
|
1920
|
+
"弦",
|
|
1921
|
+
"德西马",
|
|
1922
|
+
"恰朗戈",
|
|
1923
|
+
"所有乐器",
|
|
1924
|
+
"所有乐器演奏",
|
|
1925
|
+
"手摇琴",
|
|
1926
|
+
"手碟",
|
|
1927
|
+
"手鼓",
|
|
1928
|
+
"打击垫",
|
|
1929
|
+
"扬琴",
|
|
1930
|
+
"拇指琴",
|
|
1931
|
+
"拉巴卜",
|
|
1932
|
+
"指弹吉他",
|
|
1933
|
+
"排笛",
|
|
1934
|
+
"排箫",
|
|
1935
|
+
"提琴",
|
|
1936
|
+
"曼陀林",
|
|
1937
|
+
"月琴",
|
|
1938
|
+
"木吉他",
|
|
1939
|
+
"木棒",
|
|
1940
|
+
"木琴",
|
|
1941
|
+
"木箱鼓",
|
|
1942
|
+
"木鱼",
|
|
1943
|
+
"杜杜克",
|
|
1944
|
+
"板胡",
|
|
1945
|
+
"柳琴",
|
|
1946
|
+
"框鼓",
|
|
1947
|
+
"梅洛特隆",
|
|
1948
|
+
"次中音号",
|
|
1949
|
+
"沙锤",
|
|
1950
|
+
"波德兰鼓",
|
|
1951
|
+
"洞萧",
|
|
1952
|
+
"滑棒吉他",
|
|
1953
|
+
"牛铃",
|
|
1954
|
+
"特雷门琴",
|
|
1955
|
+
"玉琴",
|
|
1956
|
+
"班卓琴",
|
|
1957
|
+
"班多钮",
|
|
1958
|
+
"班苏里笛",
|
|
1959
|
+
"瑶琴",
|
|
1960
|
+
"电吉他",
|
|
1961
|
+
"电子打击垫",
|
|
1962
|
+
"电子鼓",
|
|
1963
|
+
"电贝司",
|
|
1964
|
+
"电贝斯",
|
|
1965
|
+
"电钢琴",
|
|
1966
|
+
"短号",
|
|
1967
|
+
"短笛",
|
|
1968
|
+
"竖琴",
|
|
1969
|
+
"竖笛",
|
|
1970
|
+
"竹笛",
|
|
1971
|
+
"笙",
|
|
1972
|
+
"笛子",
|
|
1973
|
+
"笛萧",
|
|
1974
|
+
"筝",
|
|
1975
|
+
"箜篌",
|
|
1976
|
+
"管钟",
|
|
1977
|
+
"箫",
|
|
1978
|
+
"箱琴",
|
|
1979
|
+
"簧风琴",
|
|
1980
|
+
"编钟",
|
|
1981
|
+
"肩背键盘",
|
|
1982
|
+
"自动竖琴",
|
|
1983
|
+
"英国管",
|
|
1984
|
+
"葫芦丝",
|
|
1985
|
+
"蒂姆巴尔鼓",
|
|
1986
|
+
"西塔琴",
|
|
1987
|
+
"说话鼓",
|
|
1988
|
+
"谐振吉他",
|
|
1989
|
+
"踏板钢弦吉他",
|
|
1990
|
+
"转盘",
|
|
1991
|
+
"达布卡",
|
|
1992
|
+
"迪吉里杜管",
|
|
1993
|
+
"邦戈鼓",
|
|
1994
|
+
"采样器",
|
|
1995
|
+
"金贝鼓",
|
|
1996
|
+
"钟琴",
|
|
1997
|
+
"钢片琴",
|
|
1998
|
+
"钢鼓",
|
|
1999
|
+
"钹",
|
|
2000
|
+
"铃鼓",
|
|
2001
|
+
"锡笛",
|
|
2002
|
+
"锣",
|
|
2003
|
+
"键提琴",
|
|
2004
|
+
"镲",
|
|
2005
|
+
"长鼓",
|
|
2006
|
+
"阮",
|
|
2007
|
+
"陶笛",
|
|
2008
|
+
"非洲鼓",
|
|
2009
|
+
"颤音琴",
|
|
2010
|
+
"风琴",
|
|
2011
|
+
"风笛",
|
|
2012
|
+
"马头琴",
|
|
2013
|
+
"马林巴",
|
|
2014
|
+
"高胡",
|
|
2015
|
+
"鲁特琴",
|
|
2016
|
+
"齐特琴"
|
|
2017
|
+
]
|
|
2018
|
+
},
|
|
2019
|
+
{
|
|
2020
|
+
"id": "mixer",
|
|
2021
|
+
"kind": "role",
|
|
2022
|
+
"roles": ["MIXER"],
|
|
2023
|
+
"words": [
|
|
2024
|
+
"混音",
|
|
2025
|
+
"混音师",
|
|
2026
|
+
"混",
|
|
2027
|
+
"混音工程师",
|
|
2028
|
+
"缩混",
|
|
2029
|
+
"贴混",
|
|
2030
|
+
"混音工程",
|
|
2031
|
+
"重混音师"
|
|
2032
|
+
]
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
"id": "mastering",
|
|
2036
|
+
"kind": "role",
|
|
2037
|
+
"roles": ["MASTERING"],
|
|
2038
|
+
"words": [
|
|
2039
|
+
"母带",
|
|
2040
|
+
"母带工程师",
|
|
2041
|
+
"母带处理",
|
|
2042
|
+
"母带制作",
|
|
2043
|
+
"母带后期",
|
|
2044
|
+
"母带工程",
|
|
2045
|
+
"母带师",
|
|
2046
|
+
"母带制作人",
|
|
2047
|
+
"母带处理制作人"
|
|
2048
|
+
]
|
|
2049
|
+
},
|
|
2050
|
+
{
|
|
2051
|
+
"id": "lyrics-and-composition",
|
|
2052
|
+
"kind": "role",
|
|
2053
|
+
"roles": ["LYRICIST", "COMPOSER"],
|
|
2054
|
+
"words": [
|
|
2055
|
+
"词曲",
|
|
2056
|
+
"作词/作曲",
|
|
2057
|
+
"作词作曲",
|
|
2058
|
+
"词/曲",
|
|
2059
|
+
"词&曲",
|
|
2060
|
+
"词曲作者",
|
|
2061
|
+
"词曲创作",
|
|
2062
|
+
"作曲/作词",
|
|
2063
|
+
"作曲、作词",
|
|
2064
|
+
"作词+作曲",
|
|
2065
|
+
"作词,作曲",
|
|
2066
|
+
"作词·作曲",
|
|
2067
|
+
"作词、作曲",
|
|
2068
|
+
"作词,作曲",
|
|
2069
|
+
"词/曲作",
|
|
2070
|
+
"词、曲",
|
|
2071
|
+
"词,曲"
|
|
2072
|
+
]
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
"id": "composition-and-arrangement",
|
|
2076
|
+
"kind": "role",
|
|
2077
|
+
"roles": ["COMPOSER", "ARRANGER"],
|
|
2078
|
+
"words": [
|
|
2079
|
+
"作编曲",
|
|
2080
|
+
"作曲/编曲",
|
|
2081
|
+
"作曲编曲",
|
|
2082
|
+
"曲/编",
|
|
2083
|
+
"曲编",
|
|
2084
|
+
"作曲、编曲",
|
|
2085
|
+
"作曲,编曲"
|
|
2086
|
+
]
|
|
2087
|
+
},
|
|
2088
|
+
{
|
|
2089
|
+
"id": "mixing-and-mastering",
|
|
2090
|
+
"kind": "role",
|
|
2091
|
+
"roles": ["MIXER", "MASTERING"],
|
|
2092
|
+
"words": [
|
|
2093
|
+
"混音/母带",
|
|
2094
|
+
"混音母带",
|
|
2095
|
+
"混音&母带",
|
|
2096
|
+
"混音与母带",
|
|
2097
|
+
"混音及母带",
|
|
2098
|
+
"母带/混音",
|
|
2099
|
+
"混音、母带",
|
|
2100
|
+
"混音,母带"
|
|
2101
|
+
]
|
|
2102
|
+
},
|
|
2103
|
+
{
|
|
2104
|
+
"id": "lyrics-and-arrangement",
|
|
2105
|
+
"kind": "role",
|
|
2106
|
+
"roles": ["LYRICIST", "ARRANGER"],
|
|
2107
|
+
"words": [
|
|
2108
|
+
"作词/编曲",
|
|
2109
|
+
"作词、编曲",
|
|
2110
|
+
"作词编曲",
|
|
2111
|
+
"词/编",
|
|
2112
|
+
"词编"
|
|
2113
|
+
]
|
|
2114
|
+
},
|
|
2115
|
+
{
|
|
2116
|
+
"id": "lyrics-composition-and-arrangement",
|
|
2117
|
+
"kind": "role",
|
|
2118
|
+
"roles": [
|
|
2119
|
+
"LYRICIST",
|
|
2120
|
+
"COMPOSER",
|
|
2121
|
+
"ARRANGER"
|
|
2122
|
+
],
|
|
2123
|
+
"words": [
|
|
2124
|
+
"作词/作曲/编曲",
|
|
2125
|
+
"作词、作曲、编曲",
|
|
2126
|
+
"作词作曲编曲",
|
|
2127
|
+
"词曲编",
|
|
2128
|
+
"词曲编曲"
|
|
2129
|
+
]
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
"id": "singer-songwriter",
|
|
2133
|
+
"kind": "role",
|
|
2134
|
+
"roles": [
|
|
2135
|
+
"LYRICIST",
|
|
2136
|
+
"COMPOSER",
|
|
2137
|
+
"PERFORMER"
|
|
2138
|
+
],
|
|
2139
|
+
"words": [
|
|
2140
|
+
"唱作",
|
|
2141
|
+
"唱作人",
|
|
2142
|
+
"唱作歌手"
|
|
2143
|
+
]
|
|
2144
|
+
},
|
|
2145
|
+
{
|
|
2146
|
+
"id": "other",
|
|
2147
|
+
"kind": "role",
|
|
2148
|
+
"roles": ["OTHER"],
|
|
2149
|
+
"words": [
|
|
2150
|
+
"录音师",
|
|
2151
|
+
"录音工程师",
|
|
2152
|
+
"录音",
|
|
2153
|
+
"录制",
|
|
2154
|
+
"工程师",
|
|
2155
|
+
"混音助理",
|
|
2156
|
+
"母带助理",
|
|
2157
|
+
"制作助理",
|
|
2158
|
+
"策划",
|
|
2159
|
+
"宣发",
|
|
2160
|
+
"摄影师",
|
|
2161
|
+
"摄像",
|
|
2162
|
+
"设计师",
|
|
2163
|
+
"美术",
|
|
2164
|
+
"美工",
|
|
2165
|
+
"视觉设计",
|
|
2166
|
+
"封面设计",
|
|
2167
|
+
"插画",
|
|
2168
|
+
"插画师",
|
|
2169
|
+
"曲绘",
|
|
2170
|
+
"校对",
|
|
2171
|
+
"打轴",
|
|
2172
|
+
"时轴",
|
|
2173
|
+
"时间轴",
|
|
2174
|
+
"修音",
|
|
2175
|
+
"修音师",
|
|
2176
|
+
"调音",
|
|
2177
|
+
"调音师",
|
|
2178
|
+
"拟音",
|
|
2179
|
+
"音效",
|
|
2180
|
+
"音响",
|
|
2181
|
+
"指挥",
|
|
2182
|
+
"经纪",
|
|
2183
|
+
"顾问",
|
|
2184
|
+
"艺术指导",
|
|
2185
|
+
"艺术总监",
|
|
2186
|
+
"音乐总监",
|
|
2187
|
+
"创意总监",
|
|
2188
|
+
"舞台监督",
|
|
2189
|
+
"灯光师",
|
|
2190
|
+
"特别感谢",
|
|
2191
|
+
"特别鸣谢",
|
|
2192
|
+
"感谢",
|
|
2193
|
+
"鸣谢",
|
|
2194
|
+
"致谢",
|
|
2195
|
+
"短视频",
|
|
2196
|
+
"MIDI编程",
|
|
2197
|
+
"OP",
|
|
2198
|
+
"PGM",
|
|
2199
|
+
"Program",
|
|
2200
|
+
"SP",
|
|
2201
|
+
"主创",
|
|
2202
|
+
"乐器技师",
|
|
2203
|
+
"乐谱",
|
|
2204
|
+
"乐谱管理员",
|
|
2205
|
+
"人声指导",
|
|
2206
|
+
"人声编辑",
|
|
2207
|
+
"企划宣传",
|
|
2208
|
+
"企宣",
|
|
2209
|
+
"分轨",
|
|
2210
|
+
"分镜",
|
|
2211
|
+
"制作统筹",
|
|
2212
|
+
"前台工程师",
|
|
2213
|
+
"剪辑",
|
|
2214
|
+
"剪辑师",
|
|
2215
|
+
"动画师",
|
|
2216
|
+
"助工",
|
|
2217
|
+
"助理",
|
|
2218
|
+
"助理工程师",
|
|
2219
|
+
"化妆",
|
|
2220
|
+
"协力",
|
|
2221
|
+
"吉他技师",
|
|
2222
|
+
"后期制作",
|
|
2223
|
+
"图绘",
|
|
2224
|
+
"声工",
|
|
2225
|
+
"声设",
|
|
2226
|
+
"声音设计师",
|
|
2227
|
+
"妆发",
|
|
2228
|
+
"妆造",
|
|
2229
|
+
"客串",
|
|
2230
|
+
"宣推",
|
|
2231
|
+
"平面",
|
|
2232
|
+
"平面视觉",
|
|
2233
|
+
"平面设计",
|
|
2234
|
+
"录音助理",
|
|
2235
|
+
"录音室经理",
|
|
2236
|
+
"扒谱",
|
|
2237
|
+
"扒谱员",
|
|
2238
|
+
"承办人",
|
|
2239
|
+
"技术支持",
|
|
2240
|
+
"抄谱",
|
|
2241
|
+
"抄谱员",
|
|
2242
|
+
"拟音师",
|
|
2243
|
+
"数字剪辑",
|
|
2244
|
+
"数字编辑",
|
|
2245
|
+
"文案策划",
|
|
2246
|
+
"映像",
|
|
2247
|
+
"服装",
|
|
2248
|
+
"杜比全景声",
|
|
2249
|
+
"歌词翻译",
|
|
2250
|
+
"灯光",
|
|
2251
|
+
"特约嘉宾",
|
|
2252
|
+
"特邀",
|
|
2253
|
+
"电脑",
|
|
2254
|
+
"电脑工程师",
|
|
2255
|
+
"监听",
|
|
2256
|
+
"监听工程师",
|
|
2257
|
+
"策监",
|
|
2258
|
+
"筹划",
|
|
2259
|
+
"编程",
|
|
2260
|
+
"编程播放",
|
|
2261
|
+
"编调",
|
|
2262
|
+
"编辑",
|
|
2263
|
+
"美术指导",
|
|
2264
|
+
"舞台总监",
|
|
2265
|
+
"艺人与产品",
|
|
2266
|
+
"艺人助理",
|
|
2267
|
+
"艺人统筹",
|
|
2268
|
+
"艺术顾问",
|
|
2269
|
+
"节拍",
|
|
2270
|
+
"节拍制作",
|
|
2271
|
+
"节拍制作人",
|
|
2272
|
+
"营销",
|
|
2273
|
+
"视觉总监",
|
|
2274
|
+
"调教",
|
|
2275
|
+
"调校",
|
|
2276
|
+
"谱务",
|
|
2277
|
+
"资产管理",
|
|
2278
|
+
"跟踪工程师",
|
|
2279
|
+
"辅助监督",
|
|
2280
|
+
"造型",
|
|
2281
|
+
"造型师",
|
|
2282
|
+
"采样",
|
|
2283
|
+
"音乐制作助理",
|
|
2284
|
+
"音乐统筹",
|
|
2285
|
+
"音乐视频导演",
|
|
2286
|
+
"音响工程师",
|
|
2287
|
+
"音序",
|
|
2288
|
+
"音控师",
|
|
2289
|
+
"音效设计",
|
|
2290
|
+
"音频编辑",
|
|
2291
|
+
"项目策划",
|
|
2292
|
+
"项目统筹",
|
|
2293
|
+
"预制作",
|
|
2294
|
+
"题字",
|
|
2295
|
+
"首席运营官",
|
|
2296
|
+
"鼓技师",
|
|
2297
|
+
"封面",
|
|
2298
|
+
"海报",
|
|
2299
|
+
"原版权",
|
|
2300
|
+
"原始版权",
|
|
2301
|
+
"次级版权",
|
|
2302
|
+
"版权运营",
|
|
2303
|
+
"业务",
|
|
2304
|
+
"企划",
|
|
2305
|
+
"宣传",
|
|
2306
|
+
"推广",
|
|
2307
|
+
"发行",
|
|
2308
|
+
"统筹",
|
|
2309
|
+
"设计",
|
|
2310
|
+
"摄影",
|
|
2311
|
+
"导演",
|
|
2312
|
+
"翻译",
|
|
2313
|
+
"后期",
|
|
2314
|
+
"工程",
|
|
2315
|
+
"声音",
|
|
2316
|
+
"支持",
|
|
2317
|
+
"艺术",
|
|
2318
|
+
"指导",
|
|
2319
|
+
"监督",
|
|
2320
|
+
"视觉",
|
|
2321
|
+
"舞台",
|
|
2322
|
+
"物料",
|
|
2323
|
+
"台词",
|
|
2324
|
+
"字幕",
|
|
2325
|
+
"文案",
|
|
2326
|
+
"脚本",
|
|
2327
|
+
"花絮",
|
|
2328
|
+
"视频",
|
|
2329
|
+
"作",
|
|
2330
|
+
"封",
|
|
2331
|
+
"监",
|
|
2332
|
+
"编",
|
|
2333
|
+
"译",
|
|
2334
|
+
"谱"
|
|
2335
|
+
]
|
|
2336
|
+
}
|
|
2337
|
+
]
|
|
2338
|
+
};
|
|
2339
|
+
//#endregion
|
|
2340
|
+
//#region src/transforms/credit/rules.ts
|
|
2341
|
+
var MATCH_CACHE_LIMIT = 256;
|
|
2342
|
+
var MAX_CACHED_LABEL_LENGTH = 256;
|
|
2343
|
+
var CREDIT_ROLES = /* @__PURE__ */ new Map([
|
|
2344
|
+
["OTHER", CreditRole.OTHER],
|
|
2345
|
+
["LYRICIST", CreditRole.LYRICIST],
|
|
2346
|
+
["COMPOSER", CreditRole.COMPOSER],
|
|
2347
|
+
["ARRANGER", CreditRole.ARRANGER],
|
|
2348
|
+
["PRODUCER", CreditRole.PRODUCER],
|
|
2349
|
+
["PERFORMER", CreditRole.PERFORMER],
|
|
2350
|
+
["MIXER", CreditRole.MIXER],
|
|
2351
|
+
["MASTERING", CreditRole.MASTERING]
|
|
2352
|
+
]);
|
|
2353
|
+
var creditRules = /* @__PURE__ */ new Map();
|
|
2354
|
+
var matchCache = /* @__PURE__ */ new Map();
|
|
2355
|
+
for (const ruleSet of [zh_hans_default$1, en_default$1]) for (const group of ruleSet.groups) {
|
|
2356
|
+
const roles = group.roles.map((name) => {
|
|
2357
|
+
const role = CREDIT_ROLES.get(name);
|
|
2358
|
+
if (role === void 0) throw new TypeError("Unsupported credit role: " + name);
|
|
2359
|
+
return role;
|
|
2360
|
+
});
|
|
2361
|
+
for (const word of group.words) {
|
|
2362
|
+
const key = toRuleMatchKey(word);
|
|
2363
|
+
if (!creditRules.has(key)) creditRules.set(key, roles);
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
var haveSameRoles = (first, second) => {
|
|
2367
|
+
if (first === second) return true;
|
|
2368
|
+
if (first.length !== second.length) return false;
|
|
2369
|
+
if (first.length === 1) return first[0] === second[0];
|
|
2370
|
+
return first.every((role) => second.includes(role));
|
|
2371
|
+
};
|
|
2372
|
+
var findCoveringRoles = (label, key) => {
|
|
2373
|
+
const cuts = findRuleMatchCuts(label);
|
|
2374
|
+
if (!cuts) return;
|
|
2375
|
+
const last = cuts.length - 1;
|
|
2376
|
+
let bestCount = last + 1;
|
|
2377
|
+
let bestRoles;
|
|
2378
|
+
const search = (from, count, roles) => {
|
|
2379
|
+
if (from === last) {
|
|
2380
|
+
if (count < bestCount) {
|
|
2381
|
+
bestCount = count;
|
|
2382
|
+
bestRoles = roles;
|
|
2383
|
+
return true;
|
|
2384
|
+
}
|
|
2385
|
+
return count > bestCount || haveSameRoles(roles, bestRoles);
|
|
2386
|
+
}
|
|
2387
|
+
if (count + 1 > bestCount) return true;
|
|
2388
|
+
for (let to = last; to > from; to -= 1) {
|
|
2389
|
+
const matched = creditRules.get(key.slice(cuts[from], cuts[to]));
|
|
2390
|
+
if (!matched || roles && !haveSameRoles(roles, matched)) continue;
|
|
2391
|
+
if (!search(to, count + 1, roles ?? matched)) return false;
|
|
2392
|
+
}
|
|
2393
|
+
return true;
|
|
2394
|
+
};
|
|
2395
|
+
return search(0, 0, void 0) ? bestRoles : void 0;
|
|
2396
|
+
};
|
|
2397
|
+
/**
|
|
2398
|
+
* Prefers the complete alias, then accepts adjacent parts that each resolve to the same roles.
|
|
2399
|
+
* Parts are cut only where the source has whitespace or a script boundary, and the covering with the fewest parts wins.
|
|
2400
|
+
* Unknown parts, role conflicts, and equally short coverings that disagree stay unmatched so the source remains available to later processing.
|
|
2401
|
+
*/
|
|
2402
|
+
var matchCreditLabel = (label) => {
|
|
2403
|
+
const cached = matchCache.get(label);
|
|
2404
|
+
if (cached !== void 0) return cached ?? void 0;
|
|
2405
|
+
const key = toRuleMatchKey(label);
|
|
2406
|
+
const roles = creditRules.get(key) ?? findCoveringRoles(label, key);
|
|
2407
|
+
if (label.length <= MAX_CACHED_LABEL_LENGTH) {
|
|
2408
|
+
if (matchCache.size === MATCH_CACHE_LIMIT) {
|
|
2409
|
+
const oldest = matchCache.keys().next().value;
|
|
2410
|
+
if (oldest !== void 0) matchCache.delete(oldest);
|
|
2411
|
+
}
|
|
2412
|
+
matchCache.set(label, roles ?? null);
|
|
2413
|
+
}
|
|
2414
|
+
return roles;
|
|
2415
|
+
};
|
|
2416
|
+
//#endregion
|
|
2417
|
+
//#region src/transforms/credit/extract.ts
|
|
2418
|
+
var DEFAULT_CREDIT_NAME_SEPARATORS = [
|
|
2419
|
+
"+",
|
|
2420
|
+
":",
|
|
2421
|
+
"/"
|
|
2422
|
+
];
|
|
2423
|
+
var createCreditIndex = (credits) => {
|
|
2424
|
+
const creditIndex = /* @__PURE__ */ new Map();
|
|
2425
|
+
for (let index = 0; index < credits.length; index += 1) {
|
|
2426
|
+
const credit = credits[index];
|
|
2427
|
+
let entries = creditIndex.get(credit.raw);
|
|
2428
|
+
if (!entries) {
|
|
2429
|
+
entries = /* @__PURE__ */ new Map();
|
|
2430
|
+
creditIndex.set(credit.raw, entries);
|
|
2431
|
+
}
|
|
2432
|
+
let entry = entries.get(credit.role);
|
|
2433
|
+
if (!entry) {
|
|
2434
|
+
entry = {
|
|
2435
|
+
index,
|
|
2436
|
+
names: /* @__PURE__ */ new Set()
|
|
2437
|
+
};
|
|
2438
|
+
entries.set(credit.role, entry);
|
|
2439
|
+
}
|
|
2440
|
+
for (const name of credit.names) entry.names.add(name.text);
|
|
2441
|
+
}
|
|
2442
|
+
return creditIndex;
|
|
2443
|
+
};
|
|
2444
|
+
var prepareCreditSeparators = (selected) => {
|
|
2445
|
+
if (!selected || selected === DEFAULT_CREDIT_NAME_SEPARATORS) return DEFAULT_CREDIT_NAME_SEPARATORS;
|
|
2446
|
+
if (selected.length === DEFAULT_CREDIT_NAME_SEPARATORS.length && selected.every((separator, index) => separator === DEFAULT_CREDIT_NAME_SEPARATORS[index])) return DEFAULT_CREDIT_NAME_SEPARATORS;
|
|
2447
|
+
return [...new Set(selected)].filter(Boolean).sort((first, second) => second.length - first.length);
|
|
2448
|
+
};
|
|
2449
|
+
var readCreditNames = (text, separators) => {
|
|
2450
|
+
if (!separators.some((separator) => text.includes(separator))) {
|
|
2451
|
+
const name = trimRuleWhitespace(text);
|
|
2452
|
+
return name ? [name] : [];
|
|
2453
|
+
}
|
|
2454
|
+
let names = [text];
|
|
2455
|
+
for (const separator of separators) if (names.some((name) => name.includes(separator))) names = names.flatMap((name) => name.split(separator));
|
|
2456
|
+
const unique = /* @__PURE__ */ new Set();
|
|
2457
|
+
for (const name of names) {
|
|
2458
|
+
const trimmed = trimRuleWhitespace(name);
|
|
2459
|
+
if (trimmed) unique.add(trimmed);
|
|
2460
|
+
}
|
|
2461
|
+
return [...unique];
|
|
2462
|
+
};
|
|
2463
|
+
var canRemoveSourceLine = (line) => {
|
|
2464
|
+
if (line.backgrounds.length || line.annotation) return false;
|
|
2465
|
+
return !line.content?.words.some(({ annotation }) => {
|
|
2466
|
+
if (!annotation) return false;
|
|
2467
|
+
return !!(annotation.translations.length || annotation.romans.length);
|
|
2468
|
+
});
|
|
2469
|
+
};
|
|
2470
|
+
var hasCreditColon = (word) => {
|
|
2471
|
+
return word.text.includes(":") || word.text.includes(":");
|
|
2472
|
+
};
|
|
2473
|
+
/**
|
|
2474
|
+
* Preserves source labels and name spelling while matching normalized credit labels in normal lead lines.
|
|
2475
|
+
* Merges names by role and original label without inferring their language.
|
|
2476
|
+
*
|
|
2477
|
+
* @returns The input when unchanged, or a new lyric sharing all unchanged nodes.
|
|
2478
|
+
*/
|
|
2479
|
+
var extractCredits = (lyric, options = {}) => {
|
|
2480
|
+
const separators = prepareCreditSeparators(options.nameSeparators);
|
|
2481
|
+
const originalCredits = lyric.meta?.credits ?? [];
|
|
2482
|
+
let credits = originalCredits;
|
|
2483
|
+
let creditIndex;
|
|
2484
|
+
const originalLines = lyric.lines;
|
|
2485
|
+
let remainingLines;
|
|
2486
|
+
for (let index = 0; index < originalLines.length; index += 1) {
|
|
2487
|
+
const line = originalLines[index];
|
|
2488
|
+
if (line.type !== LineType.NORMAL) {
|
|
2489
|
+
remainingLines?.push(line);
|
|
2490
|
+
continue;
|
|
2491
|
+
}
|
|
2492
|
+
const content = line.content;
|
|
2493
|
+
if (!(content?.text !== void 0 || (content?.words.some(hasCreditColon) ?? false))) {
|
|
2494
|
+
remainingLines?.push(line);
|
|
2495
|
+
continue;
|
|
2496
|
+
}
|
|
2497
|
+
const text = getContentText(content);
|
|
2498
|
+
const colon = text.search(/[::]/);
|
|
2499
|
+
if (colon === -1) {
|
|
2500
|
+
remainingLines?.push(line);
|
|
2501
|
+
continue;
|
|
2502
|
+
}
|
|
2503
|
+
const raw = trimRuleWhitespace(text.slice(0, colon));
|
|
2504
|
+
const roles = matchCreditLabel(raw);
|
|
2505
|
+
const names = roles ? readCreditNames(text.slice(colon + 1), separators) : [];
|
|
2506
|
+
if (!roles || !names.length) {
|
|
2507
|
+
remainingLines?.push(line);
|
|
2508
|
+
continue;
|
|
2509
|
+
}
|
|
2510
|
+
creditIndex ??= createCreditIndex(originalCredits);
|
|
2511
|
+
let entries = creditIndex.get(raw);
|
|
2512
|
+
if (!entries) {
|
|
2513
|
+
entries = /* @__PURE__ */ new Map();
|
|
2514
|
+
creditIndex.set(raw, entries);
|
|
2515
|
+
}
|
|
2516
|
+
for (const role of roles) {
|
|
2517
|
+
let entry = entries.get(role);
|
|
2518
|
+
const additions = names.filter((name) => !entry?.names.has(name));
|
|
2519
|
+
if (!additions.length) continue;
|
|
2520
|
+
if (credits === originalCredits) credits = [...originalCredits];
|
|
2521
|
+
const nameNodes = additions.map((name) => makeText({ text: name }));
|
|
2522
|
+
if (!entry) {
|
|
2523
|
+
entry = {
|
|
2524
|
+
index: credits.length,
|
|
2525
|
+
names: /* @__PURE__ */ new Set()
|
|
2526
|
+
};
|
|
2527
|
+
entries.set(role, entry);
|
|
2528
|
+
credits.push(makeMetaCredit({
|
|
2529
|
+
role,
|
|
2530
|
+
raw,
|
|
2531
|
+
names: nameNodes
|
|
2532
|
+
}));
|
|
2533
|
+
} else {
|
|
2534
|
+
const credit = credits[entry.index];
|
|
2535
|
+
credits[entry.index] = {
|
|
2536
|
+
...credit,
|
|
2537
|
+
names: [...credit.names, ...nameNodes]
|
|
2538
|
+
};
|
|
2539
|
+
}
|
|
2540
|
+
for (const name of additions) entry.names.add(name);
|
|
2541
|
+
}
|
|
2542
|
+
if (options.removeSourceLines && canRemoveSourceLine(line)) remainingLines ??= originalLines.slice(0, index);
|
|
2543
|
+
else remainingLines?.push(line);
|
|
2544
|
+
}
|
|
2545
|
+
if (credits === originalCredits && !remainingLines) return lyric;
|
|
2546
|
+
const removed = !!remainingLines;
|
|
2547
|
+
const lines = remainingLines ?? originalLines;
|
|
2548
|
+
let timing = lyric.timing;
|
|
2549
|
+
if (removed && timing === Timing.WORD) {
|
|
2550
|
+
if (!lines.some((line) => {
|
|
2551
|
+
return isWordLevelLine(line) || line.backgrounds.some(isWordLevelLine);
|
|
2552
|
+
})) timing = Timing.LINE;
|
|
2553
|
+
}
|
|
2554
|
+
const meta = credits === originalCredits ? lyric.meta : lyric.meta ? {
|
|
2555
|
+
...lyric.meta,
|
|
2556
|
+
credits
|
|
2557
|
+
} : makeMeta({ credits });
|
|
2558
|
+
return {
|
|
2559
|
+
...lyric,
|
|
2560
|
+
meta,
|
|
2561
|
+
lines,
|
|
2562
|
+
timing,
|
|
2563
|
+
languages: removed ? deriveLanguageUsages(lines) : lyric.languages
|
|
2564
|
+
};
|
|
2565
|
+
};
|
|
559
2566
|
//#endregion
|
|
560
2567
|
//#region src/transforms/emphasis/index.ts
|
|
561
2568
|
var deriveContentEmphasis = (content, durationThreshold) => {
|
|
562
|
-
if (content
|
|
2569
|
+
if (!content) return content;
|
|
563
2570
|
const words = mapShared(content.words, (word) => {
|
|
564
2571
|
if (word.type !== WordType.NORMAL || word.emphasis?.derived === false) return word;
|
|
565
2572
|
const time = word.time;
|
|
566
|
-
if (time
|
|
567
|
-
if (word.emphasis?.value
|
|
2573
|
+
if (!!time && time.end !== void 0 && !validateTimeRange(time).length && time.end - time.start > durationThreshold) {
|
|
2574
|
+
if (word.emphasis?.value) return word;
|
|
568
2575
|
return {
|
|
569
2576
|
...word,
|
|
570
2577
|
emphasis: makeWordEmphasis({
|
|
@@ -573,7 +2580,7 @@ var deriveContentEmphasis = (content, durationThreshold) => {
|
|
|
573
2580
|
})
|
|
574
2581
|
};
|
|
575
2582
|
}
|
|
576
|
-
if (word.emphasis
|
|
2583
|
+
if (!word.emphasis) return word;
|
|
577
2584
|
return {
|
|
578
2585
|
...word,
|
|
579
2586
|
emphasis: void 0
|
|
@@ -619,6 +2626,258 @@ var deriveWordEmphasis = (lyric, options = {}) => {
|
|
|
619
2626
|
};
|
|
620
2627
|
};
|
|
621
2628
|
//#endregion
|
|
2629
|
+
//#region src/transforms/filter/rules.ts
|
|
2630
|
+
var nonLyricGroups = [{
|
|
2631
|
+
$schema: "../schema.json",
|
|
2632
|
+
version: 1,
|
|
2633
|
+
language: "zh-hans",
|
|
2634
|
+
normalization: {
|
|
2635
|
+
"whitespace": "remove",
|
|
2636
|
+
"case": "asciiLower"
|
|
2637
|
+
},
|
|
2638
|
+
groups: [
|
|
2639
|
+
{
|
|
2640
|
+
"id": "copyright-notice",
|
|
2641
|
+
"category": "copyright",
|
|
2642
|
+
"match": "contains",
|
|
2643
|
+
"words": [
|
|
2644
|
+
"版权所有",
|
|
2645
|
+
"保留所有权利",
|
|
2646
|
+
"侵权必究",
|
|
2647
|
+
"翻版必究",
|
|
2648
|
+
"违者必究",
|
|
2649
|
+
"未经授权",
|
|
2650
|
+
"未经许可",
|
|
2651
|
+
"版权归",
|
|
2652
|
+
"版权属于",
|
|
2653
|
+
"不得转载",
|
|
2654
|
+
"严禁转载",
|
|
2655
|
+
"盗版必究",
|
|
2656
|
+
"禁止转载"
|
|
2657
|
+
]
|
|
2658
|
+
},
|
|
2659
|
+
{
|
|
2660
|
+
"id": "copyright-label",
|
|
2661
|
+
"category": "copyright",
|
|
2662
|
+
"match": "whole",
|
|
2663
|
+
"words": ["版权", "授权"]
|
|
2664
|
+
},
|
|
2665
|
+
{
|
|
2666
|
+
"id": "adaptation-label",
|
|
2667
|
+
"category": "adaptation",
|
|
2668
|
+
"match": "whole",
|
|
2669
|
+
"words": [
|
|
2670
|
+
"改编",
|
|
2671
|
+
"翻唱",
|
|
2672
|
+
"致敬"
|
|
2673
|
+
]
|
|
2674
|
+
},
|
|
2675
|
+
{
|
|
2676
|
+
"id": "disclaimer-notice",
|
|
2677
|
+
"category": "disclaimer",
|
|
2678
|
+
"match": "contains",
|
|
2679
|
+
"words": [
|
|
2680
|
+
"仅供学习",
|
|
2681
|
+
"仅供个人",
|
|
2682
|
+
"仅供参考",
|
|
2683
|
+
"仅供交流",
|
|
2684
|
+
"禁止商业用途",
|
|
2685
|
+
"非商业用途"
|
|
2686
|
+
]
|
|
2687
|
+
},
|
|
2688
|
+
{
|
|
2689
|
+
"id": "organization-label",
|
|
2690
|
+
"category": "organization",
|
|
2691
|
+
"match": "contains",
|
|
2692
|
+
"words": [
|
|
2693
|
+
"唱片公司",
|
|
2694
|
+
"制作公司",
|
|
2695
|
+
"发行公司",
|
|
2696
|
+
"承办单位",
|
|
2697
|
+
"次级发行方",
|
|
2698
|
+
"厂牌"
|
|
2699
|
+
]
|
|
2700
|
+
},
|
|
2701
|
+
{
|
|
2702
|
+
"id": "studio-label",
|
|
2703
|
+
"category": "studio",
|
|
2704
|
+
"match": "contains",
|
|
2705
|
+
"words": [
|
|
2706
|
+
"录音室",
|
|
2707
|
+
"录音棚",
|
|
2708
|
+
"混音室",
|
|
2709
|
+
"混音工作室",
|
|
2710
|
+
"混音录音室",
|
|
2711
|
+
"母带录音室",
|
|
2712
|
+
"母带处理录音室"
|
|
2713
|
+
]
|
|
2714
|
+
}
|
|
2715
|
+
]
|
|
2716
|
+
}, {
|
|
2717
|
+
$schema: "../schema.json",
|
|
2718
|
+
version: 1,
|
|
2719
|
+
language: "en",
|
|
2720
|
+
normalization: {
|
|
2721
|
+
"whitespace": "remove",
|
|
2722
|
+
"case": "asciiLower"
|
|
2723
|
+
},
|
|
2724
|
+
groups: [
|
|
2725
|
+
{
|
|
2726
|
+
"id": "copyright-notice",
|
|
2727
|
+
"category": "copyright",
|
|
2728
|
+
"match": "contains",
|
|
2729
|
+
"words": [
|
|
2730
|
+
"Allrightsreserved",
|
|
2731
|
+
"Allrightsofthe",
|
|
2732
|
+
"Nopartofthis",
|
|
2733
|
+
"Unauthorizedreproduction",
|
|
2734
|
+
"Unauthorizedduplication",
|
|
2735
|
+
"Unauthorizedcopying",
|
|
2736
|
+
"Unauthorizeduse",
|
|
2737
|
+
"Underexclusivelicense",
|
|
2738
|
+
"Allrightsreservedby",
|
|
2739
|
+
"Anyunauthorizeduse",
|
|
2740
|
+
"Usedbypermission"
|
|
2741
|
+
]
|
|
2742
|
+
},
|
|
2743
|
+
{
|
|
2744
|
+
"id": "copyright-label",
|
|
2745
|
+
"category": "copyright",
|
|
2746
|
+
"match": "whole",
|
|
2747
|
+
"words": ["Copyright", "License"]
|
|
2748
|
+
},
|
|
2749
|
+
{
|
|
2750
|
+
"id": "adaptation-label",
|
|
2751
|
+
"category": "adaptation",
|
|
2752
|
+
"match": "whole",
|
|
2753
|
+
"words": [
|
|
2754
|
+
"Cover",
|
|
2755
|
+
"Remake",
|
|
2756
|
+
"Tribute",
|
|
2757
|
+
"Adaptation"
|
|
2758
|
+
]
|
|
2759
|
+
},
|
|
2760
|
+
{
|
|
2761
|
+
"id": "disclaimer-notice",
|
|
2762
|
+
"category": "disclaimer",
|
|
2763
|
+
"match": "contains",
|
|
2764
|
+
"words": [
|
|
2765
|
+
"Foreducationalpurposes",
|
|
2766
|
+
"Fornon-commercial",
|
|
2767
|
+
"Fornoncommercial",
|
|
2768
|
+
"Fornonprofitable",
|
|
2769
|
+
"Forpersonaluse",
|
|
2770
|
+
"Forpromotionalpurposes"
|
|
2771
|
+
]
|
|
2772
|
+
},
|
|
2773
|
+
{
|
|
2774
|
+
"id": "organization-label",
|
|
2775
|
+
"category": "organization",
|
|
2776
|
+
"match": "contains",
|
|
2777
|
+
"words": [
|
|
2778
|
+
"ManufacturingCompany",
|
|
2779
|
+
"RecordCompany",
|
|
2780
|
+
"RecordLabel",
|
|
2781
|
+
"Distribution"
|
|
2782
|
+
]
|
|
2783
|
+
},
|
|
2784
|
+
{
|
|
2785
|
+
"id": "studio-label",
|
|
2786
|
+
"category": "studio",
|
|
2787
|
+
"match": "contains",
|
|
2788
|
+
"words": [
|
|
2789
|
+
"RecordingStudio",
|
|
2790
|
+
"MasteringStudio",
|
|
2791
|
+
"Mixingstudio",
|
|
2792
|
+
"Mixstudio",
|
|
2793
|
+
"StudioPersonnel"
|
|
2794
|
+
]
|
|
2795
|
+
}
|
|
2796
|
+
]
|
|
2797
|
+
}].flatMap((ruleSet) => {
|
|
2798
|
+
return ruleSet.groups.map((group) => {
|
|
2799
|
+
if (group.match !== "contains" && group.match !== "whole") throw new TypeError("Unsupported filter match: " + group.match);
|
|
2800
|
+
return {
|
|
2801
|
+
category: group.category,
|
|
2802
|
+
whole: group.match === "whole",
|
|
2803
|
+
words: group.words.map(toRuleMatchKey)
|
|
2804
|
+
};
|
|
2805
|
+
});
|
|
2806
|
+
});
|
|
2807
|
+
/**
|
|
2808
|
+
* Categories the bundled filter rules identify, in rule order.
|
|
2809
|
+
*/
|
|
2810
|
+
var NON_LYRIC_CATEGORIES = [...new Set(nonLyricGroups.map((group) => group.category))];
|
|
2811
|
+
/**
|
|
2812
|
+
* Keeps rule order so earlier groups still take precedence within a selection; undefined selects every group.
|
|
2813
|
+
*/
|
|
2814
|
+
var selectNonLyricGroups = (categories) => {
|
|
2815
|
+
if (!categories) return nonLyricGroups;
|
|
2816
|
+
return nonLyricGroups.filter((group) => categories.includes(group.category));
|
|
2817
|
+
};
|
|
2818
|
+
/**
|
|
2819
|
+
* Returns the category of the first group that identifies the normalized text.
|
|
2820
|
+
* whole needs the complete text to equal a word, while contains accepts a word anywhere because the rules carry no word boundaries.
|
|
2821
|
+
*/
|
|
2822
|
+
var matchNonLyricCategory = (text, groups) => {
|
|
2823
|
+
const key = toRuleMatchKey(text);
|
|
2824
|
+
if (!key) return;
|
|
2825
|
+
for (const group of groups) if (group.whole ? group.words.includes(key) : group.words.some((word) => key.includes(word))) return group.category;
|
|
2826
|
+
};
|
|
2827
|
+
//#endregion
|
|
2828
|
+
//#region src/transforms/filter/remove.ts
|
|
2829
|
+
var toMusicInfoMatchText = (text) => {
|
|
2830
|
+
return text.normalize("NFC").trim().replace(/\s+/gu, " ").replace(/[A-Z]+/g, (run) => run.toLowerCase());
|
|
2831
|
+
};
|
|
2832
|
+
var findFirstMusicInfoLine = (lyric, musicInfo) => {
|
|
2833
|
+
const titles = (musicInfo.titles ?? []).map(toMusicInfoMatchText).filter(Boolean);
|
|
2834
|
+
const artists = (musicInfo.artists ?? []).map(toMusicInfoMatchText).filter(Boolean);
|
|
2835
|
+
if (!titles.length || !artists.length) return -1;
|
|
2836
|
+
const index = lyric.lines.findIndex((line) => {
|
|
2837
|
+
return line.type === LineType.NORMAL && !!getContentText(line.content).trim();
|
|
2838
|
+
});
|
|
2839
|
+
if (index === -1) return -1;
|
|
2840
|
+
const parts = getContentText(lyric.lines[index].content).trim().split(" - ");
|
|
2841
|
+
if (parts.length !== 2) return -1;
|
|
2842
|
+
const left = toMusicInfoMatchText(parts[0]);
|
|
2843
|
+
const right = toMusicInfoMatchText(parts[1]);
|
|
2844
|
+
if (!left || !right) return -1;
|
|
2845
|
+
const titleOnLeft = titles.some((title) => left.includes(title));
|
|
2846
|
+
const titleOnRight = titles.some((title) => right.includes(title));
|
|
2847
|
+
const artistOnLeft = artists.some((artist) => left.includes(artist));
|
|
2848
|
+
const artistOnRight = artists.some((artist) => right.includes(artist));
|
|
2849
|
+
return titleOnLeft && artistOnRight || artistOnLeft && titleOnRight ? index : -1;
|
|
2850
|
+
};
|
|
2851
|
+
/**
|
|
2852
|
+
* Removes normal lead lines matched by the shared notice rules and, when musicInfo is provided, first-line song information.
|
|
2853
|
+
* The first non-empty normal line must have one literal " - " separator and a known title and artist on opposite sides; either order and extra text such as bracketed aliases are accepted.
|
|
2854
|
+
* Drops attached annotations and backgrounds, refreshes language usages, and falls back to line timing when no word-level content remains.
|
|
2855
|
+
*
|
|
2856
|
+
* @returns The input when unchanged, or a new lyric sharing all unchanged nodes.
|
|
2857
|
+
*/
|
|
2858
|
+
var removeNonLyricLines = (lyric, options = {}) => {
|
|
2859
|
+
const groups = selectNonLyricGroups(options.categories);
|
|
2860
|
+
const musicInfoIndex = options.musicInfo ? findFirstMusicInfoLine(lyric, options.musicInfo) : -1;
|
|
2861
|
+
if (!groups.length && musicInfoIndex === -1) return lyric;
|
|
2862
|
+
const lines = lyric.lines.filter((line, index) => {
|
|
2863
|
+
if (index === musicInfoIndex) return false;
|
|
2864
|
+
return line.type !== LineType.NORMAL || matchNonLyricCategory(getContentText(line.content), groups) === void 0;
|
|
2865
|
+
});
|
|
2866
|
+
if (lines.length === lyric.lines.length) return lyric;
|
|
2867
|
+
let timing = lyric.timing;
|
|
2868
|
+
if (timing === Timing.WORD) {
|
|
2869
|
+
if (!lines.some((line) => {
|
|
2870
|
+
return isWordLevelLine(line) || line.backgrounds.some(isWordLevelLine);
|
|
2871
|
+
})) timing = Timing.LINE;
|
|
2872
|
+
}
|
|
2873
|
+
return {
|
|
2874
|
+
...lyric,
|
|
2875
|
+
lines,
|
|
2876
|
+
timing,
|
|
2877
|
+
languages: deriveLanguageUsages(lines)
|
|
2878
|
+
};
|
|
2879
|
+
};
|
|
2880
|
+
//#endregion
|
|
622
2881
|
//#region src/transforms/instrumental/index.ts
|
|
623
2882
|
var MAX_TIME = 2 ** 31 - 1;
|
|
624
2883
|
var readMinimum = (value, fallback, name) => {
|
|
@@ -642,7 +2901,7 @@ var readOccupiedTimeline = (lyric) => {
|
|
|
642
2901
|
const ranges = [];
|
|
643
2902
|
let firstSungStart = Infinity;
|
|
644
2903
|
const append = (time, sung) => {
|
|
645
|
-
if (time
|
|
2904
|
+
if (!time || validateTimeRange(time).length) return false;
|
|
646
2905
|
if (time.end === time.start) return true;
|
|
647
2906
|
ranges.push(time);
|
|
648
2907
|
if (sung) firstSungStart = Math.min(firstSungStart, time.start);
|
|
@@ -665,7 +2924,7 @@ var mergeLines = (lines, inserted) => {
|
|
|
665
2924
|
let source = lines;
|
|
666
2925
|
for (const [index, line] of lines.entries()) {
|
|
667
2926
|
const previous = lines[index - 1];
|
|
668
|
-
if (previous
|
|
2927
|
+
if (previous && compareLineTimes(previous, line) > 0) {
|
|
669
2928
|
source = [...lines].sort(compareLineTimes);
|
|
670
2929
|
break;
|
|
671
2930
|
}
|
|
@@ -674,7 +2933,7 @@ var mergeLines = (lines, inserted) => {
|
|
|
674
2933
|
let nextIndex = 0;
|
|
675
2934
|
for (const line of source) {
|
|
676
2935
|
let next = inserted[nextIndex];
|
|
677
|
-
while (next
|
|
2936
|
+
while (next && compareLineTimes(next, line) < 0) {
|
|
678
2937
|
merged.push(next);
|
|
679
2938
|
nextIndex += 1;
|
|
680
2939
|
next = inserted[nextIndex];
|
|
@@ -696,7 +2955,7 @@ var insertInstrumentalLines = (lyric, options = {}) => {
|
|
|
696
2955
|
const minDuration = readMinimum(options.minDuration, 1e4, "minDuration");
|
|
697
2956
|
const minIntroDuration = readMinimum(options.minIntroDuration, 5e3, "minIntroDuration");
|
|
698
2957
|
const endTime = readEndTime(options.endTime);
|
|
699
|
-
if (lyric.timing !== Timing.LINE && lyric.timing !== Timing.WORD || lyric.lines.length
|
|
2958
|
+
if (lyric.timing !== Timing.LINE && lyric.timing !== Timing.WORD || !lyric.lines.length) return lyric;
|
|
700
2959
|
const occupied = readOccupiedTimeline(lyric);
|
|
701
2960
|
if (!occupied || occupied.firstSungStart === Infinity) return lyric;
|
|
702
2961
|
const inserted = [];
|
|
@@ -714,7 +2973,7 @@ var insertInstrumentalLines = (lyric, options = {}) => {
|
|
|
714
2973
|
if (coveredEnd === Infinity) break;
|
|
715
2974
|
}
|
|
716
2975
|
if (endTime !== void 0) appendGap(endTime, minDuration);
|
|
717
|
-
if (inserted.length
|
|
2976
|
+
if (!inserted.length) return lyric;
|
|
718
2977
|
return {
|
|
719
2978
|
...lyric,
|
|
720
2979
|
lines: mergeLines(lyric.lines, inserted)
|
|
@@ -793,10 +3052,10 @@ var REPEATED_SPACES = / {2,}/gu;
|
|
|
793
3052
|
var REPEATED_MARKS = /[!;,\\?:+\-=/&]{2,}/gu;
|
|
794
3053
|
var PLACEHOLDER = /\u0001(\d+)\u0001/gu;
|
|
795
3054
|
var isDigit = (char) => {
|
|
796
|
-
return char
|
|
3055
|
+
return !!char && char >= "0" && char <= "9";
|
|
797
3056
|
};
|
|
798
3057
|
var isLatin = (char) => {
|
|
799
|
-
return char
|
|
3058
|
+
return !!char && (char >= "A" && char <= "Z" || char >= "a" && char <= "z");
|
|
800
3059
|
};
|
|
801
3060
|
/**
|
|
802
3061
|
* A comma or colon between two digits belongs to one number or clock time, so it stays tight.
|
|
@@ -1043,6 +3302,6 @@ var insertSpacesInLines = (lyric, options = {}) => {
|
|
|
1043
3302
|
};
|
|
1044
3303
|
};
|
|
1045
3304
|
//#endregion
|
|
1046
|
-
export { INSERT_SPACES_RULES, InsertSpacesRules, deriveWordEmphasis, extractBackgroundLines, insertInstrumentalLines, insertSpacesInLines, stripBackgroundBrackets };
|
|
3305
|
+
export { DEFAULT_CREDIT_NAME_SEPARATORS, INSERT_SPACES_RULES, InsertSpacesRules, NON_LYRIC_CATEGORIES, deriveWordEmphasis, extractAgents, extractBackgroundLines, extractCredits, insertInstrumentalLines, insertSpacesInLines, removeNonLyricLines, stripBackgroundBrackets };
|
|
1047
3306
|
|
|
1048
3307
|
//# sourceMappingURL=transforms.js.map
|