ipodsync 0.1.8__tar.gz → 0.1.10__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.
- {ipodsync-0.1.8 → ipodsync-0.1.10}/PKG-INFO +5 -3
- {ipodsync-0.1.8 → ipodsync-0.1.10}/README.md +4 -2
- {ipodsync-0.1.8 → ipodsync-0.1.10}/pyproject.toml +1 -1
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/__init__.py +1 -1
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/cli.py +25 -6
- {ipodsync-0.1.8 → ipodsync-0.1.10}/.github/workflows/ci.yml +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/.github/workflows/publish.yml +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/.gitignore +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/LICENSE +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/__main__.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_art_templates.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_hashab_gen.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_hashab_gen2.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_hashab_gen_rt.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_hashab_py.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_hashab_tables.bin +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_hashab_tables.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/_lib_templates.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/artwork_writer.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/cbk.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/export.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/hashab.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/importer.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/library.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/models.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/sysinfo.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/src/ipodsync/transport.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/data/ArtworkDB +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/data/Locations.itdb +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/data/Locations.itdb.cbk +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/data/hashab-traces.json +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/data/hashab-vectors.json +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/test_artwork_compact.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/test_artwork_writer.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/test_cbk.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/test_gc_orphans.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/test_hashab.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tests/test_hashab_port.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tools/build_gen2.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tools/gen_art_templates.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tools/gen_hashab_tables.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tools/gen_lib_templates.py +0 -0
- {ipodsync-0.1.8 → ipodsync-0.1.10}/tools/transpile_hashab.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipodsync
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.10
|
|
4
4
|
Summary: Upload music to an iPod nano 6G/7G without iTunes: SQLite library, hashAB signing, cover art (pure-Python).
|
|
5
5
|
Project-URL: Homepage, https://github.com/buldiei/ipodsync
|
|
6
6
|
Project-URL: Repository, https://github.com/buldiei/ipodsync
|
|
@@ -97,9 +97,11 @@ ipodsync add "Song.mp3" # + cover auto
|
|
|
97
97
|
ipodsync add a.mp3 b.mp3 c.mp3 # several at once (one library write)
|
|
98
98
|
ipodsync add -f ~/Music/album # a whole folder (recursively)
|
|
99
99
|
ipodsync add "Song.mp3" --no-cover
|
|
100
|
-
ipodsync export ~/Music/ipod --by-album
|
|
100
|
+
ipodsync export ~/Music/ipod --by-album # download everything, in Artist/Album/ folders
|
|
101
|
+
ipodsync export ~/Music/ipod --album "Breakdown" # download one album (or --artist NAME / --pid PID)
|
|
101
102
|
ipodsync cover 123456789 --image cover.jpg
|
|
102
|
-
ipodsync rm 123456789
|
|
103
|
+
ipodsync rm 123456789 # removes the track and its audio file
|
|
104
|
+
ipodsync rm 123456789 --keep-file # …but leave the audio file on the iPod
|
|
103
105
|
ipodsync -b add "Song.mp3" # -b: back up the library first (off by default)
|
|
104
106
|
```
|
|
105
107
|
|
|
@@ -65,9 +65,11 @@ ipodsync add "Song.mp3" # + cover auto
|
|
|
65
65
|
ipodsync add a.mp3 b.mp3 c.mp3 # several at once (one library write)
|
|
66
66
|
ipodsync add -f ~/Music/album # a whole folder (recursively)
|
|
67
67
|
ipodsync add "Song.mp3" --no-cover
|
|
68
|
-
ipodsync export ~/Music/ipod --by-album
|
|
68
|
+
ipodsync export ~/Music/ipod --by-album # download everything, in Artist/Album/ folders
|
|
69
|
+
ipodsync export ~/Music/ipod --album "Breakdown" # download one album (or --artist NAME / --pid PID)
|
|
69
70
|
ipodsync cover 123456789 --image cover.jpg
|
|
70
|
-
ipodsync rm 123456789
|
|
71
|
+
ipodsync rm 123456789 # removes the track and its audio file
|
|
72
|
+
ipodsync rm 123456789 --keep-file # …but leave the audio file on the iPod
|
|
71
73
|
ipodsync -b add "Song.mp3" # -b: back up the library first (off by default)
|
|
72
74
|
```
|
|
73
75
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ipodsync"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.10"
|
|
8
8
|
description = "Upload music to an iPod nano 6G/7G without iTunes: SQLite library, hashAB signing, cover art (pure-Python)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
ipodsync list # show tracks
|
|
4
4
|
ipodsync export DEST [--by-album] [--no-tag] # download everything from the iPod
|
|
5
|
-
ipodsync export DEST --
|
|
5
|
+
ipodsync export DEST --album NAME # download one album (--artist / --pid also filter)
|
|
6
6
|
ipodsync add FILE [--no-cover] # upload a track (+cover auto)
|
|
7
|
-
ipodsync rm PID [--
|
|
7
|
+
ipodsync rm PID [--keep-file] # remove a track + its file (+resign)
|
|
8
8
|
ipodsync cover PID [--image IMG] # attach a cover to a track
|
|
9
9
|
|
|
10
10
|
Export is read-only. add/rm/cover write to the database; pass -b to back the library
|
|
@@ -54,6 +54,17 @@ def cmd_export(ipod, args):
|
|
|
54
54
|
tracks = lib.list_tracks()
|
|
55
55
|
if args.pid is not None:
|
|
56
56
|
tracks = [t for t in tracks if t["pid"] == args.pid]
|
|
57
|
+
if args.album:
|
|
58
|
+
q = args.album.casefold()
|
|
59
|
+
tracks = [t for t in tracks if q in (t["album"] or "").casefold()]
|
|
60
|
+
if args.artist:
|
|
61
|
+
q = args.artist.casefold()
|
|
62
|
+
tracks = [t for t in tracks if q in (t["artist"] or "").casefold()]
|
|
63
|
+
if not tracks:
|
|
64
|
+
filt = ", ".join(f"{k}={v!r}" for k, v in
|
|
65
|
+
(("pid", args.pid), ("album", args.album), ("artist", args.artist)) if v)
|
|
66
|
+
print(f"⚠️ no tracks match ({filt or 'empty library'}). Try `ipodsync list`.")
|
|
67
|
+
lib.close(); return
|
|
57
68
|
dest = Path(args.dest)
|
|
58
69
|
layout = "artist_album" if args.by_album else "flat"
|
|
59
70
|
ok = 0
|
|
@@ -79,9 +90,12 @@ def cmd_rm(ipod, args):
|
|
|
79
90
|
if args.backup:
|
|
80
91
|
_backup_artwork(ipod, stamp)
|
|
81
92
|
|
|
93
|
+
if args.delete_file: # deprecated: deleting the file is the default now
|
|
94
|
+
print(" note: --delete-file is now the default; drop it, or use --keep-file to keep the file.")
|
|
95
|
+
|
|
82
96
|
guid = read_firewire_guid(ipod.sysinfo_extended, ipod.sysinfo, mount=ipod.root)
|
|
83
97
|
lib = ItlpLibrary(itlp)
|
|
84
|
-
music =
|
|
98
|
+
music = None if args.keep_file else ipod.music_dir # delete the file unless --keep-file
|
|
85
99
|
lib.remove_track(args.pid, music_dir=music)
|
|
86
100
|
lib.resign(guid)
|
|
87
101
|
live = {t["pid"] for t in lib.list_tracks()} # remaining tracks, after removal
|
|
@@ -90,8 +104,8 @@ def cmd_rm(ipod, args):
|
|
|
90
104
|
# drop the removed track's thumbnails from ArtworkDB + repack the .ithmb files
|
|
91
105
|
stats = compact(ipod.control / "Artwork", live)
|
|
92
106
|
|
|
93
|
-
|
|
94
|
-
|
|
107
|
+
tail = " (kept the audio file)" if args.keep_file else " (+ deleted the file)"
|
|
108
|
+
print(f"✓ Removed track pid {args.pid}{tail}. Eject the iPod.")
|
|
95
109
|
if stats["removed"]:
|
|
96
110
|
print(f" Reclaimed cover art for {stats['removed']} track"
|
|
97
111
|
f"{'s' if stats['removed'] != 1 else ''}.")
|
|
@@ -330,12 +344,17 @@ def main() -> int:
|
|
|
330
344
|
pe = sub.add_parser("export", help="download tracks from the iPod (read-only)")
|
|
331
345
|
pe.add_argument("dest", help="destination directory")
|
|
332
346
|
pe.add_argument("--pid", type=int, help="export only this track (by pid)")
|
|
347
|
+
pe.add_argument("--album", help="only tracks whose album contains this (case-insensitive)")
|
|
348
|
+
pe.add_argument("--artist", help="only tracks whose artist contains this (case-insensitive)")
|
|
333
349
|
pe.add_argument("--by-album", action="store_true", help="lay out as Artist/Album/")
|
|
334
350
|
pe.add_argument("--no-tag", action="store_true", help="don't write ID3/MP4 tags")
|
|
335
351
|
|
|
336
352
|
pr = sub.add_parser("rm", help="remove a track from the iPod")
|
|
337
353
|
pr.add_argument("pid", type=int, help="track pid (see `list`)")
|
|
338
|
-
pr.add_argument("--
|
|
354
|
+
pr.add_argument("--keep-file", action="store_true",
|
|
355
|
+
help="keep the audio file on the iPod (default: delete it too)")
|
|
356
|
+
pr.add_argument("--delete-file", action="store_true",
|
|
357
|
+
help=argparse.SUPPRESS) # deprecated: deletion is the default now
|
|
339
358
|
|
|
340
359
|
pa = sub.add_parser("add", help="upload a track (or a whole folder); cover attached automatically")
|
|
341
360
|
pa.add_argument("file", nargs="*", help="path(s) to the audio file(s) to upload")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|