import requests
import json
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os

class BilibiliSpider:
    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',
            'Referer': 'https://www.bilibili.com/'
        }
        self.session.headers.update(self.headers)
        
    def login_with_selenium(self):
        """
        使用Selenium进行登录（需要手动扫码）
        """
        options = webdriver.ChromeOptions()
        # 可以添加 --headless 参数实现无头浏览器
        driver = webdriver.Chrome(options=options)
        
        try:
            driver.get("https://passport.bilibili.com/login")
            
            # 等待用户扫码登录
            print("请在浏览器中完成扫码登录...")
            WebDriverWait(driver, 300).until(
                EC.url_contains("https://www.bilibili.com/")
            )
            
            # 获取登录后的cookies
            cookies = driver.get_cookies()
            for cookie in cookies:
                self.session.cookies.set(cookie['name'], cookie['value'])
                
            print("登录成功！")
            return True
        except Exception as e:
            print(f"登录失败: {e}")
            return False
        finally:
            driver.quit()
            
    def get_favorite_list(self, media_id):
        """
        获取收藏夹视频列表
        """
        url = "https://api.bilibili.com/x/v3/fav/resource/list"
        params = {
            'media_id': media_id,
            'pn': 1,
            'ps': 20,
            'keyword': '',
            'order': 'mtime',
            'type': 0,
            'tid': 0,
            'platform': 'web'
        }
        
        response = self.session.get(url, params=params)
        if response.status_code == 200:
            data = response.json()
            if data['code'] == 0:
                return data['data']['medias']
        return []
        
    def get_video_info(self, bvid):
        """
        获取视频详细信息
        """
        url = f"https://api.bilibili.com/x/web-interface/view"
        params = {'bvid': bvid}
        
        response = self.session.get(url, params=params)
        if response.status_code == 200:
            data = response.json()
            if data['code'] == 0:
                return data['data']
        return None
        
    def download_video(self, url, filename):
        """
        下载视频文件
        """
        try:
            response = self.session.get(url, stream=True)
            response.raise_for_status()
            
            with open(filename, 'wb') as f:
                for chunk in response.iter_content(chunk_size=8192):
                    if chunk:
                        f.write(chunk)
            print(f"下载完成: {filename}")
            return True
        except Exception as e:
            print(f"下载失败 {filename}: {e}")
            return False
            
    def run(self, favorite_id, download_path="./downloads"):
        """
        主运行函数
        """
        # 创建下载目录
        if not os.path.exists(download_path):
            os.makedirs(download_path)
            
        # 登录
        if not self.login_with_selenium():
            print("登录失败，程序退出")
            return
            
        # 获取收藏夹列表
        videos = self.get_favorite_list(favorite_id)
        if not videos:
            print("未获取到收藏夹内容")
            return
            
        print(f"获取到 {len(videos)} 个视频")
        
        # 遍历并下载视频
        for video in videos:
            bvid = video['bvid']
            title = video['title'].replace('/', '_').replace('\\', '_')  # 处理文件名
            
            print(f"正在处理: {title}")
            
            # 获取视频详情
            video_info = self.get_video_info(bvid)
            if not video_info:
                print(f"无法获取视频详情: {title}")
                continue
                
            # 注意：B站视频通常有版权保护，直接下载可能不可行
            # 这里仅作为示例，实际可能需要使用其他方式如 bilibili-api 等第三方库
            print(f"视频信息获取成功: {title}")
            
            # 添加延时避免请求过快
            time.sleep(2)

# 使用示例
if __name__ == "__main__":
    spider = BilibiliSpider()
    
    # 需要替换为实际的收藏夹ID
    # 收藏夹ID可以在B站收藏夹页面URL中找到
    favorite_id = "YOUR_FAVORITE_ID" 
    
    spider.run(favorite_id)