robot-dance-party / start_server.py
autonomous-ai's picture
Upload folder using huggingface_hub
61bd138 verified
Raw
History Blame Contribute Delete
3.43 kB
"""Static file server + YouTube audio download.
Auto-installs yt-dlp if missing. User just runs: python start_server.py
"""
import http.server
import json
import subprocess
import sys
from pathlib import Path
# Auto-install yt-dlp if missing
try:
import yt_dlp
except ImportError:
print("Installing yt-dlp...")
subprocess.check_call([
sys.executable, "-m", "pip", "install", "yt-dlp", "-q",
"--break-system-packages",
])
import yt_dlp
DOWNLOADS = Path(__file__).resolve().parent / "downloads"
DOWNLOADS.mkdir(exist_ok=True)
def extract_video_id(url):
"""Extract YouTube video ID from URL without downloading."""
with yt_dlp.YoutubeDL({"quiet": True, "skip_download": True}) as ydl:
info = ydl.extract_info(url, download=False)
return info.get("id"), info.get("title", "Unknown")
def download_audio(url):
"""Download YouTube audio as mp3, return (filepath, title). Reuses cached files."""
video_id, title = extract_video_id(url)
# Reuse cached file if already downloaded
mp3 = DOWNLOADS / f"{video_id}.mp3"
if mp3.exists():
print(f"Cache hit: {mp3.name}")
return mp3, title
opts = {
"format": "bestaudio/best",
"postprocessors": [{"key": "FFmpegExtractAudio", "preferredcodec": "mp3"}],
"outtmpl": str(DOWNLOADS / "%(id)s.%(ext)s"),
"noplaylist": True,
"quiet": True,
}
with yt_dlp.YoutubeDL(opts) as ydl:
ydl.download([url])
if not mp3.exists():
for f in DOWNLOADS.glob(f"{video_id}.*"):
mp3 = f
break
return mp3, title
class AppHandler(http.server.SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
self.send_header("Cross-Origin-Embedder-Policy", "credentialless")
super().end_headers()
def do_OPTIONS(self):
self.send_response(204)
self.end_headers()
def do_POST(self):
if self.path == "/api/yt/download":
self._handle_download()
else:
self.send_error(404)
def _handle_download(self):
try:
length = int(self.headers.get("Content-Length", 0))
body = json.loads(self.rfile.read(length)) if length else {}
url = body.get("url", "").strip()
if not url:
return self._json(400, {"error": "url required"})
mp3, title = download_audio(url)
self._json(200, {
"audio_url": f"/downloads/{mp3.name}",
"title": title,
})
except Exception as e:
self._json(500, {"error": str(e)})
def _json(self, code, data):
body = json.dumps(data).encode()
self.send_response(code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
if __name__ == "__main__":
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8000
print(f"Robot Dance Party — http://localhost:{port}")
with http.server.HTTPServer(("", port), AppHandler) as s:
s.serve_forever()