Saturday, June 28, 2025

নিজের জন্য ডাউনলোডার

বানানোর পর দেখতে যেমন হলো
গতরাতে একটা ফাইল ডাউনলোড করতে চাইলাম, বেশি বড়! না, মাত্র ১০ জিবি, ব্রাউজারেই ডাউনলোড করা যাচ্ছে কিন্তু সমস্যা হল, কম্পিউটার স্লিপ মোডে গেলে ডাউনলোড বন্ধ হয়ে যায়, আবার অন করলে শুরু থেকে ডাউনলোড হয়। চিন্তা করলাম কী করা যায়, লিংক নিয়ে টার্মিনালে কমান্ড দিলাম। শুরু হল, এটাতেও সেইম সমস্যা, খুঁজে পেলাম ক্যাফেইন, যেটা দিলে ডাউনলোড হওয়া পর্যন্ত কম্পিউটার জেগে থাকে।

ডাউনলোড হওয়ার পর মনে হলো নিজের জন্য একটি ডাউনলোডার হলে মন্দ কি?

কাজ শুরু করলাম, সাথে ছিল পাইথন, শেষে যা দাঁড়ালো নিজেই অবাক হলাম-



চাইলে আপনিও ব্যবহার করতে পারেন, নিচের কোডটি একটা ফাইল (file name.py) তৈরি করে পাইথনে রান করলেই হবে-

(সংবিধিবদ্ধ সতর্কীকরণ-

১। আমার উবুন্টুতে এটা কাজ করেছে, উইন্ডোজে কাজ করবে কিনা তা পরীক্ষা করা হয়নি- আপনি পরীক্ষা করলে আমাকে ফলাফল জানাবেন

২। ও হ্যাঁ আপনার সিস্টেমে অবশ্যই python3 (না থাকলে- Ubuntu: sudo apt install python3 ), tkinter (GUI এর জন্য- না থাকলে Ubuntu: sudo apt install python3-tk ) এবং aria2c (ডাউনলোড করার জন্য না থাকলে- Ubuntu: sudo apt install aria2 ) থাকতে হবে। না থাকলে ডাউনলোড করে নিতে হবে)

তাহলে শুরু করা যাক- (কপি বাটনে ক্লিক করে কোডটি কপি করে নিতে পারবেন)
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog, ttk
import subprocess
import os
import time
import threading

class Aria2Downloader:
    def __init__(self, root):
        self.root = root
        root.title("FDM-musfiq (Threaded with Progress & Close Confirm)")
        root.geometry("700x600")

        # URL input
        tk.Label(root, text="Download URLs (one per line):").pack()
        self.url_text = tk.Text(root, height=5, width=85)
        self.url_text.pack(pady=5)

        # Folder select
        tk.Label(root, text="Download Folder:").pack()
        self.folder_var = tk.StringVar()
        folder_frame = tk.Frame(root)
        folder_frame.pack()
        self.folder_entry = tk.Entry(folder_frame, textvariable=self.folder_var, width=60)
        self.folder_entry.pack(side=tk.LEFT, padx=(10, 5))
        tk.Button(folder_frame, text="Browse", command=self.browse_folder).pack(side=tk.LEFT)

        # Buttons
        button_frame = tk.Frame(root)
        button_frame.pack(pady=10)
        tk.Button(button_frame, text="Start Download", command=self.start_download).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="Pause All", command=self.pause_all).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="Resume All", command=self.resume_all).pack(side=tk.LEFT, padx=10)
        tk.Button(button_frame, text="Copy Status", command=self.copy_status).pack(side=tk.LEFT, padx=10)

        # Progress bar
        tk.Label(root, text="Progress:").pack()
        self.progress = ttk.Progressbar(root, orient="horizontal", length=600, mode="determinate")
        self.progress.pack(pady=5)
        self.progress_label = tk.Label(root, text="Idle")
        self.progress_label.pack()

        # Status area
        tk.Label(root, text="Status:").pack()
        self.status = tk.Text(root, height=12, width=85)
        self.status.pack()

        # Download history file
        self.history_file = os.path.expanduser("~/aria2_download_history.txt")

        # Thread control
        self.download_thread = None

        # Handle window close event
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def browse_folder(self):
        folder = filedialog.askdirectory()
        if folder:
            self.folder_var.set(folder)

    def copy_status(self):
        self.root.clipboard_clear()
        text = self.status.get("1.0", tk.END)
        self.root.clipboard_append(text)
        messagebox.showinfo("Copied", "Status text copied to clipboard.")

    def start_download(self):
        if self.download_thread and self.download_thread.is_alive():
            messagebox.showwarning("Warning", "Download is already in progress.")
            return

        urls = self.url_text.get("1.0", tk.END).strip().splitlines()
        folder = self.folder_var.get().strip()

        if not urls or not folder:
            messagebox.showerror("Error", "Please enter URLs and select a folder.")
            return

        self.files = []
        for url in urls:
            suggested_name = url.split("/")[-1]
            filename = simpledialog.askstring("File Name", f"Enter file name for:\n{url}", initialvalue=suggested_name)
            if not filename:
                self.status.insert(tk.END, f"Skipped: {url}\n")
            self.files.append((url, filename))

        self.download_thread = threading.Thread(target=self.download_all, daemon=True)
        self.download_thread.start()

    def download_all(self):
        total = len(self.files)
        self.progress["maximum"] = total
        self.progress["value"] = 0

        for idx, (url, filename) in enumerate(self.files, start=1):
            if not filename:
                self.progress["value"] = idx
                self.root.update()
                continue

            folder = self.folder_var.get().strip()

            def append_status(text):
                self.status.insert(tk.END, text)
                self.status.see(tk.END)

            append_status(f"\nDownloading: {filename}\n")
            self.progress_label.config(text=f"Downloading {filename}...")
            self.root.update()

            try:
                if "youtube.com" in url or "youtu.be" in url:
                    # ইউটিউব লিঙ্ক হলে yt-dlp ব্যবহার
                    output_path = os.path.join(folder, filename)
                    if not os.path.splitext(output_path)[1]:
                        output_path += ".mp4"
                    command = [
                        "yt-dlp",
                        "-f", "bestvideo+bestaudio",
                        "-o", output_path,
                        url
                    ]
                else:
                    # অন্য লিঙ্ক হলে aria2c ব্যবহার
                    command = [
                        "aria2c", "--max-connection-per-server=16", "--split=16", "--min-split-size=1M", "--continue",
                        "--header=User-Agent: Mozilla/5.0",
                        "--referer=https://pixeldrain.com",
                        "-d", folder, "-o", filename, url
                    ]

                process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

                with open(self.history_file, "a") as hist:
                    hist.write(f"{time.ctime()} - {filename} from {url}\n")

                for line in process.stdout:
                    append_status(line)
                    self.root.update()

                stderr = process.stderr.read()
                if stderr:
                    append_status("\n[Error Output]:\n" + stderr)

                process.wait()
                if process.returncode == 0:
                    self.progress_label.config(text=f"Completed: {filename}")
                else:
                    self.progress_label.config(text=f"Error downloading {filename}")

            except Exception as e:
                append_status(f"Exception: {e}\n")
                self.progress_label.config(text="Error")

            self.progress["value"] = idx
            self.root.update()

        self.progress_label.config(text="All downloads completed.")

    def pause_all(self):
        os.system("pkill -STOP aria2c")
        os.system("pkill -STOP yt-dlp")
        self.status.insert(tk.END, "All downloads paused.\n")
        self.status.see(tk.END)
        self.progress_label.config(text="Paused")

    def resume_all(self):
        os.system("pkill -CONT aria2c")
        os.system("pkill -CONT yt-dlp")
        self.status.insert(tk.END, "All downloads resumed.\n")
        self.status.see(tk.END)
        self.progress_label.config(text="Resumed")

    def on_closing(self):
        if self.download_thread and self.download_thread.is_alive():
            if not messagebox.askokcancel("Quit", "Download is still in progress. Are you sure you want to quit?"):
                return
        self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = Aria2Downloader(root)
    root.mainloop()
  


বাদবাকি সাজানো গোছানোর কাজ নিজেই করে নিতে পারবেন।

শুভ প্রোগ্রামিং।

 

আপনার মন্তব্য লিখুন

ফেসবুক লাইক ও শেয়ার