This commit is contained in:
2026-01-11 12:28:16 -08:00
parent d86caa902f
commit 1f3de7db1c
2 changed files with 88 additions and 30 deletions

View File

@@ -70,11 +70,11 @@ class HIFI(Provider):
"hifi.track": ["download-file"], "hifi.track": ["download-file"],
} }
QUERY_ARG_CHOICES = { QUERY_ARG_CHOICES = {
"album": (),
"artist": (), "artist": (),
"playlist": (), "album": (),
"track": (), "track": (),
"title": (), "title": (),
"playlist": (),
"video": (), "video": (),
} }
INLINE_QUERY_FIELD_CHOICES = QUERY_ARG_CHOICES INLINE_QUERY_FIELD_CHOICES = QUERY_ARG_CHOICES
@@ -272,7 +272,7 @@ class HIFI(Provider):
title = self._stringify(detail.get("title")) or title title = self._stringify(detail.get("title")) or title
return SearchResult( return SearchResult(
table="hifi", table="hifi.track",
title=title, title=title,
path=f"hifi://track/{track_id}", path=f"hifi://track/{track_id}",
detail=f"id:{track_id}", detail=f"id:{track_id}",
@@ -792,7 +792,7 @@ class HIFI(Provider):
md["_artist_name"] = artist_name md["_artist_name"] = artist_name
return SearchResult( return SearchResult(
table="hifi", table="hifi.album",
title=title, title=title,
path=path, path=path,
detail="album", detail="album",
@@ -1384,7 +1384,7 @@ class HIFI(Provider):
if not isinstance(hit, dict): if not isinstance(hit, dict):
continue continue
hit_type = str(hit.get("type") or "").upper() hit_type = str(hit.get("type") or "").upper()
if hit_type != "TRACKS": if hit_type != "TRACKS" and hit_type != "TRACK":
continue continue
value = hit.get("value") value = hit.get("value")
if isinstance(value, dict): if isinstance(value, dict):
@@ -1510,7 +1510,7 @@ class HIFI(Provider):
if not isinstance(hit, dict): if not isinstance(hit, dict):
continue continue
hit_type = str(hit.get("type") or "").upper() hit_type = str(hit.get("type") or "").upper()
if hit_type != "ARTISTS": if hit_type != "ARTISTS" and hit_type != "ARTIST":
continue continue
value = hit.get("value") value = hit.get("value")
if isinstance(value, dict): if isinstance(value, dict):
@@ -1557,10 +1557,10 @@ class HIFI(Provider):
columns.append(("Popularity", popularity)) columns.append(("Popularity", popularity))
return SearchResult( return SearchResult(
table="hifi", table="hifi.artist",
title=name, title=name,
path=path, path=path,
detail="artist", detail="hifi.artist",
annotations=["tidal", "artist"], annotations=["tidal", "artist"],
media_kind="audio", media_kind="audio",
columns=columns, columns=columns,
@@ -1656,11 +1656,11 @@ class HIFI(Provider):
tags = self._build_track_tags(full_md) tags = self._build_track_tags(full_md)
result = SearchResult( result = SearchResult(
table="hifi", table="hifi.track",
title=title, title=title,
path=path, path=path,
detail=detail, detail="hifi.track",
annotations=["tidal"], annotations=["tidal", "track"],
media_kind="audio", media_kind="audio",
tag=tags, tag=tags,
columns=columns, columns=columns,
@@ -1816,6 +1816,28 @@ class HIFI(Provider):
def _build_track_tags(self, metadata: Dict[str, Any]) -> set[str]: def _build_track_tags(self, metadata: Dict[str, Any]) -> set[str]:
return build_track_tags(metadata) return build_track_tags(metadata)
def selection_auto_stage(
self,
table_type: str,
stage_args: Optional[Sequence[str]] = None,
) -> Optional[List[str]]:
"""Determine if selection should auto-run download-file."""
t = str(table_type or "").strip().lower()
# Explicit track tables always auto-download.
if t == "hifi.track":
return ["download-file"]
# For the generic "hifi" table (first-stage search results),
# only auto-download if we're selecting track items.
# Otherwise, let selector() handle navigation (artist -> album -> track).
if t == "hifi":
# If we can't see the items yet, we have to guess.
# Default to None so selector() gets a chance to run first.
return None
return super().selection_auto_stage(table_type, stage_args)
def selector( def selector(
self, self,
selected_items: List[Any], selected_items: List[Any],
@@ -1836,11 +1858,11 @@ class HIFI(Provider):
current_table = ctx.get_last_result_table() current_table = ctx.get_last_result_table()
except Exception: except Exception:
current_table = None current_table = None
table_type = ( table_type = str(
current_table.table current_table.table
if current_table and hasattr(current_table, "table") if current_table and hasattr(current_table, "table")
else None else ""
) ).strip().lower()
try: try:
debug( debug(
@@ -1849,8 +1871,12 @@ class HIFI(Provider):
except Exception: except Exception:
pass pass
# Unified selection logic: detect artist/album/track by inspecting path or metadata
# when the table name is just the generic "hifi" (from search-file).
is_generic_hifi = (table_type == "hifi")
# Artist selection: selecting @N should open an albums list. # Artist selection: selecting @N should open an albums list.
if isinstance(table_type, str) and table_type.strip().lower() == "hifi.artist": if table_type == "hifi.artist" or (is_generic_hifi and any(str(get_field(i, "path")).startswith("hifi://artist/") for i in selected_items)):
contexts = self._extract_artist_selection_context(selected_items) contexts = self._extract_artist_selection_context(selected_items)
try: try:
debug(f"[hifi.selector] artist contexts={len(contexts)}") debug(f"[hifi.selector] artist contexts={len(contexts)}")
@@ -1911,7 +1937,7 @@ class HIFI(Provider):
return True return True
# Album selection: selecting @N should open the track list for that album. # Album selection: selecting @N should open the track list for that album.
if isinstance(table_type, str) and table_type.strip().lower() == "hifi.album": if table_type == "hifi.album" or (is_generic_hifi and any(str(get_field(i, "path")).startswith("hifi://album/") for i in selected_items)):
contexts = self._extract_album_selection_context(selected_items) contexts = self._extract_album_selection_context(selected_items)
try: try:
debug(f"[hifi.selector] album contexts={len(contexts)}") debug(f"[hifi.selector] album contexts={len(contexts)}")
@@ -1978,7 +2004,7 @@ class HIFI(Provider):
return True return True
if isinstance(table_type, str) and table_type.strip().lower() == "hifi.track": if table_type == "hifi.track" or (is_generic_hifi and any(str(get_field(i, "path")).startswith("hifi://track/") for i in selected_items)):
try: try:
meta = ( meta = (
current_table.get_table_metadata() current_table.get_table_metadata()
@@ -2051,7 +2077,7 @@ class HIFI(Provider):
url_value = self._stringify(detail.get("url")) url_value = self._stringify(detail.get("url"))
result = SearchResult( result = SearchResult(
table="hifi", table="hifi.track",
title=title, title=title,
path=resolved_path, path=resolved_path,
detail=f"id:{track_id}", detail=f"id:{track_id}",

View File

@@ -593,38 +593,61 @@ def main() -> int:
return 1 return 1
return 0 return 0
def _update_config_value(root: Path, key: str, value: str) -> bool:
config_path = root / "config.conf"
if not config_path.exists():
fallback = root / "config.conf.remove"
if fallback.exists():
shutil.copy(fallback, config_path)
else:
return False
try:
content = config_path.read_text(encoding="utf-8")
pattern = rf'^(\s*{re.escape(key)}\s*=\s*)(.*)$'
if re.search(pattern, content, flags=re.MULTILINE):
new_content = re.sub(pattern, rf'\1"{value}"', content, flags=re.MULTILINE)
else:
section_pattern = r'\[store=hydrusnetwork\]'
if re.search(section_pattern, content):
new_content = re.sub(section_pattern, f'[store=hydrusnetwork]\n{key}="{value}"', content, count=1)
else:
new_content = content + f'\n\n[store=hydrusnetwork]\nname="hydrus"\n{key}="{value}"'
config_path.write_text(new_content, encoding="utf-8")
return True
except Exception as e:
print(f"Error updating config: {e}")
return False
def _interactive_menu() -> str | int: def _interactive_menu() -> str | int:
"""Show a simple interactive menu to choose install/uninstall or delegate.""" """Show a simple interactive menu to choose install/uninstall or delegate."""
try: try:
installed = _is_installed() installed = _is_installed()
while True: while True:
print("\nMedeia-Macina bootstrap - interactive menu") os.system("cls" if os.name == "nt" else "clear")
print("====================================")
print(" MEDEIA MACINA BOOTSTRAP MENU")
print("====================================")
print("1) Install / Reinstall") print("1) Install / Reinstall")
print("2) Extras") print("2) Extras > HydrusNetwork")
if installed: if installed:
print("3) Uninstall") print("3) Uninstall")
print("4) Status") print("4) Status")
print("q) Quit") print("q) Quit")
choice = input("Choose an option: ").strip().lower() choice = input("\nChoose an option: ").strip().lower()
if choice in ("1", "install", "reinstall"): if choice in ("1", "install", "reinstall"):
return "install" return "install"
if choice in ("2", "extras"): if choice in ("2", "extras", "hydrus"):
print("\nExtras Menu:")
print(" 1) HydrusNetwork (Setup & Clone)")
print(" b) Back")
extra_choice = input("Choose an extra: ").strip().lower()
if extra_choice == "1":
return "extras_hydrus" return "extras_hydrus"
continue # back to main menu
if installed and choice in ("3", "uninstall"): if installed and choice in ("3", "uninstall"):
return "uninstall" return "uninstall"
if installed and choice in ("4", "status"): if installed and choice in ("4", "status"):
print("Installation detected." if installed else "Not installed.") print("\nInstallation detected." if installed else "\nNot installed.")
input("\nPress Enter to continue...")
continue continue
if choice in ("q", "quit", "exit"): if choice in ("q", "quit", "exit"):
@@ -795,6 +818,15 @@ def main() -> int:
if hydrus_script.exists(): if hydrus_script.exists():
try: try:
subprocess.check_call([sys.executable, str(hydrus_script)]) subprocess.check_call([sys.executable, str(hydrus_script)])
# New: Prompt for location as requested
print("\n" + "="*40)
print(" HYDRUS CONFIGURATION")
print("="*40)
location = input("\nEnter the absolute path to your Hydrus git clone\n(to link it with Medios-Macina config): ").strip()
if location:
if _update_config_value(repo_root, "gitclone", location):
print(f"✅ Updated config.conf with gitclone=\"{location}\"")
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
print("\nHydrusNetwork setup exited with an error.") print("\nHydrusNetwork setup exited with an error.")
except Exception as e: except Exception as e: