lrclib-api
Version:
The unofficial lrclib.net library for JS and TS
351 lines (346 loc) • 11.8 kB
JavaScript
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