diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-14 11:17:38 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-14 11:17:38 +0200 |
| commit | daec4bc6a2a9f9e038e5269586b06018ff327a27 (patch) | |
| tree | c34c58aad624d594dbb1aa8a47f71ab38a5e3081 /packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py | |
| parent | 80ac882346b474bb7ea4e8c8afd4694bd13dd9dd (diff) | |
| download | meshbay-daec4bc6a2a9f9e038e5269586b06018ff327a27.tar.gz | |
With the system's default setting (LongPathsEnabled off) every call given
a plain path of 260 characters or more refuses it, so a deep library was
partly invisible: the walk could not list such a directory and its files
never reached the members.
The node now hands each call that touches a group's disk the extended
form (paths.long_path), and keeps the plain path in the index, the hash
cache and the log. A directory is listed under its long form and its
entries named from the plain one (indexer.walk_files, wire._walk_dirs).
Covered: the walk, stats and hashing, reconcile and the watcher, the
folder list members see, serving over WebRTC and QUIC, deletion, uploads
and their recovery, folder creation and removal, audio tags and the
cover beside a track, photos, and a show's episode numbering. ffmpeg
extends a long path itself and keeps the plain one.
long_path now normalises before prefixing (the extended form skips the
system's normalisation) and starts at 248 characters, where creating a
directory is already refused.
test_long_paths.py runs with the setting off: 15 of its 17 tests fail
without the change. Checked by hand in the installed app with files at
312 to 380 characters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py b/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py index 397f760..ecc3b5e 100644 --- a/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py +++ b/packages/meshbay-node/src/meshbay_node/indexer/enrich_audio.py @@ -60,11 +60,13 @@ image-file fallback for cover art, same as everything else. import asyncio import logging +import os import re from collections.abc import Awaitable, Callable from pathlib import Path import blake3 +from meshbay_common.paths import long_path from meshbay_common.protocol import IndexEntry from mutagen import File as MutagenFile from mutagen.asf import ASF @@ -155,8 +157,9 @@ _WMP_ALBUMART_GUID_RE = re.compile(r"^albumart_\{([0-9a-f-]{36})\}_(large|small) def _find_sibling_cover(folder: Path) -> Path | None: try: - candidates = [p for p in folder.iterdir() - if p.is_file() and p.suffix.lower() in _COVER_EXTS] + with os.scandir(long_path(folder)) as listing: + candidates = [folder / e.name for e in listing + if e.is_file() and Path(e.name).suffix.lower() in _COVER_EXTS] except OSError: return None if not candidates: @@ -240,12 +243,12 @@ def _read_format_specific_tags(path: Path) -> tuple[dict, float | None] | None: suffix = path.suffix.lower() if suffix == ".wma": try: - return _asf_tags_from_object(ASF(str(path))) + return _asf_tags_from_object(ASF(long_path(path))) except Exception: return {}, None if suffix == ".mpc": try: - return _musepack_tags_from_object(Musepack(str(path))) + return _musepack_tags_from_object(Musepack(long_path(path))) except Exception: return {}, None return None @@ -257,7 +260,7 @@ def _read_generic_tags_and_cover( tags: dict = {} duration: float | None = None try: - easy = MutagenFile(str(path), easy=True) + easy = MutagenFile(long_path(path), easy=True) except Exception: easy = None if easy is not None: @@ -277,7 +280,7 @@ def _read_generic_tags_and_cover( cover: bytes | None = None if not skip_cover: try: - raw = MutagenFile(str(path)) + raw = MutagenFile(long_path(path)) except Exception: raw = None if raw is not None: @@ -339,7 +342,8 @@ def _read_sibling_cover(path: Path) -> bytes | None: if sibling is None: return None try: - return sibling.read_bytes() + with open(long_path(sibling), "rb") as f: + return f.read() except OSError: return None |