import os
import json
import time
import qrcode
import requests
from PIL import Image
from config import BILIBILI_API, DOWNLOAD_CONFIG
import subprocess

class BilibiliDownloader:
    def __init__(self):
        self.session = requests.Session()
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        self.session.headers.update(self.headers)
        self.cookies = self._load_cookies()

    def _load_cookies(self):
        """加载保存的cookies"""
        if os.path.exists(DOWNLOAD_CONFIG['cookie_file']):
            with open(DOWNLOAD_CONFIG['cookie_file'], 'r') as f:
                return json.load(f)
        return None

    def _save_cookies(self):
        """保存cookies到文件"""
        with open(DOWNLOAD_CONFIG['cookie_file'], 'w') as f:
            json.dump(dict(self.session.cookies), f)

    def login(self):
        """使用二维码登录B站"""
        # 获取二维码URL
        response = self.session.get('https://passport.bilibili.com/x/passport-login/web/qrcode/generate')
        data = response.json()
        if data['code'] != 0:
            print(f"获取二维码失败：{data}")
            return False
            
        qr_url = data['data']['url']
        qr_key = data['data']['qrcode_key']

        # 生成二维码
        qr = qrcode.QRCode()
        qr.add_data(qr_url)
        qr.make()
        img = qr.make_image()
        img.save('login_qr.png')
        
        # 打开二维码
        try:
            # 在Windows系统下使用默认图片查看器打开
            os.system('start login_qr.png')
        except:
            try:
                Image.open('login_qr.png').show()
            except:
                print("二维码已保存到login_qr.png文件，请手动打开扫描")
        
        print("\n请使用B站手机客户端扫描二维码登录")
        print("二维码文件保存在：", os.path.abspath('login_qr.png'))

        # 等待扫描登录
        while True:
            response = self.session.get(
                'https://passport.bilibili.com/x/passport-login/web/qrcode/poll',
                params={'qrcode_key': qr_key}
            )
            data = response.json()
            
            if data['code'] != 0:
                print(f"查询状态失败：{data}")
                time.sleep(2)
                continue
                
            result_data = data['data']
            
            if result_data['code'] == 0:
                print("登录成功！")
                self._save_cookies()
                os.remove('login_qr.png')
                return True
            elif result_data['code'] == 86038:
                print("二维码已过期，请重新运行程序")
                os.remove('login_qr.png')
                return False
            elif result_data['code'] == 86090:
                print("等待扫码中...")
                time.sleep(2)
            elif result_data['code'] == 86101:
                print("二维码已扫描，请在手机上确认登录")
                time.sleep(2)
            else:
                print(f"等待操作中... (状态码：{result_data['code']})")
                time.sleep(2)

    def get_favorite_folders(self):
        """获取用户收藏夹列表"""
        response = self.session.get(BILIBILI_API['favorite_list'])
        data = response.json()
        if data['code'] == 0:
            return data['data']['list']
        return []

    def get_favorite_videos(self, folder_id, page=1, pagesize=20):
        """获取收藏夹中的视频"""
        params = {
            'media_id': folder_id,
            'pn': page,
            'ps': pagesize,
            'order': 'mtime',
            'type': 0,
            'tid': 0,
            'platform': 'web'
        }
        response = self.session.get(BILIBILI_API['favorite_content'], params=params)
        data = response.json()
        if data['code'] == 0:
            return data['data']
        return None

    def download_video(self, bvid):
        """使用you-get下载视频"""
        if not os.path.exists(DOWNLOAD_CONFIG['output_dir']):
            os.makedirs(DOWNLOAD_CONFIG['output_dir'])
        
        url = f'https://www.bilibili.com/video/{bvid}'
        command = [
            'you-get',
            '--cookies', DOWNLOAD_CONFIG['cookie_file'],
            '-o', DOWNLOAD_CONFIG['output_dir'],
            url
        ]
        try:
            subprocess.run(command, check=True)
            return True
        except subprocess.CalledProcessError as e:
            print(f"下载失败：{e}")
            return False

def main():
    downloader = BilibiliDownloader()
    
    # 如果没有cookie或cookie已过期，进行登录
    if not downloader.cookies:
        if not downloader.login():
            return

    # 获取收藏夹列表
    folders = downloader.get_favorite_folders()
    if not folders:
        print("未找到收藏夹，请确保已登录并有收藏内容")
        return

    # 显示收藏夹列表
    print("\n=== 你的收藏夹列表 ===")
    for i, folder in enumerate(folders):
        print(f"{i+1}. {folder['title']} (共{folder['media_count']}个视频)")

    # 选择要下载的收藏夹
    while True:
        try:
            choice = int(input("\n请选择要下载的收藏夹序号（输入0退出）：")) - 1
            if choice == -1:
                return
            if 0 <= choice < len(folders):
                break
            print("无效的选择，请重试")
        except ValueError:
            print("请输入有效的数字")

    selected_folder = folders[choice]
    print(f"\n开始下载收藏夹：{selected_folder['title']}")

    # 获取并下载视频
    page = 1
    while True:
        videos = downloader.get_favorite_videos(selected_folder['id'], page)
        if not videos or not videos['medias']:
            break

        for video in videos['medias']:
            print(f"\n正在下载：{video['title']}")
            if downloader.download_video(video['bvid']):
                print(f"下载完成：{video['title']}")
            else:
                print(f"下载失败：{video['title']}")

        if videos['has_more']:
            page += 1
        else:
            break

    print("\n所有视频下载完成！")

if __name__ == "__main__":
    main()