This guide explains how to set up a local FluxTuner development environment, run the app, execute tests, and validate changes before opening a pull request.
FluxTuner is a Python application with CLI, TUI, and optional GTK GUI entry points.
Recommended local tools:
- Python 3.11 or newer.
pip.venv.mpvand/orffplayfor manual playback testing.- Git.
- Optional: Flatpak tooling if you work on packaging.
The CI currently validates supported Python versions, package builds, dependency audits, static security checks, and tests.
git clone https://github.com/pitill0/fluxtuner.git
cd fluxtunerpython -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pipOn Windows PowerShell:
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pipInstall FluxTuner in editable mode with development dependencies:
python -m pip install -e ".[dev]"If you only want to install runtime dependencies:
python -m pip install -e .Default TUI:
python -m fluxtunerLegacy CLI:
python -m fluxtuner --cliExperimental GTK GUI:
python -m fluxtuner --guiList player backends:
python -m fluxtuner --list-playersList available themes:
python -m fluxtuner --list-themesRun with debug logging:
python -m fluxtuner --verboseor:
FLUXTUNER_DEBUG=1 python -m fluxtunerDebug logs are intended for development and diagnostics. They should not expose stream URLs, station names, full local paths, imported data contents, or unnecessary user data.
FluxTuner supports external player backends such as:
mpvffplay
Install at least one backend locally for manual playback testing.
Examples:
sudo apt install mpvor:
sudo apt install ffmpegffplay is usually provided by FFmpeg packages.
The automated test suite mocks player execution and should not require mpv or ffplay to be installed.
Commonly edited areas:
fluxtuner/
__main__.py CLI entry point and import/export commands
config.py User configuration and playback state
logging_config.py Project logging configuration
paths.py XDG/user data path helpers
theme_runtime.py Runtime theme application helpers
fluxtuner/core/
api.py Radio Browser API integration
cache.py Search cache
data_usage.py Playback data usage tracking
favorites.py Favorites persistence and updates
history.py Playback history
importers.py Import validation for favorites/playlists
manual_playlists.py User-managed playlists
playlists.py Built-in playlist/tag helpers
stations.py Station normalization helpers
storage.py Atomic JSON writes
stream_metadata.py ICY stream metadata parsing
fluxtuner/players/
base.py Player interface and errors
ffplay.py ffplay backend
mpv.py mpv backend
security.py Player executable and stream URL validation
fluxtuner/gui/
app.py GTK GUI entry point
window.py GTK GUI window
tests/
test_*.py Unit and regression tests
Before opening a pull request, run the same core checks used in CI.
ruff check .
ruff format --check .To apply formatting:
ruff format .python -m compileall fluxtuner testspython -m pytestRun a focused subset while developing:
python -m pytest tests/test_api.py
python -m pytest tests/test_main.py
python -m pytest tests/test_players_mpv.py tests/test_players_ffplay.pypython -m buildRun this from a clean virtual environment to avoid auditing unrelated system packages:
python -m pip install pip-audit
pip-audit --localExpected note for editable local installs:
fluxtuner Dependency not found on PyPI and could not be audited
That is expected because the local project itself is not a published PyPI dependency. The important result is that no known vulnerabilities are found in installed dependencies.
bandit -r fluxtuner -c pyproject.tomlBandit scans production code only. Subprocess-related skips are limited to the external player backends, which intentionally launch mpv or ffplay.
A useful pre-PR sequence:
ruff check .
ruff format --check .
python -m compileall fluxtuner tests
python -m pytest
python -m build
pip-audit --local
bandit -r fluxtuner -c pyproject.tomlRecommended workflow:
git checkout main
git pull
git checkout -b area/short-descriptionMake focused changes, then run validation.
Commit message examples:
git commit -m "Validate imported favorites and playlists"
git commit -m "Add Bandit security analysis to CI"
git commit -m "Add persistence error logging"Push and open a PR:
git push -u origin area/short-descriptionA good PR should include:
- Summary of what changed.
- Validation commands run locally.
- Linked issue, for example
Closes #15orPart of #20. - Notes about scope or intentional follow-up work.
Prefer small, focused tests that cover behavior rather than implementation details.
Good candidates for tests:
- URL validation.
- Import validation.
- Atomic persistence.
- Error handling and fallback behavior.
- Player command construction without requiring real player binaries.
- Radio Browser API failure handling.
- ICY metadata parsing limits.
- Runtime theme parsing and application.
Avoid tests that depend on:
- A real network call.
- Installed player binaries.
- User-specific local paths.
- A specific terminal size, unless isolated/mocked.
- GUI availability unless the test is explicitly marked or isolated as a smoke test.
FluxTuner uses opt-in debug logging through:
python -m fluxtuner --verboseor:
FLUXTUNER_DEBUG=1 python -m fluxtunerWhen adding logs:
- Use
get_logger(__name__). - Prefer
debugfor diagnostic details. - Use
warningorerrorwhen a fallback or failure matters operationally. - Avoid logging stream URLs.
- Avoid logging station names unless there is a strong reason.
- Avoid logging full local paths.
- Avoid logging imported/exported data contents.
- Use
exc_info=Truefor debugging exceptions when useful.
Example:
from fluxtuner.logging_config import get_logger
logger = get_logger(__name__)
try:
...
except OSError:
logger.warning("Could not read favorites data; returning empty favorites", exc_info=True)
return []Security-sensitive areas include:
- Player subprocess execution.
- Stream URL validation.
- Imported JSON files.
- Local user data persistence.
- ICY stream metadata parsing.
- Dependency updates.
- Packaging and Flatpak permissions.
When changing these areas:
- Keep validation explicit.
- Avoid broad exception swallowing without logs.
- Avoid
shell=True. - Do not pass unvalidated URLs to player backends.
- Keep local writes atomic where possible.
- Add tests for failure paths.
- Run Bandit and dependency audit before opening a PR.
See also:
SECURITY.md
Favorites and playlists can be imported/exported as JSON from the CLI.
Exports should preserve user data.
Imports should validate incoming structures before persisting them. Invalid items should be skipped, and imports with no valid items should fail safely.
Relevant commands:
python -m fluxtuner --export-favs favorites.json
python -m fluxtuner --import-favs favorites.json
python -m fluxtuner --export-playlists playlists.json
python -m fluxtuner --import-playlists playlists.jsonFluxTuner themes are TCSS files.
At startup, Textual loads the selected theme directly. At runtime, FluxTuner also supports applying a practical subset of TCSS declarations without relying on Textual development CSS watching.
Runtime theme support intentionally parses only a limited subset:
- Supported selectors are listed in
fluxtuner/theme_runtime.py. - Variables such as
$surfaceare ignored at runtime. - Unsupported selectors are ignored.
- Unsupported style properties are logged at debug level and skipped.
Flatpak work may require additional local tooling.
The exact Flatpak workflow depends on the manifest and packaging setup. If you work on Flatpak permissions or packaging, validate the package manually in addition to normal Python checks.
Make sure your virtual environment is active:
which python
which pip
which pip-auditIf the audit reports unrelated packages such as system tools, recreate a clean virtual environment and reinstall the project:
rm -rf .venv
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
python -m pip install pip-audit
pip-audit --localAutomated tests should mock player executable resolution. If a test requires real player binaries, adjust the test to mock:
monkeypatch.setattr("fluxtuner.players.mpv.resolve_executable", lambda _name: "/usr/bin/mpv")
monkeypatch.setattr("fluxtuner.players.ffplay.resolve_executable", lambda _name: "/usr/bin/ffplay")Enable debug logging:
python -m fluxtuner --verboseor:
FLUXTUNER_DEBUG=1 python -m fluxtunerCheck that the selector and property are supported by fluxtuner/theme_runtime.py.
Runtime theme application is intentionally limited and may not support every TCSS feature.