feat: integrate artwork module into sync pipeline for Nano 7G

This commit is contained in:
Maksim Totmin 2026-05-31 21:45:51 +07:00
parent 9da689782a
commit 71928d3478

View File

@ -35,6 +35,8 @@ from typing import Any, Optional
from mutagen import File as MutagenFile
from mutagen.easyid3 import EasyID3
from artwork import prepare_artwork_for_track, ArtworkEntry, write_artworkdb
_IOP_ROOT = "/tmp/iOpenPod"
_IOP_CACHE: dict[str, Any] = {}
_IOP_READY = False
@ -188,7 +190,8 @@ def _read_audio_tags(filepath: str) -> dict[str, Any]:
def _scanned_tracks_to_iop(mountpoint: str,
scanned: list[dict]) -> list:
scanned: list[dict],
artwork_map: dict[str, tuple[int, int, int]] | None = None) -> list:
"""Convert our scanned track dicts to iOpenPod TrackInfo objects."""
IopTrackInfo = _import_iop("iTunesDB_Writer.mhit_writer").TrackInfo
tracks: list = []
@ -201,6 +204,12 @@ def _scanned_tracks_to_iop(mountpoint: str,
location = f":iPod_Control:Music:{rel.replace('/', ':')}"
size = os.path.getsize(fpath)
art_count = 0
art_size = 0
mhii_link = 0
if artwork_map and fpath in artwork_map:
mhii_link, art_count, art_size = artwork_map[fpath]
t = IopTrackInfo(
title=s.get("title") or base,
location=location,
@ -219,9 +228,9 @@ def _scanned_tracks_to_iop(mountpoint: str,
total_tracks=s.get("track_count", 0),
disc_number=s.get("disc_number", 0),
total_discs=s.get("disc_count", 0),
artwork_count=s.get("art_count", 0),
artwork_size=s.get("art_size", 0),
mhii_link=s.get("mhii_link", 0),
artwork_count=art_count,
artwork_size=art_size,
mhii_link=mhii_link,
)
tracks.append(t)
return tracks
@ -487,11 +496,58 @@ class Nano7Database:
self._write_empty_databases()
return
# 2. Convert to iOpenPod TrackInfo
tracks = _scanned_tracks_to_iop(self.mountpoint, scanned)
# 2. Prepare artwork for all tracks
artwork_map: dict[str, tuple[int, int, int]] = {}
art_entries: list[ArtworkEntry] = []
art_hash_to_img_id: dict[str, int] = {}
next_img_id = 100
for idx, s in enumerate(scanned):
fpath = s["file_path"]
try:
art_result = prepare_artwork_for_track(fpath)
except Exception:
art_result = None
if art_result is not None:
art_hash, formats = art_result
art_count = len(formats)
total_size = sum(p.size for p in formats.values())
if art_hash not in art_hash_to_img_id:
img_id = next_img_id
next_img_id += 1
art_hash_to_img_id[art_hash] = img_id
art_entries.append(ArtworkEntry(
img_id=img_id,
db_track_id=idx,
art_hash=art_hash,
src_img_size=total_size,
formats=formats,
db_track_ids=[idx],
))
else:
img_id = art_hash_to_img_id[art_hash]
for entry in art_entries:
if entry.img_id == img_id:
if idx not in entry.db_track_ids:
entry.db_track_ids.append(idx)
break
artwork_map[fpath] = (img_id, art_count, total_size)
if art_entries:
try:
write_artworkdb(self.mountpoint, art_entries)
logger.info("ArtworkDB written: %d unique covers, %d total tracks",
len(art_entries), len(artwork_map))
except Exception as e:
logger.warning("ArtworkDB write failed: %s", e)
# 3. Convert to iOpenPod TrackInfo
tracks = _scanned_tracks_to_iop(self.mountpoint, scanned, artwork_map)
logger.info("Built %d iOpenPod TrackInfo objects", len(tracks))
# 3. Determine capabilities for this device
# 4. Determine capabilities for this device
ipod_device = _import_iop("ipod_device")
capabilities = None
try:
@ -505,7 +561,7 @@ class Nano7Database:
except Exception as e:
logger.debug("Capabilities detection failed: %s", e)
# 4. Generate and write binary iTunesDB first (to get db_pid)
# 5. Generate and write binary iTunesDB first (to get db_pid)
try:
firewire_id = ipod_device.get_firewire_id(self.mountpoint)
except Exception:
@ -525,7 +581,7 @@ class Nano7Database:
return
logger.info("iTunesDB written (%d tracks)", len(tracks))
# 5. Extract db_pid from the binary DB for SQLite cross-reference
# 6. Extract db_pid from the binary DB for SQLite cross-reference
db_pid = 0
try:
ipod_dev = _import_iop("ipod_device")
@ -539,7 +595,7 @@ class Nano7Database:
except Exception as e:
logger.warning("Could not extract db_pid: %s", e)
# 6. Write SQLite databases (Nano 6G/7G require this)
# 7. Write SQLite databases (Nano 6G/7G require this)
try:
write_sqlite_databases = _import_iop("SQLiteDB_Writer").write_sqlite_databases
sqlite_ok = write_sqlite_databases(