This commit is contained in:
nose
2025-11-27 18:35:06 -08:00
parent 9eff65d1af
commit ed417c8200
6 changed files with 143 additions and 93 deletions

View File

@@ -330,9 +330,12 @@ class LocalStorageBackend(StorageBackend):
except Exception:
word_regex = None
else:
# Use word boundary for exact terms (backwards compatibility)
# Use custom boundary that treats underscores as separators
# \b treats _ as a word character, so "foo_bar" wouldn't match "bar" with \b
try:
word_regex = re.compile(r'\b' + re.escape(term) + r'\b', re.IGNORECASE)
# Match if not preceded or followed by alphanumeric chars
pattern = r'(?<![a-zA-Z0-9])' + re.escape(term) + r'(?![a-zA-Z0-9])'
word_regex = re.compile(pattern, re.IGNORECASE)
except Exception:
word_regex = None
@@ -459,71 +462,19 @@ class LocalStorageBackend(StorageBackend):
if results:
debug(f"Returning {len(results)} results from DB")
return results
else:
debug("No results found in DB, falling back to filesystem scan")
debug("No results found in DB")
return results
except Exception as e:
log(f"⚠️ Database search failed: {e}", file=sys.stderr)
debug(f"DB search exception details: {e}")
# Fallback to filesystem search if database search fails or returns nothing
debug("Starting filesystem scan...")
recursive = kwargs.get("recursive", True)
pattern = "**/*" if recursive else "*"
# Split query into terms for AND logic
terms = [t.strip() for t in query_lower.replace(',', ' ').split() if t.strip()]
if not terms:
terms = [query_lower]
count = 0
for file_path in search_dir.glob(pattern):
if not file_path.is_file():
continue
lower_name = file_path.name.lower()
if lower_name.endswith('.tags') or lower_name.endswith('.metadata') \
or lower_name.endswith('.notes') or lower_name.endswith('.tags.txt'):
continue
if not match_all:
# Check if ALL terms are present in the filename
# For single terms with wildcards, use fnmatch; otherwise use substring matching
if len(terms) == 1 and ('*' in terms[0] or '?' in terms[0]):
# Wildcard pattern matching for single term
from fnmatch import fnmatch
if not fnmatch(lower_name, terms[0]):
continue
else:
# Substring matching for all terms (AND logic)
if not all(term in lower_name for term in terms):
continue
size_bytes = file_path.stat().st_size
path_str = str(file_path)
results.append({
"name": file_path.stem,
"title": file_path.stem,
"ext": file_path.suffix.lstrip('.'),
"path": path_str,
"target": path_str,
"origin": "local",
"size": size_bytes,
"size_bytes": size_bytes,
})
count += 1
if limit is not None and len(results) >= limit:
break
debug(f"Filesystem scan found {count} matches")
return []
except Exception as exc:
log(f"❌ Local search failed: {exc}", file=sys.stderr)
raise
return results
class HydrusStorageBackend(StorageBackend):
"""File storage backend for Hydrus client."""