feat(tilderadio): add the tildeverse community stream as a catalogue
This commit is contained in:
1 parent
58e9202e25
commit
058d336a2c
8 files changed
+883
-4
No files matched your search
+37
-1
@@ -3,7 +3,9 @@
|
||||
Everything lives in the usual XDG places:
|
||||
|
||||
~/.config/beefy-player/config.json favourites, volume, station
|
||||
~/.cache/beefy-player/channels.json last good station list
|
||||
~/.cache/beefy-player/channels.json last good station list (SomaFM)
|
||||
~/.cache/beefy-player/channels-<id>.json ... for every other catalogue
|
||||
~/.cache/beefy-player/schedule-<id>.json last good broadcast schedule
|
||||
~/.cache/beefy-player/playlists.json resolved .pls -> stream URLs
|
||||
~/.cache/beefy-player/songs/<id>.json last good song history
|
||||
~/.cache/beefy-player/artwork/<sha1> cached album/channel artwork
|
||||
@@ -17,6 +19,7 @@ from __future__ import annotations
|
||||
import contextlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from pathlib import Path
|
||||
@@ -70,6 +73,24 @@ LEGACY_CONFIG_PATH = _xdg("XDG_CONFIG_HOME", ".config") / LEGACY_APP_NAME / "con
|
||||
VISUALIZERS = ("both", "bars", "wave", "waterfall", "radial", "braille")
|
||||
|
||||
|
||||
def channels_cache_path(provider_id: str) -> Path:
|
||||
"""Where a catalogue caches its last good station list.
|
||||
|
||||
SomaFM keeps the historical ``channels.json``; every other provider gets
|
||||
its own file, so two catalogues can never overwrite each other's cache.
|
||||
"""
|
||||
slug = re.sub(r"[^a-z0-9_-]", "_", provider_id.strip().lower())
|
||||
if not slug or slug == "somafm":
|
||||
return CHANNELS_CACHE
|
||||
return CACHE_DIR / f"channels-{slug}.json"
|
||||
|
||||
|
||||
def schedule_cache_path(provider_id: str) -> Path:
|
||||
"""Where a catalogue caches its last good broadcast schedule."""
|
||||
slug = re.sub(r"[^a-z0-9_-]", "_", provider_id.strip().lower()) or "provider"
|
||||
return CACHE_DIR / f"schedule-{slug}.json"
|
||||
|
||||
|
||||
def ensure_dirs() -> None:
|
||||
for directory in (CONFIG_DIR, CACHE_DIR, SONGS_CACHE_DIR):
|
||||
with contextlib.suppress(OSError):
|
||||
@@ -115,6 +136,9 @@ def migrate_legacy_state() -> None:
|
||||
class Config:
|
||||
favorites: list[str] = field(default_factory=list)
|
||||
last_station: str = "groovesalad"
|
||||
#: Which station each catalogue was last tuned to, keyed by provider slug,
|
||||
#: so switching back lands where you left off.
|
||||
last_stations: dict[str, str] = field(default_factory=dict)
|
||||
volume: int = 70
|
||||
visualizer: str = "both"
|
||||
autoplay: bool = False
|
||||
@@ -141,6 +165,14 @@ class Config:
|
||||
if isinstance(last_station, str) and last_station:
|
||||
config.last_station = last_station
|
||||
|
||||
last_stations = raw.get("last_stations")
|
||||
if isinstance(last_stations, dict):
|
||||
config.last_stations = {
|
||||
str(key): str(value)
|
||||
for key, value in last_stations.items()
|
||||
if isinstance(value, str) and value
|
||||
}
|
||||
|
||||
volume = raw.get("volume")
|
||||
if isinstance(volume, (int, float)):
|
||||
config.volume = max(0, min(100, int(volume)))
|
||||
@@ -168,6 +200,10 @@ class Config:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def last_station_for(self, provider_id: str) -> str:
|
||||
"""The station to re-tune for a catalogue (old configs have one only)."""
|
||||
return self.last_stations.get(provider_id) or self.last_station
|
||||
|
||||
def is_favorite(self, station_id: str) -> bool:
|
||||
return station_id in self.favorites
|
||||
|
||||
|
||||
Reference in new issue
Block a user