torrent-downloader-react 1.0.20__py3-none-any.whl → 1.0.21__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- torrent_downloader/server.py +22 -43
- torrent_downloader/static/assets/index-BAUKkMK0.js +49 -0
- torrent_downloader/static/assets/{index-CdUAChFP.css → index-DpeprjRI.css} +1 -1
- torrent_downloader/static/index.html +2 -2
- {torrent_downloader_react-1.0.20.dist-info → torrent_downloader_react-1.0.21.dist-info}/METADATA +1 -1
- torrent_downloader_react-1.0.21.dist-info/RECORD +11 -0
- torrent_downloader/static/assets/index-DFkOG9rp.js +0 -49
- torrent_downloader_react-1.0.20.dist-info/RECORD +0 -11
- {torrent_downloader_react-1.0.20.dist-info → torrent_downloader_react-1.0.21.dist-info}/WHEEL +0 -0
- {torrent_downloader_react-1.0.20.dist-info → torrent_downloader_react-1.0.21.dist-info}/entry_points.txt +0 -0
- {torrent_downloader_react-1.0.20.dist-info → torrent_downloader_react-1.0.21.dist-info}/top_level.txt +0 -0
torrent_downloader/server.py
CHANGED
@@ -92,6 +92,7 @@ class TorrentInfo(BaseModel):
|
|
92
92
|
state: str
|
93
93
|
total_size: int
|
94
94
|
downloaded: int
|
95
|
+
eta_seconds: Optional[int] = None
|
95
96
|
|
96
97
|
@app.post("/api/torrent/add")
|
97
98
|
async def add_torrent(request: TorrentRequest):
|
@@ -132,11 +133,28 @@ async def list_torrents() -> List[TorrentInfo]:
|
|
132
133
|
state_str = "finished"
|
133
134
|
elif status.state == lt.torrent_status.checking_files:
|
134
135
|
state_str = "checking"
|
135
|
-
elif status.state == lt.torrent_status.paused:
|
136
|
-
state_str = "paused"
|
137
136
|
|
138
137
|
logging.debug(f"Torrent {torrent_id} state: {state_str} (raw state: {status.state})")
|
139
138
|
|
139
|
+
# Calculate ETA
|
140
|
+
eta = None
|
141
|
+
try:
|
142
|
+
if state_str == "downloading":
|
143
|
+
remaining_bytes = status.total_wanted - status.total_wanted_done
|
144
|
+
if remaining_bytes <= 0:
|
145
|
+
eta = 0 # Download complete
|
146
|
+
elif status.download_rate > 0:
|
147
|
+
eta = int(remaining_bytes / status.download_rate)
|
148
|
+
else:
|
149
|
+
eta = None # Can't calculate ETA with zero download rate
|
150
|
+
elif state_str in ["finished", "seeding"]:
|
151
|
+
eta = 0 # Already complete
|
152
|
+
elif state_str == "checking":
|
153
|
+
eta = None # Can't estimate during checking
|
154
|
+
except Exception as e:
|
155
|
+
logging.error(f"Error calculating ETA for torrent {torrent_id}: {e}")
|
156
|
+
eta = None
|
157
|
+
|
140
158
|
info = TorrentInfo(
|
141
159
|
id=torrent_id,
|
142
160
|
name=handle.name(),
|
@@ -145,7 +163,8 @@ async def list_torrents() -> List[TorrentInfo]:
|
|
145
163
|
upload_speed=status.upload_rate / 1024, # Convert to KB/s
|
146
164
|
state=state_str,
|
147
165
|
total_size=status.total_wanted,
|
148
|
-
downloaded=status.total_wanted_done
|
166
|
+
downloaded=status.total_wanted_done,
|
167
|
+
eta_seconds=eta
|
149
168
|
)
|
150
169
|
result.append(info)
|
151
170
|
|
@@ -173,46 +192,6 @@ async def open_downloads():
|
|
173
192
|
raise HTTPException(status_code=500, detail="Failed to open downloads folder")
|
174
193
|
return {"message": "Downloads folder opened successfully"}
|
175
194
|
|
176
|
-
@app.post("/api/torrent/{torrent_id}/pause")
|
177
|
-
async def pause_torrent(torrent_id: str):
|
178
|
-
"""Pause a specific torrent."""
|
179
|
-
if torrent_id not in active_torrents:
|
180
|
-
raise HTTPException(status_code=404, detail="Torrent not found")
|
181
|
-
|
182
|
-
handle = active_torrents[torrent_id]
|
183
|
-
logging.info(f"Pausing torrent {torrent_id}, current state: {handle.status().state}")
|
184
|
-
handle.pause()
|
185
|
-
# Force an immediate pause
|
186
|
-
handle.flush_cache()
|
187
|
-
logging.info(f"Torrent {torrent_id} paused, new state: {handle.status().state}")
|
188
|
-
return {"message": "Torrent paused successfully"}
|
189
|
-
|
190
|
-
@app.post("/api/torrent/{torrent_id}/resume")
|
191
|
-
async def resume_torrent(torrent_id: str):
|
192
|
-
"""Resume a specific torrent."""
|
193
|
-
if torrent_id not in active_torrents:
|
194
|
-
raise HTTPException(status_code=404, detail="Torrent not found")
|
195
|
-
|
196
|
-
handle = active_torrents[torrent_id]
|
197
|
-
logging.info(f"Resuming torrent {torrent_id}, current state: {handle.status().state}")
|
198
|
-
handle.resume()
|
199
|
-
logging.info(f"Torrent {torrent_id} resumed, new state: {handle.status().state}")
|
200
|
-
return {"message": "Torrent resumed successfully"}
|
201
|
-
|
202
|
-
@app.post("/api/torrent/pause-all")
|
203
|
-
async def pause_all_torrents():
|
204
|
-
"""Pause all active torrents."""
|
205
|
-
for handle in active_torrents.values():
|
206
|
-
handle.pause()
|
207
|
-
return {"message": "All torrents paused successfully"}
|
208
|
-
|
209
|
-
@app.post("/api/torrent/resume-all")
|
210
|
-
async def resume_all_torrents():
|
211
|
-
"""Resume all active torrents."""
|
212
|
-
for handle in active_torrents.values():
|
213
|
-
handle.resume()
|
214
|
-
return {"message": "All torrents resumed successfully"}
|
215
|
-
|
216
195
|
def main():
|
217
196
|
"""Entry point for the application."""
|
218
197
|
import uvicorn
|