2026-08-26 09:05:23 -04:00
2025-11-17 09:29:21 -05:00

Journey FM Playlist Creator

Desktop app + script that pulls recently played songs from Journey FM / Spirit FM and updates a Plex playlist.

What It Does

  • Scrapes recently played songs from:
    • https://www.myjourneyfm.com/recently-played/
    • https://spiritfm.com/ajax/now_playing_history.txt
    • https://www.klove.com/music/songs
  • Matches tracks in your Plex Music library with title/artist normalization.
  • Creates or updates your configured Plex playlist.
  • Avoids adding duplicates already in the target playlist.
  • Tracks run history in playlist_history.db.
  • Writes missing songs to amazon_buy_list.txt with Amazon search links.
  • Provides a GUI with system tray support, settings, log viewer, history, stats, analytics, and CSV export.

Requirements

  • Python 3.10+
  • Plex account token + reachable Plex server
  • A Chrome/Chromium browser for Selenium scraping

Dependencies are listed in requirements.txt (GUI uses PySide6).

Install

Windows

Simple install from GitHub (recommended):

  1. Open PowerShell.
  2. Run:
git clone https://github.com/nmemmert/journey-fm-playlist.git
cd journey-fm-playlist
.\install_windows.bat
  1. Launch from:
    • Start Menu: Journey FM Playlist Creator
    • Desktop shortcut: Journey FM Playlist Creator

No Git? Download ZIP from GitHub (Code -> Download ZIP), extract, open PowerShell in that folder, and run:

.\install_windows.bat

If script execution is blocked:

powershell -NoProfile -ExecutionPolicy Bypass -File .\install_windows.ps1

Optional installer switches:

  • -NoDesktopShortcut skips Desktop shortcut creation
  • -NoStartMenuShortcut skips Start Menu shortcut creation

Manual install (advanced):

py -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
python journey_fm_app.py

Installer files:

  • install_windows.bat - one-click installer launcher
  • install_windows.ps1 - installer logic

Linux

Quick setup:

./install.sh

Interactive install now captures defaults and writes .env (auto with optional values):

./install.sh

The installer sets defaults:

  • UPDATE_UNIT=Minutes
  • CONTAINER_RUN_MODE=loop
  • SERVER_IP=172.16.16.106
  • PLAYLIST_NAME=Radio
  • SELECTED_STATIONS=journey_fm,spirit_fm,klove
  • UPDATE_INTERVAL=15
  • AUTO_UPDATE=true
  • PLEX_TOKEN=pU-m3HWYUZU6iXJFhJyA
  • PYTHONUNBUFFERED=1
  • JOURNEYFM_DATA_DIR=/data
  • TERM=xterm
  • CHROME_BINARY=/usr/bin/chromium
  • JOURNEYFM_CONTAINER=1
  • LANG=C.UTF-8
  • CHROMEDRIVER_PATH=/usr/bin/chromedriver

Web dashboard defaults to enabled with start at http://localhost:8765 (or DASHBOARD_PORT).

Manual setup:

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python journey_fm_app.py

Configuration

Use the GUI setup wizard (first launch) or edit config.json directly.

The Plex token is now stored in your OS credential store via keyring when available. On Windows this means the app no longer needs to persist PLEX_TOKEN in config.json.

Example config.json:

{
  "SERVER_IP": "192.168.1.100",
  "PLAYLIST_NAME": "Journey FM Recently Played",
  "AUTO_UPDATE": true,
  "UPDATE_INTERVAL": 15,
  "UPDATE_UNIT": "Minutes",
  "SELECTED_STATIONS": "journey_fm,spirit_fm,klove"
}

You can also provide runtime env vars:

  • PLEX_TOKEN
  • SERVER_IP
  • PLAYLIST_NAME
  • AUTO_UPDATE
  • UPDATE_INTERVAL
  • UPDATE_UNIT
  • SELECTED_STATIONS

Optional browser override:

  • CHROME_BINARY (absolute path to Chrome/Chromium executable)

If CHROME_BINARY is not set, the app auto-detects browser locations for Windows/Linux/macOS and then falls back to PATH.

Running Without GUI

Run one update cycle from CLI:

python main.py

Run one update cycle and start a local web dashboard for live counts and station metrics:

python main.py --serve-web

Advanced options:

  • --host: Web dashboard listen host (default 127.0.0.1)
  • --port: Web dashboard listen port (default 8765)
  • --no-open: Do not open default browser automatically

Example:

python main.py --serve-web --host 0.0.0.0 --port 8765 --no-open

Dashboard: station and song playback counts

Once the web dashboard is running at http://localhost:8765, you'll see:

  • station-level scrape totals (station_breakdown aggregated)
  • overall count metrics (scraped, matched, added, missing, duplicates)
  • per-station top tracks by play count (history-aware)

API endpoints

  • GET /api/stats - returns JSON:
    • total_updates, total_scraped, etc.
    • station_counts by station
    • song_counts nested station -> song -> count
  • GET /api/refresh - triggers a full scrape + playlist update and returns run result

Force refresh from CLI

curl http://localhost:8765/api/refresh

View raw stats

curl http://localhost:8765/api/stats | jq .song_counts

Update script (docker + podman)

A helper script is now included: update.sh

Usage:

chmod +x update.sh
./update.sh

What it does:

  1. Detects Docker or Podman (prompts if both are present)
  2. git pull origin main
  3. Rebuilds compose images (docker compose build or podman compose build)
  4. Starts services (compose up -d)
  5. Prints compose ps

Container Deployment

Container Deployment

Container mode is intended for scheduled/headless playlist updates. The container now runs as a long-lived loop and sleeps between syncs instead of relying on restart churn.

  1. Copy .env.example to .env and fill in your Plex values.
cp .env.example .env
  1. Edit .env in the project root:
PLEX_TOKEN=your-plex-token
SERVER_IP=192.168.1.100
PLAYLIST_NAME=Journey FM Recently Played
SELECTED_STATIONS=journey_fm,spirit_fm,klove
UPDATE_INTERVAL=15
UPDATE_UNIT=Minutes
CONTAINER_RUN_MODE=loop
  1. Build and run with Docker Compose:
docker-compose up -d --build

Podman equivalent:

podman compose up -d --build
  1. Trigger a one-off run and review logs:
docker-compose run --rm -e CONTAINER_RUN_MODE=once journey-fm-playlist
docker-compose logs -f journey-fm-playlist

Podman equivalent:

podman compose run --rm -e CONTAINER_RUN_MODE=once journey-fm-playlist
podman compose logs -f journey-fm-playlist

GitHub Container Build

GitHub Actions now builds the container on every pull request to main and on every push to main. Pushes to main also publish the image to GitHub Container Registry.

Image location:

ghcr.io/nmemmert/journey-fm-playlist

Pull with Podman:

podman pull ghcr.io/nmemmert/journey-fm-playlist:latest

If the package is private, authenticate first:

podman login ghcr.io

Notes:

  • The container uses Chromium + chromedriver in headless mode.
  • Runtime state is stored in the named volume mounted at /data, so config.json, playlist_history.db, playlist_log.txt, amazon_buy_list.txt, and debug_scrapes/ persist without bind-mounting the repo.
  • GUI (journey_fm_app.py) is still intended to run natively on your desktop.
  • In container mode, environment variables are preferred over local config or keyring storage.
  • The Compose file is Podman-friendly because it uses a named volume instead of a source bind mount.

Podman Quick Start

On a Podman host, the shortest path is:

git clone https://github.com/nmemmert/journey-fm-playlist.git
cd journey-fm-playlist
cp .env.example .env
podman compose up -d --build

Useful follow-up commands:

podman compose logs -f journey-fm-playlist
podman compose run --rm -e CONTAINER_RUN_MODE=once journey-fm-playlist
podman compose down

GUI Notes

  • Minimize-to-tray on close when tray is available.
  • Tray menu supports Show / Update Now / Quit.
  • Auto-update runs on configurable interval.
  • Works on X11 and Wayland Linux sessions.
  • Updated visual style includes a dashboard hero section, richer status chips, and a refreshed control layout.
  • Setup now includes Plex connection testing, keyring-backed token storage, playlist browsing with item counts, music-only filtering, and typed creation of new playlist names.

Output Files

  • config.json - non-secret runtime settings shared by GUI and CLI
  • playlist_history.db - update history and statistics data
  • playlist_log.txt - GUI update logs
  • amazon_buy_list.txt - missing songs with Amazon links
  • playlist_export.csv - exported playlist from GUI action
  • debug_scrapes/ - captured raw station responses for scraper debugging

In container mode these files live under /data inside the container volume.

Troubleshooting

  • Server not found: verify SERVER_IP, Plex availability, and that you are signed in with the correct account token.
  • No songs added: confirm scraped songs exist in your Plex library and metadata is correct.
  • Browser startup errors: install Chrome/Chromium or set CHROME_BINARY explicitly.
  • No tray icon: some desktop environments disable or hide legacy trays.
  • GUI fails at startup (libGL.so.1 / PySide6 import errors): install missing system graphics libs (Linux example: sudo apt install libgl1) and reinstall Python deps with pip install -r requirements.txt.

Core Files

  • journey_fm_app.py - desktop GUI and tray app
  • main.py - CLI entrypoint for a single update run
  • run_container.py - loop/once runner used by container deployments
  • journeyfm/ - shared service modules (config, scraper, Plex, history, orchestration)
  • requirements.txt - Python dependencies
  • install.sh - Linux setup helper

Pre-Release Checklist

  • Verify config.json has valid SERVER_IP, PLAYLIST_NAME, and station/schedule settings.
  • Run one CLI update: python main.py and confirm songs/history are written.
  • Run GUI update: python journey_fm_app.py and verify status/log output updates.
  • Confirm tray behavior (minimize to tray, Show/Update/Quit actions).
  • On Windows/Linux, confirm Chrome/Chromium detection or set CHROME_BINARY.
  • Export playlist once and verify playlist_export.csv is created.
  • For container mode, run docker-compose run --rm -e CONTAINER_RUN_MODE=once journey-fm-playlist and verify logs/history output.
S
Description
No description provided
Readme
1.4 MiB
0 Stars 1 Watchers 0 Forks
Languages
Python 93%
Shell 3.2%
PowerShell 3%
Dockerfile 0.5%
Batchfile 0.3%