ipodsync 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 (41) hide show
  1. ipodsync-0.1.0/.github/workflows/ci.yml +22 -0
  2. ipodsync-0.1.0/.github/workflows/publish.yml +35 -0
  3. ipodsync-0.1.0/.gitignore +25 -0
  4. ipodsync-0.1.0/LICENSE +21 -0
  5. ipodsync-0.1.0/PKG-INFO +114 -0
  6. ipodsync-0.1.0/README.md +87 -0
  7. ipodsync-0.1.0/pyproject.toml +48 -0
  8. ipodsync-0.1.0/src/ipodsync/__init__.py +27 -0
  9. ipodsync-0.1.0/src/ipodsync/__main__.py +5 -0
  10. ipodsync-0.1.0/src/ipodsync/_art_templates.py +29 -0
  11. ipodsync-0.1.0/src/ipodsync/_hashab_gen.py +1588 -0
  12. ipodsync-0.1.0/src/ipodsync/_hashab_gen2.py +838 -0
  13. ipodsync-0.1.0/src/ipodsync/_hashab_gen_rt.py +134 -0
  14. ipodsync-0.1.0/src/ipodsync/_hashab_py.py +285 -0
  15. ipodsync-0.1.0/src/ipodsync/_hashab_tables.bin +0 -0
  16. ipodsync-0.1.0/src/ipodsync/_hashab_tables.py +31 -0
  17. ipodsync-0.1.0/src/ipodsync/_lib_templates.py +16 -0
  18. ipodsync-0.1.0/src/ipodsync/artwork_writer.py +252 -0
  19. ipodsync-0.1.0/src/ipodsync/cbk.py +44 -0
  20. ipodsync-0.1.0/src/ipodsync/cli.py +314 -0
  21. ipodsync-0.1.0/src/ipodsync/export.py +91 -0
  22. ipodsync-0.1.0/src/ipodsync/hashab.py +44 -0
  23. ipodsync-0.1.0/src/ipodsync/importer.py +137 -0
  24. ipodsync-0.1.0/src/ipodsync/library.py +360 -0
  25. ipodsync-0.1.0/src/ipodsync/models.py +31 -0
  26. ipodsync-0.1.0/src/ipodsync/sysinfo.py +50 -0
  27. ipodsync-0.1.0/src/ipodsync/transport.py +165 -0
  28. ipodsync-0.1.0/tests/data/ArtworkDB +0 -0
  29. ipodsync-0.1.0/tests/data/Locations.itdb +0 -0
  30. ipodsync-0.1.0/tests/data/Locations.itdb.cbk +0 -0
  31. ipodsync-0.1.0/tests/data/hashab-traces.json +35 -0
  32. ipodsync-0.1.0/tests/data/hashab-vectors.json +502 -0
  33. ipodsync-0.1.0/tests/test_artwork_writer.py +139 -0
  34. ipodsync-0.1.0/tests/test_cbk.py +28 -0
  35. ipodsync-0.1.0/tests/test_hashab.py +16 -0
  36. ipodsync-0.1.0/tests/test_hashab_port.py +75 -0
  37. ipodsync-0.1.0/tools/build_gen2.py +316 -0
  38. ipodsync-0.1.0/tools/gen_art_templates.py +77 -0
  39. ipodsync-0.1.0/tools/gen_hashab_tables.py +62 -0
  40. ipodsync-0.1.0/tools/gen_lib_templates.py +89 -0
  41. ipodsync-0.1.0/tools/transpile_hashab.py +233 -0
@@ -0,0 +1,22 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ os: [macos-latest, ubuntu-latest]
14
+ python: ["3.9", "3.12"]
15
+ runs-on: ${{ matrix.os }}
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python }}
21
+ - run: pip install -e ".[dev]"
22
+ - run: pytest -q
@@ -0,0 +1,35 @@
1
+ name: publish
2
+
3
+ # Build and publish to PyPI on a version tag (vX.Y.Z), using PyPI Trusted
4
+ # Publishing (OIDC) — no API token stored anywhere.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: actions/setup-python@v5
15
+ with:
16
+ python-version: "3.12"
17
+ - run: pip install build
18
+ - run: python -m build
19
+ - uses: actions/upload-artifact@v4
20
+ with:
21
+ name: dist
22
+ path: dist/
23
+
24
+ publish:
25
+ needs: build
26
+ runs-on: ubuntu-latest
27
+ environment: pypi # must match the environment set on the PyPI trusted publisher
28
+ permissions:
29
+ id-token: write # required for OIDC / trusted publishing
30
+ steps:
31
+ - uses: actions/download-artifact@v4
32
+ with:
33
+ name: dist
34
+ path: dist/
35
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,25 @@
1
+ # python
2
+ __pycache__/
3
+ *.pyc
4
+ .venv/
5
+ build/
6
+ dist/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+
10
+ # object files (none expected — pure-Python package)
11
+ *.o
12
+ *.obj
13
+
14
+ # iPod database backups — never commit (personal data)
15
+ *.bak
16
+ ipod-backups/
17
+
18
+ # local-only material (non-English notes, scratch, personal docs)
19
+ local/
20
+
21
+ # editors / IDEs
22
+ .idea/
23
+ .vscode/
24
+
25
+ .DS_Store
ipodsync-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alex Buldiei
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,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: ipodsync
3
+ Version: 0.1.0
4
+ Summary: Upload music to an iPod nano 6G/7G without iTunes: SQLite library, hashAB signing, cover art (pure-Python).
5
+ Project-URL: Homepage, https://github.com/buldiei/ipodsync
6
+ Project-URL: Repository, https://github.com/buldiei/ipodsync
7
+ Project-URL: Issues, https://github.com/buldiei/ipodsync/issues
8
+ Project-URL: LinkedIn, https://www.linkedin.com/in/alex-buldiei-b10a9a150/
9
+ Author-email: Alex Buldiei <abuldiei@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: artwork,ipod,itunes,music,nano,sync
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: End Users/Desktop
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Topic :: Multimedia :: Sound/Audio
21
+ Requires-Python: >=3.9
22
+ Requires-Dist: mutagen>=1.47
23
+ Requires-Dist: pillow>=10.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8.0; extra == 'dev'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # ipodsync
29
+
30
+ [![CI](https://github.com/buldiei/ipodsync/actions/workflows/ci.yml/badge.svg)](https://github.com/buldiei/ipodsync/actions/workflows/ci.yml)
31
+ [![PyPI](https://img.shields.io/pypi/v/ipodsync.svg)](https://pypi.org/project/ipodsync/)
32
+ [![Python](https://img.shields.io/pypi/pyversions/ipodsync.svg)](https://pypi.org/project/ipodsync/)
33
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
34
+
35
+ Upload music to an **iPod nano 6G/7G** without iTunes/Apple Music — straight from
36
+ the terminal, on macOS and Linux. The iPod mounts as a plain volume; `ipodsync`
37
+ edits its SQLite library, signs it (hashAB) and **generates cover art itself**.
38
+
39
+ > ⚠️ Alpha. Works on real hardware, but it writes to the player's binary database.
40
+ > **Keep backups** (the tool makes one before every edit) and don't open this iPod
41
+ > in iTunes.
42
+
43
+ ## Features
44
+
45
+ - `list` / `export` — inspect and download tracks from the device (with tags).
46
+ - `add` — upload an MP3, metadata from tags, **cover art attached automatically**
47
+ (from an embedded APIC/covr): shown both in Now Playing and in list/Albums views.
48
+ - `rm` — remove a track (+file), re-sign.
49
+ - playlists — `playlists` / `pl-create` / `pl-add` / `pl-rm` / `pl-del`.
50
+ - `cover` — attach a cover to an already-uploaded track.
51
+ - works on an **empty (wiped) library** too — no iTunes needed to initialize it.
52
+
53
+ ## Install
54
+
55
+ ```bash
56
+ pipx install ipodsync # recommended (isolated), or: pip install ipodsync
57
+ ```
58
+
59
+ Requires Python ≥ 3.9. Pure-Python — no compiler or native library needed.
60
+
61
+ > Note: uploading currently supports **MP3 only**. FLAC/AAC → ALAC transcoding
62
+ > (which will need `ffmpeg`) is on the roadmap and not implemented yet.
63
+
64
+ ## Usage
65
+
66
+ ```bash
67
+ ipodsync status # ready / no access / not connected
68
+ ipodsync list
69
+ ipodsync add "Song.mp3" # + cover auto
70
+ ipodsync add "Song.mp3" --no-cover
71
+ ipodsync export ~/Music/ipod --by-album
72
+ ipodsync cover 123456789 --image cover.jpg
73
+ ipodsync rm 123456789 --delete-file
74
+ ```
75
+
76
+ The iPod is discovered under `/Volumes` (macOS) and `/media`, `/run/media`, `/mnt`
77
+ (Linux) by the presence of `iPod_Control/`. To point at it explicitly, set
78
+ `IPODSYNC_MOUNT=/path/to/mount`.
79
+
80
+ ## How it works
81
+
82
+ - **Transport** — mass storage: files are written under `iPod_Control/`.
83
+ - **Database** — SQLite `iTunes Library.itlp/*.itdb` (not `iTunesCDB`, which the
84
+ device regenerates on its own). Only `Locations.itdb` is hash-protected (`.cbk`).
85
+ - **hashAB** — anti-tamper `.cbk` signature (white-box AES). **Pure-Python** port of
86
+ [dstaley/hashab](https://github.com/dstaley/hashab) (public domain), 100/100 test
87
+ vectors. No compiler or native lib — the package installs everywhere.
88
+ - **Cover art** — pure-Python writer for `ArtworkDB` + `F<fmt>_1.ithmb` (RGB565 LE,
89
+ formats 1010/1013/1015/1016), appended incrementally.
90
+
91
+ ## Status / roadmap
92
+
93
+ | | Status |
94
+ |---|---|
95
+ | Upload / remove / export / playlists (MP3) | ✅ confirmed on nano 7G |
96
+ | Cover art (pure-Python) | ✅ confirmed on nano 7G |
97
+ | Empty-library bootstrap | ✅ |
98
+ | **Pure-Python hashAB** (no native lib, installs everywhere) | ✅ 100/100 vectors |
99
+ | Cross-platform device discovery (macOS + Linux) | ✅ |
100
+ | FLAC/AAC → ALAC | ⬜ |
101
+
102
+ ## Development
103
+
104
+ ```bash
105
+ git clone … && cd ipodsync
106
+ python -m venv .venv && . .venv/bin/activate
107
+ pip install -e ".[dev]"
108
+ pytest
109
+ ```
110
+
111
+ ## License
112
+
113
+ MIT (see [LICENSE](LICENSE)). The vendored hashAB algorithm is public domain.
114
+ Not affiliated with Apple; iPod and iTunes are trademarks of Apple.
@@ -0,0 +1,87 @@
1
+ # ipodsync
2
+
3
+ [![CI](https://github.com/buldiei/ipodsync/actions/workflows/ci.yml/badge.svg)](https://github.com/buldiei/ipodsync/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/ipodsync.svg)](https://pypi.org/project/ipodsync/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/ipodsync.svg)](https://pypi.org/project/ipodsync/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+
8
+ Upload music to an **iPod nano 6G/7G** without iTunes/Apple Music — straight from
9
+ the terminal, on macOS and Linux. The iPod mounts as a plain volume; `ipodsync`
10
+ edits its SQLite library, signs it (hashAB) and **generates cover art itself**.
11
+
12
+ > ⚠️ Alpha. Works on real hardware, but it writes to the player's binary database.
13
+ > **Keep backups** (the tool makes one before every edit) and don't open this iPod
14
+ > in iTunes.
15
+
16
+ ## Features
17
+
18
+ - `list` / `export` — inspect and download tracks from the device (with tags).
19
+ - `add` — upload an MP3, metadata from tags, **cover art attached automatically**
20
+ (from an embedded APIC/covr): shown both in Now Playing and in list/Albums views.
21
+ - `rm` — remove a track (+file), re-sign.
22
+ - playlists — `playlists` / `pl-create` / `pl-add` / `pl-rm` / `pl-del`.
23
+ - `cover` — attach a cover to an already-uploaded track.
24
+ - works on an **empty (wiped) library** too — no iTunes needed to initialize it.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pipx install ipodsync # recommended (isolated), or: pip install ipodsync
30
+ ```
31
+
32
+ Requires Python ≥ 3.9. Pure-Python — no compiler or native library needed.
33
+
34
+ > Note: uploading currently supports **MP3 only**. FLAC/AAC → ALAC transcoding
35
+ > (which will need `ffmpeg`) is on the roadmap and not implemented yet.
36
+
37
+ ## Usage
38
+
39
+ ```bash
40
+ ipodsync status # ready / no access / not connected
41
+ ipodsync list
42
+ ipodsync add "Song.mp3" # + cover auto
43
+ ipodsync add "Song.mp3" --no-cover
44
+ ipodsync export ~/Music/ipod --by-album
45
+ ipodsync cover 123456789 --image cover.jpg
46
+ ipodsync rm 123456789 --delete-file
47
+ ```
48
+
49
+ The iPod is discovered under `/Volumes` (macOS) and `/media`, `/run/media`, `/mnt`
50
+ (Linux) by the presence of `iPod_Control/`. To point at it explicitly, set
51
+ `IPODSYNC_MOUNT=/path/to/mount`.
52
+
53
+ ## How it works
54
+
55
+ - **Transport** — mass storage: files are written under `iPod_Control/`.
56
+ - **Database** — SQLite `iTunes Library.itlp/*.itdb` (not `iTunesCDB`, which the
57
+ device regenerates on its own). Only `Locations.itdb` is hash-protected (`.cbk`).
58
+ - **hashAB** — anti-tamper `.cbk` signature (white-box AES). **Pure-Python** port of
59
+ [dstaley/hashab](https://github.com/dstaley/hashab) (public domain), 100/100 test
60
+ vectors. No compiler or native lib — the package installs everywhere.
61
+ - **Cover art** — pure-Python writer for `ArtworkDB` + `F<fmt>_1.ithmb` (RGB565 LE,
62
+ formats 1010/1013/1015/1016), appended incrementally.
63
+
64
+ ## Status / roadmap
65
+
66
+ | | Status |
67
+ |---|---|
68
+ | Upload / remove / export / playlists (MP3) | ✅ confirmed on nano 7G |
69
+ | Cover art (pure-Python) | ✅ confirmed on nano 7G |
70
+ | Empty-library bootstrap | ✅ |
71
+ | **Pure-Python hashAB** (no native lib, installs everywhere) | ✅ 100/100 vectors |
72
+ | Cross-platform device discovery (macOS + Linux) | ✅ |
73
+ | FLAC/AAC → ALAC | ⬜ |
74
+
75
+ ## Development
76
+
77
+ ```bash
78
+ git clone … && cd ipodsync
79
+ python -m venv .venv && . .venv/bin/activate
80
+ pip install -e ".[dev]"
81
+ pytest
82
+ ```
83
+
84
+ ## License
85
+
86
+ MIT (see [LICENSE](LICENSE)). The vendored hashAB algorithm is public domain.
87
+ Not affiliated with Apple; iPod and iTunes are trademarks of Apple.
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ipodsync"
7
+ version = "0.1.0"
8
+ description = "Upload music to an iPod nano 6G/7G without iTunes: SQLite library, hashAB signing, cover art (pure-Python)."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Alex Buldiei", email = "abuldiei@gmail.com" }]
13
+ keywords = ["ipod", "nano", "itunes", "music", "sync", "artwork"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Environment :: Console",
17
+ "Intended Audience :: End Users/Desktop",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: MacOS",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3",
22
+ "Topic :: Multimedia :: Sound/Audio",
23
+ ]
24
+ dependencies = [
25
+ "mutagen>=1.47", # audio metadata + embedded cover art
26
+ "Pillow>=10.0", # resize cover art to RGB565 for .ithmb
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/buldiei/ipodsync"
31
+ Repository = "https://github.com/buldiei/ipodsync"
32
+ Issues = "https://github.com/buldiei/ipodsync/issues"
33
+ LinkedIn = "https://www.linkedin.com/in/alex-buldiei-b10a9a150/"
34
+
35
+ [project.scripts]
36
+ ipodsync = "ipodsync.cli:main"
37
+
38
+ [project.optional-dependencies]
39
+ dev = ["pytest>=8.0"]
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["src/ipodsync"]
43
+ # hashAB is pure-Python; no native lib needed. The white-box AES tables (433 KB)
44
+ # ship as package data.
45
+ artifacts = ["*.bin"]
46
+
47
+ [tool.pytest.ini_options]
48
+ testpaths = ["tests"]
@@ -0,0 +1,27 @@
1
+ """ipodsync — upload music to iPod nano 6G/7G without iTunes/Apple Music.
2
+
3
+ Transport is a plain volume (mass storage); it edits the SQLite library
4
+ `iTunes Library.itlp` and the `Locations.itdb.cbk` signature (hashAB). Cover art
5
+ is written in pure Python (ArtworkDB + .ithmb). Knows nothing about where the
6
+ files came from.
7
+
8
+ Public API:
9
+ from ipodsync import find_ipod, ItlpLibrary, Track, HashAB
10
+ """
11
+ from .hashab import HashAB, HashABError
12
+ from .library import ItlpLibrary
13
+ from .models import Track
14
+ from .transport import IPod, IPodNotFound, find_ipod
15
+
16
+ __version__ = "0.1.0"
17
+
18
+ __all__ = [
19
+ "find_ipod",
20
+ "IPod",
21
+ "IPodNotFound",
22
+ "ItlpLibrary",
23
+ "Track",
24
+ "HashAB",
25
+ "HashABError",
26
+ "__version__",
27
+ ]
@@ -0,0 +1,5 @@
1
+ """`python -m ipodsync` -> CLI."""
2
+ from .cli import main
3
+
4
+ if __name__ == "__main__":
5
+ raise SystemExit(main())
@@ -0,0 +1,29 @@
1
+ """Constant byte templates of nano 7G ArtworkDB atoms.
2
+
3
+ Generated by scripts/gen_art_templates.py from the iTunes reference
4
+ native/fixtures/itunes_artwork/ArtworkDB. Do not edit by hand —
5
+ these are real iTunes bytes; the writer patches only image_id/song_id/ithmb_offset.
6
+ """
7
+
8
+ MHII_HEADER = bytes.fromhex("6d68696998000000a0030000050000006500000000000000000000000000000000000000000000000000000000000000cd4401000000000001000000010000000000000000000000000000000000f87f000000000000f87f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
9
+ MHOD_CONTAINER = bytes.fromhex("6d686f6418000000a4000000020000000000000000000000")
10
+ MHOD_MHAF = bytes.fromhex("6d686f6418000000780000000600000000000000000000006d686166600000003c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
11
+ MHFD_TEMPLATE = bytes.fromhex("6d6866648400000020290a000000000006000000030000000000000031030000ea356c5898804379b5100a34de06a1c70100000000000000000000005b96a7fed08a706600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
12
+ MHLI_TEMPLATE = bytes.fromhex("6d686c695c000000cc0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
13
+ MHLA_TEMPLATE = bytes.fromhex("6d686c615c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
14
+ MHLF_TEMPLATE = bytes.fromhex("6d686c665c000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
15
+ MHIF_ALL = bytes.fromhex("6d6869667c0000007c00000000000000ed03000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d6869667c0000007c00000000000000ef03000000a80c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d6869667c0000007c00000000000000f203000000c20100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d6869667c0000007c00000000000000f503000088130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d6869667c0000007c00000000000000f7030000481a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d6869667c0000007c00000000000000f8030000d419000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
16
+
17
+ MHNI = {
18
+ 1010: bytes.fromhex("6d686e694c0000008c00000001000000f20300000000000000c2010000000000f000f0000000000000c201000000000000000000000000000000000000000000000000000000000000000000"),
19
+ 1013: bytes.fromhex("6d686e694c0000008c00000001000000f50300000000000088130000000000003200320000000000881300000000000000000000000000000000000000000000000000000000000000000000"),
20
+ 1015: bytes.fromhex("6d686e694c0000008c00000001000000f703000000000000481a0000000000003a003a0000000000481a00000000000000000000000000000000000000000000000000000000000000000000"),
21
+ 1016: bytes.fromhex("6d686e694c0000008c00000001000000f803000000000000d4190000000000003900390000000000d41900000000000000000000000000000000000000000000000000000000000000000000"),
22
+ }
23
+
24
+ STRMHOD = {
25
+ 1010: bytes.fromhex("6d686f6418000000400000000300000000000000000000001c00000002000000000000003a00460031003000310030005f0031002e006900740068006d006200"),
26
+ 1013: bytes.fromhex("6d686f6418000000400000000300000000000000000000001c00000002000000000000003a00460031003000310033005f0031002e006900740068006d006200"),
27
+ 1015: bytes.fromhex("6d686f6418000000400000000300000000000000000000001c00000002000000000000003a00460031003000310035005f0031002e006900740068006d006200"),
28
+ 1016: bytes.fromhex("6d686f6418000000400000000300000000000000000000001c00000002000000000000003a00460031003000310036005f0031002e006900740068006d006200"),
29
+ }