flashpod 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
flashpod-0.1.5/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 David Barnhart
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,317 @@
1
+ Metadata-Version: 2.4
2
+ Name: flashpod
3
+ Version: 0.1.5
4
+ Summary: Command-line iPod sync + card-flashing tooling for early FireWire-era iPods, pure Python
5
+ Author: David Barnhart
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/davidbarnhart/flashpod
8
+ Project-URL: Issues, https://github.com/davidbarnhart/flashpod/issues
9
+ Keywords: ipod,itunesdb,firmware,flash,compactflash
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Operating System :: POSIX :: Linux
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.6
16
+ Classifier: Programming Language :: Python :: 3.7
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Multimedia :: Sound/Audio
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.6
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: mutagen
29
+ Dynamic: license-file
30
+
31
+ # flashpod
32
+
33
+ flashpod is a command-line tool for putting flash storage cards into
34
+ early-generation iPods and managing the music on them.
35
+
36
+ It handles the whole setup without iTunes, so you can revive a vintage iPod
37
+ and run it from a modern desktop: it writes the firmware to the card, creates
38
+ the initial music database, and loads the card with music. Then, once you pop
39
+ the card into an iPod and connect it over USB or FireWire, flashpod manages
40
+ the library on the device too — adding and removing songs right on the iPod.
41
+
42
+ ## Requirements
43
+
44
+ - **iPod:** Gen 1, 2, or 3 (tested successfully); Gen 4 should work but isn't
45
+ tested yet. Later models (2007 and newer) aren't supported — they need an
46
+ iTunesDB checksum/hash flashpod doesn't generate.
47
+ - **Operating system:** Linux and macOS (tested). Windows has a backend but
48
+ isn't tested yet.
49
+
50
+ flashpod was originally written to run from a modern Linux desktop. The
51
+ one-time flashing operation only needs a working USB card reader. For a 3rd- or
52
+ 4th-gen iPod, a modern machine can flash the card and manage the iPod. For a 1st-
53
+ or 2nd-gen iPod, you can still flash the card from a modern machine, but you'll
54
+ need a FireWire interface to manage the music on the iPod afterward.
55
+
56
+ ## FireWire
57
+
58
+ A FireWire interface is a rarity these days. On a desktop, the easiest option
59
+ is to add a FireWire card — Linux still supports FireWire well, so a Linux
60
+ machine with a FireWire card lets flashpod manage a 1st- or 2nd-gen iPod.
61
+
62
+ That's not the only option, though. Older Macs shipped with FireWire built in,
63
+ and flashpod was deliberately written with as few external dependencies as
64
+ possible — and against a relatively old Python — to stay runnable on vintage
65
+ Mac hardware. It's been tested on a MacBook running OS X 10.8 so far. Since old
66
+ Macs often can't get online, the macOS release can be copied to a USB drive on
67
+ a modern machine and installed on the MacBook from there.
68
+
69
+ ## Install
70
+
71
+ Download the archive for your OS from the
72
+ [Releases page](https://github.com/davidbarnhart/flashpod/releases) — each holds
73
+ a single self-contained executable (no Python or anything else to install).
74
+
75
+ **Linux** (`flashpod-linux-x86_64.tar.gz`):
76
+ ```sh
77
+ tar xzf flashpod-linux-x86_64.tar.gz
78
+ cd flashpod-linux-x86_64
79
+ ./install.sh # to ~/.local/bin (no root); or: sudo ./install.sh
80
+ flashpod --help
81
+ ```
82
+
83
+ **Windows** (`flashpod-windows-x86_64.zip`): unzip it and run `flashpod.exe`
84
+ from a terminal (an Administrator terminal for `flash`).
85
+
86
+ The **Linux and Windows** builds don't bundle firmware — `flashpod flash`
87
+ downloads the image you pick (verified by checksum), or you supply your own with
88
+ `--firmware`. (The **macOS 10.8** build is different — see below.) Building the
89
+ binaries yourself is documented in [BUILD.md](BUILD.md).
90
+
91
+ **Vintage Macs (OS X 10.8):** use `flashpod-macos-10.8.tar.gz`. Extract it,
92
+ then make the binary runnable and clear the Gatekeeper quarantine (it's unsigned):
93
+
94
+ ```sh
95
+ tar xzf flashpod-macos-10.8.tar.gz && cd flashpod-macos-10.8
96
+ chmod +x flashpod
97
+ xattr -d com.apple.quarantine flashpod # or right-click → Open once
98
+ ./flashpod --help
99
+ ```
100
+
101
+ > `flashpod flash` needs root. `sudo` uses root's PATH, so if `sudo flashpod`
102
+ > isn't found, run it by full path — `sudo "$(command -v flashpod)" flash`, or
103
+ > `cd` into the extracted folder and run `sudo ./flashpod flash`.
104
+
105
+ ## Typical workflow
106
+
107
+ **Set the card up in a USB reader first — transfers are far faster there than
108
+ over FireWire.** Flash it, then let flashpod initialize the database and load
109
+ your music, all in one sitting:
110
+
111
+ ```sh
112
+ sudo flashpod flash # flash firmware + format the card; then answer Y to
113
+ # init the database, and Y to load your music onto it
114
+ ```
115
+
116
+ Load the **bulk** of your library now, while the card is in the reader. Once the
117
+ card is in the iPod, music transfers over FireWire are much slower — fine for a
118
+ song or two, painful for a discography. So front-load it here.
119
+
120
+ Now pop the card into the iPod and connect the iPod to your computer. flashpod
121
+ finds it on its own — no mounting, no device paths, no `sudo` to type:
122
+
123
+ ```
124
+ $ flashpod ls
125
+ flashpod: looking for an iPod means reading attached disks, which needs root — elevating via sudo...
126
+ Password:
127
+ Found iPod on /dev/rdisk1 — 82 tracks.
128
+ iPod "David's iPod": 38 tracks, 2 artists, 2 albums
129
+ New Order
130
+ Power, Corruption & Lies (8 tracks)
131
+ Substance (12 tracks)
132
+ The Cure
133
+ Kiss Me, Kiss Me, Kiss Me (18 tracks)
134
+ ```
135
+
136
+ Add or remove the odd track right on the device:
137
+
138
+ ```
139
+ $ flashpod add ~/music/New\ Order\ -\ Blue\ Monday.mp3
140
+ Found iPod on /dev/rdisk1 — 82 tracks.
141
+ [1/1] Adding: Blue Monday — New Order... 100% (6.8/6.8 MiB)
142
+ 1 track added in 26s (6.8 MiB at 268 KiB/s)
143
+
144
+ $ flashpod rm album Substance
145
+ Found iPod on /dev/rdisk1 — 83 tracks.
146
+ Removed: New Order - Ceremony
147
+ Removed: New Order - Temptation
148
+
149
+ Removed 12 tracks
150
+ ```
151
+
152
+ ## Commands
153
+
154
+ flashpod finds your iPod for you. With no flags, it uses one that's already
155
+ mounted; otherwise it scans the attached disks and picks out the iPod by the
156
+ iTunes database on it (no guessing from volume labels), then reads and writes it
157
+ **directly over the raw device** with its own FAT driver — no OS mount required.
158
+ That raw path is what lets flashpod manage an iPod the OS *can't* mount, like a
159
+ flash-modded FireWire iPod on a Mac (macOS's read-ahead corrupts the boot
160
+ sector, so it refuses the volume). Raw access needs root, so flashpod re-runs
161
+ itself under sudo and prompts for your password — you never type `sudo`
162
+ yourself.
163
+
164
+ To skip detection, name the target explicitly — `--mount <path>` for a
165
+ mountpoint or `--raw <device>` for a raw device (the data partition or the whole
166
+ disk), before or after the subcommand. On Linux you can also just mount the iPod
167
+ yourself and let flashpod find the mount. On a non-terminal, flashpod won't
168
+ guess — pass one of these.
169
+
170
+ All four library commands — `ls`, `add`, `rm`, `init` — work this way.
171
+
172
+ ### `flashpod ls` (alias: `flashpod list`)
173
+
174
+ ```
175
+ $ flashpod ls # artist → album tree with track counts
176
+ iPod "iPod": 68 tracks, 1 artists, 5 albums
177
+ New Order
178
+ Power, Corruption & Lies (8 tracks)
179
+ Substance (12 tracks)
180
+
181
+ $ flashpod ls all # same tree + every track (id, track no., duration)
182
+ New Order
183
+ Substance
184
+ 52 1. Ceremony 4:25
185
+ 53 2. Everything's Gone Green 5:31
186
+
187
+ $ flashpod ls artist # flat per-artist track counts (or `artists`)
188
+ $ flashpod ls album # flat per-album track counts (or `albums`)
189
+ ```
190
+
191
+ Track ids shown by `ls all` are what `flashpod rm <id>` takes.
192
+
193
+ ### `flashpod add [path ...]`
194
+
195
+ Add audio files and/or directories. Directories are scanned recursively in
196
+ sorted order; macOS `._*` AppleDouble files and non-audio files are skipped.
197
+ Recognized extensions: `.mp3 .m4a .m4b .aac .wav .aif .aiff`. Tags, duration,
198
+ and bitrate are read automatically (mutagen).
199
+
200
+ Files already on the iPod are skipped, so you can safely re-point `add` at an
201
+ overlapping set — e.g. add a single, then later add the whole album folder
202
+ that contains it, and only the new tracks are copied. A track is considered a
203
+ duplicate when its size, duration, and title all match one already present
204
+ (this also de-duplicates within a single batch). Re-encoded or re-tagged
205
+ copies have a different size and are added as new.
206
+
207
+ ```
208
+ $ flashpod add ~/music/Some\ Album # a directory
209
+ $ flashpod add a.mp3 b.mp3 ~/music/More/ # mix files and directories
210
+ $ flashpod add # no args: prompts, with tab completion
211
+ ```
212
+
213
+ Progress is one line per track, shown in a scrolling 4-line window so a big
214
+ batch doesn't flood the terminal history (when output is piped or redirected,
215
+ every line is printed instead). Skips and failures stay visible above the
216
+ window, are counted in the summary, and don't stop the batch:
217
+
218
+ ```
219
+ [3/14] skipping ._cover.mp3: not a recognized audio file
220
+ [4/14] skipping 01 Come Together.mp3: already on iPod
221
+ [11/14] Adding: Pet Cemetery — Relic Pop... ⌝
222
+ [12/14] Adding: Rarely Seen Violence — Relic Pop... | last 4 only;
223
+ [13/14] Adding: Sister Sky — Relic Pop... | older lines scroll away
224
+ [14/14] Adding: Thick as Thieves — Relic Pop... ⌟
225
+ 12 tracks added, 1 skipped (already on iPod), 1 failed in 1m02s
226
+ ```
227
+
228
+ > **Adding over FireWire is slow** (~270 KiB/s — a hardware limit of these early
229
+ > bridges, not something a setting can fix). For **bulk** loads, pull the card
230
+ > into a USB reader and `add` over the normal mount — USB bypasses the bridge
231
+ > and is far faster. Keep the raw FireWire path for quick incremental edits.
232
+
233
+ ### `flashpod rm`
234
+
235
+ ```
236
+ $ flashpod rm 52 53 # by track id (see `flashpod ls all`)
237
+ $ flashpod rm artist Relic Pop # every track by the artist
238
+ $ flashpod rm album Thick As Thieves # every track in the album
239
+ ```
240
+
241
+ Artist/album matching is case-insensitive exact match; multiword names need
242
+ no quotes. `remove`, `delete`, and `erase` all work as synonyms for `rm`.
243
+ **Removal is immediate — there is no confirmation prompt.**
244
+
245
+ ### `flashpod init [name]`
246
+
247
+ Create the `iPod_Control` directory structure and an empty music database.
248
+ Use on a freshly flashed/formatted card or after a wipe. Destroys any
249
+ existing database, but not music files already in the `F##` folders.
250
+
251
+ ### `flashpod flash [/dev/sdX]`
252
+
253
+ Write the iPod firmware and partition layout to a CF/SD card. **Erases the
254
+ card.** Needs root (`sudo flashpod flash`).
255
+
256
+ ```
257
+ $ sudo flashpod flash # interactive: pick from removable disks
258
+ $ sudo flashpod flash /dev/sdb # direct
259
+ $ flashpod flash /dev/sdb --dry-run # print the plan, write nothing (no root)
260
+ $ flashpod flash --self-test # validate layout logic, no hardware
261
+ ```
262
+
263
+ **Firmware:** with no `--firmware`, an interactive chooser lists the images
264
+ from the bundled catalog (`flashpod/firmware/firmware.json`) by iPod
265
+ generation, version, and description (the default entry is preselected;
266
+ non-interactive runs use it outright). The chosen `.ipsw` is then **downloaded
267
+ from GitHub**, cached under `~/.cache/flashpod/`, and **verified against its
268
+ SHA-256** before use; later flashes reuse the cached copy (no network). The
269
+ images aren't bundled with flashpod — they're Apple's copyright, hosted as
270
+ [release assets](https://github.com/davidbarnhart/flashpod/releases/tag/firmware).
271
+
272
+ To use a firmware flashpod doesn't host (or to work fully offline), download
273
+ an `.ipsw` yourself and pass it with `--firmware <file>` — that path never
274
+ touches the network. To add an image to the catalog, upload it to the firmware
275
+ release and add a manifest entry (`file`, `url`/`base_url`, `sha256`,
276
+ `generation`, `version`, `description`).
277
+
278
+ Options:
279
+
280
+ | Flag | Meaning |
281
+ |------|---------|
282
+ | `--firmware <file>` | use a local `.ipsw` (bring-your-own; no download). Default: pick from the catalog and download it |
283
+ | `--yes` | skip the typed `ERASE sdX` confirmation |
284
+ | `--no-format` | don't format the data partition |
285
+ | `--dry-run` | show the plan only |
286
+ | `--self-test` | check layout-building logic and exit |
287
+
288
+ Safety: only removable/USB disks are offered, the disk backing the running
289
+ system is always refused, partition nodes (`/dev/sdb1`) are rejected, the
290
+ target is unmounted first, and an explicit typed confirmation is required.
291
+ After writing, the firmware region is read back and compared byte-for-byte
292
+ before the card is ejected. Cards larger than 128 GiB are capped at the
293
+ iPod's LBA28 addressing limit.
294
+
295
+ After a successful interactive flash, flashpod offers to run init on the new
296
+ card right away, and after that to load music onto it too — answer Y (the
297
+ default) to both and the card comes out of the flash step ready to play. The
298
+ offers are skipped for `--dry-run`, `--no-format`, and non-interactive runs.
299
+
300
+
301
+ ## Notes
302
+
303
+ - Close Rhythmbox before syncing/ejecting — its libgpod plugin grabs the
304
+ iPod mount and blocks unmount.
305
+ - A batch `flashpod add` writes the database **once**, at the end — not per
306
+ track. If a batch is interrupted, you may be left with orphaned music files
307
+ but an unchanged database; just re-run the same `add` (files already present
308
+ are skipped).
309
+ - Don't trust `fsck.vfat` on iPod cards: dosfstools chokes on iPod boot
310
+ sectors that the kernel mounts fine.
311
+
312
+ ## License
313
+
314
+ flashpod is released under the [MIT License](LICENSE). The firmware `.ipsw`
315
+ images that `flashpod flash` downloads are Apple's copyright, not covered by
316
+ that license and not part of this source tree — they are hosted separately for
317
+ convenience, and you may supply your own instead.
@@ -0,0 +1,287 @@
1
+ # flashpod
2
+
3
+ flashpod is a command-line tool for putting flash storage cards into
4
+ early-generation iPods and managing the music on them.
5
+
6
+ It handles the whole setup without iTunes, so you can revive a vintage iPod
7
+ and run it from a modern desktop: it writes the firmware to the card, creates
8
+ the initial music database, and loads the card with music. Then, once you pop
9
+ the card into an iPod and connect it over USB or FireWire, flashpod manages
10
+ the library on the device too — adding and removing songs right on the iPod.
11
+
12
+ ## Requirements
13
+
14
+ - **iPod:** Gen 1, 2, or 3 (tested successfully); Gen 4 should work but isn't
15
+ tested yet. Later models (2007 and newer) aren't supported — they need an
16
+ iTunesDB checksum/hash flashpod doesn't generate.
17
+ - **Operating system:** Linux and macOS (tested). Windows has a backend but
18
+ isn't tested yet.
19
+
20
+ flashpod was originally written to run from a modern Linux desktop. The
21
+ one-time flashing operation only needs a working USB card reader. For a 3rd- or
22
+ 4th-gen iPod, a modern machine can flash the card and manage the iPod. For a 1st-
23
+ or 2nd-gen iPod, you can still flash the card from a modern machine, but you'll
24
+ need a FireWire interface to manage the music on the iPod afterward.
25
+
26
+ ## FireWire
27
+
28
+ A FireWire interface is a rarity these days. On a desktop, the easiest option
29
+ is to add a FireWire card — Linux still supports FireWire well, so a Linux
30
+ machine with a FireWire card lets flashpod manage a 1st- or 2nd-gen iPod.
31
+
32
+ That's not the only option, though. Older Macs shipped with FireWire built in,
33
+ and flashpod was deliberately written with as few external dependencies as
34
+ possible — and against a relatively old Python — to stay runnable on vintage
35
+ Mac hardware. It's been tested on a MacBook running OS X 10.8 so far. Since old
36
+ Macs often can't get online, the macOS release can be copied to a USB drive on
37
+ a modern machine and installed on the MacBook from there.
38
+
39
+ ## Install
40
+
41
+ Download the archive for your OS from the
42
+ [Releases page](https://github.com/davidbarnhart/flashpod/releases) — each holds
43
+ a single self-contained executable (no Python or anything else to install).
44
+
45
+ **Linux** (`flashpod-linux-x86_64.tar.gz`):
46
+ ```sh
47
+ tar xzf flashpod-linux-x86_64.tar.gz
48
+ cd flashpod-linux-x86_64
49
+ ./install.sh # to ~/.local/bin (no root); or: sudo ./install.sh
50
+ flashpod --help
51
+ ```
52
+
53
+ **Windows** (`flashpod-windows-x86_64.zip`): unzip it and run `flashpod.exe`
54
+ from a terminal (an Administrator terminal for `flash`).
55
+
56
+ The **Linux and Windows** builds don't bundle firmware — `flashpod flash`
57
+ downloads the image you pick (verified by checksum), or you supply your own with
58
+ `--firmware`. (The **macOS 10.8** build is different — see below.) Building the
59
+ binaries yourself is documented in [BUILD.md](BUILD.md).
60
+
61
+ **Vintage Macs (OS X 10.8):** use `flashpod-macos-10.8.tar.gz`. Extract it,
62
+ then make the binary runnable and clear the Gatekeeper quarantine (it's unsigned):
63
+
64
+ ```sh
65
+ tar xzf flashpod-macos-10.8.tar.gz && cd flashpod-macos-10.8
66
+ chmod +x flashpod
67
+ xattr -d com.apple.quarantine flashpod # or right-click → Open once
68
+ ./flashpod --help
69
+ ```
70
+
71
+ > `flashpod flash` needs root. `sudo` uses root's PATH, so if `sudo flashpod`
72
+ > isn't found, run it by full path — `sudo "$(command -v flashpod)" flash`, or
73
+ > `cd` into the extracted folder and run `sudo ./flashpod flash`.
74
+
75
+ ## Typical workflow
76
+
77
+ **Set the card up in a USB reader first — transfers are far faster there than
78
+ over FireWire.** Flash it, then let flashpod initialize the database and load
79
+ your music, all in one sitting:
80
+
81
+ ```sh
82
+ sudo flashpod flash # flash firmware + format the card; then answer Y to
83
+ # init the database, and Y to load your music onto it
84
+ ```
85
+
86
+ Load the **bulk** of your library now, while the card is in the reader. Once the
87
+ card is in the iPod, music transfers over FireWire are much slower — fine for a
88
+ song or two, painful for a discography. So front-load it here.
89
+
90
+ Now pop the card into the iPod and connect the iPod to your computer. flashpod
91
+ finds it on its own — no mounting, no device paths, no `sudo` to type:
92
+
93
+ ```
94
+ $ flashpod ls
95
+ flashpod: looking for an iPod means reading attached disks, which needs root — elevating via sudo...
96
+ Password:
97
+ Found iPod on /dev/rdisk1 — 82 tracks.
98
+ iPod "David's iPod": 38 tracks, 2 artists, 2 albums
99
+ New Order
100
+ Power, Corruption & Lies (8 tracks)
101
+ Substance (12 tracks)
102
+ The Cure
103
+ Kiss Me, Kiss Me, Kiss Me (18 tracks)
104
+ ```
105
+
106
+ Add or remove the odd track right on the device:
107
+
108
+ ```
109
+ $ flashpod add ~/music/New\ Order\ -\ Blue\ Monday.mp3
110
+ Found iPod on /dev/rdisk1 — 82 tracks.
111
+ [1/1] Adding: Blue Monday — New Order... 100% (6.8/6.8 MiB)
112
+ 1 track added in 26s (6.8 MiB at 268 KiB/s)
113
+
114
+ $ flashpod rm album Substance
115
+ Found iPod on /dev/rdisk1 — 83 tracks.
116
+ Removed: New Order - Ceremony
117
+ Removed: New Order - Temptation
118
+
119
+ Removed 12 tracks
120
+ ```
121
+
122
+ ## Commands
123
+
124
+ flashpod finds your iPod for you. With no flags, it uses one that's already
125
+ mounted; otherwise it scans the attached disks and picks out the iPod by the
126
+ iTunes database on it (no guessing from volume labels), then reads and writes it
127
+ **directly over the raw device** with its own FAT driver — no OS mount required.
128
+ That raw path is what lets flashpod manage an iPod the OS *can't* mount, like a
129
+ flash-modded FireWire iPod on a Mac (macOS's read-ahead corrupts the boot
130
+ sector, so it refuses the volume). Raw access needs root, so flashpod re-runs
131
+ itself under sudo and prompts for your password — you never type `sudo`
132
+ yourself.
133
+
134
+ To skip detection, name the target explicitly — `--mount <path>` for a
135
+ mountpoint or `--raw <device>` for a raw device (the data partition or the whole
136
+ disk), before or after the subcommand. On Linux you can also just mount the iPod
137
+ yourself and let flashpod find the mount. On a non-terminal, flashpod won't
138
+ guess — pass one of these.
139
+
140
+ All four library commands — `ls`, `add`, `rm`, `init` — work this way.
141
+
142
+ ### `flashpod ls` (alias: `flashpod list`)
143
+
144
+ ```
145
+ $ flashpod ls # artist → album tree with track counts
146
+ iPod "iPod": 68 tracks, 1 artists, 5 albums
147
+ New Order
148
+ Power, Corruption & Lies (8 tracks)
149
+ Substance (12 tracks)
150
+
151
+ $ flashpod ls all # same tree + every track (id, track no., duration)
152
+ New Order
153
+ Substance
154
+ 52 1. Ceremony 4:25
155
+ 53 2. Everything's Gone Green 5:31
156
+
157
+ $ flashpod ls artist # flat per-artist track counts (or `artists`)
158
+ $ flashpod ls album # flat per-album track counts (or `albums`)
159
+ ```
160
+
161
+ Track ids shown by `ls all` are what `flashpod rm <id>` takes.
162
+
163
+ ### `flashpod add [path ...]`
164
+
165
+ Add audio files and/or directories. Directories are scanned recursively in
166
+ sorted order; macOS `._*` AppleDouble files and non-audio files are skipped.
167
+ Recognized extensions: `.mp3 .m4a .m4b .aac .wav .aif .aiff`. Tags, duration,
168
+ and bitrate are read automatically (mutagen).
169
+
170
+ Files already on the iPod are skipped, so you can safely re-point `add` at an
171
+ overlapping set — e.g. add a single, then later add the whole album folder
172
+ that contains it, and only the new tracks are copied. A track is considered a
173
+ duplicate when its size, duration, and title all match one already present
174
+ (this also de-duplicates within a single batch). Re-encoded or re-tagged
175
+ copies have a different size and are added as new.
176
+
177
+ ```
178
+ $ flashpod add ~/music/Some\ Album # a directory
179
+ $ flashpod add a.mp3 b.mp3 ~/music/More/ # mix files and directories
180
+ $ flashpod add # no args: prompts, with tab completion
181
+ ```
182
+
183
+ Progress is one line per track, shown in a scrolling 4-line window so a big
184
+ batch doesn't flood the terminal history (when output is piped or redirected,
185
+ every line is printed instead). Skips and failures stay visible above the
186
+ window, are counted in the summary, and don't stop the batch:
187
+
188
+ ```
189
+ [3/14] skipping ._cover.mp3: not a recognized audio file
190
+ [4/14] skipping 01 Come Together.mp3: already on iPod
191
+ [11/14] Adding: Pet Cemetery — Relic Pop... ⌝
192
+ [12/14] Adding: Rarely Seen Violence — Relic Pop... | last 4 only;
193
+ [13/14] Adding: Sister Sky — Relic Pop... | older lines scroll away
194
+ [14/14] Adding: Thick as Thieves — Relic Pop... ⌟
195
+ 12 tracks added, 1 skipped (already on iPod), 1 failed in 1m02s
196
+ ```
197
+
198
+ > **Adding over FireWire is slow** (~270 KiB/s — a hardware limit of these early
199
+ > bridges, not something a setting can fix). For **bulk** loads, pull the card
200
+ > into a USB reader and `add` over the normal mount — USB bypasses the bridge
201
+ > and is far faster. Keep the raw FireWire path for quick incremental edits.
202
+
203
+ ### `flashpod rm`
204
+
205
+ ```
206
+ $ flashpod rm 52 53 # by track id (see `flashpod ls all`)
207
+ $ flashpod rm artist Relic Pop # every track by the artist
208
+ $ flashpod rm album Thick As Thieves # every track in the album
209
+ ```
210
+
211
+ Artist/album matching is case-insensitive exact match; multiword names need
212
+ no quotes. `remove`, `delete`, and `erase` all work as synonyms for `rm`.
213
+ **Removal is immediate — there is no confirmation prompt.**
214
+
215
+ ### `flashpod init [name]`
216
+
217
+ Create the `iPod_Control` directory structure and an empty music database.
218
+ Use on a freshly flashed/formatted card or after a wipe. Destroys any
219
+ existing database, but not music files already in the `F##` folders.
220
+
221
+ ### `flashpod flash [/dev/sdX]`
222
+
223
+ Write the iPod firmware and partition layout to a CF/SD card. **Erases the
224
+ card.** Needs root (`sudo flashpod flash`).
225
+
226
+ ```
227
+ $ sudo flashpod flash # interactive: pick from removable disks
228
+ $ sudo flashpod flash /dev/sdb # direct
229
+ $ flashpod flash /dev/sdb --dry-run # print the plan, write nothing (no root)
230
+ $ flashpod flash --self-test # validate layout logic, no hardware
231
+ ```
232
+
233
+ **Firmware:** with no `--firmware`, an interactive chooser lists the images
234
+ from the bundled catalog (`flashpod/firmware/firmware.json`) by iPod
235
+ generation, version, and description (the default entry is preselected;
236
+ non-interactive runs use it outright). The chosen `.ipsw` is then **downloaded
237
+ from GitHub**, cached under `~/.cache/flashpod/`, and **verified against its
238
+ SHA-256** before use; later flashes reuse the cached copy (no network). The
239
+ images aren't bundled with flashpod — they're Apple's copyright, hosted as
240
+ [release assets](https://github.com/davidbarnhart/flashpod/releases/tag/firmware).
241
+
242
+ To use a firmware flashpod doesn't host (or to work fully offline), download
243
+ an `.ipsw` yourself and pass it with `--firmware <file>` — that path never
244
+ touches the network. To add an image to the catalog, upload it to the firmware
245
+ release and add a manifest entry (`file`, `url`/`base_url`, `sha256`,
246
+ `generation`, `version`, `description`).
247
+
248
+ Options:
249
+
250
+ | Flag | Meaning |
251
+ |------|---------|
252
+ | `--firmware <file>` | use a local `.ipsw` (bring-your-own; no download). Default: pick from the catalog and download it |
253
+ | `--yes` | skip the typed `ERASE sdX` confirmation |
254
+ | `--no-format` | don't format the data partition |
255
+ | `--dry-run` | show the plan only |
256
+ | `--self-test` | check layout-building logic and exit |
257
+
258
+ Safety: only removable/USB disks are offered, the disk backing the running
259
+ system is always refused, partition nodes (`/dev/sdb1`) are rejected, the
260
+ target is unmounted first, and an explicit typed confirmation is required.
261
+ After writing, the firmware region is read back and compared byte-for-byte
262
+ before the card is ejected. Cards larger than 128 GiB are capped at the
263
+ iPod's LBA28 addressing limit.
264
+
265
+ After a successful interactive flash, flashpod offers to run init on the new
266
+ card right away, and after that to load music onto it too — answer Y (the
267
+ default) to both and the card comes out of the flash step ready to play. The
268
+ offers are skipped for `--dry-run`, `--no-format`, and non-interactive runs.
269
+
270
+
271
+ ## Notes
272
+
273
+ - Close Rhythmbox before syncing/ejecting — its libgpod plugin grabs the
274
+ iPod mount and blocks unmount.
275
+ - A batch `flashpod add` writes the database **once**, at the end — not per
276
+ track. If a batch is interrupted, you may be left with orphaned music files
277
+ but an unchanged database; just re-run the same `add` (files already present
278
+ are skipped).
279
+ - Don't trust `fsck.vfat` on iPod cards: dosfstools chokes on iPod boot
280
+ sectors that the kernel mounts fine.
281
+
282
+ ## License
283
+
284
+ flashpod is released under the [MIT License](LICENSE). The firmware `.ipsw`
285
+ images that `flashpod flash` downloads are Apple's copyright, not covered by
286
+ that license and not part of this source tree — they are hosted separately for
287
+ convenience, and you may supply your own instead.
@@ -0,0 +1,7 @@
1
+ """flashpod — command-line iPod sync + card-flashing tooling for early
2
+ (1st/2nd/3rd-generation, FireWire-era) iPods.
3
+
4
+ Pure Python, no libgpod. See the README for usage.
5
+ """
6
+
7
+ __version__ = "0.1.5"
@@ -0,0 +1,8 @@
1
+ """Entry point for `python -m flashpod`."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())