update refactoring and add new features
This commit is contained in:
+165
-3
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user