File size: 4,859 Bytes
6dcf562 5eee105 36bda90 dc50e93 2e81e75 db46eb3 49ea85c db46eb3 2e81e75 886864f 15d97c1 18d2a16 87c7342 18d2a16 87c7342 36bda90 18d2a16 87c7342 36bda90 78ececa 36bda90 78ececa 36bda90 18d2a16 36bda90 18d2a16 36bda90 18d2a16 36bda90 18d2a16 36bda90 15d97c1 2e81e75 dd2f10e 18d2a16 dd2f10e 18d2a16 dc50e93 49ea85c 9c0c806 dc50e93 9c0c806 dc50e93 18d2a16 dc50e93 9c0c806 dc50e93 18d2a16 dc50e93 18d2a16 9c0c806 dc50e93 9c0c806 dc50e93 9c0c806 dc50e93 18d2a16 dc50e93 |
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
from fastapi.responses import JSONResponse, FileResponse, Response
from fastapi import FastAPI, HTTPException, Request
import mimetypes
from threading import Thread
from Instance import Instance
from api import LoadBalancerAPI
import os
import aiofiles
from urllib.parse import unquote
# Constants and Configuration
CACHE_DIR = os.getenv("CACHE_DIR")
TOKEN = os.getenv("TOKEN")
REPO = os.getenv("REPO")
ID = os.getenv("ID")
URL = os.getenv("URL")
LOAD_BALANCER_URL = os.getenv("LOAD_BALANCER_URL")
load_balancer_api = LoadBalancerAPI(base_url=LOAD_BALANCER_URL)
instance = Instance(id=ID, url=URL, cache_dir=CACHE_DIR, token=TOKEN, repo=REPO, load_balancer_api=load_balancer_api)
app = FastAPI()
from fastapi import HTTPException, Request
from fastapi.responses import Response, FileResponse
import os
import mimetypes
import aiofiles
async def serve_media(file_path: str, request: Request):
"""Serve any media file with support for range requests."""
if not os.path.isfile(file_path):
raise HTTPException(status_code=404, detail="Media file not found")
file_size = os.path.getsize(file_path)
range_header = request.headers.get('range', None)
# Determine the MIME type based on the file extension
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type is None:
mime_type = 'application/octet-stream' # Fallback MIME type
# Handle range requests
if range_header:
range_specifier = range_header.replace('bytes=', '').strip()
start, end = (None, None)
if '-' in range_specifier:
start_str, end_str = range_specifier.split('-')
start = int(start_str)
end = int(end_str) if end_str else file_size - 1
# Validate the range
if start is None or start >= file_size or (end is not None and end >= file_size) or (end is not None and start > end):
raise HTTPException(status_code=416, detail="Requested range not satisfiable")
headers = {
'Content-Range': f'bytes {start}-{end or file_size - 1}/{file_size}',
'Accept-Ranges': 'bytes',
'Content-Length': str((end - start + 1) if end is not None else file_size - start),
'Content-Type': mime_type
}
async with aiofiles.open(file_path, 'rb') as f:
await f.seek(start)
chunk_size = 8192 # Read in 8KB chunks
data = bytearray()
while start <= (end or file_size - 1):
remaining = (end or file_size - 1) - start + 1
read_size = min(chunk_size, remaining)
chunk = await f.read(read_size)
if not chunk: # End of file
break
data.extend(chunk)
start += read_size
return Response(content=bytes(data), status_code=206, headers=headers)
# Fallback for serving the entire file if no range requested
return FileResponse(file_path, media_type=mime_type)
@app.get("/")
async def index():
return instance.version
@app.get("/api/get/report")
async def get_report():
report = instance.compile_report()
return JSONResponse(report)
@app.get('/api/get/music/store')
async def get_media_store_api():
"""Endpoint to get the music store JSON."""
return JSONResponse(instance.MUSIC_STORE)
@app.get("/api/get/music/{filename}")
async def get_media_api(request: Request, filename: str):
"""Endpoint to get the music file (audio or video) by filename with support for range requests."""
filename = unquote(filename)
if not filename:
raise HTTPException(status_code=400, detail="filename parameter is required")
if filename in instance.MUSIC_STORE:
cache_path = instance.MUSIC_STORE[filename]
if os.path.exists(cache_path):
return await serve_media(cache_path, request)
media_path = instance.find_music_path(filename)
if not media_path:
raise HTTPException(status_code=404, detail="Media not found")
cache_path = os.path.join(CACHE_DIR, media_path)
file_url = f"https://huggingface.co/{REPO}/resolve/main/{media_path}"
music_id = instance.get_music_id(filename)
if music_id not in instance.download_threads or not instance.download_threads[music_id].is_alive():
thread = Thread(target=instance.download_music, args=(file_url, TOKEN, cache_path, music_id, filename))
instance.download_threads[music_id] = thread
thread.start()
return JSONResponse({"status": "Download started", "music_id": music_id})
@app.get("/api/get/progress/{id}")
async def get_progress_api(id: str):
"""Endpoint to get the download progress of a media file."""
progress = instance.get_download_progress(id)
return JSONResponse({"id": id, "progress": progress})
|