add lyrics support to deezer, bump version

This commit is contained in:
uh wot
2024-09-21 00:17:27 +02:00
parent 7e8f4fadf8
commit 164a7b821f
3 changed files with 63 additions and 16 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "lucida",
"version": "2.0.0-46",
"version": "2.0.0-47",
"description": "A modular music downloader tool",
"main": "build/index.js",
"type": "module",

View File

@@ -25,7 +25,8 @@ import {
parseAlbum,
parseArtist,
parseTrack,
parsePlaylistMetadata
parsePlaylistMetadata,
DeezerLyrics
} from './parse.js'
import { Readable, Transform } from 'stream'
import { Blowfish } from 'blowfish-cbc'
@@ -51,6 +52,7 @@ interface APIMethod {
}
'deezer.pageTrack': {
DATA: DeezerTrack
LYRICS?: DeezerLyrics
}
'deezer.pagePlaylist': {
DATA: DeezerPlaylistMetadata
@@ -318,7 +320,7 @@ export default class Deezer implements StreamerWithLogin {
const data = {
metadata: { ...parseAlbum(DATA), trackCount: SONGS.data.length },
tracks: SONGS.data.map(parseTrack)
tracks: SONGS.data.map((t) => parseTrack(t))
}
if (!data.metadata.trackCount) data.metadata.trackCount = data.tracks.length
@@ -345,18 +347,16 @@ export default class Deezer implements StreamerWithLogin {
return {
type: 'playlist',
metadata: parsePlaylistMetadata(playlistMetadata),
tracks: playlistTracks.map(parseTrack)
tracks: playlistTracks.map((t) => parseTrack(t))
}
}
// Track
async #getTrackData(id: number): Promise<DeezerTrack> {
return (
await this.#apiCall('deezer.pageTrack', {
sng_id: id
})
).DATA
async #getTrackPage(id: number): Promise<APIMethod['deezer.pageTrack']> {
return await this.#apiCall('deezer.pageTrack', {
sng_id: id
})
}
async #getStream(track: DeezerTrack): Promise<GetStreamResponse> {
@@ -531,12 +531,12 @@ export default class Deezer implements StreamerWithLogin {
}
}
case 'track': {
const track = await this.#getTrackData(id)
const trackPage = await this.#getTrackPage(id)
return {
type: 'track',
metadata: parseTrack(track),
metadata: parseTrack(trackPage.DATA, trackPage.LYRICS),
getStream: () => {
return this.#getStream(track)
return this.#getStream(trackPage.DATA)
}
}
}

View File

@@ -1,4 +1,4 @@
import { Album, Artist, CoverArtwork, Playlist, Track } from '../../types.js'
import { Album, Artist, CoverArtwork, LyricLine, Playlist, Track } from '../../types.js'
import { SIZES } from './constants.js'
export enum DeezerFormat {
@@ -69,7 +69,7 @@ export function parseArtist(
)
let parsedTracks
if (tracks) parsedTracks = tracks.map(parseTrack)
if (tracks) parsedTracks = tracks.map((t) => parseTrack(t))
let parsedAlbums
if (albums) parsedAlbums = albums.map(parseAlbum)
@@ -142,7 +142,20 @@ export interface DeezerTrack {
FALLBACK?: DeezerTrack
}
export function parseTrack(track: DeezerTrack): Track {
export interface DeezerLyrics {
LYRICS_ID: string
LYRICS_SYNC_JSON: DeezerSyncedLine[]
LYRICS_TEXT: string
}
export interface DeezerSyncedLine {
lrc_timestamp?: string
milliseconds?: string
duration?: string
line: string
}
export function parseTrack(track: DeezerTrack, lyricsData?: DeezerLyrics): Track {
const addt: {
regions?: string[]
copyright?: string
@@ -158,6 +171,39 @@ export function parseTrack(track: DeezerTrack): Track {
if (track.SNG_CONTRIBUTORS?.composer) addt.composers = track.SNG_CONTRIBUTORS?.composer
if (track.SNG_CONTRIBUTORS?.composer) addt.lyricists = track.SNG_CONTRIBUTORS?.lyricist
let lyrics
if (lyricsData) {
const lines: LyricLine[] = []
const syncedLyrics = lyricsData.LYRICS_SYNC_JSON
if (syncedLyrics) {
let lastLineEnd = 0
for (const line of syncedLyrics) {
if (!line.line) {
const lastLine = lines[lines.length - 1]
if (lastLine) lastLine.endTimeMs = lastLineEnd
continue
}
lines.push({
text: line.line,
startTimeMs: parseInt(line.milliseconds!)
})
lastLineEnd = parseInt(line.milliseconds!) + parseInt(line.duration!)
}
} else {
lines.push({
text: lyricsData.LYRICS_TEXT
})
}
lyrics = {
id: lyricsData.LYRICS_ID,
source: 'deezer',
lines
}
}
return {
title: track.VERSION ? `${track.SNG_TITLE} ${track.VERSION}` : track.SNG_TITLE,
id: track.SNG_ID,
@@ -174,6 +220,7 @@ export function parseTrack(track: DeezerTrack): Track {
}),
durationMs: parseInt(track.DURATION) * 1e3,
coverArtwork: parseArtwork(track.ALB_PICTURE),
lyrics,
...addt
}
}