Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 44x 2x | import { MILLISECONDS } from "./constants"; import { IlrclibResponse, ILyrics } from "types/lyrics"; function convertTimestampToMs( minutes: string, seconds: string, centiseconds: string ): number { return ( parseInt(minutes) * MILLISECONDS.MINUTE + parseInt(seconds) * MILLISECONDS.SECOND + parseInt(centiseconds) * MILLISECONDS.CENTISECOND ); } function parseSyncedLyrics( syncedLyrics: IlrclibResponse["syncedLyrics"] ): ILyrics["lyrics"]["lines"] { const lines = syncedLyrics?.split("\n").filter((line) => line.trim()); const mappedLines = lines?.map((line, index, array) => { const timeMatch = RegExp(/\[(\d{2}):(\d{2})\.(\d{2})\]/).exec(line); Iif (!timeMatch) return null; const [, minutes, seconds, centiseconds] = timeMatch; const startTimeMs = convertTimestampToMs( minutes, seconds, centiseconds ).toString(); let endTimeMs = startTimeMs; if (index < array.length - 1) { const nextTimeMatch = RegExp(/\[(\d{2}):(\d{2})\.(\d{2})\]/).exec( array[index + 1] ); Iif (nextTimeMatch) { const [, nextMin, nextSec, nextCent] = nextTimeMatch; endTimeMs = convertTimestampToMs(nextMin, nextSec, nextCent).toString(); } } else { endTimeMs = (parseInt(startTimeMs) + 5000).toString(); } const words = line.replace(/\[\d{2}:\d{2}\.\d{2}\]/, "").trim(); return { startTimeMs, endTimeMs, words, syllables: [], }; }); return ( mappedLines?.filter( (line): line is NonNullable<typeof line> => line !== null ) || [] ); } function parseUnsyncedLyrics( plainLyrics: IlrclibResponse["plainLyrics"] ): ILyrics["lyrics"]["lines"] { const lines = plainLyrics?.split("\n").filter((line) => line.trim()); return ( lines?.map((line) => ({ startTimeMs: "0", endTimeMs: "0", words: line.trim(), syllables: [], })) || [] ); } function getInstrumentalLine(): ILyrics["lyrics"]["lines"] { return [ { startTimeMs: "0", endTimeMs: "0", words: "♪ Instrumental ♪", syllables: [], }, ]; } function getLines(lrclibResponse: IlrclibResponse, hasSync: boolean) { Iif (lrclibResponse.instrumental) { return getInstrumentalLine(); } Iif (hasSync) { return parseSyncedLyrics(lrclibResponse.syncedLyrics); } return parseUnsyncedLyrics(lrclibResponse.plainLyrics); } export function normalizeLrcLibLyrics( lrclibResponse: IlrclibResponse ): ILyrics { const hasSync = !!lrclibResponse.syncedLyrics?.includes("["); const syncType = hasSync ? "LINE_SYNCED" : "UNSYNCED"; const lines = getLines(lrclibResponse, hasSync); return { lyrics: { syncType: syncType, lines: lines, provider: "lrclib", providerLyricsId: lrclibResponse.id.toString(), providerDisplayName: "LRCLib", syncLyricsUri: `https://lrclib.net/api/get/${lrclibResponse.id}`, isDenseTypeface: false, alternatives: [], language: "en", isRtlLanguage: false, fullscreenAction: "FULLSCREEN_LYRICS", }, colors: { background: -9013642, text: -16777216, highlightText: -1, }, hasVocalRemoval: false, }; } |