bigbossmonster commited on
Commit
6859d16
·
verified ·
1 Parent(s): 2e43905

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -0
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import subprocess
3
+ import os
4
+
5
+ # --- Configuration ---
6
+
7
+ # Use persistent storage (/data/) if available.
8
+ if os.path.exists("/data"):
9
+ SAVE_PATH = "/data/torrents"
10
+ else:
11
+ SAVE_PATH = "./torrents"
12
+ print("WARNING: /data directory not found. Using ephemeral storage.")
13
+ print("Files will be DELETED when the Space restarts.")
14
+
15
+ # Create the save directory
16
+ os.makedirs(SAVE_PATH, exist_ok=True)
17
+
18
+ print(f"File save location: {SAVE_PATH}")
19
+
20
+ # Keep track of running processes (by magnet link)
21
+ processes = {}
22
+
23
+ def add_torrent(magnet_link):
24
+ """
25
+ Starts an aria2c download process in the background.
26
+ """
27
+ if not magnet_link or not magnet_link.startswith("magnet:?"):
28
+ return "Error: Invalid magnet link. Must start with 'magnet:?'"
29
+
30
+ if magnet_link in processes:
31
+ # Check if the process is still running
32
+ poll = processes[magnet_link].poll()
33
+ if poll is None:
34
+ return f"Download for this link is already running."
35
+
36
+ log_file = os.path.join(SAVE_PATH, "aria2.log")
37
+
38
+ # Command to run aria2
39
+ # --seed-time=0: Stop seeding immediately after download
40
+ # --daemon=true: Run in the background
41
+ # --enable-rpc=false: We don't need the RPC server
42
+ command = [
43
+ "aria2c",
44
+ magnet_link,
45
+ f"--dir={SAVE_PATH}",
46
+ "--seed-time=0",
47
+ "--daemon=true",
48
+ "--enable-rpc=false",
49
+ f"--log={log_file}",
50
+ "--log-level=info",
51
+ "--follow-torrent=mem" # Don't save .torrent file
52
+ ]
53
+
54
+ try:
55
+ # Start the process
56
+ # We use Popen to run it non-blockingly (in the background)
57
+ process = subprocess.Popen(command)
58
+ processes[magnet_link] = process
59
+ print(f"Started process {process.pid} for: {magnet_link}")
60
+ return f"Download started. Check status below."
61
+
62
+ except Exception as e:
63
+ print(f"Error starting aria2: {e}")
64
+ return f"Error: {e}"
65
+
66
+ def get_status_report():
67
+ """
68
+ Scans the download directory and lists files.
69
+ .aria2 files are temporary control files; their presence means
70
+ a download is incomplete.
71
+ """
72
+ try:
73
+ files = os.listdir(SAVE_PATH)
74
+ except Exception as e:
75
+ return f"Could not read directory: {e}"
76
+
77
+ if not files:
78
+ return "No downloads yet. Add a magnet link to start."
79
+
80
+ incomplete = []
81
+ completed = []
82
+
83
+ for f in files:
84
+ if f.endswith(".aria2"):
85
+ # It's a control file, so the real file is "in progress"
86
+ incomplete.append(f.replace(".aria2", ""))
87
+ elif f == "aria2.log":
88
+ continue # Ignore the log file
89
+ else:
90
+ # Check if it has a matching .aria2 file
91
+ if f"{f}.aria2" not in files:
92
+ completed.append(f)
93
+
94
+ # Build the report
95
+ report = ""
96
+ if incomplete:
97
+ report += "🔽 IN PROGRESS:\n" + "\n".join(f" - {f}" for f in incomplete) + "\n\n"
98
+
99
+ if completed:
100
+ report += "✅ COMPLETED:\n" + "\n".join(f" - {f}" for f in completed)
101
+
102
+ if not incomplete and not completed:
103
+ return "Directory is empty (or only has log file)."
104
+
105
+ return report
106
+
107
+ # --- Build the Gradio App ---
108
+ with gr.Blocks(title="Torrent Downloader") as demo:
109
+ gr.Markdown(
110
+ "# Hugging Face Torrent Downloader (aria2)\n"
111
+ f"Add a magnet link to download files. Files are saved in: `{SAVE_PATH}`"
112
+ )
113
+
114
+ with gr.Row():
115
+ magnet_input = gr.Textbox(
116
+ label="Magnet Link",
117
+ placeholder="magnet:?xt=urn:btih:...",
118
+ scale=4
119
+ )
120
+ add_button = gr.Button("Add Torrent", variant="primary", scale=1)
121
+
122
+ # This Textbox will automatically refresh every 5 seconds
123
+ status_output = gr.Textbox(
124
+ label="Download Status (refreshes every 5s)",
125
+ lines=15,
126
+ interactive=False,
127
+ value=get_status_report,
128
+ every=5
129
+ )
130
+
131
+ add_result_output = gr.Textbox(label="System Message", interactive=False)
132
+
133
+ add_button.click(
134
+ fn=add_torrent,
135
+ inputs=magnet_input,
136
+ outputs=add_result_output
137
+ )
138
+ add_button.click(lambda: "", outputs=magnet_input) # Clear input on click
139
+
140
+ # Launch the app
141
+ demo.launch()