pygpod
Pure-Python library and command line tool for iPods that mount as USB mass storage: it reads and writes the iPod's music database (iTunesDB), cover art (ArtworkDB), photos (Photo Database) and the shuffle's iTunesSD. A spiritual successor to libgpod: same file formats, same output, no C code.
Beta. The file formats are checked against libgpod and on real iPods (see Supported iPods), but not every model has been tried on hardware. Keep a backup (
pygpod backup) before writing to an iPod you care about.
Features
Database
- Parse and re-write iTunesDB and ArtworkDB byte-identically (also those written by iTunes or libgpod); new data is written the way libgpod writes it (checked against libgpod itself in the test suite). A Photo Database written by pygpod round-trips byte-identically too; one written by iTunes or libgpod is rewritten in pygpod's (libgpod-readable) layout on its first save.
- Checksums per model like libgpod: hash58 (Classic, nano 3G/4G), hash72, unsigned databases for older models; an unidentified iPod is signed like the database already on it.
- Crash-safe saves (all database files are committed together through a journal), one writer at a
time (lock file,
ConflictErrorwhen someone else saved meanwhile). - iTunesSD for the iPod shuffle: version 1 (1G/2G) and version 2 (3G/4G), written on every save.
Tracks
- Tags read from MP3, AAC/ALAC (M4A/M4B), FLAC, Ogg and others (mutagen): titles, sort fields,
compilation, rating, BPM, grouping, explicit/clean, release date, podcast fields, embedded cover.
Keyword arguments of
add_track()always win over the tags. - The file's content is checked against what the model plays;
convert=Trueconverts the rest with ffmpeg (Apple Lossless where the iPod plays it, else AAC; video to H.264 Baseline + AAC). - Sound Check from iTunNORM / ReplayGain tags, or measured with ffmpeg.
- Gapless playback data from LAME/Info tags, iTunSMPB and MP4 edit lists; an estimate for files without them (experimental).
- Chapters of audiobooks and podcasts (MP4 chapter track, Nero
chpl, ID3CHAP). - Video: movies, music videos, TV shows (with show/season/episode fields).
Playlists, play counts, artwork, photos
- Playlists, podcast playlists and smart playlists (rules evaluated like libgpod, live ones refreshed on save).
- Play counts, skips, ratings and bookmarks recorded on the iPod are merged on open.
- On-The-Go playlists made on the iPod are imported as "OTG Playlist n" on save, like iTunes.
- Cover art and photos in the iPod's own formats (from its SysInfoExtended, else a per-model table), letterboxed like libgpod.
- Timestamps are the iPod's local time, like iTunes and libgpod.
Maintenance
doctor: a read-only consistency check (missing/orphan files, broken artwork or playlist references, wrong lengths, photo database problems, checksum, free space ...) and a repair.- Backup and restore of the whole iPod (database, artwork, photos, optionally the media) to a tar archive, verified before anything is written.
init_ipod(): create the folder structure and an empty, correctly signed database.
Documentation: docs/ has one page per area with runnable examples and an API reference generated from the docstrings. Changes: CHANGELOG.md.
Installation
pip install "pygpod[all]"
| extra | package | needed for |
|---|---|---|
tags |
mutagen | reading tags, cover art, chapters and gapless data from files |
artwork |
Pillow | cover art and photos |
usb |
pyusb | finding iPods on USB (discover, model/GUID when SysInfo lacks them) |
all |
all of the above, plus tzdata on Windows |
Without the extras pygpod still reads and writes databases; you pass the metadata yourself and
artwork is not available (pygpod warns on import about what is missing). ffmpeg and ffprobe
are needed only for conversion (convert=True), Sound Check analysis and the gapless estimate.
Python 3.8 or newer; Linux, macOS and Windows. Windows has no time zone database of its own:
without tzdata (in all, or pip install tzdata; Python 3.9+) a city time zone set on a Classic
or nano 3G/4G cannot be resolved and pygpod uses the computer's UTC offset for the iPod's timestamps.
Quick start
import pygpod
db = pygpod.Database("/mnt/ipod") # the iPod's mount point
for track in db.tracks:
print(track.artist, "-", track.title, f"({track.album})")
# Tags are read from the file; keyword arguments override them.
track = db.add_track("/path/to/song.mp3", artist="Океан Ельзи", album="Земля", year=2013)
track.rating = 80 # 0-100, 20 per star
road_trip = db.create_playlist("У дорогу")
db.add_track_to_playlist(road_trip, track)
db.set_playlist("Обране", [track]) # create or replace a playlist's members
db.save() # nothing is written before save()
The context manager saves on a clean exit:
with pygpod.Database("/mnt/ipod") as db:
db.tracks[0].play_count = 3
Files the iPod cannot play, Sound Check measured with ffmpeg, the gapless estimate, explicit chapters and video fields (these need ffmpeg or real media files):
db.add_track("/path/to/song.flac", convert=True) # -> ALAC or AAC
db.add_track("/path/to/movie.mkv", convert=True, video_size="large") # -> H.264 .m4v
db.add_track("/path/to/live.mp3", soundcheck="auto", gapless="estimate", gapless_album_flag=True)
db.add_track("/path/to/book.m4b", chapters=[(0, "Вступ"), (90000, "Розділ 1")])
db.add_track("/path/to/episode.m4v", tvshow="Show", season_number=1, episode_number=3)
Cover art, photos, smart playlists, check and backup:
from pygpod import SPLAction, SPLField, SPLRule
db = pygpod.Database("/mnt/ipod")
db.set_artwork(db.tracks[0], open("/path/to/cover.png", "rb").read())
db.create_smart_playlist("Rock", [SPLRule(field=SPLField.GENRE, action=SPLAction.CONTAINS,
string="Rock")])
db.save()
photos = pygpod.PhotoDB("/mnt/ipod")
album = photos.create_album("Літо")
photos.add_photo_to_album(album, photos.add_photo("/path/to/cover.png"))
photos.save()
report = pygpod.Database("/mnt/ipod").check() # read-only; repair() fixes and saves
print(report.summary())
pygpod.backup("/mnt/ipod", "ipod.tar.gz", include_media=False)
More in docs/: database, tracks, playlists, device and models, play counts and On-The-Go, artwork and photos, tags and conversion, check, backup, restore, errors, command line.
Command line
export PYGPOD_MOUNTPOINT=/mnt/ipod # or pass -m /mnt/ipod to every command
pygpod info # device and database summary
pygpod track list # list tracks (track info <id>: every field)
pygpod track add ~/Music/album/*.mp3 # add files (tags read; --title, --artist ... override)
pygpod track remove <id> # remove a track
pygpod track export <id> dest/ # copy a track's file off the iPod
pygpod playlist create "У дорогу" # playlist list / add / remove / delete
pygpod playlist add "У дорогу" 1 2 3
pygpod doctor # read-only check (exit 1 = issues found)
pygpod doctor --fix # repair; --delete-orphans also deletes unreferenced files
pygpod backup ipod.tar.gz # --no-media: database, artwork and photos only
pygpod restore ipod.tar.gz --dry-run # verify and plan; without --dry-run: restore
pygpod init --model classic_6g # create the folder structure and an empty database
pygpod discover # find connected iPods
pygpod dump # raw iTunesDB record tree
pygpod fix-checksums # re-sign the database
pygpod purge --yes # delete all music and the database
Every command and option: docs/cli.md.
Supported iPods
pygpod works with iPods that mount as USB mass storage. iPod touch, iPhone and iPad are not supported (they do not expose the database as files).
| model | database | checksum | cover art / photos / video |
|---|---|---|---|
| iPod 1G-4G, mini 1G/2G | read, write | none | - / - / - |
| iPod Photo (4G color) | read, write | none | yes / yes / - |
| iPod Video 5G/5.5G | read, write | none (like libgpod and iTunes) | yes / yes (incl. TV-out) / yes |
| nano 1G/2G | read, write | none (like libgpod and iTunes) | yes / yes / - |
| nano 3G/4G | read, write | hash58 | yes / yes / yes |
| Classic 6G/6.5G/7G | read, write | hash58 | yes / yes / yes |
| shuffle 1G/2G, 3G/4G | read, write + iTunesSD v1 / v2 | none | - / - / - |
| nano 5G | not supported (see below) | hash72 | |
| nano 6G/7G | not supported | hashAB (nano 7G: unidentified model) |
hash58 needs the iPod's FirewireGuid, which pygpod reads from iPod_Control/Device/SysInfo or,
when that file lacks it, from USB (usb extra). The model comes from SysInfo/SysInfoExtended the
same way; an iPod pygpod cannot identify is signed like the database already on it.
Tested on real hardware: iPod Classic 6G 80 GB and Classic 7G 160 GB (modded), on Linux. The other models are tested on emulated volumes against libgpod. macOS and Windows support (mount points, USB lookups) is implemented but little tested. Reports for other models are welcome at the issue tracker.
Known limitations
- nano 5G: the firmware reads its library from SQLite databases (
iTunesCDB,*.itdb), which pygpod does not write;save()warns. The hash72 signature itself is implemented and needsiPod_Control/Device/HashInfoor a database signed by iTunes once. - nano 6G/7G need the hashAB signature (and SQLite databases), which pygpod does not write.
On a nano 6G
save()raisesHashError; pygpod has no model entry for the nano 7G, so it is handled like any unidentified iPod (signed like the database on it, elseHashError). - Gapless estimate (
gapless="estimate") is experimental; files with exact gapless data always use it. - On-The-Go: by default a save imports the iPod's On-The-Go lists and deletes them from the
iPod, like iTunes (
DatabaseConfig(otg_on_save="keep")keeps them; the Classic empties a kept list anyway once the database changed). - Several iPods connected: when SysInfo lacks the model or FirewireGuid, pygpod asks USB only
for the iPod behind the mount point. If that mapping fails and several iPods are connected,
nothing is guessed: a signed iPod's
save()raisesHashError(create SysInfo, or connect one iPod at a time). The macOS/Windows mapping is untested on real systems. - Real serial number: reading it over SCSI (VPD page 0x80) needs read access to the block
device (root, or the
diskgroup on Linux). Tested on Linux only. init_ipod(reset=True)deletes everything underiPod_Control/iTunes, including iTunes'IC-Info.sidb; the SysInfo files are kept unlesskeep_sysinfo=False.
Roadmap
- Confirm more models on real hardware (iPod Video, nano 3G/4G, shuffles, iPod Photo).
- iPod nano 5G-7G: the SQLite databases and the hashAB signature - see docs/research/hashab-hash72.md.
- Maybe games: only copying a user's own purchased games looks possible - see docs/research/ipod-games.md.
Development
git clone https://github.com/Bionded/pygpod.git
cd pygpod
pip install -e ".[all]" pytest pytest-xdist ruff
python -m pytest tests -n 3 # tests (-m "not slow" skips the benchmarks)
PYGPOD_REQUIRE_LIBGPOD=1 python -m pytest tests -m libgpod # libgpod interop: fail, not skip
ruff check pygpod tests && ruff format --check pygpod tests
python docs/gen_reference.py # regenerate the API reference in docs/
The libgpod interop tests (marker libgpod) build a small C tool against libgpod
(integration_tests/libgpod_tool.c; needs gcc, pkg-config and libgpod-dev) and compare what
both libraries write and read; they are skipped when libgpod is missing.
Acknowledgments
pygpod is a spiritual successor to libgpod, originally written by Jörg Schuler and made into a standalone library by Christophe Fergeau. The iPod model database, hash algorithms, and binary format knowledge are all derived from libgpod's C implementation.
AI Disclosure
This project was developed with assistance from Claude (Anthropic) and ChatGPT (OpenAI). AI was used throughout the porting and rewriting process - sometimes for consulting on architecture decisions, sometimes for tracking down bugs. The hash/checksum implementation (hash58, hash72) relied heavily on AI assistance to port the cryptographic logic from libgpod's C code to Python. All AI-generated code was reviewed, tested, and verified against the original libgpod behavior. Maybe not perfect, but i really tried to make sure it was correct and secure.
License
pygpod is licensed under the GNU Lesser General Public License v2.1 or later (LGPL-2.1-or-later).
Metadata
Release files for pygpod 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| pygpod-0.2.0.tar.gz | 410.0 kB | With provenance | Details for pygpod-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pygpod-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for pygpod-0.2.0-py3-none-any.whl |
Total release size: 642.1 kB
Release files / pygpod-0.2.0.tar.gz
| Download URL | pygpod-0.2.0.tar.gz |
|---|---|
| Size | 410.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b17f5ae13c2f316a005595cb216e489f37876e0ff892d8419b35f1439ff95934
|
|
BLAKE2b-256 checksum How to use checksums |
865df274f9d654a54050e6c184a16400b5a37fa2d6ade7945f83371fd3c70d3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logRelease files / pygpod-0.2.0-py3-none-any.whl
| Download URL | pygpod-0.2.0-py3-none-any.whl |
|---|---|
| Size | 232.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
22427b63ed636b36a4cef0a961b3c11a8290a0c4c0b896fe5503857379417a41
|
|
BLAKE2b-256 checksum How to use checksums |
d5472ef952a918c74f0a285405041724bc9d7da4aba3ea68583b26b94d196ae0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logSecurity for pygpod 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pygpod-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.