chore: update public repo

This commit is contained in:
desu-bot 2025-08-14 09:21:11 +00:00
parent ccc5f98f34
commit 728699b3ec
No known key found for this signature in database
8 changed files with 1990 additions and 95 deletions

View file

@ -311,12 +311,93 @@ function getTrackName(track: GwTrack) {
return name
}
// todo
// async function resolveMusicbrainzIds(albumId: number) {
// const deezerUrl = `https://www.deezer.com/album/${albumId}`
// // try odesli api to fetch extra links
// const odesliRes = await ffetch('https://api.song.link/v1-alpha.1/links', {
// query: {
// url: deezerUrl,
// key: '71d7be8a-3a76-459b-b21e-8f0350374984',
// },
// }).parsedJson(z.object({
// linksByPlatform: z.record(z.string(), z.object({
// url: z.string(),
// })),
// })).catch(() => null)
// const urls = [deezerUrl]
// if (odesliRes) {
// for (const { url } of Object.values(odesliRes.linksByPlatform)) {
// urls.push(url)
// }
// }
// // try to resolve musicbrainz album id
// const mbRes1 = await ffetch('https://musicbrainz.org/ws/2/url', {
// query: {
// resource: urls,
// inc: 'release-rels',
// },
// }).parsedJson(z.object({
// urls: z.array(z.object({
// relations: z.array(z.any()),
// })),
// }))
// const uniqueMbIds = new Set<string>()
// for (const { relations } of mbRes1.urls) {
// for (const rel of relations) {
// if (rel['target-type'] !== 'release') continue
// uniqueMbIds.add(rel.release.id)
// }
// }
// if (uniqueMbIds.size === 0) return null
// const releaseMbId = uniqueMbIds.values().next().value
// // resolve the rest of the ids from the release
// const releaseRes = await ffetch(`https://musicbrainz.org/ws/2/release/${releaseMbId}`, {
// query: {
// inc: 'artists recordings',
// },
// }).parsedJson(z.object({
// 'artist-credit': z.array(z.object({
// artist: z.object({
// id: z.string(),
// }),
// })).optional(),
// 'media': z.array(z.object({
// id: z.string(),
// tracks: z.array(z.object({
// position: z.number(),
// title: z.string(),
// id: z.string(),
// recording: z.object({
// id: z.string(),
// }),
// })),
// })).optional(),
// }))
// return {
// release: releaseMbId,
// artists: releaseRes['artist-credit']?.map(it => it.artist.id) ?? [],
// tracks: releaseRes['media']?.[0]
// }
// }
async function downloadTrack(track: GwTrack, opts: {
destination: string
album?: GwAlbum
}) {
const albumUrl = `https://cdn-images.dzcdn.net/images/cover/${track.ALB_PICTURE}/1500x1500-000000-80-0-0.jpg`
const [getUrlRes, albumAb, lyricsRes] = await Promise.all([
const [
getUrlRes,
albumAb,
lyricsRes,
] = await Promise.all([
ffetch.post('https://media.deezer.com/v1/get_url', {
json: {
license_token: userData.USER.OPTIONS.license_token,
@ -343,6 +424,8 @@ async function downloadTrack(track: GwTrack, opts: {
}),
])
// console.dir(getUrlRes, { depth: null })
const albumCoverPath = join(`assets/deezer-tmp-${track.SNG_ID}.jpg`)
await writeFile(albumCoverPath, new Uint8Array(albumAb))
@ -487,6 +570,10 @@ async function downloadTrack(track: GwTrack, opts: {
params.push(`--set-tag=COPYRIGHT=${opts.album.COPYRIGHT}`)
}
if (lyricsLrc) {
params.push(`--set-tag=LYRICS=${lyricsLrc}`)
}
params.push(filename)
await $`metaflac ${params}`
@ -605,9 +692,10 @@ async function downloadArtist(artistId: string) {
spinnies.succeed('collect', { text: `collected ${albums.length} albums with a total of ${trackCount} tracks` })
}
// fixme: singles should always contain artist name and be saved in artist root dir
// fixme: "featured" albums (i.e. when main artist of the album is not the one we're dling) should have album artist name in its dirname
// fixme: "featured" albums/tracks (i.e. when main artist of the album is not the one we're dling) should have album artist name in its dirname
// fixme: singles should be saved in artist root dir
// todo: automatic musicbrainz matching
// todo: automatic genius/musixmatch matching for lyrics if unavailable directly from deezer
await asyncPool(albums, async (alb) => {
const tracks = await gwLightApi({
@ -784,6 +872,14 @@ if (url.match(/^(artist|album|track):(\d+)$/)) {
node: z.object({
id: z.string(),
title: z.string(),
contributors: z.object({
edges: z.array(z.object({
node: z.object({
id: z.string(),
name: z.string(),
}),
})),
}),
}),
})),
}),
@ -801,7 +897,7 @@ if (url.match(/^(artist|album|track):(\d+)$/)) {
}
for (const [i, { node }] of iter.enumerate(searchResult.instantSearch.results.tracks.edges)) {
console.log(`track:${node.id}: ${node.title}`)
console.log(`track:${node.id}: ${node.contributors.edges.map(it => it.node.name).join(', ')} - ${node.title}`)
}
const uri = await question('option > ')