UNPKG

beatprints.js

Version:

A Node.js version of the original Python BeatPrints project (https://github.com/TrueMyst/BeatPrints/) by TrueMyst. Create eye-catching, Pinterest-style music posters effortlessly. BeatPrints integrates with Spotify and LRClib API to help you design custom

73 lines (72 loc) 2.85 kB
import * as lrc from 'lrclib-api'; import { NoLyricsAvailable, InvalidFormatError, InvalidSelectionError, LineLimitExceededError } from './errors.js'; /** * A class for interacting with the LRClib API to fetch and manage song lyrics. */ export class Lyrics { constructor() { this.api = new lrc.Client(); } /** * Determines if a track is instrumental. * @param {TrackMetadata} metadata The metadata of the track. * @returns {boolean} True if the track is instrumental (i.e., no lyrics found), false otherwise. * @throws `NoLyricsAvailable` if no lyrics are found for the specified track and artist. */ async checkInstrumental(metadata) { const result = await this.api.findLyrics({ track_name: metadata.name, artist_name: metadata.artist }); return result.instrumental; } async getLyrics(metadata, index = false) { this.metadata = metadata; const lyrics = (await this.api.findLyrics({ track_name: metadata.name, artist_name: metadata.artist })).plainLyrics; if (await this.checkInstrumental(metadata)) return ''; if (!lyrics) { throw new NoLyricsAvailable(); } // Remove blanks between verses const clearedLyrics = lyrics.split('\n').filter(x => x.trim()); return index ? clearedLyrics.map((verse, i) => `${i + 1}. ${verse}`).join('\n') : clearedLyrics.join('\n'); } async selectLines(lyrics, selection) { if (await this.checkInstrumental(this.metadata) || !lyrics) return ''; const rawLines = lyrics.split('\n'); let lines; // Remove indexes (e.g., 1. Verse) from lyrics if exists if (rawLines.some(v => /^\d+\./.test(v))) { lines = rawLines.map(line => line.replace(/^\d+\.\s*/, '')); } else lines = rawLines; const lineCount = lines.length; try { const pattern = /^\d+-\d+$/; if (!pattern.test(selection)) { throw new InvalidFormatError(); } const selected = selection.split('-').map((num) => parseInt(num, 10)); if (selected.length !== 2 || selected[0] >= selected[1] || selected[0] <= 0 || selected[1] > lineCount) { throw new InvalidSelectionError(); } const extracted = lines.slice(selected[0] - 1, selected[1]); const selectedLines = extracted.filter(line => line !== ''); if (selectedLines.length !== 4) { throw new LineLimitExceededError(); } return selectedLines.join('\n'); } catch (err) { if (err instanceof Error) { throw err; } } } }