dnd-music-console/croaker/controller.py

142 lines
3.7 KiB
Python
Raw Normal View History

2024-03-01 01:00:17 -08:00
import logging
import os
from pathlib import Path
from subprocess import Popen
from time import sleep
from Exscript.protocols import Telnet
from croaker import path
from croaker.pidfile import pidfile
from croaker.playlist import Playlist, load_playlist
NOW_PLAYING = None
LIQUIDSOAP_CONFIG = """
set("server.telnet",true)
set("request.grace_time", 1.0)
set("init.daemon.pidfile.path", "{pidfile.path}")
set("decoder.ffmpeg.codecs.alac", ["alac"])
# deeebuggin
set("log.file.path","{debug_log}")
# set up the stream
stream = crossfade(normalize(playlist.safe(
id='stream',
reload_mode='watch',
mode='normal',
'{playlist_root}/now_playing',
)))
# if source files don't contain metadata tags, use the filename
def apply_metadata(m) =
title = m["title"]
print("Now Playing: #{{m['filename']}}")
if (title == "") then
[("title", "#{{path.remove_extension(path.basename(m['filename']))}}")]
else
[("title", "#{{title}}")]
end
end
# apply the metadata parser
stream = map_metadata(apply_metadata, stream)
# define the source. ignore errors and provide no infallibale fallback. yolo.
radio = fallback(track_sensitive=false, [stream])
# transcode to icecast
output.icecast(
%mp3.vbr(quality=3),
name='Croaker Radio',
description='Background music for The Frog Hat Club',
host="{icecast_host}",
port={icecast_port},
password="{icecast_password}",
mount="{icecast_mount}",
icy_metadata="true",
url="{icecast_url}",
fallible=true,
radio
)
"""
def generate_liquidsoap_config():
log = path.root() / "liquidsoap.log"
if log.exists():
log.unlink()
log.touch()
ls_config = path.root() / "croaker.liq"
with ls_config.open("wt") as fh:
fh.write(
LIQUIDSOAP_CONFIG.format(
pidfile=_pidfile(terminate_if_running=False),
debug_log=log,
playlist_root=path.playlist_root(),
icecast_host=os.environ.get("ICECAST_HOST"),
icecast_port=os.environ.get("ICECAST_PORT"),
icecast_mount=os.environ.get("ICECAST_MOUNT"),
icecast_password=os.environ.get("ICECAST_PASSWORD"),
icecast_url=os.environ.get("ICECAST_URL"),
)
)
path.playlist_root().mkdir(exist_ok=True)
def start_liquidsoap():
logging.debug("Staring liquidsoap...")
pf = _pidfile(terminate_if_running=False)
pid = pf.read_pid()
if not pid:
logging.info("Liquidsoap does not appear to be running. Starting it...")
generate_liquidsoap_config()
Popen([os.environ["LIQUIDSOAP"], "--daemon", path.root() / "croaker.liq"])
sleep(1)
def start():
play_next("session_start")
def stop():
_pidfile(terminate_if_running=True)
def play_next(playlist_name: str = None):
start_liquidsoap()
if playlist_name:
pl = load_playlist(playlist_name)
logging.debug(f"Loaded playlist {pl = }")
if NOW_PLAYING != pl.name:
_switch_to(pl)
_send_liquidsoap_command("skip")
def _pidfile(terminate_if_running: bool = True):
pf = os.environ.get("LIQUIDSOAP_PIDFILE", None)
if pf:
pf = Path(pf)
else:
pf = path.root() / "liquidsoap.pid"
return pidfile(pf, terminate_if_running=terminate_if_running)
def _switch_to(playlist: Playlist):
logging.debug(f"Switching to {playlist = }")
np = path.playlist_root() / Path("now_playing")
with np.open("wt") as fh:
for track in playlist.tracks:
fh.write(f"{track}\n")
playlist.name
def _send_liquidsoap_command(command: str):
conn = Telnet()
conn.connect("localhost", port=1234)
conn.send(f"Croaker_Radio.{command}\r")
conn.send("quit\r")
conn.close()