lksjalk
Some checks failed
smoke-mm / Install & smoke test mm --help (push) Has been cancelled
Some checks failed
smoke-mm / Install & smoke test mm --help (push) Has been cancelled
This commit is contained in:
@@ -1,8 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
|
||||||
import shutil
|
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
@@ -11,7 +8,7 @@ from SYS.logger import log
|
|||||||
|
|
||||||
|
|
||||||
class YouTube(Provider):
|
class YouTube(Provider):
|
||||||
"""Search provider for YouTube using yt-dlp."""
|
"""Search provider for YouTube using the yt_dlp Python package."""
|
||||||
|
|
||||||
def search(
|
def search(
|
||||||
self,
|
self,
|
||||||
@@ -20,75 +17,56 @@ class YouTube(Provider):
|
|||||||
filters: Optional[Dict[str, Any]] = None,
|
filters: Optional[Dict[str, Any]] = None,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> List[SearchResult]:
|
) -> List[SearchResult]:
|
||||||
ytdlp_path = shutil.which("yt-dlp")
|
# Use the yt_dlp Python module (installed via requirements.txt).
|
||||||
if not ytdlp_path:
|
|
||||||
log("[youtube] yt-dlp not found in PATH", file=sys.stderr)
|
|
||||||
return []
|
|
||||||
|
|
||||||
search_query = f"ytsearch{limit}:{query}"
|
|
||||||
cmd = [ytdlp_path, "--dump-json", "--flat-playlist", "--no-warnings", search_query]
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
process = subprocess.run(
|
import yt_dlp # type: ignore
|
||||||
cmd,
|
ydl_opts: Dict[str, Any] = {"quiet": True, "skip_download": True, "extract_flat": True}
|
||||||
capture_output=True,
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl: # type: ignore[arg-type]
|
||||||
text=True,
|
search_query = f"ytsearch{limit}:{query}"
|
||||||
encoding="utf-8",
|
info = ydl.extract_info(search_query, download=False)
|
||||||
errors="replace",
|
entries = info.get("entries") or []
|
||||||
)
|
results: List[SearchResult] = []
|
||||||
|
for video_data in entries[:limit]:
|
||||||
|
title = video_data.get("title", "Unknown")
|
||||||
|
video_id = video_data.get("id", "")
|
||||||
|
url = video_data.get("url") or f"https://youtube.com/watch?v={video_id}"
|
||||||
|
uploader = video_data.get("uploader", "Unknown")
|
||||||
|
duration = video_data.get("duration", 0)
|
||||||
|
view_count = video_data.get("view_count", 0)
|
||||||
|
|
||||||
if process.returncode != 0:
|
duration_str = f"{int(duration // 60)}:{int(duration % 60):02d}" if duration else ""
|
||||||
log(f"[youtube] yt-dlp failed: {process.stderr}", file=sys.stderr)
|
views_str = f"{view_count:,}" if view_count else ""
|
||||||
return []
|
|
||||||
|
|
||||||
results: List[SearchResult] = []
|
results.append(
|
||||||
for line in process.stdout.splitlines():
|
SearchResult(
|
||||||
if not line.strip():
|
table="youtube",
|
||||||
continue
|
title=title,
|
||||||
|
path=url,
|
||||||
try:
|
detail=f"By: {uploader}",
|
||||||
video_data = json.loads(line)
|
annotations=[duration_str, f"{views_str} views"],
|
||||||
except json.JSONDecodeError:
|
media_kind="video",
|
||||||
continue
|
columns=[
|
||||||
|
("Title", title),
|
||||||
title = video_data.get("title", "Unknown")
|
("Uploader", uploader),
|
||||||
video_id = video_data.get("id", "")
|
("Duration", duration_str),
|
||||||
url = video_data.get("url") or f"https://youtube.com/watch?v={video_id}"
|
("Views", views_str),
|
||||||
uploader = video_data.get("uploader", "Unknown")
|
],
|
||||||
duration = video_data.get("duration", 0)
|
full_metadata={
|
||||||
view_count = video_data.get("view_count", 0)
|
"video_id": video_id,
|
||||||
|
"uploader": uploader,
|
||||||
duration_str = f"{int(duration // 60)}:{int(duration % 60):02d}" if duration else ""
|
"duration": duration,
|
||||||
views_str = f"{view_count:,}" if view_count else ""
|
"view_count": view_count,
|
||||||
|
},
|
||||||
results.append(
|
)
|
||||||
SearchResult(
|
|
||||||
table="youtube",
|
|
||||||
title=title,
|
|
||||||
path=url,
|
|
||||||
detail=f"By: {uploader}",
|
|
||||||
annotations=[duration_str, f"{views_str} views"],
|
|
||||||
media_kind="video",
|
|
||||||
columns=[
|
|
||||||
("Title", title),
|
|
||||||
("Uploader", uploader),
|
|
||||||
("Duration", duration_str),
|
|
||||||
("Views", views_str),
|
|
||||||
],
|
|
||||||
full_metadata={
|
|
||||||
"video_id": video_id,
|
|
||||||
"uploader": uploader,
|
|
||||||
"duration": duration,
|
|
||||||
"view_count": view_count,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
return results
|
||||||
|
except Exception:
|
||||||
return results
|
log("[youtube] yt_dlp import failed", file=sys.stderr)
|
||||||
|
|
||||||
except Exception as exc:
|
|
||||||
log(f"[youtube] Error: {exc}", file=sys.stderr)
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def validate(self) -> bool:
|
def validate(self) -> bool:
|
||||||
return shutil.which("yt-dlp") is not None
|
try:
|
||||||
|
import yt_dlp # type: ignore
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|||||||
@@ -501,6 +501,8 @@ fi
|
|||||||
# At this point REPO may still be wrong if mm was invoked outside any project; keep the embedded path as a last resort.
|
# At this point REPO may still be wrong if mm was invoked outside any project; keep the embedded path as a last resort.
|
||||||
|
|
||||||
VENV="$REPO/.venv"
|
VENV="$REPO/.venv"
|
||||||
|
# Ensure tools installed into the venv are discoverable to subprocess-based providers
|
||||||
|
export PATH="$VENV/bin:$PATH"
|
||||||
|
|
||||||
# Debug mode: set MM_DEBUG=1 to print repository, venv, and import diagnostics
|
# Debug mode: set MM_DEBUG=1 to print repository, venv, and import diagnostics
|
||||||
if [ -n "${MM_DEBUG:-}" ]; then
|
if [ -n "${MM_DEBUG:-}" ]; then
|
||||||
|
|||||||
@@ -303,6 +303,8 @@ set -e
|
|||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
REPO="$SCRIPT_DIR"
|
REPO="$SCRIPT_DIR"
|
||||||
VENV="$REPO/.venv"
|
VENV="$REPO/.venv"
|
||||||
|
# Make tools installed into the local venv available in PATH for provider discovery
|
||||||
|
export PATH="$VENV/bin:$PATH"
|
||||||
PY="$VENV/bin/python"
|
PY="$VENV/bin/python"
|
||||||
if [ -x "$PY" ]; then
|
if [ -x "$PY" ]; then
|
||||||
exec "$PY" -m medeia_macina.cli_entry "$@"
|
exec "$PY" -m medeia_macina.cli_entry "$@"
|
||||||
@@ -320,6 +322,9 @@ fi
|
|||||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
$repo = $scriptDir
|
$repo = $scriptDir
|
||||||
$venv = Join-Path $repo '.venv'
|
$venv = Join-Path $repo '.venv'
|
||||||
|
# Ensure venv Scripts dir is on PATH for provider discovery
|
||||||
|
$venvScripts = Join-Path $venv 'Scripts'
|
||||||
|
if (Test-Path $venvScripts) { $env:PATH = $venvScripts + ';' + $env:PATH }
|
||||||
$py = Join-Path $venv 'Scripts\python.exe'
|
$py = Join-Path $venv 'Scripts\python.exe'
|
||||||
$cli = Join-Path $repo 'CLI.py'
|
$cli = Join-Path $repo 'CLI.py'
|
||||||
if (Test-Path $py) { & $py -m medeia_macina.cli_entry @args; exit $LASTEXITCODE }
|
if (Test-Path $py) { & $py -m medeia_macina.cli_entry @args; exit $LASTEXITCODE }
|
||||||
@@ -335,10 +340,10 @@ python -m medeia_macina.cli_entry @args
|
|||||||
bat_text = (
|
bat_text = (
|
||||||
"@echo off\r\n"
|
"@echo off\r\n"
|
||||||
"set SCRIPT_DIR=%~dp0\r\n"
|
"set SCRIPT_DIR=%~dp0\r\n"
|
||||||
|
"set PATH=%SCRIPT_DIR%\.venv\Scripts;%PATH%\r\n"
|
||||||
"if exist \"%SCRIPT_DIR%\\.venv\\Scripts\\python.exe\" \"%SCRIPT_DIR%\\.venv\\Scripts\\python.exe\" -m medeia_macina.cli_entry %*\r\n"
|
"if exist \"%SCRIPT_DIR%\\.venv\\Scripts\\python.exe\" \"%SCRIPT_DIR%\\.venv\\Scripts\\python.exe\" -m medeia_macina.cli_entry %*\r\n"
|
||||||
"if exist \"%SCRIPT_DIR%\\CLI.py\" python \"%SCRIPT_DIR%\\CLI.py\" %*\r\n"
|
"if exist \"%SCRIPT_DIR%\\CLI.py\" python \"%SCRIPT_DIR%\\CLI.py\" %*\r\n"
|
||||||
"python -m medeia_macina.cli_entry %*\r\n"
|
"python -m medeia_macina.cli_entry %*\r\n"
|
||||||
"python -m medeia_macina.cli_entry %*\r\n"
|
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
bat.write_text(bat_text, encoding="utf-8")
|
bat.write_text(bat_text, encoding="utf-8")
|
||||||
|
|||||||
Reference in New Issue
Block a user