update refactoring and add new features

This commit is contained in:
2026-07-24 20:55:58 -07:00
parent 7f12bc7f40
commit 03fbbbcf28
69 changed files with 16332 additions and 17600 deletions
+165 -3
View File
@@ -4,11 +4,27 @@ import shutil
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple
from PluginCore.base import Provider
from SYS.metadata import write_metadata, write_tags
from PluginCore.base import Provider, SearchResult
from SYS.metadata import _read_sidecar_metadata, read_tags_from_file, write_metadata, write_tags
from SYS.utils import sanitize_filename, sha256_file, unique_path
def _format_size_safe(size_bytes: Any) -> str:
if size_bytes is None:
return ""
try:
size = int(size_bytes)
except (TypeError, ValueError):
return str(size_bytes or "")
if size < 1024:
return f"{size} B"
if size < 1024 * 1024:
return f"{size / 1024:.1f} KB"
if size < 1024 * 1024 * 1024:
return f"{size / (1024 * 1024):.1f} MB"
return f"{size / (1024 * 1024 * 1024):.2f} GB"
def _copy_sidecars(source_path: Path, target_path: Path) -> None:
possible_sidecars = [
source_path.with_suffix(source_path.suffix + ".json"),
@@ -80,7 +96,7 @@ class Local(Provider):
PLUGIN_NAME = "local"
PLUGIN_ALIASES = ("filesystem", "fs")
MULTI_INSTANCE = True
SUPPORTED_CMDLETS = frozenset({"add-file"})
SUPPORTED_CMDLETS = frozenset({"add-file", "search-file"})
@property
def label(self) -> str:
@@ -165,6 +181,152 @@ class Local(Provider):
def validate(self) -> bool:
return True
@staticmethod
def _infer_media_kind(ext: str) -> str:
e = str(ext or "").strip().lower().lstrip(".")
if e in {"mp3", "flac", "wav", "ogg", "opus", "m4a", "aac", "wma", "aiff"}:
return "audio"
if e in {"mp4", "mkv", "avi", "mov", "webm", "wmv", "flv", "m4v"}:
return "video"
if e in {"pdf", "epub", "mobi", "azw3", "djvu", "cbr", "cbz", "chm"}:
return "book"
if e in {"zip", "rar", "7z", "tar", "gz", "bz2", "xz", "iso"}:
return "archive"
if e in {"exe", "msi", "apk", "deb", "rpm", "appimage", "bin"}:
return "software"
if e in {"jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "tiff", "ico"}:
return "image"
return "file"
def search(
self,
query: str,
limit: int = 50,
filters: Optional[Dict[str, Any]] = None,
**kwargs: Any,
) -> List[SearchResult]:
q = str(query or "").strip()
match_all = not q or q == "*"
query_tokens = [t.lower() for t in q.split()] if not match_all else []
max_results = max(1, int(limit))
target_instance = None
if filters:
target_instance = str(filters.get("instance") or filters.get("store") or "").strip() or None
results: List[SearchResult] = []
instances = self.plugin_instance_configs()
for inst_name, inst_cfg in instances.items():
if target_instance and str(inst_name or "").strip().lower() != target_instance.lower():
continue
settings = self._settings_from_config(inst_cfg, instance_name=inst_name)
root_text = str(settings.get("path") or "").strip()
if not root_text:
continue
root = Path(root_text).expanduser()
if not root.is_dir():
continue
try:
for entry in root.rglob("*"):
if len(results) >= max_results:
break
if not entry.is_file():
continue
file_name = entry.name
file_stem = entry.stem
tag_path = entry.parent / (file_name + ".tag")
meta_path = entry.parent / (file_name + ".metadata")
has_tag = tag_path.is_file()
has_meta = meta_path.is_file()
if not has_tag and not has_meta:
continue
tags: List[str] = []
if has_tag:
try:
tags = read_tags_from_file(tag_path)
except Exception:
tags = []
hash_value: Optional[str] = None
urls: List[str] = []
if has_meta:
try:
hash_value, _extra_tags, urls = _read_sidecar_metadata(meta_path)
except Exception:
pass
if not match_all and query_tokens:
url_text = " ".join(urls) if urls else ""
search_text = " ".join([file_name.lower(), file_stem.lower().replace("_", " "), *tags, url_text])
if hash_value:
search_text += " " + hash_value.lower()
if not all(token in search_text for token in query_tokens):
continue
try:
size_bytes = int(entry.stat().st_size)
except Exception:
size_bytes = None
ext = entry.suffix.lstrip(".")
media_kind = self._infer_media_kind(ext)
inst_label = str(inst_name or "").strip()
if inst_label.lower() == "default":
inst_label = ""
store_label = f"local:{inst_label}" if inst_label else "local"
tag_text = ", ".join(tags[:8]) if tags else ""
metadata: Dict[str, Any] = {
"store": store_label,
"ext": ext,
"size": size_bytes,
}
if inst_label:
metadata["instance"] = inst_label
if hash_value:
metadata["hash"] = hash_value
if urls:
metadata["url"] = urls
sr = SearchResult(
table="local",
title=file_name,
path=str(entry),
detail=store_label,
annotations=[store_label],
media_kind=media_kind,
size_bytes=size_bytes,
tag=set(tags),
columns=[
("Title", file_name),
("Tag", tag_text),
("Store", store_label),
("Size", _format_size_safe(size_bytes)),
("Ext", ext),
],
full_metadata=metadata,
)
sr.ext = ext
sr.size = size_bytes
if hash_value:
sr.hash = hash_value
results.append(sr)
except Exception:
continue
return results[:max_results]
@staticmethod
def _folder_name_from_pipe(pipe_obj: Any) -> str:
metadata = getattr(pipe_obj, "metadata", None)