Ok.Ru Uploader – DarkCorners

Date: 16/12/2025

Category: Python

  1. Khởi động phần mềm.
  2. Chọn thư mục chứa toàn bộ video cần upload.
  3. Chọn thư mục xuất file chứa danh sách link đã upload.
  4. Chọn kiểu đăng nhập tài khoản. Nếu chọn TXT File, cần chuẩn bị sẵn file cookies-okru.txt
  5. Nếu chọn Đăng Nhập bằng tài khoản. Hãy điền thông tin user và password.
  6. Có cần ẩn trình duyệt hay không.
  7. Nhấn nút [Bắt Đầu].
  8. Theo dõi lịch trình xử lý.
import os
import sys
import threading
import time
from tkinter import *
from tkinter import filedialog, scrolledtext, messagebox
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager

# Xác định thư mục chứa Tool2 (file đang chạy)
base_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
cookie_path = os.path.join(base_dir, "cookies-okru.txt")

def center_window(root, width=800, height=500):
    # 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 OkRuUploader:
    def __init__(self, root):
        self.root = root
        self.root.title("Ok.Ru Uploader - DarkCorners")
        self.root.resizable(False, False)
        center_window(self.root, 800, 500)
        self.video_folder = StringVar()
        self.output_folder = StringVar()
        self.username = StringVar()
        self.password = StringVar()
        self.silent_mode = BooleanVar()
        self.cookie_mode = StringVar(value="Đăng Nhập")
        self.videos = []
        self.total = 0
        self.uploaded = 0
        self.errors = 0
        self.stop_flag = False
        self.build_gui()

    def build_gui(self):
        # Hàng 1 : Tiêu đề phần mềm
        Label(self.root, text="Ok.Ru Uploader - DarkCorners", font=("Arial", 16, "bold")).pack(pady=5)

        # Hàng 2 : Khung chọn thư mục
        frame_folders = Frame(self.root)
        frame_folders.pack(pady=5)
        # Hàng 2 : Khung chọn thư mục trái
        Button(frame_folders, text="Chọn Thư Mục Video", command=self.select_video_folder).grid(row=0, column=0, padx=5)
        Entry(frame_folders, textvariable=self.video_folder, width=40).grid(row=0, column=1, padx=5)
        # Hàng 2 : Khung chọn thư mục phải
        Button(frame_folders, text="Chọn Thư Mục Xuất File", command=self.select_output_folder).grid(row=0, column=2, padx=5)
        Entry(frame_folders, textvariable=self.output_folder, width=40).grid(row=0, column=3, padx=5)

        # Hàng 3 : Xác thực tài khoản
        frame_row3 = Frame(self.root)
        frame_row3.pack(fill=X, padx=10, pady=5)
        frame_login_box = LabelFrame(frame_row3, text="XÁC THỰC TÀI KHOẢN OK.RU", font=("Arial", 10, "bold"), padx=10, pady=5)
        frame_login_box.pack(fill=X)
        # Hàng 3 : Kiểu cookies
        Label(frame_login_box, text="Kiểu Cookies:").grid(row=0, column=0, padx=5, sticky=W)
        option_frame = Frame(frame_login_box)
        option_frame.grid(row=0, column=1, padx=5, sticky=W)
        Radiobutton(option_frame, text="TXT File", variable=self.cookie_mode, value="TXT File", command=self.toggle_login_fields).pack(side=LEFT)
        Radiobutton(option_frame, text="Đăng Nhập", variable=self.cookie_mode, value="Đăng Nhập", command=self.toggle_login_fields).pack(side=LEFT)
        # Hàng 3 : Khung tài khoản
        Label(frame_login_box, text="User:").grid(row=0, column=2, padx=5, sticky=E)
        self.user_entry = Entry(frame_login_box, textvariable=self.username, width=20)
        self.user_entry.grid(row=0, column=3, padx=5)
        # Hàng 3 : Khung mật khẩu
        Label(frame_login_box, text="Password:").grid(row=0, column=4, padx=5, sticky=E)
        self.pass_entry = Entry(frame_login_box, textvariable=self.password, show="*", width=20)
        self.pass_entry.grid(row=0, column=5, padx=5)
        # Hàng 3 : Nút ẩn trình duyện chrome
        Label(frame_login_box, text="Ẩn Trình Duyệt").grid(row=0, column=6, padx=(15, 2), sticky=E)
        Checkbutton(frame_login_box, variable=self.silent_mode).grid(row=0, column=7, sticky=W)
        # Hàng 3 : Phần ghi chú
        # Dòng 1: hướng dẫn cookies
        Label(frame_login_box, text="Nếu chọn TXT File thì hãy chắc chắn file cookies-okru.txt tồn tại trong thư mục.", fg="gray").grid(row=1, column=0, columnspan=8, sticky=W, pady=(5, 0))
        # Dòng 2: ví dụ thêm ghi chú
        Label(frame_login_box, text="Định dạng cookie phải là Netscape(.txt). Bạn có thể xuất bằng tiện ích Cookie-Editor trên Google Chrome", fg="gray").grid(row=2, column=0, columnspan=8, sticky=W, pady=(0, 5))

        # Hàng 4
        frame_buttons = Frame(self.root)
        frame_buttons.pack(fill=X, padx=10, pady=10)
        # Hàng 4 Bên trái: Thông tin trạng thái dạng label màu
        frame_left = Frame(frame_buttons)
        frame_left.pack(side=LEFT, expand=True, anchor=W)
        self.label_total = Label(frame_left, text="Tổng Số Videos: 0", font=("Arial", 10, "bold"), fg="red")
        self.label_total.pack(side=LEFT, padx=5)
        self.label_uploaded = Label(frame_left, text="Đã Upload: 0", font=("Arial", 10, "bold"), fg="green")
        self.label_uploaded.pack(side=LEFT, padx=5)
        self.label_waiting = Label(frame_left, text="Đợi Upload: 0", font=("Arial", 10, "bold"), fg="blue")
        self.label_waiting.pack(side=LEFT, padx=5)
        self.label_errors = Label(frame_left, text="Lỗi Upload: 0", font=("Arial", 10, "bold"), fg="black")
        self.label_errors.pack(side=LEFT, padx=5)
        # Hàng 4 Bên phải: Các nút điều khiển
        frame_right = Frame(frame_buttons)
        frame_right.pack(side=RIGHT, anchor=E)
        Button(frame_right, text="Bắt Đầu", width=12, command=self.start_upload).pack(side=LEFT, padx=5)
        Button(frame_right, text="Dừng Lại", width=12, command=self.stop_upload).pack(side=LEFT, padx=5)
        Button(frame_right, text="Thoát", width=12, command=self.root.quit).pack(side=LEFT, padx=5)

        self.log_text = scrolledtext.ScrolledText(self.root, width=110, height=15)
        self.log_text.pack(padx=10, pady=5)
        self.status_var = StringVar()
        self.status_var.set("Tổng Videos: 0 --- Đã Upload: 0 --- Đợi Upload: 0 --- Lỗi Upload: 0")
        Label(self.root, textvariable=self.status_var, font=("Arial", 10)).pack(pady=5)

    def toggle_login_fields(self):
        is_txt = self.cookie_mode.get() == "TXT File"
        state = DISABLED if is_txt else NORMAL
        self.user_entry.config(state=state)
        self.pass_entry.config(state=state)

    def log(self, message):
        self.log_text.insert(END, f"{message}\n")
        self.log_text.see(END)

    def update_status(self):
        waiting = self.total - self.uploaded - self.errors
        self.status_var.set(f"Tổng Videos: {self.total} --- Đã Upload: {self.uploaded} --- Đợi Upload: {waiting} --- Lỗi Upload: {self.errors}")
        # Cập nhật các nhãn màu ở dòng nút
        self.label_total.config(text=f"Tổng Số Videos: {self.total}")
        self.label_uploaded.config(text=f"Đã Upload: {self.uploaded}")
        self.label_waiting.config(text=f"Đợi Upload: {waiting}")
        self.label_errors.config(text=f"Lỗi Upload: {self.errors}")

    def select_video_folder(self):
        path = filedialog.askdirectory()
        self.video_folder.set(path)

    def select_output_folder(self):
        path = filedialog.askdirectory()
        self.output_folder.set(path)

    def start_upload(self):
        self.stop_flag = False
        threading.Thread(target=self.upload_videos).start()

    def stop_upload(self):
        self.stop_flag = True
        self.log("⛔ Đã yêu cầu dừng upload sau video hiện tại.")

    def upload_videos(self):
        self.videos = [f for f in os.listdir(self.video_folder.get())
                       if f.lower().endswith(('.mp4', '.avi', '.webm', '.mkv', '.flv', '.ts', '.m2ts'))]
        self.total = len(self.videos)
        self.uploaded = 0
        self.errors = 0
        self.update_status()
        if self.total == 0:
            messagebox.showerror("Lỗi", "Không tìm thấy video trong thư mục đã chọn.")
            return
        self.log("Khởi động ChromeDriver...")
        options = Options()
        options.add_argument("--start-maximized")
        if self.silent_mode.get():
            options.add_argument("--headless=new")
            options.add_argument("--disable-gpu")
            options.add_argument("--no-sandbox")
        driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
        self.log("Đăng nhập vào Ok.ru...")
        try:
            driver.get("https://ok.ru")
            time.sleep(2)

            if self.cookie_mode.get() == "TXT File":
                cookies = []
                try:
                    with open(cookie_path, "r", encoding="utf-8") as f:
                        for line in f:
                            if not line.strip() or line.startswith("#") and not line.startswith("#HttpOnly_"):
                                continue
                            if line.startswith("#HttpOnly_"):
                                line = line[len("#HttpOnly_"):]
                            parts = line.strip().split("\t")
                            if len(parts) < 6:
                                continue
                            try:
                                domain = parts[0]
                                flag = parts[1]
                                path = parts[2]
                                secure = parts[3]
                                expiration = parts[4] if len(parts) > 5 else ""
                                name = parts[5] if len(parts) > 6 else ""
                                value = parts[6] if len(parts) > 6 else parts[5]  # Trường hợp chỉ có 6 trường
                                cookie = {
                                    "domain": domain,
                                    "name": name,
                                    "value": value,
                                    "path": path,
                                    "secure": secure.lower() == "true"
                                }
                                if expiration.isdigit():
                                    cookie["expiry"] = int(expiration)
                                cookies.append(cookie)
                            except Exception as cookie_error:
                                self.log(f"⚠️ Cookie lỗi bị bỏ qua: {line.strip()} ({cookie_error})")
                    for cookie in cookies:
                        driver.add_cookie(cookie)
                    driver.get("https://ok.ru/video/manager")
                    time.sleep(5)
                except Exception as e:
                    self.log(f"❌ Lỗi khi tải cookies: {e}")
                    driver.quit()
                    return
            else:
                driver.find_element(By.NAME, "st.email").send_keys(self.username.get())
                driver.find_element(By.NAME, "st.password").send_keys(self.password.get())
                WebDriverWait(driver, 10).until(
                    EC.element_to_be_clickable((By.CSS_SELECTOR, 'input[type="submit"].button-pro'))
                ).click()
                time.sleep(5)
                driver.get("https://ok.ru/video/manager")
                time.sleep(5)
        except Exception as e:
            self.log(f"❌ Lỗi khi đăng nhập: {e}")
            driver.quit()
            return
        output_path = os.path.join(self.output_folder.get(), "link.txt")
        error_path = os.path.join(self.output_folder.get(), "upload_errors.txt")
        for video_file in self.videos:
            if self.stop_flag:
                self.log("🛑 Dừng upload theo yêu cầu người dùng.")
                break
            success = False
            for attempt in range(3):
                try:
                    file_path = os.path.join(self.video_folder.get(), video_file)
                    self.log(f"🎞️ [{attempt+1}/3] Upload: {video_file}")
                    upload_input = driver.find_element(By.CSS_SELECTOR, 'input[type="file"].video-upload-input')
                    upload_input.send_keys(file_path)
                    self.log("⏳ Đợi nút Publish (tối đa 20 phút)...")
                    WebDriverWait(driver, 1200).until(
                        EC.element_to_be_clickable((By.CSS_SELECTOR, "a.js-uploader-publish-link"))
                    )
                    publish_btn = driver.find_element(By.CSS_SELECTOR,
                        "a.button-pro.__small.video-uploader_ac.__publish-btn")
                    edit_btn = driver.find_element(By.CSS_SELECTOR,
                        "a.button-pro.__small.__sec.video-uploader_ac.__go-to-editor-btn")
                    video_href = edit_btn.get_attribute("href")
                    self.log(f"🔎 href của nút Edit: {video_href}")
                    if video_href and "/video/editor/" in video_href:
                        video_id = video_href.split("/")[-1]
                        video_link = f"https://ok.ru/video/{video_id}"
                    else:
                        raise Exception(f"Không lấy được ID video: href={video_href}")
                    publish_btn.click()
                    time.sleep(3)
                    with open(output_path, "a", encoding="utf-8") as f:
                        f.write(f"{video_file}|{video_link}\n")
                    self.uploaded += 1
                    self.log(f"✅ Upload thành công: {video_link}")
                    success = True
                    driver.get("https://ok.ru/video/manager")
                    time.sleep(5)
                    break
                except Exception as e:
                    self.log(f"⚠️ Thử lại {attempt+1}/3 thất bại: {e}")
                    time.sleep(3)
            # ✅ CHỈ thực hiện sau khi đã thử đủ 3 lần
            if not success:
                self.errors += 1
                self.log(f"❌ Upload thất bại: {video_file}")
                with open(error_path, "a", encoding="utf-8") as ef:
                    ef.write(f"{video_file}\n")
            self.update_status()
            time.sleep(3)
        driver.quit()
        self.log("✅ Hoàn tất toàn bộ quá trình upload.")

# Run app
if __name__ == "__main__":
    root = Tk()
    app = OkRuUploader(root)
    root.mainloop()
pyinstaller --noconsole --onefile --windowed --add-data "2-OkRuUploader-icon.ico;." --icon=2-OkRuUploader-icon.ico 2-OkRuUploader-Source.py

Để lại một bình luận