#!/usr/bin/env python3 """HTTP server with Range request support for audio streaming.""" import os from http.server import HTTPServer, SimpleHTTPRequestHandler MIME_OVERRIDES = {'.m4a': 'audio/mp4', '.srt': 'text/plain'} class RangeHandler(SimpleHTTPRequestHandler): def do_GET(self): path = self.translate_path(self.path) if not os.path.isfile(path): return super().do_GET() range_header = self.headers.get('Range') file_size = os.path.getsize(path) ext = os.path.splitext(path)[1].lower() ctype = MIME_OVERRIDES.get(ext) or self.guess_type(path) if not range_header: # Normal response but with Accept-Ranges self.send_response(200) self.send_header('Content-Type', ctype) self.send_header('Content-Length', str(file_size)) self.send_header('Accept-Ranges', 'bytes') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() with open(path, 'rb') as f: self.copyfile(f, self.wfile) return # Parse range try: range_spec = range_header.replace('bytes=', '') parts = range_spec.split('-') start = int(parts[0]) if parts[0] else 0 end = int(parts[1]) if parts[1] else file_size - 1 end = min(end, file_size - 1) length = end - start + 1 except (ValueError, IndexError): self.send_error(416) return self.send_response(206) self.send_header('Content-Type', ctype) self.send_header('Content-Range', f'bytes {start}-{end}/{file_size}') self.send_header('Content-Length', str(length)) self.send_header('Accept-Ranges', 'bytes') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() with open(path, 'rb') as f: f.seek(start) remaining = length buf_size = 65536 while remaining > 0: chunk = f.read(min(buf_size, remaining)) if not chunk: break self.wfile.write(chunk) remaining -= len(chunk) def end_headers(self): # Don't double-add Accept-Ranges super().end_headers() if __name__ == '__main__': port = 9123 print(f"http://0.0.0.0:{port}") HTTPServer(('0.0.0.0', port), RangeHandler).serve_forever()