Compare commits
4 Commits
d033b6da8e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a4e1513c02 | |||
| 1621f8d357 | |||
| 8af2e6aa64 | |||
| 5c96820d6d |
@@ -636,15 +636,18 @@ def iter_stream_transcode(target_url):
|
|||||||
finally:
|
finally:
|
||||||
process.kill()
|
process.kill()
|
||||||
|
|
||||||
def iter_stream(target_url):
|
def iter_stream(r):
|
||||||
import requests
|
try:
|
||||||
with requests.get(target_url, stream=True, timeout=10) as r:
|
|
||||||
for chunk in r.iter_content(chunk_size=8192):
|
for chunk in r.iter_content(chunk_size=8192):
|
||||||
if chunk:
|
if chunk:
|
||||||
yield chunk
|
yield chunk
|
||||||
|
finally:
|
||||||
|
r.close()
|
||||||
|
|
||||||
|
from fastapi import Request
|
||||||
|
|
||||||
@app.get("/live/{station}")
|
@app.get("/live/{station}")
|
||||||
def live_stream_redirect(station: str, db: Session = Depends(db_session)):
|
def live_stream_redirect(station: str, request: Request, db: Session = Depends(db_session)):
|
||||||
# Usuwamy sztuczne rozszerzenia dodane dla Mopidy
|
# Usuwamy sztuczne rozszerzenia dodane dla Mopidy
|
||||||
if station.endswith(".aac"):
|
if station.endswith(".aac"):
|
||||||
station = station[:-4]
|
station = station[:-4]
|
||||||
@@ -658,13 +661,35 @@ def live_stream_redirect(station: str, db: Session = Depends(db_session)):
|
|||||||
if station == "radio357":
|
if station == "radio357":
|
||||||
config_url = db.query(Config).filter_by(key="r357_live_url").first()
|
config_url = db.query(Config).filter_by(key="r357_live_url").first()
|
||||||
target_url = config_url.value if config_url else "https://stream.rcs.revma.com/ye5kghkgcm0uv"
|
target_url = config_url.value if config_url else "https://stream.rcs.revma.com/ye5kghkgcm0uv"
|
||||||
|
|
||||||
|
# Statyczne metadane nagłówkowe dla Mopidy (ponieważ FFmpeg gubi te dynamiczne wbudowane w strumień)
|
||||||
|
resp_headers = {
|
||||||
|
"icy-name": "Radio 357",
|
||||||
|
"icy-description": "RadioSync Proxy (AAC to MP3 Transcode)"
|
||||||
|
}
|
||||||
|
|
||||||
# Proxy + Transkodowanie AAC -> MP3 w locie!
|
# Proxy + Transkodowanie AAC -> MP3 w locie!
|
||||||
return StreamingResponse(iter_stream_transcode(target_url), media_type="audio/mpeg")
|
return StreamingResponse(iter_stream_transcode(target_url), media_type="audio/mpeg", headers=resp_headers)
|
||||||
|
|
||||||
elif station == "rns":
|
elif station == "rns":
|
||||||
config_url = db.query(Config).filter_by(key="rns_live_url").first()
|
config_url = db.query(Config).filter_by(key="rns_live_url").first()
|
||||||
target_url = config_url.value if config_url else "https://stream.rcs.revma.com/4md4m0a0fs8uv"
|
target_url = config_url.value if config_url else "https://stream.rcs.revma.com/4md4m0a0fs8uv"
|
||||||
return StreamingResponse(iter_stream(target_url), media_type="audio/mpeg")
|
|
||||||
|
# Przekazujemy żądanie o metadane z odtwarzacza (Mopidy) do serwera (Revma)
|
||||||
|
req_headers = {}
|
||||||
|
if "icy-metadata" in request.headers:
|
||||||
|
req_headers["Icy-MetaData"] = request.headers["icy-metadata"]
|
||||||
|
|
||||||
|
import requests
|
||||||
|
r = requests.get(target_url, stream=True, timeout=10, headers=req_headers)
|
||||||
|
|
||||||
|
# Odbieramy nagłówki metadanych od Revmy i przekazujemy z powrotem do odtwarzacza
|
||||||
|
resp_headers = {}
|
||||||
|
for k, v in r.headers.items():
|
||||||
|
if k.lower().startswith("icy-"):
|
||||||
|
resp_headers[k] = v
|
||||||
|
|
||||||
|
return StreamingResponse(iter_stream(r), media_type="audio/mpeg", headers=resp_headers)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=404, detail="Brak streamu dla podanej stacji")
|
raise HTTPException(status_code=404, detail="Brak streamu dla podanej stacji")
|
||||||
|
|||||||
+13
-3
@@ -93,9 +93,9 @@
|
|||||||
<li class="nav-item"><a class="nav-link" href="/programs/jazz">Jazz FM</a></li>
|
<li class="nav-item"><a class="nav-link" href="/programs/jazz">Jazz FM</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="d-flex gap-2">
|
<div class="d-flex gap-2">
|
||||||
<a href="/live/radio357.mp3" class="btn btn-outline-info btn-sm" target="_blank" title="Bezpośredni stream premium Radia 357 (wyższa jakość, brak reklam)">Stream 357</a>
|
<button onclick="copyToClipboard('/live/radio357', this)" class="btn btn-outline-info btn-sm" title="Kopiuj bezpośredni stream premium Radia 357">Stream 357</button>
|
||||||
<a href="/live/rns.mp3" class="btn btn-outline-info btn-sm" target="_blank" title="Bezpośredni stream premium RNŚ (wyższa jakość, brak reklam)">Stream RNŚ</a>
|
<button onclick="copyToClipboard('/live/rns', this)" class="btn btn-outline-info btn-sm" title="Kopiuj bezpośredni stream premium RNŚ">Stream RNŚ</button>
|
||||||
<a href="/feeds/Podcasts.opml" class="btn btn-outline-warning btn-sm" target="_blank">Master OPML</a>
|
<button onclick="copyToClipboard('/feeds/Podcasts.opml', this)" class="btn btn-outline-warning btn-sm">Master OPML</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -104,5 +104,15 @@
|
|||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
function copyToClipboard(path, btn) {
|
||||||
|
const fullUrl = window.location.origin + path;
|
||||||
|
navigator.clipboard.writeText(fullUrl).then(() => {
|
||||||
|
const originalText = btn.innerText;
|
||||||
|
btn.innerText = 'Skopiowano!';
|
||||||
|
setTimeout(() => { btn.innerText = originalText; }, 2000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user