ldn-analyse/webapp/server.py
Dotty Dotter 011ac49f3d Initialer Daten-Stand: 96 transkribierte Episoden (LdN379-LdN474)
- project.yaml: 473 katalogisierte Episoden, 10 Staffeln 2017-2026
- data/mindmap_data.json + srt_index.json: Stand vom 21.04.2026
- audio/*.json: 96 Whisper-Outputs (large-v3) mit Wort-Timestamps
- Makefile + webapp/server.py analog tobias/neu-denken-analyse
- download_ldn.sh: Bezugsskript fuer die MP3s von lagedernation.org
- MP3s und MBPro-Backup via .gitignore ausgeschlossen

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:29:49 +02:00

74 lines
2.4 KiB
Python

#!/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()