pypodlib 0.1.0__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.
Files changed (184) hide show
  1. pypodlib-0.1.0/.gitignore +29 -0
  2. pypodlib-0.1.0/LICENSE +26 -0
  3. pypodlib-0.1.0/PKG-INFO +124 -0
  4. pypodlib-0.1.0/README.md +94 -0
  5. pypodlib-0.1.0/pyproject.toml +85 -0
  6. pypodlib-0.1.0/src/pypodlib/__init__.py +45 -0
  7. pypodlib-0.1.0/src/pypodlib/api.py +939 -0
  8. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/__init__.py +3 -0
  9. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/chunk_parser.py +66 -0
  10. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/constants.py +11 -0
  11. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/mhfd_parser.py +61 -0
  12. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/mhii_parser.py +60 -0
  13. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/mhli_parser.py +16 -0
  14. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/mhni_parser.py +47 -0
  15. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/mhod_parser.py +59 -0
  16. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/mhsd_parser.py +16 -0
  17. pypodlib-0.1.0/src/pypodlib/artworkdb_parser/parser.py +15 -0
  18. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/__init__.py +2 -0
  19. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/binary.py +66 -0
  20. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/constants.py +72 -0
  21. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/ithmb_paths.py +27 -0
  22. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/mhlf.py +47 -0
  23. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/mhni.py +184 -0
  24. pypodlib-0.1.0/src/pypodlib/artworkdb_shared/mhod.py +72 -0
  25. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/__init__.py +77 -0
  26. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/art_extractor.py +319 -0
  27. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/artwork_types.py +115 -0
  28. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/artwork_writer.py +1482 -0
  29. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/artworkdb_chunks.py +475 -0
  30. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/ithmb_codecs.py +723 -0
  31. pypodlib-0.1.0/src/pypodlib/artworkdb_writer/rgb565.py +227 -0
  32. pypodlib-0.1.0/src/pypodlib/device/__init__.py +158 -0
  33. pypodlib-0.1.0/src/pypodlib/device/artwork.py +184 -0
  34. pypodlib-0.1.0/src/pypodlib/device/artwork_presets.py +119 -0
  35. pypodlib-0.1.0/src/pypodlib/device/authority.py +764 -0
  36. pypodlib-0.1.0/src/pypodlib/device/bootstrap.py +210 -0
  37. pypodlib-0.1.0/src/pypodlib/device/capabilities.py +737 -0
  38. pypodlib-0.1.0/src/pypodlib/device/checksum.py +41 -0
  39. pypodlib-0.1.0/src/pypodlib/device/diagnostic_log.py +180 -0
  40. pypodlib-0.1.0/src/pypodlib/device/dump.py +496 -0
  41. pypodlib-0.1.0/src/pypodlib/device/durability.py +431 -0
  42. pypodlib-0.1.0/src/pypodlib/device/eject.py +1153 -0
  43. pypodlib-0.1.0/src/pypodlib/device/filesystem.py +181 -0
  44. pypodlib-0.1.0/src/pypodlib/device/filesystem_profile.py +633 -0
  45. pypodlib-0.1.0/src/pypodlib/device/images.py +409 -0
  46. pypodlib-0.1.0/src/pypodlib/device/info.py +2752 -0
  47. pypodlib-0.1.0/src/pypodlib/device/linux_identity.py +557 -0
  48. pypodlib-0.1.0/src/pypodlib/device/linux_integration.py +370 -0
  49. pypodlib-0.1.0/src/pypodlib/device/lookup.py +204 -0
  50. pypodlib-0.1.0/src/pypodlib/device/metadata_write.py +201 -0
  51. pypodlib-0.1.0/src/pypodlib/device/models.py +715 -0
  52. pypodlib-0.1.0/src/pypodlib/device/path_safety.py +140 -0
  53. pypodlib-0.1.0/src/pypodlib/device/recovery.py +147 -0
  54. pypodlib-0.1.0/src/pypodlib/device/scanner.py +2653 -0
  55. pypodlib-0.1.0/src/pypodlib/device/storage_safety.py +104 -0
  56. pypodlib-0.1.0/src/pypodlib/device/sysinfo.py +528 -0
  57. pypodlib-0.1.0/src/pypodlib/device/usb_backend.py +132 -0
  58. pypodlib-0.1.0/src/pypodlib/device/virtual.py +490 -0
  59. pypodlib-0.1.0/src/pypodlib/device/virtual_identity.py +50 -0
  60. pypodlib-0.1.0/src/pypodlib/device/vpd_iokit.py +617 -0
  61. pypodlib-0.1.0/src/pypodlib/device/vpd_libusb.py +1464 -0
  62. pypodlib-0.1.0/src/pypodlib/device/vpd_linux.py +256 -0
  63. pypodlib-0.1.0/src/pypodlib/device/vpd_usb_control.py +211 -0
  64. pypodlib-0.1.0/src/pypodlib/device/vpd_windows.py +311 -0
  65. pypodlib-0.1.0/src/pypodlib/device/write_guard.py +553 -0
  66. pypodlib-0.1.0/src/pypodlib/device/write_readiness.py +208 -0
  67. pypodlib-0.1.0/src/pypodlib/infrastructure/__init__.py +1 -0
  68. pypodlib-0.1.0/src/pypodlib/infrastructure/media_folders.py +180 -0
  69. pypodlib-0.1.0/src/pypodlib/infrastructure/settings_paths.py +83 -0
  70. pypodlib-0.1.0/src/pypodlib/infrastructure/settings_persistence.py +135 -0
  71. pypodlib-0.1.0/src/pypodlib/infrastructure/settings_runtime.py +526 -0
  72. pypodlib-0.1.0/src/pypodlib/infrastructure/settings_schema.py +345 -0
  73. pypodlib-0.1.0/src/pypodlib/infrastructure/settings_secrets.py +127 -0
  74. pypodlib-0.1.0/src/pypodlib/infrastructure/theme_catalog.py +371 -0
  75. pypodlib-0.1.0/src/pypodlib/infrastructure/theme_renderer.py +1109 -0
  76. pypodlib-0.1.0/src/pypodlib/infrastructure/theme_runtime.py +28 -0
  77. pypodlib-0.1.0/src/pypodlib/infrastructure/version.py +18 -0
  78. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/__init__.py +22 -0
  79. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/_parsing.py +120 -0
  80. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/artwork_links.py +108 -0
  81. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/byte_walk.py +586 -0
  82. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/chunk_parser.py +203 -0
  83. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/exceptions.py +59 -0
  84. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/forensics.py +851 -0
  85. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/ipod_library.py +174 -0
  86. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhbd_parser.py +43 -0
  87. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhia_parser.py +31 -0
  88. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhii_parser.py +34 -0
  89. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhip_parser.py +31 -0
  90. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhit_parser.py +34 -0
  91. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhod_parser.py +674 -0
  92. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhsd_parser.py +48 -0
  93. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/mhyp_parser.py +50 -0
  94. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/otg.py +187 -0
  95. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/parser.py +140 -0
  96. pypodlib-0.1.0/src/pypodlib/itunesdb_parser/playcounts.py +282 -0
  97. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/__init__.py +32 -0
  98. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/album_identity.py +93 -0
  99. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/constants.py +393 -0
  100. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/device_time.py +250 -0
  101. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/extraction.py +173 -0
  102. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/field_base.py +478 -0
  103. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhbd_defs.py +57 -0
  104. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhia_defs.py +39 -0
  105. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhii_defs.py +18 -0
  106. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhip_defs.py +33 -0
  107. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhit_defs.py +237 -0
  108. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhod_defs.py +811 -0
  109. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhsd_defs.py +15 -0
  110. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/mhyp_defs.py +58 -0
  111. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/playlist_hierarchy.py +285 -0
  112. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/playlist_kinds.py +41 -0
  113. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/playlist_lifecycle.py +55 -0
  114. pypodlib-0.1.0/src/pypodlib/itunesdb_shared/playlist_properties.py +193 -0
  115. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/__init__.py +146 -0
  116. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/hash58.py +279 -0
  117. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/hash72.py +496 -0
  118. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/hashab.py +290 -0
  119. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhbd_writer.py +1588 -0
  120. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhip_writer.py +150 -0
  121. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhit_writer.py +511 -0
  122. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhla_writer.py +211 -0
  123. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhli_writer.py +141 -0
  124. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhlp_writer.py +261 -0
  125. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhlt_writer.py +52 -0
  126. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhod52_writer.py +344 -0
  127. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhod_spl_writer.py +448 -0
  128. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhod_writer.py +589 -0
  129. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhsd_writer.py +98 -0
  130. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/mhyp_writer.py +641 -0
  131. pypodlib-0.1.0/src/pypodlib/itunesdb_writer/wasm/calcHashAB.wasm +0 -0
  132. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/__init__.py +21 -0
  133. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/_helpers.py +62 -0
  134. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/cbk_writer.py +183 -0
  135. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/dynamic_writer.py +123 -0
  136. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/extras_writer.py +84 -0
  137. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/genius_writer.py +56 -0
  138. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/library_writer.py +1187 -0
  139. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/locations_writer.py +145 -0
  140. pypodlib-0.1.0/src/pypodlib/sqlitedb_writer/sqlite_writer.py +310 -0
  141. pypodlib-0.1.0/src/pypodlib/sync/__init__.py +182 -0
  142. pypodlib-0.1.0/src/pypodlib/sync/_db_io.py +580 -0
  143. pypodlib-0.1.0/src/pypodlib/sync/_formats.py +79 -0
  144. pypodlib-0.1.0/src/pypodlib/sync/_playlist_builder.py +645 -0
  145. pypodlib-0.1.0/src/pypodlib/sync/_track_conversion.py +462 -0
  146. pypodlib-0.1.0/src/pypodlib/sync/album_chapters.py +1185 -0
  147. pypodlib-0.1.0/src/pypodlib/sync/audio_fingerprint.py +517 -0
  148. pypodlib-0.1.0/src/pypodlib/sync/backup_manager.py +3762 -0
  149. pypodlib-0.1.0/src/pypodlib/sync/capability_filter.py +61 -0
  150. pypodlib-0.1.0/src/pypodlib/sync/contracts.py +601 -0
  151. pypodlib-0.1.0/src/pypodlib/sync/core/__init__.py +27 -0
  152. pypodlib-0.1.0/src/pypodlib/sync/core/context.py +115 -0
  153. pypodlib-0.1.0/src/pypodlib/sync/core/engine.py +283 -0
  154. pypodlib-0.1.0/src/pypodlib/sync/core/models.py +141 -0
  155. pypodlib-0.1.0/src/pypodlib/sync/database_commit.py +251 -0
  156. pypodlib-0.1.0/src/pypodlib/sync/dependency_manager.py +352 -0
  157. pypodlib-0.1.0/src/pypodlib/sync/existing_track_matcher.py +268 -0
  158. pypodlib-0.1.0/src/pypodlib/sync/fingerprint_diff_engine.py +2132 -0
  159. pypodlib-0.1.0/src/pypodlib/sync/integrity.py +333 -0
  160. pypodlib-0.1.0/src/pypodlib/sync/ipod_track_paths.py +272 -0
  161. pypodlib-0.1.0/src/pypodlib/sync/itunes_prefs.py +666 -0
  162. pypodlib-0.1.0/src/pypodlib/sync/lastfm_scrobbler.py +482 -0
  163. pypodlib-0.1.0/src/pypodlib/sync/lb_scrobbler.py +583 -0
  164. pypodlib-0.1.0/src/pypodlib/sync/mapping.py +604 -0
  165. pypodlib-0.1.0/src/pypodlib/sync/path_identity.py +34 -0
  166. pypodlib-0.1.0/src/pypodlib/sync/pc_library.py +1770 -0
  167. pypodlib-0.1.0/src/pypodlib/sync/photos.py +2706 -0
  168. pypodlib-0.1.0/src/pypodlib/sync/plan_validator.py +595 -0
  169. pypodlib-0.1.0/src/pypodlib/sync/planning_stages.py +229 -0
  170. pypodlib-0.1.0/src/pypodlib/sync/playlist_parser.py +355 -0
  171. pypodlib-0.1.0/src/pypodlib/sync/quick_writes.py +384 -0
  172. pypodlib-0.1.0/src/pypodlib/sync/review_selection.py +254 -0
  173. pypodlib-0.1.0/src/pypodlib/sync/rockbox_metadata.py +1341 -0
  174. pypodlib-0.1.0/src/pypodlib/sync/scrobble_plan.py +43 -0
  175. pypodlib-0.1.0/src/pypodlib/sync/source_identity.py +255 -0
  176. pypodlib-0.1.0/src/pypodlib/sync/spl_evaluator.py +571 -0
  177. pypodlib-0.1.0/src/pypodlib/sync/sync_executor.py +4673 -0
  178. pypodlib-0.1.0/src/pypodlib/sync/sync_playlist_files.py +191 -0
  179. pypodlib-0.1.0/src/pypodlib/sync/sync_playlist_planner.py +204 -0
  180. pypodlib-0.1.0/src/pypodlib/sync/track_identity.py +194 -0
  181. pypodlib-0.1.0/src/pypodlib/sync/transcode_cache.py +829 -0
  182. pypodlib-0.1.0/src/pypodlib/sync/transcoder.py +2292 -0
  183. pypodlib-0.1.0/src/pypodlib/sync/unknown_metadata.py +307 -0
  184. pypodlib-0.1.0/src/pypodlib/sync_progress_stages.py +295 -0
@@ -0,0 +1,29 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+
9
+ # MkDocs build output
10
+ site/
11
+
12
+ # Virtual environments
13
+ .venv/
14
+ venv/
15
+
16
+ # Tooling
17
+ .pytest_cache/
18
+ .mypy_cache/
19
+ .ruff_cache/
20
+ .coverage
21
+ htmlcov/
22
+
23
+ # Editor / OS
24
+ .idea/
25
+ .vscode/
26
+ .DS_Store
27
+
28
+ # Local build/install flags
29
+ *.local
pypodlib-0.1.0/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pyPodLib contributors
4
+
5
+ pyPodLib is derived from the iOpenPod project
6
+ (https://github.com/TheRealSavi/iOpenPod), Copyright (c) John Gibbons,
7
+ licensed under the MIT License, which grants permission to copy, modify,
8
+ merge, publish, distribute, sublicense, and/or sell copies of the Software.
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.5
2
+ Name: pypodlib
3
+ Version: 0.1.0
4
+ Summary: Communicate with iPod Classic/Nano/Mini devices — detect and identify the device, read and write the iTunesDB library, and sync media — without iTunes.
5
+ Project-URL: Homepage, https://la22e.github.io/pyPodLib/
6
+ Project-URL: Repository, https://github.com/La22e/pyPodLib
7
+ Author: La22e
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: ipod,ipod-classic,ipod-manager,ipod-sync,itunes,itunes-alternative,itunesdb,music-library,music-sync
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Multimedia :: Sound/Audio
19
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Players
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: libusb-package>=1.0.30.0
22
+ Requires-Dist: pycryptodome>=3.20.0
23
+ Requires-Dist: pyusb>=1.3.1
24
+ Requires-Dist: wasmtime>=30.0.0
25
+ Provides-Extra: artwork
26
+ Requires-Dist: mutagen>=1.47.0; extra == 'artwork'
27
+ Requires-Dist: numpy>=2.0.0; extra == 'artwork'
28
+ Requires-Dist: pillow>=10.0.0; extra == 'artwork'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # pyPodLib
32
+
33
+ Read, write, and sync iPod Classic/Nano/Mini libraries from Python — no
34
+ iTunes required.
35
+
36
+ pyPodLib is a pure-Python library extracted from
37
+ [iOpenPod](https://github.com/TheRealSavi/iOpenPod) (MIT, © John Gibbons).
38
+ It keeps the battle-tested iTunesDB / iTunesCDB parsing and writing engine,
39
+ device detection, and sync logic, and exposes it as a headless library.
40
+
41
+ ## Features
42
+
43
+ - **Device detection** — scan for connected iPods and identify model,
44
+ generation, capacity, colour, serial, and checksum type (`scan_ipods`,
45
+ `identify_ipod_at_path`).
46
+ - **Read** — parse the full library: tracks, user playlists, podcast
47
+ playlists, smart playlists (dataset 2/3/5), play counts, artwork refs.
48
+ - **Write** — save edits back with the correct per-device signature
49
+ (HASH58 via FireWire GUID, HASH72 via AES, HASHAB via WebAssembly,
50
+ NONE for pre-2007 devices), plus SQLite DBs for Nano 6G/7G and
51
+ iTunesPrefs protection.
52
+ - **Sync** — plan and execute media sync, with optional artwork and
53
+ transcode support.
54
+ - **Testable without hardware** — create "virtual iPods" (a folder
55
+ identity + seeded database) for round-trip tests
56
+ (`pypodlib.device.create_virtual_ipod`).
57
+
58
+ ## Install
59
+
60
+ ```console
61
+ pip install pypodlib # core (device + library read/write)
62
+ pip install 'pypodlib[artwork]' # + embedded-art extraction/encoding
63
+ ```
64
+
65
+ Runtime dependencies: `pyusb` / `libusb-package` (USB identification),
66
+ `pycryptodome` (HASH72 signing), `wasmtime` (HASHAB signing).
67
+
68
+ ## Documentation
69
+
70
+ Full documentation: [la22e.github.io/pyPodLib](https://la22e.github.io/pyPodLib/)
71
+
72
+ ## Quick start
73
+
74
+ ```python
75
+ import pypodlib
76
+
77
+ ipod = pypodlib.connect("/media/user/IPOD") # or pypodlib.scan_ipods()[0]
78
+ print(ipod.model_number, ipod.generation, ipod.capacity)
79
+
80
+ lib = ipod.library()
81
+ print(len(lib.tracks), "tracks")
82
+
83
+ track = lib.tracks[0]
84
+ track.title = "New Title"
85
+ track.rating = 80 # 4 stars
86
+ ipod.save() # writes iTunesDB + signature
87
+ ```
88
+
89
+ ### Low-level access
90
+
91
+ Every layer stays importable:
92
+
93
+ ```python
94
+ from pypodlib.device import scan_for_ipods, identify_ipod_at_path
95
+ from pypodlib.itunesdb_parser import parse_itunesdb, load_ipod_library
96
+ from pypodlib.itunesdb_writer import write_itunesdb, detect_checksum_type
97
+ from pypodlib.sync._db_io import read_existing_database, write_database
98
+ ```
99
+
100
+ ### Virtual iPods (no hardware)
101
+
102
+ ```python
103
+ from pypodlib.device import create_virtual_ipod, available_virtual_ipod_models
104
+
105
+ import tempfile
106
+ root = tempfile.mkdtemp()
107
+ info = create_virtual_ipod(root, "MC297") # iPod Classic 7th Gen (HASH58)
108
+ ipod = pypodlib.connect(root)
109
+ ipod.library()
110
+ ipod.save() # round-trips through real writer
111
+ ```
112
+
113
+ ## Limitations
114
+
115
+ - Requires a mounted iPod volume (or a virtual iPod root) — USB enumeration
116
+ is used for identification only.
117
+ - Photo sync and embedded-art encoding need the `artwork` extra
118
+ (`numpy`, `Pillow`, `mutagen`).
119
+ - Video/ffmpeg transcoding requires an `ffmpeg`/`ffprobe` binary.
120
+ - Smart playlists are re-evaluated on save (matching iTunes behaviour).
121
+
122
+ ## License
123
+
124
+ MIT. pyPodLib is derived from iOpenPod (MIT, © John Gibbons).
@@ -0,0 +1,94 @@
1
+ # pyPodLib
2
+
3
+ Read, write, and sync iPod Classic/Nano/Mini libraries from Python — no
4
+ iTunes required.
5
+
6
+ pyPodLib is a pure-Python library extracted from
7
+ [iOpenPod](https://github.com/TheRealSavi/iOpenPod) (MIT, © John Gibbons).
8
+ It keeps the battle-tested iTunesDB / iTunesCDB parsing and writing engine,
9
+ device detection, and sync logic, and exposes it as a headless library.
10
+
11
+ ## Features
12
+
13
+ - **Device detection** — scan for connected iPods and identify model,
14
+ generation, capacity, colour, serial, and checksum type (`scan_ipods`,
15
+ `identify_ipod_at_path`).
16
+ - **Read** — parse the full library: tracks, user playlists, podcast
17
+ playlists, smart playlists (dataset 2/3/5), play counts, artwork refs.
18
+ - **Write** — save edits back with the correct per-device signature
19
+ (HASH58 via FireWire GUID, HASH72 via AES, HASHAB via WebAssembly,
20
+ NONE for pre-2007 devices), plus SQLite DBs for Nano 6G/7G and
21
+ iTunesPrefs protection.
22
+ - **Sync** — plan and execute media sync, with optional artwork and
23
+ transcode support.
24
+ - **Testable without hardware** — create "virtual iPods" (a folder
25
+ identity + seeded database) for round-trip tests
26
+ (`pypodlib.device.create_virtual_ipod`).
27
+
28
+ ## Install
29
+
30
+ ```console
31
+ pip install pypodlib # core (device + library read/write)
32
+ pip install 'pypodlib[artwork]' # + embedded-art extraction/encoding
33
+ ```
34
+
35
+ Runtime dependencies: `pyusb` / `libusb-package` (USB identification),
36
+ `pycryptodome` (HASH72 signing), `wasmtime` (HASHAB signing).
37
+
38
+ ## Documentation
39
+
40
+ Full documentation: [la22e.github.io/pyPodLib](https://la22e.github.io/pyPodLib/)
41
+
42
+ ## Quick start
43
+
44
+ ```python
45
+ import pypodlib
46
+
47
+ ipod = pypodlib.connect("/media/user/IPOD") # or pypodlib.scan_ipods()[0]
48
+ print(ipod.model_number, ipod.generation, ipod.capacity)
49
+
50
+ lib = ipod.library()
51
+ print(len(lib.tracks), "tracks")
52
+
53
+ track = lib.tracks[0]
54
+ track.title = "New Title"
55
+ track.rating = 80 # 4 stars
56
+ ipod.save() # writes iTunesDB + signature
57
+ ```
58
+
59
+ ### Low-level access
60
+
61
+ Every layer stays importable:
62
+
63
+ ```python
64
+ from pypodlib.device import scan_for_ipods, identify_ipod_at_path
65
+ from pypodlib.itunesdb_parser import parse_itunesdb, load_ipod_library
66
+ from pypodlib.itunesdb_writer import write_itunesdb, detect_checksum_type
67
+ from pypodlib.sync._db_io import read_existing_database, write_database
68
+ ```
69
+
70
+ ### Virtual iPods (no hardware)
71
+
72
+ ```python
73
+ from pypodlib.device import create_virtual_ipod, available_virtual_ipod_models
74
+
75
+ import tempfile
76
+ root = tempfile.mkdtemp()
77
+ info = create_virtual_ipod(root, "MC297") # iPod Classic 7th Gen (HASH58)
78
+ ipod = pypodlib.connect(root)
79
+ ipod.library()
80
+ ipod.save() # round-trips through real writer
81
+ ```
82
+
83
+ ## Limitations
84
+
85
+ - Requires a mounted iPod volume (or a virtual iPod root) — USB enumeration
86
+ is used for identification only.
87
+ - Photo sync and embedded-art encoding need the `artwork` extra
88
+ (`numpy`, `Pillow`, `mutagen`).
89
+ - Video/ffmpeg transcoding requires an `ffmpeg`/`ffprobe` binary.
90
+ - Smart playlists are re-evaluated on save (matching iTunes behaviour).
91
+
92
+ ## License
93
+
94
+ MIT. pyPodLib is derived from iOpenPod (MIT, © John Gibbons).
@@ -0,0 +1,85 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pypodlib"
7
+ version = "0.1.0"
8
+ description = "Communicate with iPod Classic/Nano/Mini devices — detect and identify the device, read and write the iTunesDB library, and sync media — without iTunes."
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ {name = "La22e"},
14
+ ]
15
+ keywords = [
16
+ "ipod", "ipod-classic", "itunes", "itunesdb", "music-sync",
17
+ "ipod-manager", "music-library", "ipod-sync", "itunes-alternative",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Developers",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Topic :: Multimedia :: Sound/Audio",
28
+ "Topic :: Multimedia :: Sound/Audio :: Players",
29
+ ]
30
+ dependencies = [
31
+ "pyusb>=1.3.1",
32
+ "libusb-package>=1.0.30.0",
33
+ "pycryptodome>=3.20.0",
34
+ "wasmtime>=30.0.0",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ artwork = [
39
+ "numpy>=2.0.0",
40
+ "pillow>=10.0.0",
41
+ "mutagen>=1.47.0",
42
+ ]
43
+
44
+ [project.urls]
45
+ Homepage = "https://la22e.github.io/pyPodLib/"
46
+ Repository = "https://github.com/La22e/pyPodLib"
47
+
48
+ [dependency-groups]
49
+ dev = [
50
+ "mypy>=1.15.0",
51
+ "pytest>=8.3.5",
52
+ "ruff>=0.11.7",
53
+ "mkdocs>=1.6",
54
+ "mkdocs-material>=9.5",
55
+ "mkdocstrings[python]>=0.28",
56
+ "mkdocs-gen-files",
57
+ "mkdocs-literate-nav",
58
+ "mkdocs-section-index",
59
+ ]
60
+
61
+ [tool.hatch.build.targets.wheel]
62
+ packages = ["src/pypodlib"]
63
+ include = [
64
+ "/src/pypodlib/**/*.py",
65
+ "/src/pypodlib/itunesdb_writer/wasm/calcHashAB.wasm",
66
+ ]
67
+
68
+ [tool.hatch.build.targets.sdist]
69
+ include = [
70
+ "/src",
71
+ "/README.md",
72
+ "/LICENSE",
73
+ ]
74
+
75
+ [tool.pytest.ini_options]
76
+ addopts = "-p no:cacheprovider"
77
+ testpaths = ["tests"]
78
+ pythonpath = ["."]
79
+
80
+ [tool.ruff]
81
+ line-length = 320
82
+ target-version = "py311"
83
+
84
+ [tool.ruff.lint]
85
+ select = ["B", "E", "F", "I", "UP"]
@@ -0,0 +1,45 @@
1
+ """
2
+ pypodlib — communicate with iPod Classic/Nano/Mini devices from Python.
3
+
4
+ pyPodLib is a pure-Python library that reads and writes the iPod's on-disk
5
+ library (iTunesDB / iTunesCDB) without iTunes. It can:
6
+
7
+ - detect and identify a connected iPod (model, generation, capacity, colour)
8
+ - read tracks, playlists, podcasts, smart playlists and play counts
9
+ - write the database back with the correct per-device checksum signature
10
+ - copy media files onto the device and regenerate the database
11
+
12
+ Typical usage::
13
+
14
+ import pypodlib
15
+
16
+ ipod = pypodlib.connect("/media/user/IPOD") # or scan_ipods()[0]
17
+ print(ipod.model.family, ipod.model.generation)
18
+
19
+ lib = ipod.library()
20
+ for track in lib.tracks:
21
+ print(track.title, track.artist)
22
+
23
+ lib.tracks[0].rating = 5
24
+ ipod.save()
25
+
26
+ The low-level modules remain importable directly (``pypodlib.device``,
27
+ ``pypodlib.itunesdb_parser``, ``pypodlib.itunesdb_writer``, ...).
28
+ """
29
+
30
+ from __future__ import annotations
31
+
32
+ from .api import IPod, Library, Playlist, Track, connect, library_from_path, scan_ipods
33
+
34
+ __version__ = "0.1.0"
35
+
36
+ __all__ = [
37
+ "__version__",
38
+ "connect",
39
+ "scan_ipods",
40
+ "library_from_path",
41
+ "IPod",
42
+ "Library",
43
+ "Track",
44
+ "Playlist",
45
+ ]