跳转至

下载歌曲

获取歌曲文件链接需要登录凭证。基本流程:先获取 CDN 节点,再请求文件地址。

基本用法

import asyncio
import random

from qqmusic_api import Client, Credential
from qqmusic_api.modules.song import SongFileInfo


async def main() -> None:
    credential = Credential(musicid=123456, musickey="Q_H_L_xxx")
    async with Client(credential=credential) as client:
        cdn_dispatch = await client.song.get_cdn_dispatch()
        cdn = random.choice(cdn_dispatch.sip)

        urls = await client.song.get_song_urls(
            [SongFileInfo(mid="003w2xz20QlUZt")]
        )
        for info in urls.data:
            if info.purl:
                print(f"{info.mid}: {cdn}{info.purl}")


asyncio.run(main())

检查下载权限

通过 query_song 获取歌曲信息后,可从 pay 字段判断是否需要付费:

song = await client.song.query_song(["003w2xz20QlUZt"])
track = song.tracks[0]

# pay_play: 1=需要付费播放, 0=免费
# pay_down: 1=需要付费下载, 0=免费
# pay_month: 1=需要绿钻/付费包
if track.pay.pay_month == 1:
    print("需要绿钻或付费包权限")
elif track.pay.pay_down == 1:
    print("需要单独付费下载")
else:
    print("可免费下载")

请求文件链接后,UrlinfoItem.result 会返回授权结果码:

result 含义
0 成功,purl 可用
104003 无权限(未登录或等级不够)
104004 VKey 获取失败
104013 播放设备受限
urls = await client.song.get_song_urls([SongFileInfo(mid="003w2xz20QlUZt")])
for info in urls.data:
    if info.result == 0 and info.purl:
        url = cdn + info.purl
        print(f"可下载: {url}")
    else:
        print(f"无法下载 (result={info.result})")

检查文件是否存在

query_song 返回的 file 字段包含各音质的文件大小,值为 0 表示该音质不存在:

song = await client.song.query_song(["003w2xz20QlUZt"])
track = song.tracks[0]

file = track.file
if file.size_flac > 0:
    print(f"FLAC 无损可用, 大小: {file.size_flac / 1024 / 1024:.1f} MB")
if file.size_320mp3 > 0:
    print(f"MP3 320k 可用, 大小: {file.size_320mp3 / 1024 / 1024:.1f} MB")
if file.size_128mp3 > 0:
    print(f"MP3 128k 可用, 大小: {file.size_128mp3 / 1024 / 1024:.1f} MB")

同时获取多种音质

get_song_urls 支持在一次请求中为同一首歌请求不同音质。为每首歌构造多个 SongFileInfo,指定不同的 file_type

from qqmusic_api.modules.song import SongFileInfo, SongFileType

song_mid = "003w2xz20QlUZt"
media_mid = "003w2xz20QlUZt"  # 从 track.file.media_mid 获取

urls = await client.song.get_song_urls(
    [
        SongFileInfo(mid=song_mid, file_type=SongFileType.MP3_128, media_mid=media_mid),
        SongFileInfo(mid=song_mid, file_type=SongFileType.FLAC, media_mid=media_mid),
        SongFileInfo(mid=song_mid, file_type=SongFileType.OGG_320, media_mid=media_mid),
    ]
)

for info in urls.data:
    if info.result == 0 and info.purl:
        print(f"{info.filename}: {cdn}{info.purl}")

常用的 SongFileType

枚举值 音质 格式
MP3_128 标准音质 MP3 128k
MP3_320 HQ 高品质 MP3 320k
OGG_192 HQ 高品质 OGG 192k
OGG_320 HQ 高品质 OGG 320k
FLAC SQ 无损 FLAC
OGG_640 SQ 无损 OGG 640k
MASTER 臻品母带 FLAC 24Bit/192kHz

Tip

ACC_96音质部分 VIP 歌曲即使未登录或无会员,也可能通过该音质获取到播放链接(试听级别)。