Sync your music library to a classic iPod from a modern Mac
Project description
clickwheel
A CLI for syncing a music library to a classic iPod from a modern Mac.
Handles the full workflow: audit and clean up your library's metadata and album art, interactively select what goes on the iPod, and sync with a progress bar — all without iTunes.
Prerequisites
- macOS with Homebrew
- Python 3.11+
- Music library accessible via local or network mount
- iPod Classic (stock firmware, connected via USB)
Quick Start
git clone https://github.com/pdugan20/clickwheel.git
cd clickwheel
cp .env.example .env # edit with your music path + API key
./scripts/setup.sh # install all dependencies
# metadata cleanup (one-time)
clickwheel scan # audit library quality
clickwheel fix # fix tags, art, genres via beets
# iPod workflow (ongoing)
clickwheel select # pick artists/albums for iPod
clickwheel diff # preview changes
clickwheel sync # push to iPod
Commands
| Command | Description |
|---|---|
clickwheel scan |
Index the music library, report on metadata/art quality |
clickwheel fix |
Clean up metadata, fetch album art, fill genres (beets) |
clickwheel select |
Interactive picker — browse by artist/album/genre, track size vs. capacity |
clickwheel playlist |
List, save, and load selections |
clickwheel diff |
Preview what would be added/removed on the iPod |
clickwheel sync |
Push current selection to iPod with progress bar |
clickwheel ls |
Show what's currently on the iPod |
clickwheel eject |
Safely unmount the iPod |
Configuration
All config lives in .env in the project root:
MUSIC_DIR=/path/to/your/music # local path or network mount
ACOUSTID_API_KEY=your_key_here # from acoustid.org (free)
IPOD_MOUNT=/Volumes/IPOD # iPod mount point (auto-detected if omitted)
Project Structure
clickwheel/ # Python CLI package
__main__.py # entry point
cli.py # Typer command definitions
library.py # music library indexing
selector.py # interactive subset picker
ipod.py # iPod sync via libgpod
db.py # local SQLite for library index + selections
beets/ # beets configuration
config.yaml.template
scripts/ # bash utilities
setup.sh # install all dependencies
audit.sh # standalone metadata audit (ffprobe-based)
fix-metadata.sh # standalone beets cleanup
playlists/ # saved selections
reports/ # audit output and logs (gitignored)
Stack
- Typer — CLI framework
- Rich — terminal UI (tables, progress bars, trees)
- beets — metadata cleanup engine
- libgpod — iPod database management
- tqdm — progress bars for sync
- ffprobe — audio file inspection
Notes
- Metadata changes are written in-place. If your library is shared with Plex or other apps, changes will be picked up on their next scan.
- beets is configured to never move or rename files.
- FLAC files are not synced to the iPod (stock firmware doesn't support FLAC). Convert them separately if needed.
- The
scanandaudit.shcommands are fully non-destructive (read-only).
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clickwheel-0.1.0.tar.gz.
File metadata
- Download URL: clickwheel-0.1.0.tar.gz
- Upload date:
- Size: 538.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
474e88581a7ea71f326e98570cdf70139b9aadb7ed22bda1adafc56b50744fbd
|
|
| MD5 |
4fd4177dd15cd2707c95c58a391057d3
|
|
| BLAKE2b-256 |
7461107a624cb28af5f4813dbb6efb69dde6a50f63376b4564ba8a81bc0d166d
|
Provenance
The following attestation bundles were made for clickwheel-0.1.0.tar.gz:
Publisher:
publish.yml on pdugan20/clickwheel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clickwheel-0.1.0.tar.gz -
Subject digest:
474e88581a7ea71f326e98570cdf70139b9aadb7ed22bda1adafc56b50744fbd - Sigstore transparency entry: 1108229696
- Sigstore integration time:
-
Permalink:
pdugan20/clickwheel@13fbf3bed94a0385ec2ec04d6d437d8bd88e37d8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/pdugan20
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13fbf3bed94a0385ec2ec04d6d437d8bd88e37d8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file clickwheel-0.1.0-py3-none-any.whl.
File metadata
- Download URL: clickwheel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 545.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c97cca90ea64534c964729adf2e7e005e972a6304297004a0a3a9e0e408c6a6
|
|
| MD5 |
f7a3ecb0283c3a8f6da51437a06a8984
|
|
| BLAKE2b-256 |
55cb58650cf53106613ab8f4ec86786a70a05f63f8fb117a808d3b85c098b1a9
|
Provenance
The following attestation bundles were made for clickwheel-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on pdugan20/clickwheel
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clickwheel-0.1.0-py3-none-any.whl -
Subject digest:
1c97cca90ea64534c964729adf2e7e005e972a6304297004a0a3a9e0e408c6a6 - Sigstore transparency entry: 1108229727
- Sigstore integration time:
-
Permalink:
pdugan20/clickwheel@13fbf3bed94a0385ec2ec04d6d437d8bd88e37d8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/pdugan20
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13fbf3bed94a0385ec2ec04d6d437d8bd88e37d8 -
Trigger Event:
push
-
Statement type: