PolyIndex is a Python CLI tool that generates .m3u playlists from audio file directory structures. It scans directories recursively, discovers audio files, and outputs deterministic playlists with relative paths.
- Recursive directory scanning - Discovers all audio files in directory trees
- Deterministic output - Same input always produces identical output (lexicographically sorted)
- Single or multiple playlists - Generate one playlist or separate playlists per subdirectory
- No metadata parsing - Identifies files by extension only
- Cross-platform paths - Uses forward slashes for maximum portability
- UTF-8 support - Handles Unicode filenames correctly
- Stdlib-only - No external dependencies
- Fast - Pure Python, efficient file discovery
.mp3- MPEG Audio.flac- Free Lossless Audio Codec.wav- Waveform Audio.ogg- Ogg Vorbis.m4a- MPEG-4 Audio.opus- Opus Audio.aac- Advanced Audio Coding.dsf- DSD Stream File
No installation required. Run directly as a Python module:
python -m polyindex /path/to/musicGenerate playlist from a directory and print to stdout:
python -m polyindex /path/to/musicSave playlist to a file:
python -m polyindex /path/to/music -o playlist.m3uOr use shell redirection:
python -m polyindex /path/to/music > playlist.m3uWhen -o points to a directory, PolyIndex generates separate .m3u files for each top-level subdirectory:
python -m polyindex /path/to/music -o /output/directoryThis creates one playlist file per album/subdirectory:
/output/directory/Album1.m3u
/output/directory/Album2.m3u
/output/directory/Album3.m3u
Each playlist contains only files from that subdirectory, with paths relative to the output directory.
root- (Required) Root directory to scan for audio files-o, --output- (Optional) Output destination:- If file path: Creates a single
.m3ufile - If directory: Creates separate
.m3ufiles for each top-level subdirectory - If omitted: Writes single playlist to stdout
- If file path: Creates a single
python -m polyindex ~/MusicOutput:
artist/album/track01.mp3
artist/album/track02.mp3
another_artist/work/song01.flac
python -m polyindex /Volumes/MyDrive/MUSIC -o /Volumes/MyDrive/playlist.m3upython -m polyindex /Volumes/SD_CARD/MUSIC -o /Volumes/SD_CARDCreates:
/Volumes/SD_CARD/Album1.m3u
/Volumes/SD_CARD/Album2.m3u
/Volumes/SD_CARD/Album3.m3u
...
Each .m3u file contains only tracks from that album, with paths relative to /Volumes/SD_CARD:
MUSIC/Album1/track01.mp3
MUSIC/Album1/track02.mp3
...
python -m polyindex /path/to/music | head -20- Scan - Recursively walks the directory tree from the root
- Filter - Keeps only files with recognized audio extensions (case-insensitive)
- Normalize - Converts file paths to POSIX format (forward slashes)
- Sort - Sorts paths lexicographically for deterministic output
- Output - Writes one path per line to stdout or specified file
- Zero implicit behavior - No hidden rules or configuration
- Pure functions - Scanner and playlist builder have no side effects
- Deterministic - Same input always produces identical output
- Simple - Minimal code, no framework dependencies
- Read-only - Never modifies source directory or files
First, install the development dependencies:
pip install -r requirements.txtThen run the test suite:
python -m pytest tests/ -vTests use temporary directories to verify:
- File discovery and filtering
- Path normalization (forward slashes on all platforms)
- UTF-8 encoding
- Deterministic sorting
- Error handling (missing directories, permission errors)
- Integration between scanner, playlist, and output modules
PolyIndex follows a three-module design:
- scanner.py - Directory traversal and audio file discovery
- playlist.py - Playlist structure and formatting
- output.py - Writing to stdout or files
- main.py - CLI argument parsing and orchestration
Each module is independent and testable with no side effects except at I/O boundaries.
- Does not follow symbolic links
- Does not parse audio file metadata
- Does not generate .m3u8 (extended format) playlists
- Does not support custom file ordering or filtering
- No recursive symlink protection (will detect loops and report error)
[Specify your license here]
Contributions are welcome. Please ensure:
- All tests pass:
python -m pytest tests/ -v - Code follows PEP 8
- Type hints are present on all functions
- New features include unit tests