import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext, messagebox
import os
import threading
import gdown
import time
import re
import requests
import http.cookiejar
from pathlib import Path
def center_window(root, width=800, height=600):
# Lấy kích thước màn hình
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# Tính vị trí bắt đầu trục ngang và trục đứng
aaaxxx = (screen_width // 2) - (width // 2)
bbbyyy = (screen_height // 2) - (height // 2) - (40)
# Đặt geometry
root.geometry(f"{width}x{height}+{aaaxxx}+{bbbyyy}")
class GoogleDriveDownloader:
def __init__(self, root):
self.root = root
self.root.title("Google Drive Downloader - DarkCorners")
self.root.resizable(False, False)
center_window(self.root, 800, 600)
self.download_folder = tk.StringVar()
self.pause_flag = False
self.downloading = False
self.delay_time = tk.IntVar(value=300)
# Hàng 1: Tiêu đề
tk.Label(root, text="Google Drive Downloader - DarkCorners", font=("Helvetica", 18, "bold")).pack(pady=10)
# Hàng 2: Thư mục lưu + Điều khiển
frame_top = tk.Frame(root)
frame_top.pack(pady=5, fill=tk.X)
# Hàng 2 Bên trái: Thư mục lưu
folder_frame = tk.LabelFrame(frame_top, text="THƯ MỤC LƯU VIDEOS", font=("Helvetica", 10, "bold"), padx=5, pady=5)
folder_frame.pack(side=tk.LEFT, padx=10, fill=tk.X, expand=True)
row1 = tk.Frame(folder_frame)
row1.pack(anchor="w")
tk.Button(row1, text="Chọn Thư Mục", command=self.select_folder).pack(side=tk.LEFT, padx=5)
self.folder_entry = tk.Entry(row1, textvariable=self.download_folder, width=60)
self.folder_entry.pack(side=tk.LEFT)
tk.Label(folder_frame, text="Cookies xuất bằng tiện ích Cookie-Editor. Tên : cookies-google-drive.txt", font=("Helvetica", 10, "bold"), fg="red").pack(anchor="w", pady=(5, 0))
# Hàng 2 Bên phải: Điều khiển
control_frame = tk.LabelFrame(frame_top, text="ĐIỀU KHIỂN", font=("Helvetica", 10, "bold"), padx=5, pady=5)
control_frame.pack(side=tk.RIGHT, padx=10)
# Thời gian chờ khi lỗi
delay_frame = tk.Frame(control_frame)
delay_frame.pack(pady=(0, 5))
tk.Label(delay_frame, text="Thời gian chờ khi bị lỗi").pack(side=tk.LEFT)
tk.Spinbox(delay_frame, from_=10, to=3600, increment=10, textvariable=self.delay_time, width=6).pack(side=tk.LEFT, padx=2)
tk.Label(delay_frame, text="giây").pack(side=tk.LEFT)
# Dãy nút điều khiển
btn_frame = tk.Frame(control_frame)
btn_frame.pack()
tk.Button(btn_frame, text="Bắt Đầu Tải Xuống", command=self.start_download_thread).pack(side=tk.LEFT, padx=5)
tk.Button(btn_frame, text="Tạm Dừng", command=self.pause_download).pack(side=tk.LEFT, padx=5)
tk.Button(btn_frame, text="Thoát", command=self.root.quit).pack(side=tk.LEFT, padx=5)
# Hàng 3: Khung nhập liên kết và Lưu ý
frame_links_notes = tk.Frame(root)
frame_links_notes.pack(pady=5, fill=tk.X)
# Hàng 3 Trái: Liên kết cần tải
links_frame = tk.LabelFrame(frame_links_notes, text="LIÊN KẾT CẦN TẢI XUỐNG - TỐI ĐA 100", font=("Helvetica", 10, "bold"), padx=5, pady=5, width=500, height=200)
links_frame.pack(side=tk.LEFT, padx=10)
links_frame.pack_propagate(False)
self.link_text = scrolledtext.ScrolledText(links_frame, width=60, height=10)
self.link_text.pack()
# Hàng 3 Phải: Tiến trình xử lý
notes_frame = tk.LabelFrame(frame_links_notes, text="TIẾN TRÌNH XỬ LÝ", font=("Helvetica", 10, "bold"), padx=5, pady=5, width=300, height=200)
notes_frame.pack(side=tk.RIGHT, padx=10)
notes_frame.pack_propagate(False)
tk.Label(notes_frame, text="Tiến Độ Tải Xuống").pack(anchor="w")
self.total_progress = ttk.Progressbar(notes_frame, length=250)
self.total_progress.pack(pady=5)
self.label_total = tk.Label(notes_frame, text="Tổng Số Files: 0", font=("Helvetica", 10, "bold"), fg="red")
self.label_total.pack(anchor="w", pady=(10, 0))
self.label_success = tk.Label(notes_frame, text="Đã Tải Xuống: 0", font=("Helvetica", 10, "bold"), fg="green")
self.label_success.pack(anchor="w")
self.label_pending = tk.Label(notes_frame, text="Đợi Tải Xuống: 0", font=("Helvetica", 10, "bold"), fg="blue")
self.label_pending.pack(anchor="w")
self.label_error = tk.Label(notes_frame, text="Bị Lỗi: 0", font=("Helvetica", 10, "bold"), fg="black")
self.label_error.pack(anchor="w")
# Hàng 4: Logs
log_frame = tk.LabelFrame(root, text="LỊCH TRÌNH XỬ LÝ", font=("Helvetica", 10, "bold"), padx=5, pady=5)
log_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)
self.log_text = scrolledtext.ScrolledText(log_frame, width=95, height=11, state='disabled')
self.log_text.pack(pady=5)
def log(self, message):
self.log_text.config(state='normal')
self.log_text.insert(tk.END, f"{message}\n")
self.log_text.yview(tk.END)
self.log_text.config(state='disabled')
def select_folder(self):
folder = filedialog.askdirectory()
if folder:
self.download_folder.set(folder)
def pause_download(self):
self.pause_flag = True
self.log("⏸️ Đã tạm dừng quá trình tải.")
def start_download_thread(self):
if self.downloading:
messagebox.showwarning("Đang tải", "Đang có quá trình tải đang chạy!")
return
thread = threading.Thread(target=self.download_files)
thread.start()
def extract_filename_from_url(self, url):
# Lấy ID file để truy vấn metadata
match = re.search(r'/d/([a-zA-Z0-9_-]+)', url)
if match:
return match.group(1)
alt_match = re.search(r"id=([a-zA-Z0-9_-]+)", url)
if alt_match:
return alt_match.group(1)
return None
def create_session_with_cookies(self):
session = requests.Session()
# Luôn lấy thư mục chứa file .exe (khi đóng gói PyInstaller)
base_path = Path(sys.executable).parent
cookies_path = base_path / "cookies-google-drive.txt"
if not cookies_path.exists():
raise FileNotFoundError(f"Không tìm thấy file cookies tại: {cookies_path}")
cookie_jar = http.cookiejar.MozillaCookieJar()
cookie_jar.load(str(cookies_path), ignore_discard=True, ignore_expires=True)
session.cookies.update(cookie_jar)
return session
def download_files(self):
links = self.link_text.get("1.0", tk.END).strip().splitlines()
folder = self.download_folder.get()
if not links:
messagebox.showerror("Lỗi", "Vui lòng nhập ít nhất 1 liên kết.")
return
if not folder:
messagebox.showerror("Lỗi", "Vui lòng chọn thư mục lưu.")
return
self.downloading = True
self.pause_flag = False
total_links = len(links)
self.total_progress['value'] = 0
progress_step = 100 / total_links
# Khởi tạo bộ đếm trạng thái
total = len(links)
success_count = 0
error_count = 0
pending_count = total
self.label_total.config(text=f"Tổng Số Files: {total}")
self.label_success.config(text="Đã Tải Xuống: 0")
self.label_error.config(text="Bị Lỗi: 0")
self.label_pending.config(text=f"Đợi Tải Xuống: {pending_count}")
# Tạo session có cookies
session = None
try:
session = self.create_session_with_cookies()
self.log("✅ Đã tải cookies thành công.")
except Exception as e:
self.log(f"⚠️ Không thể tải cookies: {e}")
self.log("🚀 Bắt đầu tải các file từ Google Drive...")
for idx, link in enumerate(links, 1):
if self.pause_flag:
break
output_path = os.path.join(folder, "")
self.log(f"🔗 Đang tải file {idx}/{total_links}...")
retry_count = 0
while not self.pause_flag:
retry_count += 1
downloaded_path = None
try:
if session:
import gdown.download as gdown_dl
gdown_dl._session = session
downloaded_path = gdown.download(
url=link,
output=output_path,
quiet=True,
fuzzy=True,
use_cookies=True,
)
except Exception as e:
self.log(f"⚠️ Gdown lỗi: {e}")
if downloaded_path:
filename_display = os.path.basename(downloaded_path)
success_count += 1
pending_count -= 1
self.label_success.config(text=f"Đã Tải Xuống: {success_count}")
self.label_pending.config(text=f"Đợi Tải Xuống: {pending_count}")
self.log(f"✅ Đã tải xong file {idx}: {filename_display}")
break
else:
self.log(f"❌ Tải thất bại lần {retry_count}. Sẽ thử lại link {idx} sau {self.delay_time.get()} giây...")
time.sleep(self.delay_time.get())
self.total_progress['value'] += progress_step
time.sleep(1)
if not self.pause_flag:
self.log("🎉 Hoàn tất tải xuống tất cả các file.")
else:
self.log("⏸️ Quá trình tải đã bị tạm dừng.")
self.downloading = False
if __name__ == "__main__":
root = tk.Tk()
app = GoogleDriveDownloader(root)
root.mainloop()