diff --git a/src/YTMusic.ts b/src/YTMusic.ts index 229441d..9e18b36 100644 --- a/src/YTMusic.ts +++ b/src/YTMusic.ts @@ -346,6 +346,23 @@ export default class YTMusic { return video } + /** + * Get lyrics of a specific Song + * + * @param videoId Video ID + * @returns Lyrics + */ + public async getLyrics(videoId: string) { + if (!videoId.match(/^[a-zA-Z0-9-_]{11}$/)) throw new Error("Invalid videoId") + const data = await this.constructRequest("next", { videoId }) + const browseId = traverse(traverseList(data, "tabs", "tabRenderer")[1], "browseId") + + const lyricsData = await this.constructRequest("browse", { browseId }) + const lyrics = traverseString(lyricsData, "description", "runs", "text")() + + return lyrics ? lyrics.replaceAll("\r", "").split("\n") : null + } + /** * Get all possible information of an Artist * diff --git a/src/tests/traversing.spec.ts b/src/tests/traversing.spec.ts index 27aa0b4..ea4b005 100644 --- a/src/tests/traversing.spec.ts +++ b/src/tests/traversing.spec.ts @@ -21,10 +21,10 @@ const errors: Problem[] = [] const queries = ["Lilac", "Weekend", "Eill", "Eminem", "Lisa Hannigan"] const expect = (data: any, type: Type) => { const result = type(data) - if (!result.data && "problems" in result) { + if (!result.data && result.problems?.length) { errors.push(...result.problems!) } - equal(!!result.data, true) + equal(result.problems, undefined) } const ytmusic = new YTMusic() @@ -67,6 +67,12 @@ queries.forEach(query => { expect(results, arrayOf(SearchResult)) }) + it("Get lyrics of the first song result", async () => { + const songs = await ytmusic.searchSongs(query) + const lyrics = await ytmusic.getLyrics(songs[0]!.videoId) + expect(lyrics, type("string[]|null")) + }) + it("Get details of the first song result", async () => { const songs = await ytmusic.searchSongs(query) const song = await ytmusic.getSong(songs[0]!.videoId)