This commit is contained in:
root
2026-05-19 02:25:21 +00:00
parent fa422fb7b8
commit e1d7251545
7 changed files with 345 additions and 29 deletions

View File

@@ -12,6 +12,45 @@ prune_path() {
rm -rf "$target"
}
ensure_profile_preferences() {
if ! command -v python3 >/dev/null 2>&1; then
return 0
fi
mkdir -p "$profile_dir/Default"
PROFILE_DIR="$profile_dir" python3 - <<'PY'
import json
import os
from pathlib import Path
profile_dir = Path(os.environ["PROFILE_DIR"])
def load_json(path: Path) -> dict:
if path.exists():
try:
return json.loads(path.read_text(encoding="utf-8"))
except Exception:
return {}
return {}
def save_json(path: Path, data: dict) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(
json.dumps(data, ensure_ascii=False, separators=(",", ":")),
encoding="utf-8",
)
for relative_path in ("Default/Preferences", "Local State"):
path = profile_dir / relative_path
data = load_json(path)
extensions = data.setdefault("extensions", {})
ui = extensions.setdefault("ui", {})
ui["developer_mode"] = True
profile = data.setdefault("profile", {})
profile["exit_type"] = "Normal"
save_json(path, data)
PY
}
find_bin() {
if [ "$family" = "google-chrome" ]; then
command -v google-chrome 2>/dev/null || command -v google-chrome-stable 2>/dev/null || true
@@ -67,25 +106,74 @@ prune_path "$profile_dir/Default/Code Cache"
prune_path "$profile_dir/Default/GPUCache"
prune_path "$profile_dir/Default/DawnGraphiteCache"
prune_path "$profile_dir/Default/DawnWebGPUCache"
ensure_profile_preferences
exec "$browser_bin" \
${render_flags} \
--window-position=0,0 \
--display="${DISPLAY:?DISPLAY is required}" \
--user-data-dir="$profile_dir" \
--password-store=basic \
--no-first-run \
--start-minimized \
--force-dark-mode \
--disable-file-system \
--disable-dev-shm-usage \
--disable-background-networking \
--disable-breakpad \
--disable-default-apps \
--disable-extensions \
--disable-sync \
--disable-translate \
--metrics-recording-only \
--no-default-browser-check \
--no-first-run \
"$start_url"
browser_class="google-chrome"
if [ "$family" != "google-chrome" ]; then
browser_class="chromium"
fi
launch_browser() {
"$browser_bin" \
${render_flags} \
--window-position=0,0 \
--display="${DISPLAY:?DISPLAY is required}" \
--remote-debugging-address=127.0.0.1 \
--remote-debugging-port=9222 \
--user-data-dir="$profile_dir" \
--password-store=basic \
--no-first-run \
--new-window \
--start-maximized \
--force-dark-mode \
--disable-background-mode \
--disable-dev-shm-usage \
--disable-background-networking \
--disable-breakpad \
--disable-default-apps \
--disable-sync \
--disable-translate \
--metrics-recording-only \
--no-default-browser-check \
--no-first-run \
"$start_url" &
browser_pid=$!
}
visible_window_count() {
if ! command -v xdotool >/dev/null 2>&1; then
return 1
fi
DISPLAY="${DISPLAY:?DISPLAY is required}" xdotool search --onlyvisible --class "$browser_class" 2>/dev/null | wc -l | tr -d ' '
}
launch_browser
seen_window=0
startup_misses=0
closed_misses=0
while kill -0 "$browser_pid" 2>/dev/null; do
window_count="$(visible_window_count || true)"
if [ -n "${window_count:-}" ] && [ "$window_count" -gt 0 ] 2>/dev/null; then
seen_window=1
startup_misses=0
closed_misses=0
else
if [ "$seen_window" -eq 0 ]; then
startup_misses=$((startup_misses + 1))
if [ "$startup_misses" -ge 15 ]; then
kill -TERM "$browser_pid" 2>/dev/null || true
break
fi
else
closed_misses=$((closed_misses + 1))
if [ "$closed_misses" -ge 3 ]; then
kill -TERM "$browser_pid" 2>/dev/null || true
break
fi
fi
fi
sleep 2
done
wait "$browser_pid"

View File

@@ -40,8 +40,9 @@ services:
- "${NEKO_PROFILE_HOST_DIR_1}:/home/neko/.config/google-chrome"
- "./policies:/etc/chromium/policies/managed:ro"
- "./policies:/etc/opt/chrome/policies/managed:ro"
- "./provisioning:/var/www/provisioning:ro"
- "./browser-launch.sh:/etc/neko/browser-launch.sh:ro"
- "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/browser.conf:ro"
- "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro"
neko2:
<<: *neko-common
@@ -61,8 +62,9 @@ services:
- "${NEKO_PROFILE_HOST_DIR_2}:/home/neko/.config/google-chrome"
- "./policies:/etc/chromium/policies/managed:ro"
- "./policies:/etc/opt/chrome/policies/managed:ro"
- "./provisioning:/var/www/provisioning:ro"
- "./browser-launch.sh:/etc/neko/browser-launch.sh:ro"
- "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/browser.conf:ro"
- "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro"
neko3:
<<: *neko-common
@@ -82,5 +84,6 @@ services:
- "${NEKO_PROFILE_HOST_DIR_3}:/home/neko/.config/google-chrome"
- "./policies:/etc/chromium/policies/managed:ro"
- "./policies:/etc/opt/chrome/policies/managed:ro"
- "./provisioning:/var/www/provisioning:ro"
- "./browser-launch.sh:/etc/neko/browser-launch.sh:ro"
- "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/browser.conf:ro"
- "./${NEKO_BROWSER_SUPERVISOR_CONF}:/etc/neko/supervisord/${NEKO_BROWSER_SUPERVISOR_CONF}:ro"

View File

@@ -17,5 +17,19 @@
"VideoCaptureAllowedUrls": ["https://*.google.com/*", "https://*.youtube.com/*"],
"AudioCaptureAllowedUrls": ["https://*.google.com/*", "https://*.youtube.com/*"],
"DeveloperToolsAvailability": 1,
"DefaultGeolocationSetting": 1
"DefaultGeolocationSetting": 1,
"3rdparty": {
"extensions": {
"dhdgffkkebhmkfjojejmpbldmpobfkfo": {
"jsonImport": [
{
"hash": "1:1b41fa75bfe51a730bb246022f619811bc508da3176463c86009fe5a0a9f16b5",
"url": "http://127.0.0.1:8080/provisioning/tampermonkey-provisioning.json",
"haltOnError": false,
"installAsSystemScripts": true
}
]
}
}
}
}

View File

@@ -0,0 +1,15 @@
{
"version": "1",
"scripts": [
{
"name": "YouTube Studio Auto Dismiss",
"file_url": "https://greasyfork.org/scripts/557378-youtube-studio-auto-dismiss/code/YouTube%20Studio%20Auto%20Dismiss.user.js",
"source": "// ==UserScript==\n// @name YouTube Studio Auto Dismiss\n// @namespace http://tampermonkey.net/\n// @version 1.1\n// @description 每5秒自动检测并点击 YouTube Studio 直播页面的 Dismiss 按钮,支持延迟加载\n// @author You\n// @match https://studio.youtube.com/channel/*/livestreaming\n// @match https://studio.youtube.com/video/*/livestreaming\n// @match https://studio.youtube.com/*/livestreaming\n// @license MIT\n// @grant none\n// @downloadURL https://update.greasyfork.org/scripts/557378/YouTube%20Studio%20Auto%20Dismiss.user.js\n// @updateURL https://update.greasyfork.org/scripts/557378/YouTube%20Studio%20Auto%20Dismiss.meta.js\n// ==/UserScript==\n\n(function () {\n \"use strict\";\n\n function triggerClick(el) {\n if (!el) return;\n const evt = new MouseEvent(\"click\", {\n view: window,\n bubbles: true,\n cancelable: true,\n });\n el.dispatchEvent(evt);\n console.log(\"Dismiss 按钮已点击:\", el, \"父元素:\", el.parentElement);\n }\n\n function findDismiss(root = document) {\n const allElements = root.querySelectorAll(\"button\");\n for (const el of allElements) {\n try {\n const text = el.innerText ? el.innerText.trim() : \"\";\n if (text === \"Dismiss\" && isElementVisible(el)) {\n console.log(\"找到 Dismiss 按钮:\", el);\n return el;\n }\n\n if (el.shadowRoot) {\n const shadowBtn = findDismiss(el.shadowRoot);\n if (shadowBtn) return shadowBtn;\n }\n } catch (error) {\n console.log(\"检查元素时出错:\", error);\n }\n }\n return null;\n }\n\n function isElementVisible(el) {\n const style = window.getComputedStyle(el);\n return style.display !== \"none\" && style.visibility !== \"hidden\" && el.offsetParent !== null;\n }\n\n function checkAndClick() {\n const btn = findDismiss();\n if (btn) {\n triggerClick(btn);\n } else {\n console.log(\"未找到 Dismiss 按钮或按钮不可见\");\n }\n }\n\n if (document.readyState === \"complete\") {\n checkAndClick();\n } else {\n window.addEventListener(\"load\", checkAndClick, { once: true });\n }\n\n setInterval(checkAndClick, 5000);\n})();\n",
"enabled": true,
"position": 1
}
],
"settings": {
"runtime_content_mode": "content"
}
}

View File

@@ -0,0 +1,72 @@
// ==UserScript==
// @name YouTube Studio Auto Dismiss
// @namespace http://tampermonkey.net/
// @version 1.1
// @description 每5秒自动检测并点击 YouTube Studio 直播页面的 Dismiss 按钮,支持延迟加载
// @author You
// @match https://studio.youtube.com/channel/*/livestreaming
// @match https://studio.youtube.com/video/*/livestreaming
// @match https://studio.youtube.com/*/livestreaming
// @license MIT
// @grant none
// @downloadURL https://update.greasyfork.org/scripts/557378/YouTube%20Studio%20Auto%20Dismiss.user.js
// @updateURL https://update.greasyfork.org/scripts/557378/YouTube%20Studio%20Auto%20Dismiss.meta.js
// ==/UserScript==
(function () {
"use strict";
function triggerClick(el) {
if (!el) return;
const evt = new MouseEvent("click", {
view: window,
bubbles: true,
cancelable: true,
});
el.dispatchEvent(evt);
console.log("Dismiss 按钮已点击:", el, "父元素:", el.parentElement);
}
function findDismiss(root = document) {
const allElements = root.querySelectorAll("button");
for (const el of allElements) {
try {
const text = el.innerText ? el.innerText.trim() : "";
if (text === "Dismiss" && isElementVisible(el)) {
console.log("找到 Dismiss 按钮:", el);
return el;
}
if (el.shadowRoot) {
const shadowBtn = findDismiss(el.shadowRoot);
if (shadowBtn) return shadowBtn;
}
} catch (error) {
console.log("检查元素时出错:", error);
}
}
return null;
}
function isElementVisible(el) {
const style = window.getComputedStyle(el);
return style.display !== "none" && style.visibility !== "hidden" && el.offsetParent !== null;
}
function checkAndClick() {
const btn = findDismiss();
if (btn) {
triggerClick(btn);
} else {
console.log("未找到 Dismiss 按钮或按钮不可见");
}
}
if (document.readyState === "complete") {
checkAndClick();
} else {
window.addEventListener("load", checkAndClick, { once: true });
}
setInterval(checkAndClick, 5000);
})();