Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
BIN_NAME = "gallery-dl"
BIN_PROVIDERS = "env,pip"
PLUGIN_DIR = Path(__file__).resolve().parent.name
CONFIG = load_config()
CONFIG = load_config(hydrate_binaries=False)
SNAP_DIR = Path(CONFIG.SNAP_DIR or ".").resolve()
OUTPUT_DIR = SNAP_DIR / PLUGIN_DIR
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -77,7 +77,7 @@ def save_gallery(url: str, binary: str) -> tuple[bool, str | None, str]:
Returns: (success, output_path, error_message)
"""
# Load config from config.json (auto-resolves x-aliases and x-fallback from env)
config = load_config()
config = load_config(hydrate_binaries=False)
timeout = config.GALLERYDL_TIMEOUT
check_ssl = config.GALLERYDL_CHECK_SSL_VALIDITY
gallerydl_args = config.GALLERYDL_ARGS
Expand Down Expand Up @@ -224,7 +224,7 @@ def main(url: str):
error = ""

try:
config = load_config()
config = load_config(hydrate_binaries=False)

# Check if gallery-dl is enabled
if not config.GALLERYDL_ENABLED:
Expand All @@ -241,8 +241,9 @@ def main(url: str):
emit_archive_result_record("succeeded", "staticfile already handled")
sys.exit(0)

# Get binary from environment
binary = config.GALLERYDL_BINARY
# Hydrate the binary only after cheap skip checks have passed.
hydrated_config = load_config()
binary = hydrated_config.GALLERYDL_BINARY

# Run extraction
success, output, error = save_gallery(url, binary)
Expand Down
58 changes: 53 additions & 5 deletions abx_plugins/plugins/ytdlp/templates/card.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,61 @@
<!-- YT-DLP output list -->
{% if media_files %}
<div class="loose-items" style="pointer-events: auto;">
<div class="ytdlp-media-card" style="pointer-events: auto;">
{% for file in media_files %}
<a href="{{ file.url|default:file.path|urlencode }}" target="preview"
title="{{ file.name }}">
📄 {{ file.name }}
</a>
{% if file.is_browser_playable %}
<div class="ytdlp-media-item" style="margin-bottom: 6px;">
<button
type="button"
class="ytdlp-load-player"
data-src="{{ file.url|default:file.path|urlencode }}"
data-media-type="{{ file.media_type }}"
data-name="{{ file.name }}"
style="cursor: pointer; width: 100%; text-align: left; border: 1px solid #ddd; border-radius: 4px; background: #f8f8f8; padding: 6px 8px;"
>
{% if file.is_video %}🎬{% else %}🎧{% endif %} Play {{ file.name }}
</button>
<a href="{{ file.url|default:file.path|urlencode }}" target="preview" title="{{ file.name }}">
Download file
</a>
</div>
{% else %}
<div class="loose-items" style="pointer-events: auto;">
<a href="{{ file.url|default:file.path|urlencode }}" target="preview" title="{{ file.name }}">
{% if file.is_video %}🎬{% elif file.is_audio %}🎧{% else %}📄{% endif %} {{ file.name }}
</a>
</div>
{% endif %}
{% endfor %}
</div>
<script>
(function () {
if (window.__archiveboxYtdlpCardLoader) return;
window.__archiveboxYtdlpCardLoader = true;

document.addEventListener("click", function (event) {
var button = event.target.closest && event.target.closest(".ytdlp-load-player");
if (!button) return;

var src = button.getAttribute("data-src");
var mediaType = button.getAttribute("data-media-type");
var name = button.getAttribute("data-name") || "archived media";
if (!src) return;

var media = document.createElement(mediaType === "audio" ? "audio" : "video");
media.setAttribute("controls", "controls");
media.setAttribute("preload", "none");
media.setAttribute("data-no-preview", "1");
media.setAttribute("aria-label", name);
media.src = src;
media.style.width = "100%";
media.style.maxHeight = mediaType === "audio" ? "" : "220px";
media.style.background = "#000";
media.style.display = "block";

button.replaceWith(media);
});
}());
</script>
{% else %}
<div class="thumbnail-compact" data-plugin="ytdlp" data-compact="1">
<span class="thumbnail-compact-icon">🎬</span>
Expand Down
21 changes: 21 additions & 0 deletions abx_plugins/plugins/ytdlp/tests/test_ytdlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,27 @@ def test_hook_script_exists():
assert YTDLP_HOOK.exists(), f"Hook not found: {YTDLP_HOOK}"


def test_card_template_loads_browser_media_on_click():
"""Card template should not fetch archived media until the user asks to play it."""
template = (PLUGIN_DIR / "templates" / "card.html").read_text()

assert "ytdlp-load-player" in template
assert 'data-src="{{ file.url|default:file.path|urlencode }}"' in template
assert "media.src = src" in template
assert "<video" not in template
assert "<audio" not in template


def test_card_template_links_non_browser_media_without_player():
"""Non-browser-playable yt-dlp outputs should stay as regular file links."""
template = (PLUGIN_DIR / "templates" / "card.html").read_text()

assert "{% if file.is_browser_playable %}" in template
assert "{% else %}" in template
assert "Download file" in template
assert 'href="{{ file.url|default:file.path|urlencode }}"' in template


def test_verify_deps_with_abxpkg():
"""Verify yt-dlp resolves through the real dependency preflight."""
binary_path = require_ytdlp_binary()
Expand Down