# -*- coding: utf-8 -*-
import sys
import requests
import re
import os
import time
import json
from datetime import datetime
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

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[解析步骤] 浏览器模拟访问...")
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1")

    service = Service(ChromeDriverManager().install())
    driver = webdriver.Chrome(service=service, options=chrome_options)
    try:
        driver.get(redirect_url)
        time.sleep(3)
        page_source = driver.page_source
    finally:
        driver.quit()

    print("\n[解析步骤] 提取数据标签...")
    soup = BeautifulSoup(page_source, 'html.parser')

    script_tag = soup.find('script', id='RENDER_DATA') or soup.find('script', id='__INITIAL_STATE__')

    if not script_tag or not script_tag.string:
        print("页面关键标签:")
        print(soup.find('body') or "无有效内容")
        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[解析步骤] 提取视频信息...")
    try:
        aweme_data = video_data.get('aweme', {}).get('detail', {})
        video_url = aweme_data.get('video', {}).get('playAddr', [{}])[0].get('src', '')
        video_cover = aweme_data.get('video', {}).get('cover', {}).get('urlList', [None])[0]
        author = aweme_data.get('author', {}).get('nickname')
        video_description = aweme_data.get('desc')
        audio_description = aweme_data.get('music', {}).get('title')
        open_app_text = soup.find('div', class_='bottom-btn-con-new__text').text

        return {
            "data": {
                "video_url": video_url,
                "video_cover": video_cover,
                "author": author,
                "video_description": video_description,
                "audio_description": audio_description,
                "open_app_text": open_app_text
            }
        }
    except Exception as e:
        print(f"❗ 信息提取异常: {str(e)}")
        print("调试数据:", json.dumps(video_data, indent=2, ensure_ascii=False)[:500])
        return None
    
def download_media(url, save_path):
    try:
        print(f"\n开始下载: {url[:60]}...")
        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",
            "Referer": "https://www.douyin.com/"
        }
        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 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1",
            "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()