# -*- coding: utf-8 -*-
import sys
import requests
import re
import os
import time
import json
from datetime import datetime
from bs4 import BeautifulSoup

BASE_PATH = ""

def main():
    global BASE_PATH
    BASE_PATH = "./file/result/file_" + str(int(round(time.time() * 1000)))
    
    while True:
        r = get_dy_video()
        if r == 0:
            break

def get_dy_video():
    url = input("\n请输入抖音视频链接(输入0退出): ")
    if url == "0":
        return 0
    
    print(f"\n=== 开始处理 ===")
    print(f"输入链接: {url}")

    print("\n[1/4] 正在解析视频信息...")
    v_info = get_dy_video_info(url)
    if not v_info:
        print("❗ 获取视频信息失败")
        return 1
    
    try:
        print("\n[2/4] 构建下载地址...")
        v_id = v_info["video"]["play_addr"]["uri"]
        video_url = f'https://aweme.snssdk.com/aweme/v1/play/?video_id={v_id}&line=0&ratio=720p'
        print(f"原始下载地址: {video_url}")
    except KeyError as e:
        print(f"❗ 键错误: {str(e)}")
        return 1

    print("\n[3/4] 解析真实下载地址...")
    res_url = get_redirect_url(video_url)
    if not res_url:
        print("❗ 无法获取下载地址")
        return 1
    print(f"最终下载地址: {res_url[:80]}...")

    print("\n[4/4] 开始下载文件...")
    save_path = BASE_PATH + ".mp4"
    if download_media(res_url, save_path):
        print("\n------ 🎉 下载完成 ------")
        print(f"保存路径: {save_path}\n")
    return 1

def get_dy_video_info(url):
    print("\n[解析步骤] 处理短链接...")
    redirect_url = get_redirect_url(url)
    if not redirect_url:
        print("❗ 短链接解析失败")
        return None
    print(f"重定向地址: {redirect_url}")

    print("\n[解析步骤] 提取视频ID...")
    video_id = None
    patterns = [
        r'/video/(\d+)', 
        r'/(\d+)(?:/|\?|$)',
        r'(\d{19})'
    ]
    for pattern in patterns:
        match = re.search(pattern, redirect_url)
        if match:
            video_id = match.group(1)
            print(f"匹配到ID: {video_id}")
            break
    if not video_id:
        print("❗ 视频ID提取失败")
        return None

    print("\n[解析步骤] 请求视频页面...")
    headers = {
        "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1",
        "Referer": "https://www.douyin.com/",
    }
    try:
        response = requests.get(redirect_url, headers=headers, timeout=15)
        print(f"状态码: {response.status_code}")
        print(f"响应长度: {len(response.text)}字节")
    except Exception as e:
        print(f"❗ 请求失败: {str(e)}")
        return None

    print("\n[解析步骤] 提取RENDER_DATA...")
    soup = BeautifulSoup(response.text, 'html.parser')
    script_tag = soup.find('script', id='RENDER_DATA')
    if not script_tag or not script_tag.string:
        print("❗ RENDER_DATA无效")
        return None

    print("\n[解析步骤] 解析JSON数据...")
    try:
        decoded_data = requests.utils.unquote(script_tag.string)
        video_data = json.loads(decoded_data)  # 确保这里执行成功
        print("✅ JSON解析成功")
    except Exception as e:
        print(f"❗ JSON解析失败: {str(e)}")
        return None

    print("\n[解析步骤] 提取视频URI...")
    try:
        # 添加调试输出
        print("调试信息 - JSON结构片段:")
        print(json.dumps(video_data, indent=2, ensure_ascii=False)[:1000])
        
        # 改进的路径访问方式
        play_addr = video_data.get('aweme', {}).get('detail', {}).get('video', {}).get('playAddr', [{}])
        if not play_addr:
            print("❗ playAddr路径无效")
            return None
            
        video_url = play_addr[0].get('src')
        if not video_url:
            print("❗ 视频地址缺失")
            return None
            
        uri = video_url.split('/')[-1].split('.')[0]
        print(f"成功提取URI: {uri}")
        return {"video": {"play_addr": {"uri": uri}}}
    except Exception as e:
        print(f"❗ 地址提取异常: {str(e)}")
        return None

def download_media(url, save_path):
    try:
        print(f"\n开始下载: {url[:60]}...")
        headers = {"User-Agent": "Mozilla/5.0"}
        response = requests.get(url, headers=headers, stream=True, timeout=30)
        
        if response.status_code != 200:
            print(f"下载失败，状态码: {response.status_code}")
            return False
            
        total_size = int(response.headers.get('content-length', 0))
        print(f"文件大小: {total_size//1024} KB")
        
        with open(save_path, "wb") as f:
            downloaded = 0
            start = time.time()
            for chunk in response.iter_content(chunk_size=1024*1024):
                if chunk:
                    f.write(chunk)
                    downloaded += len(chunk)
                    speed = downloaded / (time.time() - start) / 1024
                    print(f"\r进度: {downloaded//1024}KB [{speed:.1f}KB/s]", end="")
            print()
        return True
    except Exception as e:
        print(f"\n下载错误: {str(e)}")
        return False

def get_redirect_url(url):
    try:
        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.douyin.com/"
        }
        response = requests.get(url, headers=headers, allow_redirects=True, timeout=15)
        print(f"重定向次数: {len(response.history)}")
        return response.url
    except Exception as e:
        print(f"重定向失败: {str(e)}")
        return None

if __name__ == "__main__":
    main()