跳转至

登录

示例:手机号登录

import asyncio

from qqmusic_api.login import (
    LoginError,
    PhoneLoginEvents,
    phone_authorize,
    send_authcode,
)


async def phone_login_example():
    """手机验证码登录示例"""
    phone = 17385716325
    country_code = 86

    try:
        # 1. 发送验证码
        event, info = await send_authcode(phone, country_code)

        if event == PhoneLoginEvents.CAPTCHA:
            print(f"需要验证,访问链接: {info}")
            return None
        if event == PhoneLoginEvents.FREQUENCY:
            print("操作过于频繁,请稍后再试")
            return None

        print("验证码已发送")

        # 2. 获取用户输入
        auth_code = input("请输入验证码: ").strip()

        # 3. 执行登录
        credential = await phone_authorize(phone, int(auth_code), country_code)
        print(f"登录成功! MusicID: {credential.musicid}")
        return credential

    except LoginError as e:
        print(f"登录失败: {e!s}")
    except ValueError:
        print("验证码必须为6位数字")
    except Exception as e:
        print(f"发生未知错误: {e!s}")


asyncio.run(phone_login_example())

示例:二维码登录

import asyncio

from qqmusic_api.login import (
    QR,
    LoginError,
    QRCodeLoginEvents,
    QRLoginType,
    check_mobile_qr,  # [新增] 导入 check_mobile_qr
    check_qrcode,
    get_qrcode,
)


def show_qrcode(qr: QR):
    """显示二维码"""
    try:
        from io import BytesIO

        from PIL import Image
        from pyzbar.pyzbar import decode
        from qrcode import QRCode  # type: ignore

        img = Image.open(BytesIO(qr.data))
        decoded = decode(img)
        if not decoded:
            print("无法解码二维码图片")
            return

        url = decoded[0].data.decode("utf-8")
        qr_console = QRCode()
        qr_console.add_data(url)
        qr_console.print_ascii()
    except ImportError:
        # 保存二维码到当前目录
        save_path = qr.save()
        print(f"二维码已保存至: {save_path}")


async def qrcode_login_example(login_type: QRLoginType):  # noqa: C901
    """二维码登录示例"""

    try:
        # 1. 获取二维码
        print(f"正在获取 {login_type.name} 二维码...")
        qr = await get_qrcode(login_type)
        print(f"获取 {login_type.name} 二维码成功")

        show_qrcode(qr)

        # 2. 监听扫码状态
        # 注意: MOBILE (QQ音乐APP) 使用 MQTT 协议 (推送流), 其他使用 HTTP 协议 (轮询)

        if login_type == QRLoginType.MOBILE:
            print(">>> 请使用 [QQ音乐APP] 扫码 (MQTT监听中)")
            async for event, credential in check_mobile_qr(qr):
                print(f"当前状态: {event.name}")

                if event == QRCodeLoginEvents.DONE:
                    print(f"登录成功! MusicID: {credential.musicid}")
                    return credential

                elif event == QRCodeLoginEvents.TIMEOUT:
                    print("二维码已过期,请重新获取")
                    break

                elif event == QRCodeLoginEvents.REFUSE:
                    print("用户拒绝了登录请求")
                    break

                # MQTT 不需要 sleep,因为是服务器推送消息

        else:
            print(f">>> 请使用 [{login_type.name}] 扫码 (HTTP轮询中)")
            while True:
                event, credential = await check_qrcode(qr)
                print(f"当前状态: {event.name}")

                if event == QRCodeLoginEvents.DONE:
                    print(f"登录成功! MusicID: {credential.musicid}")
                    return credential

                if event == QRCodeLoginEvents.TIMEOUT:
                    print("二维码已过期,请重新获取")
                    break

                if event == QRCodeLoginEvents.SCAN:
                    await asyncio.sleep(3)  # 3秒轮询一次
                else:
                    await asyncio.sleep(2)

    except LoginError as e:
        print(f"登录失败: {e!s}")
    except Exception:
        raise


async def main():
    print("请选择登录方式:")
    print("1. QQ   (使用手机QQ扫码)")
    print("2. WX   (使用微信扫码)")
    print("3. MOBILE (使用QQ音乐APP扫码)")

    choice = input("请输入选项 (1/2/3): ").strip()

    if choice == "1":
        await qrcode_login_example(QRLoginType.QQ)
    elif choice == "2":
        await qrcode_login_example(QRLoginType.WX)
    elif choice == "3":
        await qrcode_login_example(QRLoginType.MOBILE)
    else:
        print("无效的选项")


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n用户取消操作")