Facebook Video Downloader – DarkCorners

Date: 16/12/2025

Category: Python

  • Phần mềm hỗ trợ tải xuống video từ facebook hàng loạt.
  • Nhập danh sách tải xuống theo cấu trúc : [link]|[filename]
  • Phần mềm sẽ tải xuống video từ facebook. Sau đó lưu với tên mà bạn quy định.
  1. Khởi động phần mềm.
  2. Chọn thư mục chứa tệp được xuất ra.
  3. Điền danh sách liên kết facebook cần tải xuống.
  4. Chọn chất lượng video sẽ tải xuống. Hỗ trợ 360, 480, 720, 1080.
  5. Nhấn nút [Tải Xuống].
  6. Theo dõi lịch trình xử lý.
import os
import threading
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, scrolledtext
from yt_dlp import YoutubeDL

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 FacebookDownloaderApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Facebook Video Downloader - DarkCorners")
        self.root.resizable(False, False)
        center_window(self.root, 800, 600)

        self.save_folder = ""
        self.pause_flag = False
        self.downloading = False

        self.total_videos = 0
        self.completed_videos = 0
        self.pending_videos = 0
        self.failed_videos = 0

        self.setup_ui()

    def setup_ui(self):
        tk.Label(self.root, text="Facebook Video Downloader - DarkCorners", font=("Arial", 16, "bold")).pack(pady=10)

        container = tk.Frame(self.root)
        container.pack(fill=tk.X, padx=10, pady=5)

        config_frame = tk.LabelFrame(container, text="Cấu Hình", font=("Arial", 10, "bold"), padx=10, pady=10)
        config_frame.grid(row=0, column=0, sticky="nsew", padx=5)
        container.grid_columnconfigure(0, weight=1, uniform="group1")

        folder_frame = tk.Frame(config_frame)
        folder_frame.pack(fill=tk.X, pady=2)
        self.folder_path_entry = tk.Entry(folder_frame, width=45)
        self.folder_path_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=False)
        tk.Button(folder_frame, text="Chọn", command=self.select_folder, width=5).pack(side=tk.LEFT, padx=5)

        tk.Label(config_frame, text="Chọn thư mục chứa videos sẽ tải xuống !", font=("Arial", 9, "bold"), fg="red").pack(anchor="w")
        tk.Label(config_frame, text="Danh sách link cần tải xuống theo định dạng : link|filename", font=("Arial", 9, "bold"), fg="red").pack(anchor="w")

        control_frame = tk.LabelFrame(container, text="Điều Khiển", font=("Arial", 10, "bold"), padx=10, pady=10)
        control_frame.grid(row=0, column=1, sticky="nsew", padx=5)
        container.grid_columnconfigure(1, weight=1, uniform="group1")

        quality_frame = tk.Frame(control_frame)
        quality_frame.pack(fill=tk.X, pady=2)
        tk.Label(quality_frame, text="Chọn chất lượng video : ").pack(side=tk.LEFT, padx=5)
        self.quality_var = tk.StringVar(value="720p")
        ttk.Combobox(quality_frame, textvariable=self.quality_var, values=["480p", "720p", "1080p"], width=10).pack(side=tk.LEFT, padx=5)

        control_buttons = tk.Frame(control_frame)
        control_buttons.pack(pady=5)
        tk.Button(control_buttons, text="Tải Xuống", command=self.start_download_thread, width=15).pack(side=tk.LEFT, padx=5)
        tk.Button(control_buttons, text="Tạm Dừng", command=self.pause_download, width=15).pack(side=tk.LEFT, padx=5)
        tk.Button(control_buttons, text="Thoát", command=self.root.quit, width=15).pack(side=tk.LEFT, padx=5)

        links_frame = tk.LabelFrame(self.root, text="Link Videos Cần Tải Xuống", font=("Arial", 10, "bold"), padx=10, pady=5)
        links_frame.pack(fill=tk.X, padx=10, pady=5)
        self.link_text = scrolledtext.ScrolledText(links_frame, height=10)
        self.link_text.pack(fill=tk.BOTH, expand=True)

        section4 = tk.Frame(self.root)
        section4.pack(fill=tk.X, padx=10, pady=5)

        logs_frame = tk.LabelFrame(section4, text="Logs", font=("Arial", 10, "bold"), padx=10, pady=5)
        logs_frame.grid(row=0, column=0, sticky="nsew", padx=5)
        self.log_text = scrolledtext.ScrolledText(logs_frame, width=45, height=10)
        self.log_text.pack()

        status_frame = tk.LabelFrame(section4, text="Tiến Trình Xử Lý", font=("Arial", 10, "bold"), padx=10, pady=5)
        status_frame.grid(row=0, column=1, sticky="nsew", padx=5)
        section4.grid_columnconfigure(0, weight=1, uniform="group4")
        section4.grid_columnconfigure(1, weight=1, uniform="group4")

        line1 = tk.Frame(status_frame)
        line1.pack(fill=tk.X, pady=2)
        tk.Label(line1, text="Video Hiện Tại:").pack(side=tk.LEFT)
        self.progress_current = ttk.Progressbar(line1)
        self.progress_current.pack(side=tk.LEFT, padx=5, fill='x', expand=True)

        line2 = tk.Frame(status_frame)
        line2.pack(fill=tk.X, pady=2)
        tk.Label(line2, text="Tổng Thể:").pack(side=tk.LEFT)
        self.progress_total = ttk.Progressbar(line2)
        self.progress_total.pack(side=tk.LEFT, padx=5, fill='x', expand=True)

        ttk.Separator(status_frame, orient='horizontal').pack(fill='x', pady=5)

        self.label_total = tk.Label(status_frame, text="Tổng Số Videos : 0", font=("Arial", 9, "bold"), fg="red")
        self.label_total.pack(anchor="w")
        self.label_done = tk.Label(status_frame, text="Videos Đã Tải : 0", font=("Arial", 9, "bold"), fg="green")
        self.label_done.pack(anchor="w")
        self.label_pending = tk.Label(status_frame, text="Videos Đợi Tải : 0", font=("Arial", 9, "bold"), fg="blue")
        self.label_pending.pack(anchor="w")
        self.label_failed = tk.Label(status_frame, text="Videos Bị Lỗi : 0", font=("Arial", 9, "bold"), fg="black")
        self.label_failed.pack(anchor="w")

    def log(self, message):
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)

    def update_counters(self):
        self.label_total.config(text=f"Tổng Số Videos : {self.total_videos}")
        self.label_done.config(text=f"Videos Đã Tải : {self.completed_videos}")
        self.label_pending.config(text=f"Videos Đợi Tải : {self.pending_videos}")
        self.label_failed.config(text=f"Videos Bị Lỗi : {self.failed_videos}")

    def select_folder(self):
        folder = filedialog.askdirectory()
        if folder:
            self.save_folder = folder
            self.folder_path_entry.delete(0, tk.END)
            self.folder_path_entry.insert(0, folder)

    def pause_download(self):
        self.pause_flag = True
        self.log("⏸ Đã tạm dừng tải xuống.")

    def start_download_thread(self):
        if not self.save_folder:
            messagebox.showwarning("Chưa chọn thư mục", "Vui lòng chọn thư mục lưu video.")
            return
        raw_lines = self.link_text.get("1.0", tk.END).strip().splitlines()
        links = []
        for line in raw_lines:
            parts = line.strip().split("|", 1)
            url = parts[0].strip()
            filename = parts[1].strip() if len(parts) > 1 else None
            links.append((url, filename))

        if not links:
            messagebox.showwarning("Chưa nhập link", "Vui lòng nhập ít nhất 1 link video Facebook.")
            return

        self.total_videos = len(links)
        self.completed_videos = 0
        self.pending_videos = self.total_videos
        self.failed_videos = 0
        self.update_counters()

        self.downloading = True
        self.pause_flag = False
        threading.Thread(target=self.download_videos, args=(links,)).start()

    def get_format_selector(self, preferred_quality):
        if preferred_quality == "1080p":
            return "bestvideo[height<=1080]+bestaudio/best"
        elif preferred_quality == "720p":
            return "bestvideo[height<=720]+bestaudio/best"
        elif preferred_quality == "480p":
            return "bestvideo[height<=480]+bestaudio/best"
        return "best"

    def download_videos(self, links):
        self.progress_total["maximum"] = len(links)
        self.progress_total["value"] = 0

        for index, (url, custom_name) in enumerate(links):
            if self.pause_flag:
                break
            self.log(f"🚀 Đang tải video {index + 1}/{len(links)}: {url}")
            self.progress_current["value"] = 0

            outtmpl = os.path.join(self.save_folder, custom_name + ".%(ext)s") if custom_name else os.path.join(self.save_folder, '%(title).100s.%(ext)s')

            ydl_opts = {
                'format': self.get_format_selector(self.quality_var.get()),
                'outtmpl': outtmpl,
                'quiet': True,
                'noplaylist': True,
                'progress_hooks': [self.hook],
                'merge_output_format': 'mp4',
                'windowsfilenames': True,
            }

            try:
                with YoutubeDL(ydl_opts) as ydl:
                    ydl.download([url])
                self.completed_videos += 1
                self.log(f"✅ Đã tải xong: {url}")
            except Exception as e:
                self.failed_videos += 1
                self.log(f"❌ Lỗi tải video: {e}")

            self.pending_videos -= 1
            self.update_counters()
            self.progress_total["value"] = index + 1
            self.progress_current["value"] = 0

        if not self.pause_flag:
            self.log("🎉 Hoàn tất tất cả video.")
        else:
            self.log("⏸ Tải xuống đã bị tạm dừng.")

    def hook(self, d):
        if d['status'] == 'downloading':
            total = d.get('total_bytes') or d.get('total_bytes_estimate')
            downloaded = d.get('downloaded_bytes')
            if total and downloaded:
                try:
                    percent = (downloaded / total) * 100
                    self.progress_current["value"] = percent
                except:
                    pass

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

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