import gradio as gr import os import threading import asyncio from torrentp import TorrentDownloader # --- Configuration --- if os.path.exists("/data"): SAVE_PATH = "/data/torrents" else: SAVE_PATH = "./torrents" print("WARNING: /data directory not found. Using ephemeral storage.") print("Files will be DELETED when the Space restarts.") os.makedirs(SAVE_PATH, exist_ok=True) print(f"File save location: {SAVE_PATH}") # Global dictionary to track the status from our threads # We will store: {magnet_link: "Status Message"} download_status = {} def run_download_in_thread(magnet_link): """ This function runs in a separate thread. It's what allows the GUI to stay responsive. """ try: # Set status to "Starting" download_status[magnet_link] = "đŸ”Ŋ Starting download..." print(f"Thread started for: {magnet_link}") # Initialize the downloader torrent_downloader = TorrentDownloader(magnet_link, SAVE_PATH) # This is a blocking call. # We must run it in a new event loop inside this thread. asyncio.run(torrent_downloader.start_download()) # If the line above finishes, the download is done. print(f"Thread finished for: {magnet_link}") download_status[magnet_link] = "✅ Download Finished" except Exception as e: print(f"Error in download thread: {e}") download_status[magnet_link] = f"Error: {e}" def add_torrent(magnet_link): """ This is called by the Gradio button. It *starts* the background thread but does not wait for it. """ if not magnet_link or not magnet_link.startswith("magnet:?"): return "Error: Invalid magnet link." if magnet_link in download_status and download_status[magnet_link] not in ["✅ Download Finished", "Error"]: return "Download for this link is already in progress." # Create and start the new thread # target=run_download_in_thread is the function to run # args=(magnet_link,) are the arguments to pass to that function thread = threading.Thread(target=run_download_in_thread, args=(magnet_link,)) thread.start() download_status[magnet_link] = "â„šī¸ Queued. Starting thread..." return "Download process started in background." def get_status_report(): """ Reads the global 'download_status' dictionary to show progress. This is not real-time speed, but it shows "Starting" or "Finished". """ if not download_status: return "No downloads started yet." report_lines = [] for link, status in download_status.items(): # Show the first 50 chars of the magnet link as an ID link_id = link[0:50] + "..." report_lines.append(f"{status}\n ({link_id})\n") return "\n".join(report_lines) # --- Build the Gradio App --- with gr.Blocks(title="Torrent Downloader") as demo: gr.Markdown( "# Hugging Face Torrent Downloader (using 'torrentp')\n" f"Shows basic status. Files are saved in: `{SAVE_PATH}`" ) with gr.Row(): magnet_input = gr.Textbox( label="Magnet Link", placeholder="magnet:?xt=urn:btih:...", scale=4 ) add_button = gr.Button("Add Torrent", variant="primary", scale=1) status_output = gr.Textbox( label="Download Status (refreshes every 5s)", lines=15, interactive=False, value=get_status_report, every=5 ) add_result_output = gr.Textbox(label="System Message", interactive=False) add_button.click( fn=add_torrent, inputs=magnet_input, outputs=add_result_output ) add_button.click(lambda: "", outputs=magnet_input) # Launch the app demo.launch()