Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,57 +1,106 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
from fastapi.responses import StreamingResponse
|
3 |
-
|
4 |
-
import io
|
5 |
|
6 |
-
app = FastAPI(
|
|
|
7 |
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
"""
|
17 |
-
Converts an uploaded image to the specified format.
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
image = Image.open(io.BytesIO(await file.read()))
|
36 |
-
except Exception as e:
|
37 |
-
raise HTTPException(status_code=400, detail="Invalid image file.") from e
|
38 |
-
|
39 |
-
output_io = io.BytesIO()
|
40 |
try:
|
41 |
-
|
42 |
-
if output_format.lower() in ["jpeg", "webp"]:
|
43 |
-
save_kwargs["quality"] = quality
|
44 |
-
image.save(output_io, format=output_format.upper(), **save_kwargs)
|
45 |
-
except KeyError:
|
46 |
-
raise HTTPException(
|
47 |
-
status_code=400, detail=f"Conversion to {output_format} failed."
|
48 |
-
)
|
49 |
except Exception as e:
|
50 |
-
raise HTTPException(status_code=500, detail=
|
|
|
|
|
|
|
51 |
|
52 |
-
|
53 |
-
|
54 |
-
if
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
-
|
|
|
|
|
|
1 |
+
# app.py
|
2 |
+
import os
|
3 |
+
import time
|
4 |
+
import uuid
|
5 |
+
import asyncio
|
6 |
+
import libtorrent as lt
|
7 |
+
from fastapi import FastAPI, HTTPException
|
8 |
from fastapi.responses import StreamingResponse
|
9 |
+
import magic
|
|
|
10 |
|
11 |
+
app = FastAPI()
|
12 |
+
active_sessions = {}
|
13 |
|
14 |
+
def get_largest_file(torrent_info):
|
15 |
+
files = torrent_info.files()
|
16 |
+
file_sizes = [(i, files.file_size(i)) for i in range(files.num_files())]
|
17 |
+
if not file_sizes:
|
18 |
+
return None
|
19 |
+
return max(file_sizes, key=lambda x: x[1])
|
20 |
|
21 |
+
async def add_torrent(magnet_link: str, save_path: str):
|
22 |
+
ses = lt.session()
|
23 |
+
params = {
|
24 |
+
'save_path': save_path,
|
25 |
+
'storage_mode': lt.storage_mode_t(2),
|
26 |
+
}
|
|
|
|
|
27 |
|
28 |
+
handle = lt.add_magnet_uri(ses, magnet_link, params)
|
29 |
+
|
30 |
+
# Wait for metadata
|
31 |
+
while not handle.has_metadata():
|
32 |
+
await asyncio.sleep(1)
|
33 |
+
|
34 |
+
torrent_info = handle.get_torrent_info()
|
35 |
+
file_info = get_largest_file(torrent_info)
|
36 |
+
if not file_info:
|
37 |
+
raise Exception("No files found in torrent")
|
38 |
+
|
39 |
+
file_index, _ = file_info
|
40 |
+
file_path = os.path.join(save_path, torrent_info.files().file_path(file_index))
|
41 |
+
|
42 |
+
# Prioritize largest file
|
43 |
+
for i in range(torrent_info.num_files()):
|
44 |
+
handle.file_priority(i, 7 if i == file_index else 0)
|
45 |
+
|
46 |
+
handle.set_sequential_download(True)
|
47 |
+
ses.resume()
|
48 |
+
|
49 |
+
return {
|
50 |
+
"session": ses,
|
51 |
+
"handle": handle,
|
52 |
+
"file_path": file_path,
|
53 |
+
"downloading": True
|
54 |
+
}
|
55 |
|
56 |
+
@app.post("/start_stream")
|
57 |
+
async def start_stream(magnet_link: str):
|
58 |
+
torrent_id = str(uuid.uuid4())
|
59 |
+
save_path = f"./downloads/{torrent_id}"
|
60 |
+
os.makedirs(save_path, exist_ok=True)
|
61 |
+
|
|
|
|
|
|
|
|
|
|
|
62 |
try:
|
63 |
+
session_info = await add_torrent(magnet_link, save_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
except Exception as e:
|
65 |
+
raise HTTPException(status_code=500, detail=str(e))
|
66 |
+
|
67 |
+
active_sessions[torrent_id] = session_info
|
68 |
+
return {"stream_url": f"/stream/{torrent_id}"}
|
69 |
|
70 |
+
@app.get("/stream/{torrent_id}")
|
71 |
+
async def stream_torrent(torrent_id: str):
|
72 |
+
if torrent_id not in active_sessions:
|
73 |
+
raise HTTPException(status_code=404, detail="Torrent session not found")
|
74 |
+
|
75 |
+
session_info = active_sessions[torrent_id]
|
76 |
+
file_path = session_info["file_path"]
|
77 |
+
|
78 |
+
if not os.path.exists(file_path):
|
79 |
+
raise HTTPException(status_code=404, detail="File not found")
|
80 |
+
|
81 |
+
mime = magic.Magic(mime=True)
|
82 |
+
mime_type = mime.from_file(file_path)
|
83 |
+
|
84 |
+
def file_generator():
|
85 |
+
last_position = 0
|
86 |
+
while True:
|
87 |
+
if not os.path.exists(file_path):
|
88 |
+
time.sleep(1)
|
89 |
+
continue
|
90 |
+
|
91 |
+
with open(file_path, "rb") as f:
|
92 |
+
f.seek(last_position)
|
93 |
+
data = f.read(1024 * 1024) # 1MB chunks
|
94 |
+
if not data:
|
95 |
+
if session_info["handle"].is_seed():
|
96 |
+
break
|
97 |
+
time.sleep(1)
|
98 |
+
continue
|
99 |
+
last_position = f.tell()
|
100 |
+
yield data
|
101 |
+
|
102 |
+
return StreamingResponse(file_generator(), media_type=mime_type)
|
103 |
|
104 |
+
if __name__ == "__main__":
|
105 |
+
import uvicorn
|
106 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|