UNPKG

openlyrics-parser

Version:

Parses and extracts data from OpenLyrics files, and creates them!

247 lines (246 loc) 8.8 kB
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; } } }