openlyrics-parser
Version:
Parses and extracts data from OpenLyrics files, and creates them!
247 lines (246 loc) • 8.8 kB
JavaScript
import { XMLParser } from 'fast-xml-parser';
export class Parser {
lyricLineParser = new XMLParser({
ignoreAttributes: false,
attributeNamePrefix: '',
isArray: (_n, jPath) => {
return ['beat.chord'].includes(jPath);
},
});
getSongMeta(olSong) {
return {
createdIn: olSong.createdIn ?? '',
chordNotation: olSong.chordNotation ?? '',
lang: olSong['xml:lang'] ?? '',
modifiedDate: olSong.modifiedDate != null ? new Date(olSong.modifiedDate) : null,
modifiedIn: olSong.modifiedIn ?? '',
version: olSong.version.toString(),
};
}
getSongProperties(props) {
if (props.releaseDate != null) {
props.released = props.releaseDate;
}
return {
authors: this.getSongPropertyAuthors(props.authors),
ccliNo: props.ccliNo?.toString() ?? '',
comments: this.getSongPropertyComments(props.comments),
copyright: props.copyright?.toString() ?? '',
key: props.key ?? '',
keywords: props.keywords ?? '',
publisher: props.publisher ?? '',
released: props.released?.toString() ?? '',
songBooks: this.getSongPropertySongBooks(props.songbooks),
tempo: props.tempo?.['#text'].toString() ?? '',
tempoType: props.tempo?.type ?? '',
themes: this.getSongPropertyThemes(props.themes),
timeSignature: props.timeSignature ?? '',
titles: this.getSongPropertyTitles(props.titles),
transposition: props.transposition?.toString() ?? '',
variant: props.variant ?? '',
verseOrder: props.verseOrder ?? '',
version: props.version?.toString() ?? '',
};
}
getSongFormat(format) {
let application = '';
let tags = [];
if (format) {
application = format.tags.application;
tags = format.tags.tag.map((t) => {
return {
name: t.name,
open: t.open,
close: t.close ?? '',
};
});
}
return { application, tags };
}
getSongVerses(verses) {
const versesArr = [];
if (verses) {
for (const v of verses) {
versesArr.push({
break: v.break ?? '',
name: v.name,
lang: v.lang ?? '',
transliteration: v.translit ?? '',
lines: this.getVerseLines(v.lines),
});
}
}
return versesArr;
}
getSongInstruments(instruments) {
const instrumentsArr = [];
if (instruments) {
for (const i of instruments) {
instrumentsArr.push({
name: i.name,
lines: this.getInstrumentLines(i.lines),
});
}
}
return instrumentsArr;
}
getVerseLines(lines) {
const linesArr = [];
for (const line of lines) {
const rawLineTextAndXml = this.getStringOrTextProp(line);
const textAndXmlArr = this.parseLineTextForXml(rawLineTextAndXml);
linesArr.push({
break: this.getOptionalPropOnPossibleObject(line, 'break', ''),
content: this.getVerseContentObjects(textAndXmlArr),
part: this.getOptionalPropOnPossibleObject(line, 'part', ''),
repeat: this.getOptionalPropOnPossibleObject(line, 'repeat', ''),
});
}
return linesArr;
}
getInstrumentLines(lines) {
const linesArr = [];
for (const line of lines) {
const rawLineTextAndXml = this.getStringOrTextProp(line);
const textAndXmlArr = this.parseLineTextForXml(rawLineTextAndXml);
linesArr.push({
content: this.getInstrumentContentObjects(textAndXmlArr),
part: this.getOptionalPropOnPossibleObject(line, 'part', ''),
repeat: this.getOptionalPropOnPossibleObject(line, 'repeat', ''),
});
}
return linesArr;
}
parseLineTextForXml(str) {
return (str
.split(/(<[^/]+?>[\s\S]+?<\/.+?>)|(<[^/]+?\/>)/g)
.filter((x) => x !== '' && typeof x !== 'undefined'));
}
getVerseContentObjects(textAndXmlArr) {
const contentArr = [];
for (const part of textAndXmlArr) {
if (part.startsWith('<')) {
const parsedTag = this.lyricLineParser.parse(part);
if (parsedTag.comment != null) {
contentArr.push({
type: 'comment',
value: parsedTag.comment,
});
}
else if (parsedTag.tag != null) {
contentArr.push({
type: 'tag',
name: parsedTag.tag.name,
value: parsedTag.tag['#text'] ?? '',
});
}
else if (parsedTag.chord != null) {
contentArr.push(this.getChordObject(parsedTag.chord));
}
}
else {
contentArr.push({
type: 'text',
value: part,
});
}
}
return contentArr;
}
getInstrumentContentObjects(textAndXmlArr) {
const contentArr = [];
for (const part of textAndXmlArr) {
const parsedTag = this.lyricLineParser.parse(part);
if (parsedTag.chord != null) {
contentArr.push(this.getChordObject(parsedTag.chord));
}
else if (parsedTag.beat != null) {
contentArr.push({
type: 'beat',
chords: parsedTag.beat.chord.map((c) => this.getChordObject(c)),
});
}
}
return contentArr;
}
getChordObject(chordObj) {
const chord = { type: 'chord' };
Object.keys(chordObj).forEach((k) => {
let keyName = k === '#text' ? 'value' : k;
if (keyName === 'name') {
keyName = 'root';
}
chord[keyName] = chordObj[k];
});
return chord;
}
getSongPropertyAuthors(authors) {
const authorsArr = [];
if (authors) {
for (const a of authors.author) {
authorsArr.push({
lang: this.getOptionalPropOnPossibleObject(a, 'lang', ''),
type: this.getOptionalPropOnPossibleObject(a, 'type', ''),
value: this.getStringOrTextProp(a),
});
}
}
return authorsArr;
}
getSongPropertyComments(comments) {
let commentArr = [];
if (comments) {
commentArr = comments.comment.map((c) => this.getStringOrTextProp(c));
}
return commentArr;
}
getSongPropertyThemes(themes) {
const titlesArr = [];
if (themes) {
for (const t of themes.theme) {
titlesArr.push({
lang: this.getOptionalPropOnPossibleObject(t, 'lang', ''),
value: this.getStringOrTextProp(t),
});
}
}
return titlesArr;
}
getSongPropertyTitles(titles) {
const titlesArr = [];
if (titles) {
for (const t of titles.title) {
titlesArr.push({
lang: this.getOptionalPropOnPossibleObject(t, 'lang', ''),
original: this.getOptionalPropOnPossibleObject(t, 'original', null),
transliteration: this.getOptionalPropOnPossibleObject(t, 'translit', ''),
value: this.getStringOrTextProp(t),
});
}
}
return titlesArr;
}
getSongPropertySongBooks(songBooks) {
const titlesArr = [];
if (songBooks) {
for (const t of songBooks.songbook) {
titlesArr.push({
entry: t.entry?.toString() ?? '',
name: t.name,
});
}
}
return titlesArr;
}
getStringOrTextProp(str) {
return typeof str === 'string' ? str : str['#text'];
}
getOptionalPropOnPossibleObject(obj, propName, defaultVal) {
if (typeof obj === 'string' || typeof obj === 'number' || typeof obj === 'boolean') {
return defaultVal;
}
else {
return obj[propName] ?? defaultVal;
}
}
}