UNPKG

lrclib-api

Version:

The unofficial lrclib.net library for JS and TS

351 lines (346 loc) 11.8 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/errors/NotFound.ts var NotFoundError = class extends Error { constructor() { super("Track was not found"); } }; var NoResultError = class extends Error { constructor() { super("No result was found"); } }; // src/errors/RequestError.ts var RequestError = class extends Error { constructor(error) { super("Request error " + error); } }; var KeyError = class extends Error { constructor(error) { super("The key has not been configured."); } }; // src/utils.ts function parseLocalLyrics(lyrics) { const lines = lyrics.replace(/\[[a-zA-Z]+:.+\]/g, "").trim().split("\n"); const syncedTimestamp = /\[([0-9:.]+)\]/; const unsynced = []; const synced = []; lines.forEach((line) => { const syncMatch = line.match(syncedTimestamp); if (syncMatch) { const startTime = parseTime(syncMatch[1]); const text = line.replace(syncedTimestamp, "").trim(); if (text) { synced.push({ text, startTime }); } } else { const text = line.trim(); if (text) { unsynced.push({ text }); } } }); return { synced: synced.length > 0 ? synced : null, unsynced }; } function parseTime(time) { const [minutes, seconds] = time.split(":").map(Number); return minutes * 60 + seconds; } // src/client.ts var Client = class { /** * Creates a request client to api * * Example Usage; * ```typescript * const client = new Client(); * * client.findLyrics({ track_name: "The Chain", artist_name: "Fleetwood Mac" }).then(console.log); * ``` * * @notigorwastaken: I'm still working on it. * * @param options - An optional object containing Client Options * - `url`: The base URL, e.g. you can set up a custom url that uses another lrclib.net instance * - `key`: The token used to publish lyrics to the api. [click here for more info](https://lrclib.net/docs) */ constructor(options) { this._url = "https://lrclib.net/api"; this._url = (options == null ? void 0 : options.url) || this._url; this._key = options == null ? void 0 : options.key; } request(path, options) { return __async(this, null, function* () { return yield fetch(this._url + path, options); }); } post(path, body, options) { return __async(this, null, function* () { if (!this._key) throw new KeyError(); const response = yield fetch(this._url + path, __spreadProps(__spreadValues({}, options), { headers: { "X-Publish-Token": this._key }, body: JSON.stringify(body), method: "post" })); if (response.status !== 201) throw yield response.json(); return yield response.text(); }); } postAlt(path, headers, body, options) { return __async(this, null, function* () { return yield fetch(this._url + path, __spreadValues({ method: "post", headers, body }, options)); }); } /** * Sends a request to the lyrics search API at https://lrclib.net/api/search. * * Example Usage: * ```typescript * const search = await searchLyrics({ query: "The Chain" }); * ``` * * @param info - An object containing search parameters: * - `query`: The search term (conditional | e.g., song title or lyrics fragment). * - `track_name`: The name of the track (conditional). * - `artist_name`: The artist's name (optional). * - `duration`: The song duration in milliseconds (optional). * * @returns A promise that resolves to an array of {@link FindLyricsResponse | FindLyricsResponse[]}. */ searchLyrics(info, options) { return __async(this, null, function* () { const baseURL = "/search"; const params = { q: info.query || "", track_name: info.track_name || "", artist_name: info.artist_name || "", duration: info.duration ? info.duration / 1e3 : "" }; const finalURL = `${baseURL}?${Object.entries(params).filter(([_, value]) => value !== void 0 && value !== "").map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&")}`; const response = yield this.request(finalURL, options); if (!response.ok) { throw new RequestError(); } const body = yield response.json(); if (!body) { throw new NoResultError(); } return body; }); } /** * Finds lyrics for a given track using the API at https://lrclib.net/api/get. * * Example Usage: * ```typescript * const lyrics = await findLyrics({ track_name: "The Chain", artist_name: "Fleetwood Mac" }); * ``` * * @param info - An object containing query parameters: * - `id`: The unique identifier of the track (conditional). * - `track_name`: The name of the track (conditional). * - `artist_name`: The artist's name (conditional). * - `album_name`: The album's name (optional). * - `duration`: The song duration in milliseconds (optional). * * @returns A promise that resolves to a {@link FindLyricsResponse | FindLyricsResponse} object containing the track's lyrics. * @throws Will throw an error if the request fails or the track is not found. */ findLyrics(info, options) { return __async(this, null, function* () { const parseID = info.id ? `/${info.id}` : "?"; const baseURL = "/get" + parseID; const durr = (info == null ? void 0 : info.duration) ? info.duration / 1e3 : void 0; const params = { track_name: info.track_name || "", artist_name: info.artist_name || "", album_name: info.album_name || "", duration: durr || "" }; const finalURL = `${baseURL}${Object.entries(params).filter(([_, value]) => value !== void 0 && value !== "").map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&")}`; const response = yield this.request(finalURL, options); if (!response.ok && response.status === 404) { throw new NotFoundError(); } else if (!response.ok && response.status !== 200) { throw new RequestError(response.statusText); } const body = yield response.json(); return body; }); } /** * Retrieves unsynchronized (plain) lyrics for a given track. * * Example Usage: * ```typescript * const unsyncedLyrics = await getUnsynced({ track_name: "The Chain", artist_name: "Fleetwood Mac" }); * ``` * * @param info - An object containing query parameters: * - `id`: The unique identifier of the track (conditional). * - `track_name`: The name of the track (conditional). * - `artist_name`: The artist's name (conditional). * - `album_name`: The album's name (optional). * - `duration`: The song duration in milliseconds (optional). * * @returns A promise that resolves to an array of {@link LyricLine | LyricLine[]} objects * containing unsynchronized lyrics or `null` if no lyrics are found. */ getUnsynced(info) { return __async(this, null, function* () { try { const body = yield this.findLyrics(info); if ("error" in body) return null; const unsyncedLyrics = body == null ? void 0 : body.plainLyrics; const isInstrumental = body.instrumental; if (isInstrumental) return [{ text: "[Instrumental]" }]; if (!unsyncedLyrics) return null; return parseLocalLyrics(unsyncedLyrics).unsynced; } catch (e) { console.error(e); return null; } }); } /** * Retrieves synchronized (timed) lyrics for a given track. * * Example Usage: * ```typescript * const syncedLyrics = await getSynced({ track_name: "The Chain", artist_name: "Fleetwood Mac" }); * ``` * * @param info - An object containing query parameters: * - `id`: The unique identifier of the track (conditional). * - `track_name`: The name of the track (conditional). * - `artist_name`: The artist's name (conditional). * - `album_name`: The album's name (optional). * - `duration`: The song duration in milliseconds (optional). * * @returns A promise that resolves to an array of {@link LyricLine | LyricLine[]} objects * containing synchronized lyrics or `null` if no lyrics are found. */ getSynced(info) { return __async(this, null, function* () { try { const body = yield this.findLyrics(info); const syncedLyrics = body == null ? void 0 : body.syncedLyrics; const isInstrumental = body.instrumental; if (isInstrumental) return [{ text: "[Instrumental]" }]; if (!syncedLyrics) return null; return parseLocalLyrics(syncedLyrics).synced; } catch (e) { console.error(e); return null; } }); } requestChallenge() { return __async(this, null, function* () { var _a; try { const challenge = yield this.postAlt("/request-challenge"); if (!challenge.ok) throw new RequestError(challenge.statusText); const response = yield challenge.json(); if (!response.prefix || !response.target) return null; return { prefix: response.prefix, target: response.target }; } catch (e) { throw new Error((_a = e == null ? void 0 : e.message) != null ? _a : "Unknown Error"); } }); } /** * This is an experimental function / API. public async publishLyrics(info: PublishLyrics) { try { const challenge = await this.requestChallenge(); const response = await this.postAlt( "/publish", { "X-Publish-Token": challenge?.prefix + ":" + solveChallenge( challenge?.prefix as string, challenge?.target as string, ), "content-type": "application/json", Accept: "application/json", }, { track_name: info.trackName, artist_name: info.artistName, album_name: info.albumName, duration: info.duration, plain_lyrics: info.plainLyrics, synced_lyrics: "", }, ); return response; } catch (e: any) { throw new Error(e?.message ?? "Unknown Error"); } }*/ }; export { Client, KeyError, NoResultError, NotFoundError, RequestError, parseLocalLyrics, parseTime }; //# sourceMappingURL=index.mjs.map