Skip to content

Repository files navigation

Citron Presse

Never miss the daily Presse Citron quiz segment on RFJ (Radio Fréquence Jura).

The app records the live stream every day, transcribes it locally (Whisper), extracts the quiz topic with a local LLM (Ollama), stores everything in SQLite, and serves a small React web player to browse past segments by date.

RFJ Icecast stream ──▶ data/recordings/DD-MM-YYYY.mp3 ──▶ local transcription ──▶ topic
                              │                                                    │
                              └──────────────▶ SQLite (data/citron.db) ◀───────────┘
                                                     │
                                FastAPI  ──▶  React player (pick a date, listen)

The recorder just does an HTTP GET of RFJ's public live MP3 stream — no browser, no sound card, no ffmpeg — so it runs fine on a headless server.

Setup

Everything at once — creates the venv, installs backend + frontend, builds the UI, migrates the old pickle, installs the daily cron job, and starts the server:

./run.sh

Subcommands: ./run.sh setup | serve | dev | schedule [HH:MM] | record [...].

...or step by step
python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[record]'
python -m scripts.migrate_pickle      # import old daily_themes.pkl into SQLite
npm --prefix frontend install && npm --prefix frontend run build

Two things run.sh does not manage: cron (already a system service) and Ollama for topic extraction — install it separately (curl -fsSL https://ollama.com/install.sh | sh && ollama pull llama3.2). The Whisper model downloads itself on first use.

Running

Command What it does
citron-serve FastAPI + the built web player on http://127.0.0.1:8000
citron-record Record the stream right now (8 min), then transcribe
citron-record --test --seconds 30 30 s throwaway capture to check the stream is reachable (no DB, no transcription)
citron-record --seconds 120 --no-transcribe Record a custom length, skip transcription
citron-schedule Long-running daily job (default 11:48 local)
npm --prefix frontend run dev Vite dev server on :5173, proxying /api to :8000

Scheduling the daily recording

Pick one — both fire citron-record at 11:48 local time every day:

./deploy/install-cron.sh              # user crontab, no root, runs even when logged out
./deploy/install-cron.sh 12:05        # or a different HH:MM

or, system-wide with systemd (survives reboot, logs to journald):

sudo cp deploy/citron-record.{service,timer} /etc/systemd/system/
sudoedit /etc/systemd/system/citron-record.service   # fix User=/paths
sudo systemctl daemon-reload && sudo systemctl enable --now citron-record.timer
systemctl list-timers citron-record.timer

citron-schedule is a third option (a foreground schedule loop, honouring CITRON_SCHEDULE_AT) if you'd rather not use cron or systemd.

Adding recordings by hand

Drop an MP3 named DD-MM-YYYY.mp3 into data/recordings/. It shows up in the player immediately; hit Transcrire in the UI (or POST /api/recordings/DD-MM-YYYY/transcribe) to fill in the topic, or type the topic directly in the player.

Configuration

Everything is environment-driven — see citron/config.py. Common ones: CITRON_WHISPER_MODEL, CITRON_OLLAMA_MODEL, CITRON_RECORDINGS_DIR, CITRON_PORT, CITRON_SCHEDULE_AT.

About

Presse Citron auto recorder

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages