fix: resolve ipod_device import conflict with lazy imports
main.py imports our local ipod_device first, which caches it in sys.modules. When ipod_nano7_db later tried 'from ipod_device import ChecksumType', Python returned the cached local module (which lacks ChecksumType), causing 'ipod_nano7_db not available' and falling back to simple file copy into wrong /Music/ directory. Fix: replace top-level iOpenPod imports with lazy _import_iop() helper that temporarily evicts local ipod_device from sys.modules, adds /tmp/iOpenPod to sys.path, loads the iOpenPod module, then restores the path. All iOpenPod imports now happen inside method bodies only.
This commit is contained in:
parent
4c4a19640d
commit
4f7bd2709c
@ -20,6 +20,7 @@ Public API preserved for main.py compatibility:
|
|||||||
delete_orphaned_files(paths) — remove orphan files
|
delete_orphaned_files(paths) — remove orphan files
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import importlib
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import hashlib
|
import hashlib
|
||||||
@ -31,25 +32,38 @@ import struct
|
|||||||
import time
|
import time
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
os.environ.setdefault("IOPENOD_HOME", "/tmp/iOpenPod")
|
|
||||||
_iop = "/tmp/iOpenPod"
|
|
||||||
if _iop not in sys.path:
|
|
||||||
sys.path.insert(0, _iop)
|
|
||||||
|
|
||||||
from mutagen import File as MutagenFile
|
from mutagen import File as MutagenFile
|
||||||
from mutagen.easyid3 import EasyID3
|
from mutagen.easyid3 import EasyID3
|
||||||
|
|
||||||
from iTunesDB_Writer.mhit_writer import TrackInfo as IopTrackInfo
|
_IOP_ROOT = "/tmp/iOpenPod"
|
||||||
from iTunesDB_Writer.mhyp_writer import PlaylistInfo
|
|
||||||
from iTunesDB_Writer import write_itunesdb as iop_write_itunesdb
|
|
||||||
from SQLiteDB_Writer import write_sqlite_databases
|
def _import_iop(module_name: str):
|
||||||
from ipod_device import (
|
"""Import a module from iOpenPod, bypassing any locally-cached conflict.
|
||||||
DeviceCapabilities,
|
|
||||||
ChecksumType,
|
main.py imports our local ``ipod_device`` first, which caches it in
|
||||||
get_firewire_id,
|
``sys.modules``. When ipod_nano7_db later tries ``from ipod_device
|
||||||
capabilities_for_family_gen,
|
import ChecksumType``, Python returns the cached *local* module
|
||||||
get_current_device,
|
(which lacks ChecksumType). This helper temporarily evicts the
|
||||||
)
|
conflicting local modules, adds the iOpenPod root to sys.path, loads
|
||||||
|
the requested module from there, then restores the path.
|
||||||
|
"""
|
||||||
|
# Modules that may be cached as our local copies and need eviction.
|
||||||
|
_conflicting = {"ipod_device"}
|
||||||
|
_saved = {}
|
||||||
|
for name in _conflicting & set(sys.modules):
|
||||||
|
_saved[name] = sys.modules.pop(name)
|
||||||
|
|
||||||
|
had_iop = _IOP_ROOT in sys.path
|
||||||
|
if not had_iop:
|
||||||
|
sys.path.insert(0, _IOP_ROOT)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return importlib.import_module(module_name)
|
||||||
|
finally:
|
||||||
|
if not had_iop:
|
||||||
|
sys.path.remove(_IOP_ROOT)
|
||||||
|
sys.modules.update(_saved)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -165,9 +179,10 @@ def _read_audio_tags(filepath: str) -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
def _scanned_tracks_to_iop(mountpoint: str,
|
def _scanned_tracks_to_iop(mountpoint: str,
|
||||||
scanned: list[dict]) -> list[IopTrackInfo]:
|
scanned: list[dict]) -> list:
|
||||||
"""Convert our scanned track dicts to iOpenPod TrackInfo objects."""
|
"""Convert our scanned track dicts to iOpenPod TrackInfo objects."""
|
||||||
tracks: list[IopTrackInfo] = []
|
IopTrackInfo = _import_iop("iTunesDB_Writer.mhit_writer").TrackInfo
|
||||||
|
tracks: list = []
|
||||||
for s in scanned:
|
for s in scanned:
|
||||||
fpath = s["file_path"]
|
fpath = s["file_path"]
|
||||||
fname = os.path.basename(fpath)
|
fname = os.path.basename(fpath)
|
||||||
@ -467,11 +482,12 @@ class Nano7Database:
|
|||||||
logger.info("Built %d iOpenPod TrackInfo objects", len(tracks))
|
logger.info("Built %d iOpenPod TrackInfo objects", len(tracks))
|
||||||
|
|
||||||
# 3. Determine capabilities for this device
|
# 3. Determine capabilities for this device
|
||||||
|
ipod_device = _import_iop("ipod_device")
|
||||||
capabilities = None
|
capabilities = None
|
||||||
try:
|
try:
|
||||||
dev = get_current_device()
|
dev = ipod_device.get_current_device()
|
||||||
if dev and dev.model_family:
|
if dev and dev.model_family:
|
||||||
capabilities = capabilities_for_family_gen(
|
capabilities = ipod_device.capabilities_for_family_gen(
|
||||||
dev.model_family, dev.generation or "",
|
dev.model_family, dev.generation or "",
|
||||||
)
|
)
|
||||||
if capabilities:
|
if capabilities:
|
||||||
@ -481,10 +497,11 @@ class Nano7Database:
|
|||||||
|
|
||||||
# 4. Generate and write binary iTunesDB first (to get db_pid)
|
# 4. Generate and write binary iTunesDB first (to get db_pid)
|
||||||
try:
|
try:
|
||||||
firewire_id = get_firewire_id(self.mountpoint)
|
firewire_id = ipod_device.get_firewire_id(self.mountpoint)
|
||||||
except Exception:
|
except Exception:
|
||||||
firewire_id = self.firewire_id
|
firewire_id = self.firewire_id
|
||||||
|
|
||||||
|
iop_write_itunesdb = _import_iop("iTunesDB_Writer").write_itunesdb
|
||||||
ok = iop_write_itunesdb(
|
ok = iop_write_itunesdb(
|
||||||
self.mountpoint,
|
self.mountpoint,
|
||||||
tracks,
|
tracks,
|
||||||
@ -501,8 +518,8 @@ class Nano7Database:
|
|||||||
# 5. Extract db_pid from the binary DB for SQLite cross-reference
|
# 5. Extract db_pid from the binary DB for SQLite cross-reference
|
||||||
db_pid = 0
|
db_pid = 0
|
||||||
try:
|
try:
|
||||||
from ipod_device import resolve_itdb_path
|
ipod_dev = _import_iop("ipod_device")
|
||||||
cdb_path = resolve_itdb_path(self.mountpoint)
|
cdb_path = ipod_dev.resolve_itdb_path(self.mountpoint)
|
||||||
if cdb_path:
|
if cdb_path:
|
||||||
with open(cdb_path, "rb") as f:
|
with open(cdb_path, "rb") as f:
|
||||||
hdr = f.read(0x20)
|
hdr = f.read(0x20)
|
||||||
@ -514,6 +531,7 @@ class Nano7Database:
|
|||||||
|
|
||||||
# 6. Write SQLite databases (Nano 6G/7G require this)
|
# 6. Write SQLite databases (Nano 6G/7G require this)
|
||||||
try:
|
try:
|
||||||
|
write_sqlite_databases = _import_iop("SQLiteDB_Writer").write_sqlite_databases
|
||||||
sqlite_ok = write_sqlite_databases(
|
sqlite_ok = write_sqlite_databases(
|
||||||
ipod_path=self.mountpoint,
|
ipod_path=self.mountpoint,
|
||||||
tracks=tracks,
|
tracks=tracks,
|
||||||
@ -532,23 +550,26 @@ class Nano7Database:
|
|||||||
|
|
||||||
def _write_empty_databases(self) -> None:
|
def _write_empty_databases(self) -> None:
|
||||||
"""Write minimal empty databases when no tracks exist."""
|
"""Write minimal empty databases when no tracks exist."""
|
||||||
empty_tracks: list[IopTrackInfo] = []
|
ipod_device = _import_iop("ipod_device")
|
||||||
|
iop_write_itunesdb = _import_iop("iTunesDB_Writer").write_itunesdb
|
||||||
|
write_sqlite_databases = _import_iop("SQLiteDB_Writer").write_sqlite_databases
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fwid = get_firewire_id(self.mountpoint)
|
fwid = ipod_device.get_firewire_id(self.mountpoint)
|
||||||
except Exception:
|
except Exception:
|
||||||
fwid = self.firewire_id
|
fwid = self.firewire_id
|
||||||
capabilities = None
|
capabilities = None
|
||||||
try:
|
try:
|
||||||
dev = get_current_device()
|
dev = ipod_device.get_current_device()
|
||||||
if dev and dev.model_family:
|
if dev and dev.model_family:
|
||||||
capabilities = capabilities_for_family_gen(
|
capabilities = ipod_device.capabilities_for_family_gen(
|
||||||
dev.model_family, dev.generation or "")
|
dev.model_family, dev.generation or "")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
iop_write_itunesdb(self.mountpoint, empty_tracks, firewire_id=fwid,
|
iop_write_itunesdb(self.mountpoint, [], firewire_id=fwid,
|
||||||
backup=True, capabilities=capabilities)
|
backup=True, capabilities=capabilities)
|
||||||
write_sqlite_databases(
|
write_sqlite_databases(
|
||||||
ipod_path=self.mountpoint, tracks=empty_tracks,
|
ipod_path=self.mountpoint, tracks=[],
|
||||||
master_playlist_name="iPod",
|
master_playlist_name="iPod",
|
||||||
db_pid=random.getrandbits(64),
|
db_pid=random.getrandbits(64),
|
||||||
capabilities=capabilities, firewire_id=fwid, backup=True,
|
capabilities=capabilities, firewire_id=fwid, backup=True,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user