diff --git a/.claude/WIP.md b/.claude/WIP.md index f28adf87..1679c681 100644 --- a/.claude/WIP.md +++ b/.claude/WIP.md @@ -64,6 +64,13 @@ _Last updated: 2026-02-17 (v0.21.0 - Nextcloud LXC + WebRadio)_ ### Just Completed (2026-02-17) +- **PeerTube yt-dlp Video Import** — DONE (2026-02-17) + - Installed yt-dlp in PeerTube LXC container + - Added RPCD methods: import_video, import_status + - LuCI UI section with URL input and download button + - Supports YouTube, Vimeo, and 1000+ sites + - Downloads to import folder for PeerTube admin upload + - **mitmproxy WAF Filters UI** — DONE (2026-02-17) - Added new "WAF Filters" tab to mitmproxy LuCI interface - Displays 10 filter categories: sqli, xss, lfi, rce, cve_2024, scanners, webmail, api_abuse, nextcloud, roundcube diff --git a/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js index 4654a3cf..5da5dec6 100644 --- a/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js +++ b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/peertube/api.js @@ -68,5 +68,18 @@ return L.Class.extend({ object: 'luci.peertube', method: 'configure_haproxy', expect: { } + }), + + importVideo: rpc.declare({ + object: 'luci.peertube', + method: 'import_video', + params: ['url'], + expect: { } + }), + + importStatus: rpc.declare({ + object: 'luci.peertube', + method: 'import_status', + expect: { } }) }); diff --git a/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js index 886d6897..1f3a52d5 100644 --- a/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js +++ b/package/secubox/luci-app-peertube/htdocs/luci-static/resources/view/peertube/overview.js @@ -53,6 +53,15 @@ return view.extend({ } promise = api.emancipate(domain); break; + case 'import_video': + var url = args; + if (!url) { + ui.hideModal(); + ui.addNotification(null, E('p', _('Video URL is required')), 'error'); + return; + } + promise = api.importVideo(url); + break; default: ui.hideModal(); return; @@ -266,6 +275,61 @@ return view.extend({ E('hr'), + E('h4', {}, _('Import Video (yt-dlp)')), + E('p', {}, _('Download and import videos from YouTube, Vimeo, and 1000+ other sites using yt-dlp.')), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, _('Video URL')), + E('div', { 'class': 'cbi-value-field' }, [ + E('input', { + 'type': 'text', + 'id': 'import-video-url', + 'class': 'cbi-input-text', + 'placeholder': 'https://www.youtube.com/watch?v=...', + 'style': 'width: 100%; max-width: 500px;' + }) + ]) + ]), + E('div', { 'class': 'cbi-page-actions', 'style': 'margin-bottom: 15px;' }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'click': function() { + var urlInput = document.getElementById('import-video-url'); + self.handleAction('import_video', urlInput.value); + } + }, _('Download Video')), + ' ', + E('button', { + 'class': 'btn cbi-button', + 'click': function() { + api.importStatus().then(function(res) { + var statusText = res.downloading === 'true' ? + _('Download in progress...') : + _('No download running'); + statusText += '\n' + _('Videos ready: ') + (res.video_count || 0); + if (res.files) { + statusText += '\n\n' + res.files; + } + ui.showModal(_('Import Status'), [ + E('pre', { 'style': 'white-space: pre-wrap; max-height: 300px; overflow: auto;' }, statusText), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Close')) + ]) + ]); + }); + } + }, _('Check Status')) + ]), + E('p', { 'style': 'font-size: 12px; color: #666;' }, [ + _('Supported sites: YouTube, Vimeo, Dailymotion, Twitter, TikTok, and '), + E('a', { 'href': 'https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md', 'target': '_blank' }, _('1000+ more')), + _('. Videos are saved to the import folder for manual upload via PeerTube admin.') + ]), + + E('hr'), + E('h4', {}, _('Logs')), E('div', { 'id': 'peertube-logs' }, [ E('pre', { diff --git a/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube b/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube index 8be7436d..d093433c 100644 --- a/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube +++ b/package/secubox/luci-app-peertube/root/usr/libexec/rpcd/luci.peertube @@ -254,6 +254,85 @@ method_configure_haproxy() { json_dump } +# Method: import_video (yt-dlp) +method_import_video() { + read -r input + json_load "$input" + json_get_var url url + + if [ -z "$url" ]; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "URL is required" + json_dump + return + fi + + # Check container is running + if ! lxc-info -n peertube 2>/dev/null | grep -q "RUNNING"; then + json_init + json_add_boolean "success" 0 + json_add_string "error" "PeerTube container is not running" + json_dump + return + fi + + # Get videos path from UCI or use default + local videos_path + videos_path=$(uci_get main videos_path "/srv/peertube/videos") + + # Create import directory inside container + local import_dir="/var/lib/peertube/storage/tmp/import" + lxc-attach -n peertube -- mkdir -p "$import_dir" 2>/dev/null + + # Run yt-dlp in background, save to import directory + local logfile="/tmp/ytdlp-import-$$.log" + lxc-attach -n peertube -- /usr/local/bin/yt-dlp \ + --no-playlist \ + --format "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" \ + --merge-output-format mp4 \ + --output "$import_dir/%(title)s.%(ext)s" \ + --write-info-json \ + --write-thumbnail \ + "$url" > "$logfile" 2>&1 & + + local pid=$! + + # Wait up to 5 seconds for initial response + sleep 2 + + json_init + json_add_boolean "success" 1 + json_add_string "message" "Download started in background (PID: $pid)" + json_add_string "log_file" "$logfile" + json_add_string "import_dir" "$import_dir" + json_dump +} + +# Method: import_status - Check import progress +method_import_status() { + local import_dir="/var/lib/peertube/storage/tmp/import" + local files="" + local count=0 + + if lxc-info -n peertube 2>/dev/null | grep -q "RUNNING"; then + files=$(lxc-attach -n peertube -- ls -la "$import_dir" 2>/dev/null | tail -10) + count=$(lxc-attach -n peertube -- find "$import_dir" -name "*.mp4" 2>/dev/null | wc -l) + fi + + # Check for running yt-dlp processes + local downloading="false" + if lxc-attach -n peertube -- pgrep -f yt-dlp >/dev/null 2>&1; then + downloading="true" + fi + + json_init + json_add_string "downloading" "$downloading" + json_add_int "video_count" "$count" + json_add_string "files" "$files" + json_dump +} + # List available methods list_methods() { json_init @@ -281,6 +360,11 @@ list_methods() { json_close_object json_add_object "configure_haproxy" json_close_object + json_add_object "import_video" + json_add_string "url" "" + json_close_object + json_add_object "import_status" + json_close_object json_dump } @@ -327,6 +411,12 @@ case "$1" in configure_haproxy) method_configure_haproxy ;; + import_video) + method_import_video + ;; + import_status) + method_import_status + ;; *) echo '{"error":"Method not found"}' ;; diff --git a/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json b/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json index d7783459..26c1e313 100644 --- a/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json +++ b/package/secubox/luci-app-peertube/root/usr/share/rpcd/acl.d/luci-app-peertube.json @@ -3,13 +3,13 @@ "description": "Grant access to PeerTube management", "read": { "ubus": { - "luci.peertube": ["status", "logs"] + "luci.peertube": ["status", "logs", "import_status"] }, "uci": ["peertube"] }, "write": { "ubus": { - "luci.peertube": ["start", "stop", "install", "uninstall", "update", "emancipate", "live_enable", "live_disable", "configure_haproxy"] + "luci.peertube": ["start", "stop", "install", "uninstall", "update", "emancipate", "live_enable", "live_disable", "configure_haproxy", "import_video"] }, "uci": ["peertube"] }