File size: 3,120 Bytes
c918e99
 
 
 
 
 
 
e6112da
c918e99
f3fb9be
c918e99
 
f3fb9be
c918e99
 
 
 
 
 
f3fb9be
c918e99
 
 
 
 
 
e6112da
c918e99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e6112da
c918e99
 
 
 
 
 
e6112da
c918e99
e6112da
c918e99
 
 
 
e6112da
c918e99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e6112da
c918e99
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# app.py
import os
import time
import uuid
import asyncio
import libtorrent as lt
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
import magic

app = FastAPI()
active_sessions = {}

def get_largest_file(torrent_info):
    files = torrent_info.files()
    file_sizes = [(i, files.file_size(i)) for i in range(files.num_files())]
    if not file_sizes:
        return None
    return max(file_sizes, key=lambda x: x[1])

async def add_torrent(magnet_link: str, save_path: str):
    ses = lt.session()
    params = {
        'save_path': save_path,
        'storage_mode': lt.storage_mode_t(2),
    }

    handle = lt.add_magnet_uri(ses, magnet_link, params)
    
    # Wait for metadata
    while not handle.has_metadata():
        await asyncio.sleep(1)
    
    torrent_info = handle.get_torrent_info()
    file_info = get_largest_file(torrent_info)
    if not file_info:
        raise Exception("No files found in torrent")
    
    file_index, _ = file_info
    file_path = os.path.join(save_path, torrent_info.files().file_path(file_index))
    
    # Prioritize largest file
    for i in range(torrent_info.num_files()):
        handle.file_priority(i, 7 if i == file_index else 0)
    
    handle.set_sequential_download(True)
    ses.resume()
    
    return {
        "session": ses,
        "handle": handle,
        "file_path": file_path,
        "downloading": True
    }

@app.post("/start_stream")
async def start_stream(magnet_link: str):
    torrent_id = str(uuid.uuid4())
    save_path = f"./downloads/{torrent_id}"
    os.makedirs(save_path, exist_ok=True)
    
    try:
        session_info = await add_torrent(magnet_link, save_path)
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    
    active_sessions[torrent_id] = session_info
    return {"stream_url": f"/stream/{torrent_id}"}

@app.get("/stream/{torrent_id}")
async def stream_torrent(torrent_id: str):
    if torrent_id not in active_sessions:
        raise HTTPException(status_code=404, detail="Torrent session not found")
    
    session_info = active_sessions[torrent_id]
    file_path = session_info["file_path"]
    
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="File not found")
    
    mime = magic.Magic(mime=True)
    mime_type = mime.from_file(file_path)
    
    def file_generator():
        last_position = 0
        while True:
            if not os.path.exists(file_path):
                time.sleep(1)
                continue
            
            with open(file_path, "rb") as f:
                f.seek(last_position)
                data = f.read(1024 * 1024)  # 1MB chunks
                if not data:
                    if session_info["handle"].is_seed():
                        break
                    time.sleep(1)
                    continue
                last_position = f.tell()
                yield data
    
    return StreamingResponse(file_generator(), media_type=mime_type)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)