import tkinter as tk from tkinter import ttk, filedialog, scrolledtext, messagebox import subprocess import threading import os import re PYTHON_PATH = r"C:\Program Files\Python311\python.exe" COOKIE_FILE = r"C:\Users\Administrator\Desktop\TikTokDownload-main\douyin_cookie.txt" class DouyinDownloaderUI: def __init__(self, root): self.root = root self.root.title("抖音去水印下载器 v3.0 (自动Cookie)") self.root.geometry("800x700") self.root.resizable(True, True) self.download_dir = os.path.join(os.path.expanduser("~"), "Downloads", "DouyinDownloads") os.makedirs(self.download_dir, exist_ok=True) self.is_downloading = False self.cookie = None self.setup_ui() self.auto_load_cookie() def auto_load_cookie(self): """启动时自动加载Cookie""" if os.path.exists(COOKIE_FILE): try: with open(COOKIE_FILE, 'r', encoding='utf-8') as f: self.cookie = f.read().strip() if self.cookie and len(self.cookie) > 100: self.update_cookie_status(True) self.log("✓ 已自动加载Cookie", "SUCCESS") return except: pass self.update_cookie_status(False) self.log("ℹ 未检测到Cookie,首次下载时将自动获取", "INFO") def update_cookie_status(self, has_cookie): """更新Cookie状态指示""" if has_cookie: self.cookie_status.config(text="● Cookie: 有效", foreground="green") self.cookie_entry.delete(0, tk.END) self.cookie_entry.insert(0, "[已自动获取Cookie]") else: self.cookie_status.config(text="● Cookie: 未获取", foreground="gray") def setup_ui(self): style = ttk.Style() style.theme_use('clam') main_frame = ttk.Frame(self.root, padding="15") main_frame.pack(fill=tk.BOTH, expand=True) # Title title_label = ttk.Label(main_frame, text="抖音/TikTok 去水印下载器", font=('Microsoft YaHei', 18, 'bold')) title_label.pack(pady=(0, 5)) subtitle = ttk.Label(main_frame, text="自动Cookie | 无需登录 | 一键下载", font=('Microsoft YaHei', 10), foreground="gray") subtitle.pack(pady=(0, 10)) # Cookie Status Frame cookie_frame = ttk.LabelFrame(main_frame, text="Cookie状态", padding="10") cookie_frame.pack(fill=tk.X, pady=(0, 10)) self.cookie_status = ttk.Label(cookie_frame, text="● Cookie: 检测中...", font=('Microsoft YaHei', 10, 'bold')) self.cookie_status.pack(side=tk.LEFT, padx=5) ttk.Button(cookie_frame, text="自动获取Cookie", command=self.auto_get_cookie_ui, width=15).pack(side=tk.LEFT, padx=10) ttk.Label(cookie_frame, text="(首次下载时会自动获取,无需手动操作)", font=('Microsoft YaHei', 8), foreground="gray").pack(side=tk.LEFT, padx=5) # Hidden Cookie Entry (for compatibility) self.cookie_entry = ttk.Entry(cookie_frame, width=20, state='disabled') # URL Frame input_frame = ttk.LabelFrame(main_frame, text="下载设置", padding="10") input_frame.pack(fill=tk.X, pady=(0, 10)) ttk.Label(input_frame, text="分享链接:", font=('Microsoft YaHei', 10)).grid(row=0, column=0, sticky=tk.W, pady=5) self.url_entry = ttk.Entry(input_frame, width=80, font=('Microsoft YaHei', 10)) self.url_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.EW) self.url_entry.bind('', self.paste_clipboard) ttk.Label(input_frame, text="下载模式:", font=('Microsoft YaHei', 10)).grid(row=1, column=0, sticky=tk.W, pady=5) self.mode_var = tk.StringVar(value="one") mode_frame = ttk.Frame(input_frame) mode_frame.grid(row=1, column=1, sticky=tk.W, padx=5, pady=5) modes = [ ("单个作品", "one"), ("用户主页", "post"), ("用户喜欢", "like"), ("用户收藏", "collects"), ("直播", "live"), ] for i, (text, value) in enumerate(modes): rb = ttk.Radiobutton(mode_frame, text=text, value=value, variable=self.mode_var) rb.pack(side=tk.LEFT, padx=8) ttk.Label(input_frame, text="保存目录:", font=('Microsoft YaHei', 10)).grid(row=2, column=0, sticky=tk.W, pady=5) dir_frame = ttk.Frame(input_frame) dir_frame.grid(row=2, column=1, sticky=tk.EW, padx=5, pady=5) self.dir_entry = ttk.Entry(dir_frame, textvariable=tk.StringVar(value=self.download_dir), font=('Microsoft YaHei', 10)) self.dir_entry.pack(side=tk.LEFT, fill=tk.X, expand=True) ttk.Button(dir_frame, text="浏览", command=self.browse_dir, width=8).pack(side=tk.LEFT, padx=(5, 0)) input_frame.columnconfigure(1, weight=1) # Options Frame options_frame = ttk.LabelFrame(main_frame, text="选项", padding="10") options_frame.pack(fill=tk.X, pady=(0, 10)) self.download_music = tk.BooleanVar(value=False) self.download_cover = tk.BooleanVar(value=False) ttk.Checkbutton(options_frame, text="下载原声", variable=self.download_music).pack(side=tk.LEFT, padx=10) ttk.Checkbutton(options_frame, text="下载封面", variable=self.download_cover).pack(side=tk.LEFT, padx=10) ttk.Label(options_frame, text="作品数量:").pack(side=tk.LEFT, padx=(20, 5)) self.limit_entry = ttk.Entry(options_frame, width=8) self.limit_entry.insert(0, "0") self.limit_entry.pack(side=tk.LEFT) ttk.Label(options_frame, text="(0=全部)").pack(side=tk.LEFT, padx=5) # Buttons btn_frame = ttk.Frame(main_frame) btn_frame.pack(fill=tk.X, pady=10) self.download_btn = ttk.Button(btn_frame, text="开始下载", command=self.start_download) self.download_btn.pack(side=tk.LEFT, padx=5, ipadx=20, ipady=5) self.stop_btn = ttk.Button(btn_frame, text="停止", command=self.stop_download, state=tk.DISABLED) self.stop_btn.pack(side=tk.LEFT, padx=5, ipadx=20, ipady=5) ttk.Button(btn_frame, text="打开目录", command=self.open_download_dir).pack(side=tk.LEFT, padx=5) ttk.Button(btn_frame, text="清空日志", command=self.clear_log).pack(side=tk.RIGHT, padx=5) # Log Frame log_frame = ttk.LabelFrame(main_frame, text="下载日志", padding="5") log_frame.pack(fill=tk.BOTH, expand=True) self.log_text = scrolledtext.ScrolledText(log_frame, height=15, font=('Consolas', 9), bg='#1e1e1e', fg='#00ff00', insertbackground='white') self.log_text.pack(fill=tk.BOTH, expand=True) # Progress self.progress_var = tk.DoubleVar() self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, maximum=100) self.progress_bar.pack(fill=tk.X, pady=(10, 0)) self.status_label = ttk.Label(main_frame, text="就绪", font=('Microsoft YaHei', 9)) self.status_label.pack(pady=5) def auto_get_cookie_ui(self): """UI线程:自动获取Cookie""" self.log("正在自动获取Cookie...", "INFO") self.status_label.config(text="正在获取Cookie...") self.download_btn.config(state=tk.DISABLED) thread = threading.Thread(target=self.auto_get_cookie_thread) thread.daemon = True thread.start() def auto_get_cookie_thread(self): """后台线程:自动获取Cookie""" try: from auto_cookie import get_douyin_cookie_auto # 强制刷新,使用有界面模式(更稳定) cookie = get_douyin_cookie_auto(force_refresh=True, headless=False) if cookie and len(cookie) > 100: self.cookie = cookie self.root.after(0, lambda: self.update_cookie_status(True)) self.root.after(0, lambda: self.log("✓ Cookie获取成功!", "SUCCESS")) self.root.after(0, lambda: self.status_label.config(text="Cookie已就绪")) else: self.root.after(0, lambda: self.log("✗ Cookie获取失败", "ERROR")) self.root.after(0, lambda: self.status_label.config(text="Cookie获取失败")) except Exception as e: self.root.after(0, lambda: self.log(f"✗ Cookie获取失败: {str(e)}", "ERROR")) self.root.after(0, lambda: self.status_label.config(text="Cookie获取失败")) finally: self.root.after(0, lambda: self.download_btn.config(state=tk.NORMAL)) def paste_clipboard(self, event=None): try: clipboard = self.root.clipboard_get() self.url_entry.delete(0, tk.END) self.url_entry.insert(0, clipboard) except: pass return "break" def browse_dir(self): dir_path = filedialog.askdirectory(initialdir=self.download_dir) if dir_path: self.download_dir = dir_path self.dir_entry.delete(0, tk.END) self.dir_entry.insert(0, dir_path) def open_download_dir(self): os.startfile(self.download_dir) def clear_log(self): self.log_text.delete(1.0, tk.END) def log(self, message, level="INFO"): self.log_text.insert(tk.END, f"[{level}] {message}\n") self.log_text.see(tk.END) self.root.update_idletasks() def extract_url(self, text): match = re.search(r'https?://[^\s<>"{}|\\^`\[\]]+', text) if match: return match.group(0) return text def ensure_cookie(self): """确保有Cookie,如果没有则自动获取""" if self.cookie and len(self.cookie) > 100: return True self.log("检测到无Cookie,正在自动获取...", "INFO") try: from auto_cookie import get_douyin_cookie_auto # 自动获取,使用无头模式(不打扰用户) cookie = get_douyin_cookie_auto(force_refresh=False, headless=True) if cookie and len(cookie) > 100: self.cookie = cookie self.root.after(0, lambda: self.update_cookie_status(True)) self.log("✓ Cookie自动获取成功", "SUCCESS") return True else: self.log("✗ 自动获取Cookie失败", "ERROR") return False except Exception as e: self.log(f"✗ 自动获取Cookie失败: {str(e)}", "ERROR") return False def start_download(self): url = self.url_entry.get().strip() if not url: messagebox.showwarning("提示", "请输入分享链接!") return # 确保有Cookie if not self.ensure_cookie(): messagebox.showerror("错误", "无法获取Cookie,请检查网络或浏览器是否正常") return url = self.extract_url(url) self.log(f"解析链接: {url}", "INFO") self.is_downloading = True self.download_btn.config(state=tk.DISABLED) self.stop_btn.config(state=tk.NORMAL) self.progress_var.set(0) thread = threading.Thread(target=self.download_thread, args=(url,)) thread.daemon = True thread.start() def download_thread(self, url): try: self.log("开始下载任务...", "INFO") self.status_label.config(text="正在下载...") cmd = [PYTHON_PATH, "-m", "f2", "dy"] mode = self.mode_var.get() cmd.extend(["-M", mode]) cmd.extend(["-u", url]) download_dir = self.dir_entry.get().strip() cmd.extend(["-p", download_dir]) # 使用自动获取的Cookie if self.cookie: cmd.extend(["-k", self.cookie]) if self.download_music.get(): cmd.extend(["-m", "true"]) if self.download_cover.get(): cmd.extend(["-v", "true"]) limit = self.limit_entry.get().strip() if limit and limit != "0": cmd.extend(["-o", limit]) self.log("执行下载命令...", "INFO") env = os.environ.copy() env["PYTHONIOENCODING"] = "utf-8" process = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding='utf-8', errors='replace', env=env, bufsize=1 ) download_failed = False while self.is_downloading: if process.stdout is None: break line = process.stdout.readline() if not line and process.poll() is not None: break if line: line = line.strip() if line: self.log(line, "INFO") if "下载" in line or "成功" in line or "保存" in line: self.progress_var.set(min(self.progress_var.get() + 10, 90)) # 检测Cookie相关的错误 if "cookie" in line.lower() or "登录" in line or "失败" in line: download_failed = True if not self.is_downloading: process.terminate() self.log("下载已停止", "WARNING") elif process.returncode == 0: self.progress_var.set(100) self.log("✓ 下载完成!", "SUCCESS") self.status_label.config(text="下载完成!") self.root.after(0, lambda: messagebox.showinfo("完成", f"下载完成!\n\n保存位置: {download_dir}")) elif download_failed: self.log("检测到Cookie可能过期,尝试刷新...", "WARNING") # 重新获取Cookie from auto_cookie import get_douyin_cookie_auto new_cookie = get_douyin_cookie_auto(force_refresh=True, headless=True) if new_cookie: self.cookie = new_cookie self.log("Cookie已刷新,请重试下载", "INFO") self.status_label.config(text="Cookie已刷新,请重试") else: self.log("下载过程中出现错误", "WARNING") self.status_label.config(text="下载失败") except Exception as e: self.log(f"错误: {str(e)}", "ERROR") self.status_label.config(text="下载失败") self.root.after(0, lambda: messagebox.showerror("错误", f"下载失败:\n{str(e)}")) finally: self.is_downloading = False self.download_btn.config(state=tk.NORMAL) self.stop_btn.config(state=tk.DISABLED) def stop_download(self): self.is_downloading = False def main(): root = tk.Tk() app = DouyinDownloaderUI(root) root.mainloop() if __name__ == "__main__": main()