feat: implement caching and redirect endpoints for premium live streams
This commit is contained in:
@@ -276,7 +276,30 @@ class Radio357Scraper:
|
|||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.logger(f"R357: [{self.requests_made}/{self.hard_limit}] Pomyślnie pobrano {fetched} nowych linków.")
|
self.logger(f"R357: [{self.requests_made}/{self.hard_limit}] Pomyślnie pobrano {fetched} nowych linków.")
|
||||||
|
|
||||||
|
def update_live_stream_url(self):
|
||||||
|
token = self.get_token()
|
||||||
|
if not token:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.logger("R357: Aktualizacja adresu live stream...")
|
||||||
|
url = "https://stream.radio357.pl/?s=www"
|
||||||
|
try:
|
||||||
|
r = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}, cookies={"token": token}, allow_redirects=False, timeout=5)
|
||||||
|
if r.status_code in (301, 302, 307) and "Location" in r.headers:
|
||||||
|
target_url = r.headers["Location"]
|
||||||
|
config_url = self.db.query(Config).filter_by(key="r357_live_url").first()
|
||||||
|
if not config_url:
|
||||||
|
self.db.add(Config(key="r357_live_url", value=target_url))
|
||||||
|
else:
|
||||||
|
config_url.value = target_url
|
||||||
|
self.db.commit()
|
||||||
|
self.logger(f"R357: Zapisano nowy strumień: {target_url}")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger(f"R357 Błąd podczas pobierania streamu premium: {e}")
|
||||||
|
|
||||||
def run_full_sync(self, specific_program_slug=None):
|
def run_full_sync(self, specific_program_slug=None):
|
||||||
self.sync_episodes(specific_program_slug)
|
self.sync_episodes(specific_program_slug)
|
||||||
self.backfill_urls(specific_program_slug)
|
self.backfill_urls(specific_program_slug)
|
||||||
|
if not specific_program_slug:
|
||||||
|
self.update_live_stream_url()
|
||||||
self.logger(f"R357: Koniec. Wysłano zapytania: {self.requests_made}/{self.hard_limit} (w tym backfill ograniczony do {self.backfill_limit}).")
|
self.logger(f"R357: Koniec. Wysłano zapytania: {self.requests_made}/{self.hard_limit} (w tym backfill ograniczony do {self.backfill_limit}).")
|
||||||
|
|||||||
@@ -501,6 +501,34 @@ class RNScraper:
|
|||||||
self.db.commit()
|
self.db.commit()
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
def update_live_stream_url(self):
|
||||||
|
self.logger("RNŚ: Aktualizacja adresu live stream...")
|
||||||
|
try:
|
||||||
|
html = self._get_html(f"{BASE_URL}/")
|
||||||
|
if html:
|
||||||
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
|
target_url = None
|
||||||
|
for btn in soup.find_all(class_="rns-stream-tile__btn"):
|
||||||
|
src = btn.get("data-neo-player-src")
|
||||||
|
parent = btn.parent
|
||||||
|
if parent and src:
|
||||||
|
text = parent.get_text(" ", strip=True).lower()
|
||||||
|
if "256" in text or "wysoka" in text:
|
||||||
|
target_url = src
|
||||||
|
break
|
||||||
|
|
||||||
|
if target_url:
|
||||||
|
if not target_url.startswith("http"): target_url = f"{BASE_URL}/{target_url.lstrip('/')}"
|
||||||
|
config_url = self.db.query(Config).filter_by(key="rns_live_url").first()
|
||||||
|
if not config_url:
|
||||||
|
self.db.add(Config(key="rns_live_url", value=target_url))
|
||||||
|
else:
|
||||||
|
config_url.value = target_url
|
||||||
|
self.db.commit()
|
||||||
|
self.logger(f"RNS: Zaktualizowano adres streamu na {target_url}")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger(f"RNS: Błąd aktualizacji streamu: {e}")
|
||||||
|
|
||||||
def run_full_sync(self, specific_program_slug=None):
|
def run_full_sync(self, specific_program_slug=None):
|
||||||
if not self.ensure_auth():
|
if not self.ensure_auth():
|
||||||
self.logger("RNŚ: Błąd logowania przed startem!")
|
self.logger("RNŚ: Błąd logowania przed startem!")
|
||||||
@@ -511,4 +539,7 @@ class RNScraper:
|
|||||||
if self.requests_made < self.hard_limit:
|
if self.requests_made < self.hard_limit:
|
||||||
self.phase_2_backfill(specific_program_slug)
|
self.phase_2_backfill(specific_program_slug)
|
||||||
|
|
||||||
|
if not specific_program_slug:
|
||||||
|
self.update_live_stream_url()
|
||||||
|
|
||||||
self.logger(f"RNŚ: Koniec. Wysłano zapytania: {self.requests_made}/{self.hard_limit} (w tym backfill ograniczony do {self.backfill_limit}).")
|
self.logger(f"RNŚ: Koniec. Wysłano zapytania: {self.requests_made}/{self.hard_limit} (w tym backfill ograniczony do {self.backfill_limit}).")
|
||||||
|
|||||||
@@ -611,3 +611,16 @@ def podcast_rss(station: str, slug_with_ext: str, request: Request, db: Session
|
|||||||
if not xml:
|
if not xml:
|
||||||
return Response(status_code=404)
|
return Response(status_code=404)
|
||||||
return Response(content=xml, media_type="application/xml")
|
return Response(content=xml, media_type="application/xml")
|
||||||
|
|
||||||
|
@app.get("/live/{station}")
|
||||||
|
def live_stream_redirect(station: str, db: Session = Depends(db_session)):
|
||||||
|
if station == "radio357":
|
||||||
|
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"
|
||||||
|
return RedirectResponse(url=target_url)
|
||||||
|
elif station == "rns":
|
||||||
|
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"
|
||||||
|
return RedirectResponse(url=target_url)
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=404, detail="Brak streamu dla podanej stacji")
|
||||||
|
|||||||
+3
-1
@@ -92,7 +92,9 @@
|
|||||||
<li class="nav-item"><a class="nav-link" href="/programs/rns">Nowy Świat</a></li>
|
<li class="nav-item"><a class="nav-link" href="/programs/rns">Nowy Świat</a></li>
|
||||||
<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">
|
<div class="d-flex gap-2">
|
||||||
|
<a href="/live/radio357" class="btn btn-outline-info btn-sm" target="_blank" title="Pełny redirect do transmisji. Obie stacje oferują alternatywny link premium dla patronów (bez reklam i z lepszą jakością).">Stream 357</a>
|
||||||
|
<a href="/live/rns" class="btn btn-outline-info btn-sm" target="_blank" title="Pełny redirect do transmisji. Obie stacje oferują alternatywny link premium dla patronów (bez reklam i z lepszą jakością).">Stream RNŚ</a>
|
||||||
<a href="/feeds/Podcasts.opml" class="btn btn-outline-warning btn-sm" target="_blank">Master OPML</a>
|
<a href="/feeds/Podcasts.opml" class="btn btn-outline-warning btn-sm" target="_blank">Master OPML</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user