s
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
})();
|
||||
Reference in New Issue
Block a user