ghp / packages /server /src /services /kugouAudioQuality.ts
QSLY's picture
deploy: build Hugging Face Space from source
00a912e
Raw
History Blame Contribute Delete
5.22 kB
import type { AudioQuality } from '@music-together/shared'
import { normalizeKugouAudioUrl } from './kugouAudioUrl.js'
export type KugouProviderQuality =
| '128'
| '320'
| 'flac'
| 'high'
| 'super'
| 'viper_clear'
| 'viper_tape'
| 'viper_atmos'
| 'multitrack'
export interface KugouV6Good {
quality?: unknown
hash?: unknown
status?: unknown
level?: unknown
info?: {
filesize?: unknown
bitrate?: unknown
extname?: unknown
tracker_status?: unknown
tracker_type?: unknown
tracker_url?: unknown
en_filesize?: unknown
en_extname?: unknown
en_tracker_url?: unknown
en_ekey?: unknown
}
relate_goods?: unknown
}
export interface SelectedKugouV6Good {
quality: KugouProviderQuality
hash: string
bitrate: number | null
fileSize?: number
plainUrl?: string
encryptedUrl?: string
encryptedFileSize?: number
encryptedExtension?: string
ekey?: string
raw: KugouV6Good
}
const TECHNICAL_STEREO_QUALITIES = new Set<KugouProviderQuality>([
'128',
'320',
'flac',
'high',
'super',
'viper_clear',
])
function firstUrl(value: unknown): string | undefined {
if (Array.isArray(value)) {
const url = value.find((item) => typeof item === 'string' && item.length > 0)
return typeof url === 'string' ? normalizeKugouAudioUrl(url) : undefined
}
return typeof value === 'string' && value ? normalizeKugouAudioUrl(value) : undefined
}
function positiveNumber(value: unknown): number | undefined {
const number = Number(value)
return Number.isFinite(number) && number > 0 ? number : undefined
}
function normalizeGood(raw: KugouV6Good): SelectedKugouV6Good | null {
const quality = String(raw.quality ?? '').toLowerCase() as KugouProviderQuality
if (!TECHNICAL_STEREO_QUALITIES.has(quality) && quality !== 'viper_tape') return null
if (Number(raw.status) !== 1 || Number(raw.info?.tracker_status) !== 1 || raw.info?.tracker_type !== 'full') return null
const plainUrl = firstUrl(raw.info?.tracker_url)
const encryptedUrl = firstUrl(raw.info?.en_tracker_url)
const ekey = typeof raw.info?.en_ekey === 'string' && raw.info.en_ekey ? raw.info.en_ekey : undefined
if (!plainUrl && (!encryptedUrl || !ekey)) return null
return {
quality,
hash: String(raw.hash ?? ''),
bitrate: positiveNumber(raw.info?.bitrate) ?? null,
fileSize: positiveNumber(raw.info?.filesize),
plainUrl,
encryptedUrl,
encryptedFileSize: positiveNumber(raw.info?.en_filesize),
encryptedExtension:
typeof raw.info?.en_extname === 'string' ? raw.info.en_extname.toLowerCase().replace(/^\./, '') : undefined,
ekey,
raw,
}
}
export function collectKugouV6Goods(response: Record<string, unknown>): SelectedKugouV6Good[] {
const data = Array.isArray(response.data) ? response.data : response.data ? [response.data] : []
const rawGoods: KugouV6Good[] = []
for (const item of data) {
if (!item || typeof item !== 'object') continue
const root = item as KugouV6Good
rawGoods.push(root)
if (Array.isArray(root.relate_goods)) rawGoods.push(...(root.relate_goods as KugouV6Good[]))
}
const seen = new Set<string>()
return rawGoods.flatMap((raw) => {
const good = normalizeGood(raw)
if (!good) return []
const key = `${good.quality}:${good.hash.toLowerCase()}`
if (seen.has(key)) return []
seen.add(key)
return [good]
})
}
function technicalScore(good: SelectedKugouV6Good): [number, number, number] {
const defaultBitrate: Record<KugouProviderQuality, number> = {
'128': 128,
'320': 320,
flac: 900,
high: 1800,
super: 4000,
viper_clear: 3500,
viper_tape: 320,
viper_atmos: 0,
multitrack: 0,
}
return [good.bitrate ?? defaultBitrate[good.quality], good.fileSize ?? good.encryptedFileSize ?? 0, defaultBitrate[good.quality]]
}
function byTechnicalQuality(left: SelectedKugouV6Good, right: SelectedKugouV6Good): number {
const a = technicalScore(left)
const b = technicalScore(right)
return b[0] - a[0] || b[1] - a[1] || b[2] - a[2]
}
export function selectKugouV6Good(
goods: SelectedKugouV6Good[],
requested: AudioQuality,
): SelectedKugouV6Good | null {
const exact = (qualities: KugouProviderQuality[]) =>
qualities.flatMap((quality) => goods.filter((good) => good.quality === quality).sort(byTechnicalQuality))[0]
if (requested === 'kugou_master') {
return exact(['viper_tape']) ?? selectKugouV6Good(goods, 'kugou_hires')
}
if (requested === 'kugou_hires' || requested === 'highest') {
return goods.filter((good) => TECHNICAL_STEREO_QUALITIES.has(good.quality)).sort(byTechnicalQuality)[0] ?? null
}
if (typeof requested === 'number' && requested >= 999) return exact(['flac', '320', '128']) ?? null
if (typeof requested === 'number' && requested >= 320) return exact(['320', '128']) ?? null
return exact(['128']) ?? null
}
export function kugouProviderQualityToAudioQuality(quality: KugouProviderQuality): AudioQuality {
if (quality === 'viper_tape') return 'kugou_master'
if (quality === 'super' || quality === 'viper_clear' || quality === 'high') return 'kugou_hires'
if (quality === 'flac') return 999
if (quality === '320') return 320
return 128
}