import requests
import time
import json
import random
from pathlib import Path

# ================= 配置区域 =================
COOKIE_FILE = Path("./cookies.json")
TARGET_SEASON_ID = 7196643  # 目标合集 ID
ASCENDING_ORDER = True      # True: 最早发布的在前面 (1, 2, 3...)
# ===========================================

def extract_cookie_from_list(cookie_list):
    """从列表结构中提取 SESSDATA 和 bili_jct"""
    sessdata = ""
    bili_jct = ""
    for item in cookie_list:
        if item.get("name") == "SESSDATA":
            sessdata = item.get("value")
        elif item.get("name") == "bili_jct":
            bili_jct = item.get("value")
    return sessdata, bili_jct

def load_cookies(file_path):
    """智能从 json 文件加载 cookies"""
    if not file_path.exists():
        print(f"[!] 错误: 找不到文件 {file_path}")
        exit(1)
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            data = json.load(f)
            
        sessdata = ""
        bili_jct = ""
        
        if isinstance(data, list):
            sessdata, bili_jct = extract_cookie_from_list(data)
        elif isinstance(data, dict):
            if "cookie_info" in data and "cookies" in data["cookie_info"]:
                sessdata, bili_jct = extract_cookie_from_list(data["cookie_info"]["cookies"])
            elif "cookies" in data and isinstance(data["cookies"], list):
                sessdata, bili_jct = extract_cookie_from_list(data["cookies"])
            else:
                sessdata = data.get("SESSDATA", "")
                bili_jct = data.get("bili_jct", "")
            
        if not sessdata or not bili_jct:
            print("[!] 错误: cookies.json 中未找到 SESSDATA 或 bili_jct")
            exit(1)
            
        return sessdata, bili_jct
    except Exception as e:
        print(f"[!] 解析 cookies.json 失败: {e}")
        exit(1)

# 初始化 Cookie
SESSDATA, BILI_JCT = load_cookies(COOKIE_FILE)

print(f"[*] SESSDATA 读取成功: {SESSDATA[:4]}...{SESSDATA[-4:]}")
print(f"[*] bili_jct 读取成功: {BILI_JCT[:4]}...{BILI_JCT[-4:]}")

HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Cookie": f"SESSDATA={SESSDATA}; bili_jct={BILI_JCT}",
    "Content-Type": "application/json"
}

def get_section_id_by_season(season_id):
    """查找合集对应的小节ID"""
    print(f"[*] 正在查找合集 ID {season_id} 的小节信息...")
    url = "https://member.bilibili.com/x2/creative/web/seasons"
    
    page = 1
    while True:
        params = {"pn": page, "ps": 30, "order": "", "sort": ""}
        resp = requests.get(url, params=params, headers=HEADERS)
        data = resp.json()
        
        if data["code"] != 0:
            print(f"[!] 获取合集列表失败: {data['message']}")
            if data["code"] == -101:
                print("[!] 提示: 账号未登录，请检查 cookies.json")
            return None

        seasons_list = data["data"]["seasons"]
        if not seasons_list:
            break

        for s_obj in seasons_list:
            s_info = s_obj["season"]
            if s_info["id"] == season_id:
                title = s_info["title"]
                print(f"[*] 找到合集: 《{title}》")
                
                if "sections" in s_obj and "sections" in s_obj["sections"]:
                    first_section = s_obj["sections"]["sections"][0]
                    sec_id = first_section["id"]
                    sec_title = first_section["title"]
                    print(f"[*] 锁定小节: [{sec_title}] (Section ID: {sec_id})")
                    return sec_id
                else:
                    print("[!] 该合集下没有发现小节结构。")
                    return None
        
        page += 1
        time.sleep(0.5)

    print(f"[!] 未在您的账号中找到 Season ID: {season_id}")
    return None

def get_video_publish_time(bvid):
    """
    获取视频发布时间
    [FIXED] 增加了 headers 参数，防止 B 站拦截请求
    """
    url = "https://api.bilibili.com/x/web-interface/view"
    params = {"bvid": bvid}
    try:
        # ！！！关键修改：这里必须带上 headers ！！！
        resp = requests.get(url, params=params, headers=HEADERS)
        data = resp.json()
        
        if data["code"] == 0:
            return data["data"]["pubdate"], data["data"]["title"]
        else:
            # 打印具体错误原因
            print(f"\n[!] 获取视频 {bvid} 失败: code={data['code']}, msg={data['message']}")
            return 0, "Unknown"
    except Exception as e:
        print(f"\n[!] 请求异常: {e}")
        return 0, "Unknown"

def sort_videos(section_id):
    # 1. 获取小节内视频
    url_get = "https://member.bilibili.com/x2/creative/web/season/section"
    resp = requests.get(url_get, params={"id": section_id}, headers=HEADERS)
    res_json = resp.json()
    
    if res_json["code"] != 0:
        print(f"[!] API 错误: {res_json['message']}")
        return

    section_info = res_json["data"]["section"]
    episodes = res_json["data"]["episodes"]
    
    if not episodes:
        print("[!] 合集内无视频。")
        return

    total = len(episodes)
    print(f"[*] 获取到 {total} 个视频，开始查询发布时间...")
    
    video_list = []
    success_count = 0
    
    for idx, ep in enumerate(episodes):
        # 随机延迟 0.2 ~ 0.5 秒，比固定延迟更安全
        time.sleep(random.uniform(0.2, 0.5)) 
        
        bvid = ep["bvid"]
        pubdate, title = get_video_publish_time(bvid)
        
        # 简单的进度显示
        date_str = "Fail/Unknown"
        if pubdate != 0:
            date_str = time.strftime('%Y-%m-%d', time.localtime(pubdate))
            success_count += 1
            
        print(f"    [{idx+1}/{total}] {title[:15]:<15} -> {date_str}")
        
        video_list.append({
            "id": ep["id"],
            "title": ep["title"] if title == "Unknown" else title, # 优先使用 API 查到的全名
            "pubdate": pubdate
        })

    if success_count == 0:
        print("[!] 错误: 所有视频时间查询均失败，终止排序以免数据混乱。")
        return

    # 2. 排序
    print("[*] 正在计算排序顺序...")
    video_list.sort(key=lambda x: x['pubdate'], reverse=not ASCENDING_ORDER)

    # 3. 提交
    print("[*] 正在提交新的排序列表...")
    sorts_payload = [{"id": v["id"], "sort": i+1} for i, v in enumerate(video_list)]
    
    payload = {
        "section": {
            "id": section_info["id"],
            "seasonId": section_info["seasonId"],
            "title": section_info["title"],
            "type": section_info["type"]
        },
        "sorts": sorts_payload
    }

    url_edit = f"https://member.bilibili.com/x2/creative/web/season/section/edit?csrf={BILI_JCT}"
    try:
        resp_submit = requests.post(url_edit, json=payload, headers=HEADERS)
        result = resp_submit.json()

        if result["code"] == 0:
            print(f"\n[SUCCESS] 合集《{section_info['title']}》排序更新成功！")
        else:
            print(f"\n[FAIL] 更新失败: {result['message']}")
    except Exception as e:
        print(f"\n[!] 提交时发生网络错误: {e}")

if __name__ == "__main__":
    print("--- Bilibili 合集自动排序工具 (v2.0 fixed) ---")
    
    target_section_id = get_section_id_by_season(TARGET_SEASON_ID)
    
    if target_section_id:
        sort_videos(target_section_id)