From 75d1f8b93dfa0bffda3a59a6d143b06dcc3ca67f Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Mon, 24 Aug 2026 20:55:52 +0200 Subject: fix(node): skip indexing audio files under 50KB, likely-corrupt source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "P.H. Theme" failure investigated earlier turned out to be a genuinely corrupt 1256-byte source file with no audio stream at all, just an ID3 tag — a real, if rare, corruption pattern worth guarding against directly rather than only handling gracefully at playback time. Scoped to audio only, applied wherever a file actually gets hashed/typed (fresh scan and the cache-miss rehash path alike) — a tiny file of any other type is still indexed normally. --- .../meshbay-node/src/meshbay_node/indexer/indexer.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'packages/meshbay-node/src') diff --git a/packages/meshbay-node/src/meshbay_node/indexer/indexer.py b/packages/meshbay-node/src/meshbay_node/indexer/indexer.py index 3ca34f6..10981c0 100644 --- a/packages/meshbay-node/src/meshbay_node/indexer/indexer.py +++ b/packages/meshbay-node/src/meshbay_node/indexer/indexer.py @@ -79,6 +79,19 @@ def _is_indexable(path: Path) -> bool: ) +# Found live: a 1256-byte ".mp3" with no audio stream at all, just an ID3 +# tag — a truncated/corrupted rip, sitting between two good tracks of the +# same album (docs/musicbay.md). A source this small claiming to be audio +# is far more likely broken than real, so it is skipped before ever being +# hashed rather than indexed and left to fail at playback time. Scoped to +# audio only — a tiny real file of any other type is still worth indexing. +MIN_AUDIO_SIZE_BYTES = 50 * 1024 + + +def _is_indexable_size(path: Path, size: int) -> bool: + return not (_detect_type(path) == "audio" and size < MIN_AUDIO_SIZE_BYTES) + + _HASH_CHUNK = 8 * 1024 * 1024 # 8 MB streaming hash chunks @@ -134,6 +147,8 @@ def _scan_file(root: Root, file_path: Path) -> IndexEntry | None: return None try: stat = file_path.stat() + if not _is_indexable_size(file_path, stat.st_size): + return None hasher = blake3.blake3() # long_path is a no-op off Windows; there it is what lets a deep media # library past MAX_PATH. @@ -338,6 +353,8 @@ class DirectoryIndexer: st = file_path.stat() except OSError: return None + if not _is_indexable_size(file_path, st.st_size): + return None if self._cache is not None: cached = await self._cache.lookup(str(file_path), st.st_size, st.st_mtime) -- cgit v1.2.3