Skip to content

stairona/music-organizer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

97 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Music Organizer

Organize large music libraries by genre — available as a command-line tool and a native macOS desktop app with integrated Spotify playlist downloading.

Python License Tests Platform


What It Does

  • CLI Tool: A high-performance Python command-line utility that scans local folders, reads embedded metadata (ID3, Vorbis, MP4) and filename patterns, and automatically organizes files into a structured genre folder hierarchy. Operating entirely locally, it requires no internet connection.
  • Desktop App: A native macOS desktop application built with Tauri and React wrapping the organizer backend. It integrates a local Tairona downloader adapter (not generic spotdl credentials) to download Spotify playlists in the background and sort them automatically, providing a unified visual workflow.

Desktop App (macOS)

Development Requirements

  • macOS 12+
  • Node.js v18+
  • Rust (stable, for Tauri compilation)
  • Local Tairona downloader: /Users/nicolasaguirre/zprojects/spot dl nico/tairona_dl.py (or set MUSIC_ORGANIZER_DOWNLOADER_PATH)
  • FFmpeg: Existing repository docs and downloader build assumptions treat FFmpeg as required for downloader audio conversion. Install via Homebrew: brew install ffmpeg
  • Python 3.11+ (in a virtual environment or conda environment)

Start the App

All commands should be run from the repository root directory.

Terminal 1 — Backend API:

# In the repository root:
pip install -r requirements.txt
PYTHONPATH=src uvicorn app.backend.main:app --host 127.0.0.1 --port 8000

Terminal 2 — Desktop Frontend:

# From the repository root:
cd desktop
npm install
npm run tauri:dev

Workflow

  1. Download — Paste a Spotify playlist URL and select your destination folder. The app runs the local Tairona downloader in a background worker, parsing piped progress lines ([N/M] Artist - Title queued|downloading|downloaded|skipped|failed) for live UI updates.
  2. Active Queue — Monitor active operations and cancel any running downloads.
  3. Organize — Direct the local organizer to any music directory. Choose your classification depth (general, specific, or nested), configure copy vs. move mode, and execute a dry run to preview changes before they happen.
  4. History — View completed download records and task summaries.

Backend API Endpoints

Method Endpoint Description
POST /api/v1/downloads Start a playlist download
GET /api/v1/downloads/{id}/status Poll download progress
POST /api/v1/downloads/{id}/cancel Cancel a download
GET /api/v1/downloads List all downloads
POST /api/v1/organize Organize a local folder
POST /api/v1/analyze Analyze a folder without moving files

Interactive API documentation is available at http://127.0.0.1:8000/docs when the backend is active.

Production Builds & Release Notes

For local production build status, packaging details, runtime limitations, and private-beta tester guidance, see:

Current packaged-app architecture:

packaged app → bundled frozen backend → bundled downloader

Release builds launch the bundled backend automatically. If the packaged app cannot reach its backend, testers should quit and relaunch the app, then inspect packaged-app logs rather than starting FastAPI manually.

The desktop app remains unsigned and not notarized. FFmpeg bundling is still deferred, and fresh-machine packaged download behavior without separately installed FFmpeg still needs explicit verification.


CLI Tool

Install

From the repository root:

pip install -r requirements.txt

# Optional: Install as an editable command-line tool
pip install -e .

Quickstart

# Safe first run — preview classification and destination paths (no files modified)
python -m music_organizer.main "/source/path" "/destination/path" --dry-run --level both --report dry_run.csv

Basic Commands

# Copy into organized structure (default, safe mode)
python -m music_organizer.main "/src" "/dest" --mode copy --level both

# Move files (irreversible — always use --dry-run first)
python -m music_organizer.main "/src" "/dest" --mode move --level both

# Stats only — analyze library composition without copying or moving files
python -m music_organizer.main "/src" "/dest" --stats-only --report stats.csv

# Re-run targeting only unclassified/unknown files
python -m music_organizer.main "/src" "/dest" --mode copy --skip-unknown-only

# Skip files that already exist at the destination
python -m music_organizer.main "/src" "/dest" --mode copy --skip-existing

# Exclude specific subdirectories
python -m music_organizer.main "/src" "/dest" --mode copy --exclude-dir temp --exclude-dir incomplete

# Run in debug mode to see step-by-step classification decisions
python -m music_organizer.main "/src" "/dest" --mode copy --debug

Genre Levels

Flag Description Example output
--level general Broad category buckets Electronic/, Pop/, Latin/
--level specific Detailed subgenres Deep House/, Reggaeton/, Techno/
--level both Nested folder structure (recommended) Electronic/Deep House/, Latin/Reggaeton/

Output Structure (--level both)

/destination/
├── Electronic/
│   ├── Deep House/
│   ├── Techno/
│   └── Trance/
├── Hip-Hop Rap/
│   ├── Rap/
│   └── Trap/
├── Latin/
│   ├── Bachata/
│   └── Reggaeton/
└── Other Unknown/
    └── Unknown/

Supported Formats

MP3, M4A, AAC, FLAC, OGG, OPUS, WAV, AIFF, WMA

Supported Genres

80+ specific genres mapped automatically across 9 general buckets:

Bucket Examples
Electronic House, Techno, Trance, Drum And Bass, Dubstep, EDM
Hip-Hop / Rap Rap, Trap, Drill, Grime
R&B / Soul / Funk Soul, Funk, Neo-soul
Pop Dance Pop, Latin Pop, Hyperpop
Rock / Indie / Metal Rock, Metal, Indie Rock, Alternative
Latin Reggaeton, Bachata, Salsa, Moombahton, Corridos
Reggae / Dub / Dancehall Reggae, Dancehall, Dub
Jazz / Blues Jazz, Blues, Swing
Classical / Score Classical, Soundtracks, Ambient

See src/music_organizer/rules.py for the full genre mapping rules. Custom mappings can be overridden or added locally by creating ~/.config/music-organizer/config.json.

How Classification Works

  1. Metadata Reader: Reads embedded tags (ID3, Vorbis, MP4 metadata) using mutagen.
  2. Path & Filename Inference: If metadata is missing or empty, scans parent directory names and filenames using precise word-boundary pattern matching.
  3. Conservative Defaults: Undetected or ambiguous tracks default to Other Unknown/Unknown to prevent misclassification.
  4. Collision Handling: Handles identical filenames by appending numerical suffixes ((1), (2)). Optionally, --on-collision hash will deduplicate and skip files with matching content hashes.

Improving Unknown Rate

# 1. Investigate why files were not classified
python -m music_organizer.main "/src" "/dest" --debug

# 2. Add your custom keywords to the local configuration file
# Place mappings under ~/.config/music-organizer/config.json

# 3. Re-run only on previously unclassified files
python -m music_organizer.main "/src" "/dest" --mode copy --skip-unknown-only

Local Downloader Integration

music-organizer supports using a local custom Tairona downloader adapter to download Spotify playlists and resolve metadata.

1. Development Configuration & Custom Path

In development, the default local path for the downloader script is:

/Users/nicolasaguirre/zprojects/spot dl nico/tairona_dl.py

To configure it on other machines or use an alternate wrapper, define the MUSIC_ORGANIZER_DOWNLOADER_PATH environment variable:

export MUSIC_ORGANIZER_DOWNLOADER_PATH="/path/to/tairona_dl.py"

2. Legal Use Boundary

Caution

This application and the downloader workflow must only be used with audio files that you own, created, have permission to download, or that are legally downloadable. Automated tests must not perform live copyrighted downloads.

3. Media Safety

Downloaded media and local output folders should never be checked into git. It is highly recommended to configure downloads to target isolated folders outside the repository path, such as:

~/Music/tairona-test-downloads/

The repository's .gitignore file is configured to safeguard against accidental inclusion of .mp3, .m4a, and other media files.

4. Downloader Repo Note

The local Tairona downloader lives in a separate folder (spot dl nico) with no configured git remote — progress-line changes there are local-only and not pushed.

5. E2E Validation Note (June 2026)

Authorized desktop end-to-end validation succeeded in June 2026:

  • Backend /api/v1/downloads task executes and manages the local Tairona downloader correctly.
  • Progress logs are parsed from piped machine-readable lines: [N/M] Artist - Title queued|downloading|downloaded|skipped|failed.
  • Download completed successfully with authorized content only.
  • Progress bars were difficult to observe because downloads finished quickly — this is not a progress failure; the pipeline works.
  • Media files were kept outside the repository path.
  • Packaged unsigned app smoke coverage now also includes bundled backend startup/shutdown, bundled downloader availability, dashboard, history, preferences, download-to-organize handoff, and repeated explicit in-place organization.

Project Layout

music-organizer/
├── src/music_organizer/   # Core CLI library (scanner, classifier, fileops, rules)
├── app/backend/           # FastAPI backend endpoints and local services
│   ├── routes/            # API routing handlers
│   ├── services/          # Tairona downloader integration and file organization service wrappers
│   └── store/             # SQLite download-task history database
├── desktop/               # Tauri + React application frontend
│   ├── src/screens/       # UI Screens (Home, Download, Organize, Active, History)
│   └── src-tauri/         # Rust Tauri desktop shell configuration
├── tests/                 # pytest test suite (160 tests covering CLI & Backend)
├── docs/                  # Architecture and design documentation
├── requirements.txt       # Core dependencies
├── pyproject.toml         # Build system configuration
└── LICENSE                # License information

Development & Testing

Python Environment

# Install package dependencies in editable mode with dev libraries
pip install -e .[dev]

# Run unit tests
python -m pytest tests/ -v

Frontend Typecheck

cd desktop
npm install
npx tsc --noEmit

Troubleshooting

1. Downloader script not found

The backend launches the local Tairona downloader as a subprocess. If you get path errors, verify MUSIC_ORGANIZER_DOWNLOADER_PATH or the default path exists:

/Users/nicolasaguirre/zprojects/spot dl nico/tairona_dl.py
  • If using virtual environments, activate the environment before starting the FastAPI backend.

2. Missing ffmpeg

The downloader requires ffmpeg to process audio files and embed metadata.

  • Install on macOS using Homebrew: brew install ffmpeg
  • Verify with ffmpeg -version.

3. Port 8000 already in use

If another service is using port 8000, you can run the backend on a different port:

PYTHONPATH=src uvicorn app.backend.main:app --host 127.0.0.1 --port 8080

Update your frontend configuration or Tauri API requests if modifying the backend port.


Portfolio Notes & Status

This repository is maintained as a portfolio project showcasing a hybrid Python/Rust application.

  • Production Status: Stable v2.1.0 backend with fully integrated desktop GUI.
  • Testing: Includes a comprehensive test suite (160 unit and integration tests) validating scanners, rules engines, database history, and file operations.
  • Suggested GitHub Topics: music-organizer, tauri, fastapi, react, python, spotdl, rust, music-library, mp3-tagger, audio-metadata.
  • Future Improvements:
    • Archiving root-level developer planning files into docs/archive/ to keep repo root clean.
    • Adding a direct drag-and-drop interface for directories in the Tauri frontend.

License

MIT License. See LICENSE for details.

About

Python CLI tool that uses AI to categorize and organize 100+ music genres into structured folders.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors