Spaces:
Sleeping
Sleeping
| 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() |