查找适用于当前网站的用户脚本,支持多个脚本仓库
// ==UserScript==
// @name Find Scripts For This Site
// @name:zh-CN 查找适用于当前网站的脚本
// @name:zh-TW 查找適用於當前網站的腳本
// @name:ja このサイト用のスクリプトを探す
// @name:ko 이 사이트용 스크립트 찾기
// @name:es Buscar scripts para este sitio
// @name:fr Trouver des scripts pour ce site
// @name:de Skripte für diese Website finden
// @name:ru Найти скрипты для этого сайта
// @namespace https://github.com/utags
// @homepageURL https://github.com/utags/userscripts#readme
// @supportURL https://github.com/utags/userscripts/issues
// @version 0.3.0
// @description Find userscripts for the current website from popular script repositories
// @description:zh-CN 查找适用于当前网站的用户脚本,支持多个脚本仓库
// @description:zh-TW 查找適用於當前網站的用戶腳本,支持多個腳本倉庫
// @description:ja 人気のスクリプトリポジトリから現在のウェブサイト用のユーザースクリプトを見つける
// @description:ko 인기 스크립트 저장소에서 현재 웹사이트용 사용자 스크립트 찾기
// @description:es Encuentra userscripts para el sitio web actual desde repositorios populares
// @description:fr Trouvez des scripts utilisateur pour le site Web actuel à partir de référentiels de scripts populaires
// @description:de Finden Sie Benutzerskripte für die aktuelle Website aus beliebten Skript-Repositories
// @description:ru Найдите пользовательские скрипты для текущего веб-сайта из популярных репозиториев скриптов
// @author Pipecraft
// @license MIT
// @match *://*/*
// @icon data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20viewBox%3D%220%200%2064%2064%22%20fill%3D%22none%22%3E%3Ctext%20x%3D%2232%22%20y%3D%2232%22%20text-anchor%3D%22middle%22%20dominant-baseline%3D%22middle%22%20font-family%3D%22Menlo%2C%20Monaco%2C%20Consolas%2C%20Courier%20New%2C%20monospace%22%20font-size%3D%2242%22%20font-weight%3D%22700%22%20fill%3D%22%231f2937%22%3E%7B%7D%3C/text%3E%3C/svg%3E
// @noframes
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_openInTab
// @grant GM.getValue
// @grant GM_getValue
// @grant GM.setValue
// @grant GM_setValue
// @grant GM.addValueChangeListener
// @grant GM_addValueChangeListener
// ==/UserScript==
//
;(() => {
'use strict'
var __defProp = Object.defineProperty
var __getOwnPropSymbols = Object.getOwnPropertySymbols
var __hasOwnProp = Object.prototype.hasOwnProperty
var __propIsEnum = Object.prototype.propertyIsEnumerable
var __defNormalProp = (obj, key, value) =>
key in obj
? __defProp(obj, key, {
enumerable: true,
configurable: true,
writable: true,
value,
})
: (obj[key] = value)
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop])
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop])
}
return a
}
function registerMenu(caption, onClick) {
if (typeof GM_registerMenuCommand === 'function') {
return GM_registerMenuCommand(caption, onClick)
}
return 0
}
function unregisterMenu(menuId) {
if (typeof GM_unregisterMenuCommand === 'function') {
GM_unregisterMenuCommand(menuId)
}
}
function openInTab(url, options) {
if (typeof GM_openInTab === 'function') {
GM_openInTab(url, options)
return
}
globalThis.open(url, '_blank')
}
async function getValue(key, defaultValue) {
if (typeof GM !== 'undefined' && typeof GM.getValue === 'function') {
return GM.getValue(key, defaultValue)
}
if (typeof GM_getValue === 'function') {
return GM_getValue(key, defaultValue)
}
return defaultValue
}
async function setValue(key, value) {
if (typeof GM !== 'undefined' && typeof GM.setValue === 'function') {
await GM.setValue(key, value)
return
}
if (typeof GM_setValue === 'function') {
GM_setValue(key, value)
}
}
async function addValueChangeListener(key, callback) {
if (
typeof GM !== 'undefined' &&
typeof GM.addValueChangeListener === 'function'
) {
return GM.addValueChangeListener(key, callback)
}
if (typeof GM_addValueChangeListener === 'function') {
return GM_addValueChangeListener(key, callback)
}
return 0
}
function c(tag, opts) {
const el = document.createElement(tag)
if (!opts) return el
if (opts.className) el.className = opts.className
if (opts.classes) for (const cls of opts.classes) el.classList.add(cls)
if (opts.dataset)
for (const k of Object.keys(opts.dataset)) el.dataset[k] = opts.dataset[k]
if (opts.attrs)
for (const k of Object.keys(opts.attrs)) el.setAttribute(k, opts.attrs[k])
if (opts.style)
for (const k of Object.keys(opts.style)) el.style[k] = opts.style[k]
if ('text' in opts) el.textContent = opts.text || ''
if (opts.type && 'type' in el) el.type = opts.type
if ('value' in opts && 'value' in el) el.value = opts.value || ''
if (opts.rows && 'rows' in el) el.rows = opts.rows
if (opts.placeholder && 'placeholder' in el)
el.placeholder = opts.placeholder
if (typeof opts.checked === 'boolean' && 'checked' in el)
el.checked = opts.checked
if (opts.children) {
for (const ch of opts.children) {
if (typeof ch === 'string') el.append(document.createTextNode(ch))
else el.append(ch)
}
}
return el
}
function setOrDelete(obj, key, value, defaultValue) {
const normalizeToDefaultType = (val, dv) => {
const t2 = typeof dv
if (t2 === 'number') {
const n = Number(val)
return Number.isFinite(n) ? n : dv
}
if (t2 === 'object') {
return val && typeof val === 'object' ? val : dv
}
return typeof val === t2 ? val : dv
}
const normalized = normalizeToDefaultType(value, defaultValue)
const isEqual = (a, b) => {
if (a === b) return true
if (a && b && typeof a === 'object' && typeof b === 'object') {
try {
return JSON.stringify(a) === JSON.stringify(b)
} catch (e) {}
}
return false
}
if (isEqual(normalized, defaultValue)) {
delete obj[key]
} else {
obj[key] = normalized
}
}
var style_default =
'/*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */@layer properties;@layer theme, base, components, utilities;@layer theme{:host,:root{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(97.1% 0.013 17.38);--color-red-500:oklch(63.7% 0.237 25.331);--color-gray-50:oklch(98.5% 0.002 247.839);--color-gray-100:oklch(96.7% 0.003 264.542);--color-gray-300:oklch(87.2% 0.01 258.338);--color-gray-400:oklch(70.7% 0.022 261.325);--color-gray-500:oklch(55.1% 0.027 264.364);--color-gray-600:oklch(44.6% 0.03 256.802);--color-gray-700:oklch(37.3% 0.034 259.733);--color-gray-800:oklch(27.8% 0.033 256.848);--color-gray-900:oklch(21% 0.034 264.665);--color-white:#fff;--spacing:0.25rem;--font-weight-semibold:600;--font-weight-bold:700;--radius-md:0.375rem;--radius-xl:0.75rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,::backdrop,::file-selector-button,:after,:before{border:0 solid;box-sizing:border-box;margin:0;padding:0}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-size:1em;font-variation-settings:var(--default-mono-font-variation-settings,normal)}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}::file-selector-button,button,input,optgroup,select,textarea{background-color:transparent;border-radius:0;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance:-apple-pay-button)) or (contain-intrinsic-size:1px){::-moz-placeholder{color:currentcolor;@supports (color:color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}::placeholder{color:currentcolor;@supports (color:color-mix(in lab,red,red)){color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}::file-selector-button,button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer utilities{.container{width:100%;@media (width >= 40rem){max-width:40rem}@media (width >= 48rem){max-width:48rem}@media (width >= 64rem){max-width:64rem}@media (width >= 80rem){max-width:80rem}@media (width >= 96rem){max-width:96rem}}.grid{display:grid}}:host{all:initial}.user-settings{position:fixed;right:calc(var(--spacing)*3);top:calc(var(--spacing)*3);z-index:2147483649;--tw-ring-color:var(--user-color-ring,#111827)}.user-settings .panel{background-color:var(--color-gray-100);border-bottom-left-radius:var(--radius-xl);border-bottom-right-radius:var(--radius-xl);color:var(--color-gray-900);font-family:var(--font-sans);font-size:14px;max-height:90vh;overflow-y:auto;padding-inline:calc(var(--spacing)*4);padding-bottom:calc(var(--spacing)*4);padding-top:calc(var(--spacing)*0);width:420px;--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,rgba(0,0,0,.1)),0 8px 10px -6px var(--tw-shadow-color,rgba(0,0,0,.1));background:#f2f2f7;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);box-shadow:0 10px 39px 10px #3e424238!important;scrollbar-color:rgba(156,163,175,.25) transparent;scrollbar-width:thin}.user-settings .grid{display:flex;flex-direction:column;gap:calc(var(--spacing)*3)}.user-settings .row{align-items:center;display:flex;gap:calc(var(--spacing)*3);justify-content:space-between;padding-block:calc(var(--spacing)*3);padding-inline:calc(var(--spacing)*4)}.user-settings .group{background-color:var(--color-white);border-radius:var(--radius-xl);gap:calc(var(--spacing)*0);overflow:hidden}.user-settings .group .row{background-color:var(--color-white);border-radius:0;border-style:var(--tw-border-style);border-width:0;padding-block:calc(var(--spacing)*3);padding-inline:calc(var(--spacing)*4);position:relative}.user-settings .group .row:not(:last-child):after{background:#e5e7eb;bottom:0;content:"";height:1px;left:16px;position:absolute;right:0}.user-settings .header-row{align-items:center;border-radius:0;display:flex;justify-content:center;padding-inline:calc(var(--spacing)*0);padding-bottom:calc(var(--spacing)*3);padding-top:calc(var(--spacing)*0)}.user-settings .panel-stuck .header-row .panel-title{opacity:0;transform:translateY(-2px);transition:opacity .15s ease,transform .15s ease}.user-settings label{color:var(--color-gray-600)}.user-settings .label-wrap{display:flex;flex-direction:column;gap:calc(var(--spacing)*1);min-width:60px;text-align:left}.user-settings .btn{border-color:var(--color-gray-300);border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;color:var(--color-gray-700);padding-block:calc(var(--spacing)*1);padding-inline:calc(var(--spacing)*3);white-space:nowrap;&:hover{@media (hover:hover){background-color:var(--color-gray-50)}}}.user-settings .btn-danger{border-color:var(--color-red-500);color:var(--color-red-500);&:hover{@media (hover:hover){background-color:var(--color-red-50)}}}.user-settings .btn-ghost{border-radius:var(--radius-md);color:var(--color-gray-500);padding-block:calc(var(--spacing)*1);padding-inline:calc(var(--spacing)*2);&:hover{@media (hover:hover){background-color:var(--color-gray-100)}}}.user-settings input[type=text]{border-color:transparent;border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;color:var(--color-gray-700);padding-block:calc(var(--spacing)*2);padding-inline:calc(var(--spacing)*3);text-align:right;width:180px;--tw-outline-style:none;outline-style:none}.user-settings input[type=text]:focus,.user-settings input[type=text]:hover{border-color:var(--color-gray-300)}.user-settings select{background-color:var(--color-white);border-color:transparent;border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;color:var(--color-gray-700);padding-block:calc(var(--spacing)*2);padding-inline:calc(var(--spacing)*3);text-align:right;width:180px;--tw-outline-style:none;outline-style:none}.user-settings select:focus,.user-settings select:hover{border-color:var(--color-gray-300)}.user-settings input[type=color]{border-color:var(--color-gray-300);border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;height:calc(var(--spacing)*8);padding:calc(var(--spacing)*0);width:80px}.user-settings textarea{border-color:transparent;border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;color:var(--color-gray-700);padding-block:calc(var(--spacing)*2);padding-inline:calc(var(--spacing)*3);text-align:right;width:100%;--tw-outline-style:none;outline-style:none}.user-settings textarea:focus,.user-settings textarea:hover{border-color:var(--color-gray-300)}.user-settings .switch,.user-settings .toggle-wrap{align-items:center;display:flex;gap:calc(var(--spacing)*2)}.user-settings .toggle-checkbox{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#e5e5ea;border:1px solid #d1d1d6;border-radius:9999px;box-shadow:inset 0 1px 1px rgba(0,0,0,.1);cursor:pointer;display:inline-block;height:22px;position:relative;transition:background-color .2s ease,border-color .2s ease;width:42px}.user-settings .toggle-checkbox:before{background:#fff;border-radius:9999px;box-shadow:0 2px 4px rgba(0,0,0,.25);content:"";height:18px;left:2px;position:absolute;top:50%;transform:translateY(-50%);transition:transform .2s ease,background-color .2s ease,left .2s ease,right .2s ease;width:18px}.user-settings .toggle-checkbox:checked{background:var(--user-toggle-on-bg,#34c759);border-color:var(--user-toggle-on-bg,#34c759)}.user-settings .panel-title{font-size:20px;--tw-font-weight:var(--font-weight-bold);color:var(--color-gray-800);font-weight:var(--font-weight-bold)}.user-settings .outer-header{align-items:center;background-color:var(--color-gray-100);background:#f2f2f7;border-top-left-radius:var(--radius-xl);border-top-right-radius:var(--radius-xl);display:flex;font-family:var(--font-sans);height:calc(var(--spacing)*11);justify-content:center;position:relative}.user-settings .outer-header .outer-title{font-size:20px;opacity:0;transition:opacity .15s ease;--tw-font-weight:var(--font-weight-bold);color:var(--color-gray-800);font-weight:var(--font-weight-bold)}.user-settings .outer-header.stuck .outer-title{opacity:1}.user-settings .outer-header:after{background:#e5e7eb;bottom:0;content:"";height:1px;left:0;opacity:0;position:absolute;right:0;transition:opacity .15s ease}.user-settings .outer-header.stuck:after{opacity:1}.user-settings .group-title{font-size:13px;padding-inline:calc(var(--spacing)*1);--tw-font-weight:var(--font-weight-semibold);color:var(--color-gray-600);font-weight:var(--font-weight-semibold)}.user-settings .btn-ghost.icon{align-items:center;border-radius:calc(infinity*1px);color:var(--color-gray-500);cursor:pointer;display:flex;font-size:16px;height:calc(var(--spacing)*9);justify-content:center;transition:background-color .15s ease,color .15s ease;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:calc(var(--spacing)*9);&:hover{@media (hover:hover){background-color:var(--color-gray-100)}}&:hover{@media (hover:hover){color:var(--color-gray-700)}}}.user-settings .close-btn:hover{background-color:var(--color-gray-300);box-shadow:0 0 0 1px rgba(0,0,0,.05);color:var(--color-gray-900);font-size:19px;transform:translateY(-50%)}.user-settings .close-btn{position:absolute;right:12px;top:50%;transform:translateY(-50%);transition:transform .15s ease,background-color .15s ease,color .15s ease,font-size .15s ease}.user-settings .toggle-checkbox:checked:before{background:#fff;left:auto;right:2px;transform:translateY(-50%)}.user-settings .color-row{align-items:center;display:flex;gap:calc(var(--spacing)*1.5)}.user-settings .color-swatch{border-radius:var(--radius-md);cursor:pointer;height:calc(var(--spacing)*6);width:calc(var(--spacing)*6)}.user-settings .color-swatch.active{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-color:var(--user-color-ring,#111827)}.user-settings .seg{align-items:center;display:flex;flex-wrap:wrap;gap:calc(var(--spacing)*2)}.user-settings .seg-btn{border-color:var(--color-gray-300);border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;color:var(--color-gray-700);cursor:pointer;padding-block:calc(var(--spacing)*1);padding-inline:calc(var(--spacing)*3);-webkit-user-select:none;-moz-user-select:none;user-select:none;&:hover{@media (hover:hover){background-color:var(--color-gray-50)}}}.user-settings .seg-btn.active{background:var(--user-active-bg,#111827);border-color:var(--user-active-bg,#111827);color:var(--user-active-fg,#fff)}.user-settings .value-wrap{align-items:flex-end;display:flex;flex-direction:column;gap:calc(var(--spacing)*1);text-align:right}.user-settings .tabs{align-items:center;display:flex;gap:calc(var(--spacing)*2);margin-bottom:calc(var(--spacing)*2)}.user-settings .tab-btn{border-color:var(--color-gray-300);border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;color:var(--color-gray-700);cursor:pointer;padding-block:calc(var(--spacing)*1);padding-inline:calc(var(--spacing)*3);-webkit-user-select:none;-moz-user-select:none;user-select:none;&:hover{@media (hover:hover){background-color:var(--color-gray-50)}}}.user-settings .tab-btn.active{background:var(--user-active-bg,#111827);border-color:var(--user-active-bg,#111827);color:var(--user-active-fg,#fff)}.user-settings .field-help{color:var(--color-gray-400);font-size:11px}@media (prefers-color-scheme:dark){.user-settings .panel{background-color:var(--color-gray-800);border-bottom-left-radius:var(--radius-xl);border-bottom-right-radius:var(--radius-xl);box-shadow:0 10px 39px 10px #00000040!important;color:var(--color-gray-100)}.user-settings .row{background-color:transparent;border-style:var(--tw-border-style);border-width:0}.user-settings .header-row{background-color:var(--color-gray-800);border-color:var(--color-gray-700)}.user-settings .outer-header{background-color:var(--color-gray-800);border-top-left-radius:var(--radius-xl);border-top-right-radius:var(--radius-xl)}.user-settings .outer-header:after{background:#4b5563}.user-settings .footer a.issue-link{color:var(--color-gray-300);&:hover{@media (hover:hover){color:var(--color-gray-100)}}}.user-settings .footer .brand{color:var(--color-gray-400)}.user-settings label{color:var(--color-gray-300)}.user-settings .field-help{color:var(--color-gray-400)}.user-settings .group{background-color:var(--color-gray-700)}.user-settings .group .row:not(:last-child):after{background:#4b5563}}.user-settings .panel::-webkit-scrollbar{width:4px}.user-settings .panel::-webkit-scrollbar-track{background:transparent}.user-settings .panel::-webkit-scrollbar-thumb{background:rgba(156,163,175,.25);border-radius:9999px;opacity:.25}.user-settings .footer{align-items:center;color:var(--color-gray-500);display:flex;flex-direction:column;font-size:12px;gap:calc(var(--spacing)*1);padding-bottom:calc(var(--spacing)*3);padding-top:calc(var(--spacing)*6)}.user-settings .footer a.issue-link{color:var(--color-gray-600);cursor:pointer;text-decoration-line:underline;text-underline-offset:2px;-webkit-user-select:none;-moz-user-select:none;user-select:none;&:hover{@media (hover:hover){color:var(--color-gray-800)}}}.user-settings .footer .brand{color:var(--color-gray-500);cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;&:hover{@media (hover:hover){color:var(--color-gray-700)}}}.user-settings button{-webkit-user-select:none;-moz-user-select:none;user-select:none}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@layer properties{*,::backdrop,:after,:before{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-border-style:solid;--tw-font-weight:initial}}'
var currentHost
function onKeyDown(e) {
if (e.key === 'Escape') {
closeSettingsPanel()
}
}
function closeSettingsPanel() {
try {
currentHost == null ? void 0 : currentHost.remove()
} catch (e) {}
try {
globalThis.removeEventListener('keydown', onKeyDown, true)
} catch (e) {}
currentHost = void 0
}
function createToggleRow(label, key, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const seg = c('div', { className: 'toggle-wrap' })
const chk = c('input', {
type: 'checkbox',
className: 'toggle-checkbox',
dataset: { key },
})
const val = c('div', { className: 'value-wrap' })
seg.append(chk)
val.append(seg)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(val)
return { row, chk }
}
function createInputRow(label, key, placeholder, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const inp = c('input', {
type: 'text',
placeholder: placeholder || '',
dataset: { key },
})
const val = c('div', { className: 'value-wrap' })
val.append(inp)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(val)
return { row, inp }
}
function createTextareaRow(label, key, rows, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const ta = c('textarea', {
rows: rows || 4,
dataset: { key },
})
const val = c('div', { className: 'value-wrap' })
val.append(ta)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(val)
return { row, ta }
}
function createRadioRow(label, key, opts, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const seg = c('div', { className: 'seg' })
for (const o of opts) {
const b = c('button', {
className: 'seg-btn',
dataset: { key, value: o.value },
text: o.label,
})
seg.append(b)
}
const val = c('div', { className: 'value-wrap' })
val.append(seg)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(val)
return { row, seg }
}
function createColorRow(label, key, opts, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const seg = c('div', { className: 'color-row' })
for (const o of opts) {
const b = c('button', {
className: 'color-swatch',
dataset: { key, value: o.value },
style: { backgroundColor: o.value },
})
seg.append(b)
}
const val = c('div', { className: 'value-wrap' })
val.append(seg)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(val)
return { row, seg }
}
function createSelectRow(label, key, opts, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const sel = c('select', { dataset: { key } })
for (const o of opts) {
const opt = c('option', { value: o.value, text: o.label })
sel.append(opt)
}
const val = c('div', { className: 'value-wrap' })
val.append(sel)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(val)
return { row, sel }
}
function createActionRow(label, key, actions, help) {
const row = c('div', { className: 'row' })
const labWrap = c('div', { className: 'label-wrap' })
const lab = c('label', { text: label })
const wrap = c('div', { className: 'value-wrap' })
const act = c('div', { className: 'seg' })
for (const a of actions) {
const b = c('button', {
className: 'btn action-btn'.concat(
a.kind === 'danger' ? ' btn-danger' : ''
),
dataset: { key, action: a.id },
text: a.text,
})
act.append(b)
}
wrap.append(act)
labWrap.append(lab)
if (help) labWrap.append(c('div', { className: 'field-help', text: help }))
row.append(labWrap)
row.append(wrap)
return { row }
}
function openSettingsPanel(schema, store, options) {
const { host, root, existed } = ensureHostAndRoot(options)
currentHost = host
if (existed) return
let lastValues = {}
const styleTag = c('style', {
text: style_default.concat(
(options == null ? void 0 : options.styleText) || ''
),
})
root.append(styleTag)
const wrap = c('div', { className: 'user-settings' })
applyThemeStyles(wrap, options == null ? void 0 : options.theme)
const panel = c('div', { className: 'panel' })
const grid = c('div', { className: 'grid' })
const { row: headerRow } = buildHeader(schema.title)
grid.append(headerRow)
const fillers = {}
const addFiller = (key, fn) => {
if (!fillers[key]) fillers[key] = []
fillers[key].push(fn)
}
function appendAndFill(container, row, key, filler) {
container.append(row)
addFiller(key, filler)
}
function appendField(container, f) {
switch (f.type) {
case 'toggle': {
const { row, chk } = createToggleRow(f.label, f.key, f.help)
appendAndFill(container, row, f.key, () => {
fillToggleUI(chk, f.key)
})
break
}
case 'input': {
const { row, inp } = createInputRow(
f.label,
f.key,
f.placeholder,
f.help
)
appendAndFill(container, row, f.key, () => {
fillInput(inp, f.key)
})
break
}
case 'textarea': {
const { row, ta } = createTextareaRow(f.label, f.key, f.rows, f.help)
appendAndFill(container, row, f.key, () => {
fillTextarea(ta, f.key)
})
break
}
case 'radio': {
const { row, seg } = createRadioRow(f.label, f.key, f.options, f.help)
appendAndFill(container, row, f.key, () => {
fillRadioUI(seg, f.key)
})
break
}
case 'select': {
const { row, sel } = createSelectRow(
f.label,
f.key,
f.options,
f.help
)
appendAndFill(container, row, f.key, () => {
fillSelect(sel, f.key)
})
break
}
case 'colors': {
const { row, seg } = createColorRow(f.label, f.key, f.options, f.help)
appendAndFill(container, row, f.key, () => {
fillColorUI(seg, f.key)
})
break
}
case 'action': {
const { row } = createActionRow(f.label, f.key, f.actions, f.help)
container.append(row)
break
}
}
}
function sanitizeDatasetKey(rawKey) {
let out = ''
for (const ch of rawKey) {
const code = ch.codePointAt(0) || 0
out += code >= 65 && code <= 90 ? '-' + ch.toLowerCase() : ch
}
return out
}
function ensureHostAndRoot(options2) {
const keySan = sanitizeDatasetKey(
(options2 == null ? void 0 : options2.hostDatasetKey) || 'usrHost'
)
const sel = '[data-'
.concat(keySan, '="')
.concat(
(options2 == null ? void 0 : options2.hostDatasetValue) || 'settings',
'"]'
)
const existing = document.querySelector(sel)
let root2
let hostEl
if (existing instanceof HTMLDivElement && existing.shadowRoot) {
hostEl = existing
root2 = existing.shadowRoot
try {
document.documentElement.append(hostEl)
} catch (e) {}
return { host: hostEl, root: root2, existed: true }
}
const key =
(options2 == null ? void 0 : options2.hostDatasetKey) || 'userHost'
const val =
(options2 == null ? void 0 : options2.hostDatasetValue) || 'settings'
hostEl = c('div', { dataset: { [key]: val } })
root2 = hostEl.attachShadow({ mode: 'open' })
document.documentElement.append(hostEl)
return { host: hostEl, root: root2, existed: false }
}
function applyThemeStyles(wrap2, theme) {
if (!theme) return
const properties = []
if (theme.activeBg)
properties.push('--user-active-bg: '.concat(theme.activeBg, ';'))
if (theme.activeFg)
properties.push('--user-active-fg: '.concat(theme.activeFg, ';'))
if (theme.colorRing)
properties.push('--user-color-ring: '.concat(theme.colorRing, ';'))
if (theme.toggleOnBg)
properties.push('--user-toggle-on-bg: '.concat(theme.toggleOnBg, ';'))
const accent = theme.activeBg || theme.colorRing
if (accent) properties.push('--user-accent: '.concat(accent, ';'))
if (properties.length > 0) wrap2.style.cssText = properties.join(' ')
}
function buildHeader(title) {
const row = c('div', { className: 'row header-row' })
const titleEl = c('label', { className: 'panel-title', text: title })
row.append(titleEl)
return { row }
}
function renderSimplePanel(container, data) {
if (data.groups && Array.isArray(data.groups)) {
renderGroupsPanel(container, data.groups)
return
}
const fields = data.fields || []
const body = c('div', { className: 'grid group' })
container.append(body)
for (const f of fields) appendField(body, f)
}
function renderTabsPanel(container, tabs) {
var _a
const tabsWrap = c('div', { className: 'tabs' })
const panels = {}
let active = ((_a = tabs[0]) == null ? void 0 : _a.id) || ''
for (const t2 of tabs) {
const b = c('button', {
className: 'tab-btn',
dataset: { tabId: t2.id },
text: t2.title,
})
tabsWrap.append(b)
const p = c('div', { className: 'grid' })
panels[t2.id] = p
if (t2.id !== active) p.style.display = 'none'
if ('groups' in t2 && Array.isArray(t2.groups)) {
renderGroupsPanel(p, t2.groups)
} else if ('fields' in t2 && Array.isArray(t2.fields)) {
p.className = 'grid group'
for (const f of t2.fields) appendField(p, f)
}
}
container.append(tabsWrap)
for (const id of Object.keys(panels)) container.append(panels[id])
function updateTabsUI() {
for (const b of Array.from(tabsWrap.querySelectorAll('.tab-btn'))) {
const id = b.dataset.tabId || ''
if (id === active) b.classList.add('active')
else b.classList.remove('active')
}
for (const id of Object.keys(panels)) {
panels[id].style.display = id === active ? '' : 'none'
}
}
function onTabsClick(e) {
const t2 = e.target
const b = t2.closest('.tab-btn')
if (b && b instanceof HTMLElement) {
active = b.dataset.tabId || ''
updateTabsUI()
}
}
tabsWrap.addEventListener('click', onTabsClick)
updateTabsUI()
}
function renderGroupsPanel(container, groups) {
for (const g of groups) {
const body = c('div', { className: 'grid group' })
if (g.title) {
const header = c('h2', { className: 'group-title', text: g.title })
container.append(header)
}
container.append(body)
for (const f of g.fields) appendField(body, f)
}
}
const refreshAll = async () => {
try {
lastValues = await store.getAll()
} catch (e) {}
for (const k of Object.keys(fillers)) {
for (const fn of fillers[k]) {
try {
fn()
} catch (e) {}
}
}
}
function wireStoreChange(store2, fillers2) {
var _a
try {
;(_a = store2.onChange) == null
? void 0
: _a.call(store2, (e) => {
if (e.key === '*' || !fillers2[e.key]) {
void refreshAll()
return
}
for (const fn of fillers2[e.key]) {
try {
fn()
} catch (e2) {}
}
})
} catch (e) {}
}
function fillRadioUI(seg, key) {
try {
const v = lastValues[key]
for (const b of Array.from(seg.querySelectorAll('.seg-btn'))) {
const val = b.dataset.value || ''
if (val === String(v)) b.classList.add('active')
else b.classList.remove('active')
}
} catch (e) {}
}
function fillColorUI(seg, key) {
try {
const v = lastValues[key]
for (const b of Array.from(seg.querySelectorAll('.color-swatch'))) {
const val = b.dataset.value || ''
if (val.toLowerCase() === String(v || '').toLowerCase())
b.classList.add('active')
else b.classList.remove('active')
}
} catch (e) {}
}
function fillToggleUI(onBtn, key) {
try {
const v = lastValues[key]
if (onBtn instanceof HTMLInputElement && onBtn.type === 'checkbox') {
onBtn.checked = Boolean(v)
}
} catch (e) {}
}
function fillInput(inp, key) {
try {
const v = lastValues[key]
inp.value = String(v != null ? v : '')
} catch (e) {}
}
function fillTextarea(ta, key) {
try {
const v = lastValues[key]
ta.value = String(v != null ? v : '')
} catch (e) {}
}
function fillSelect(sel, key) {
try {
const v = lastValues[key]
for (const o of Array.from(sel.querySelectorAll('option'))) {
o.selected = o.value === String(v)
}
} catch (e) {}
}
async function handleSegButton(rb) {
const key = rb.dataset.key || ''
const val = rb.dataset.value || ''
if (!key) return
try {
await store.set(key, val)
} catch (e) {}
}
async function handleColorSwatch(cs) {
const key = cs.dataset.key || ''
const val = cs.dataset.value || ''
if (!key) return
try {
await store.set(key, val)
} catch (e) {}
}
function handleActionBtn(ab) {
var _a
const key = ab.dataset.key || ''
const actionId = ab.dataset.action || ''
try {
;(_a = options == null ? void 0 : options.onAction) == null
? void 0
: _a.call(options, { key, actionId, target: ab })
} catch (e) {}
}
function onPanelClick(e) {
const t2 = e.target
if (t2 === topCloseBtn) {
closeSettingsPanel()
return
}
const rb = t2.closest('.seg-btn')
if (rb && rb instanceof HTMLElement) {
void handleSegButton(rb)
return
}
const cs = t2.closest('.color-swatch')
if (cs && cs instanceof HTMLElement) {
void handleColorSwatch(cs)
return
}
const ab = t2.closest('.action-btn')
if (ab && ab instanceof HTMLElement) handleActionBtn(ab)
}
function handleInputChange(inp) {
var _a
const key = (_a = inp.dataset) == null ? void 0 : _a.key
if (!key) return
const isCheckbox = (inp.type || '').toLowerCase() === 'checkbox'
const v = isCheckbox ? Boolean(inp.checked) : inp.value
void store.set(key, v)
}
function handleTextareaChange(ta) {
var _a
const key = (_a = ta.dataset) == null ? void 0 : _a.key
if (!key) return
void store.set(key, ta.value)
}
function handleSelectChange(sel) {
var _a
const key = (_a = sel.dataset) == null ? void 0 : _a.key
if (!key) return
void store.set(key, sel.value)
}
function onPanelChange(e) {
const t2 = e.target
const inp = t2.closest('input')
if (inp && inp instanceof HTMLInputElement) {
handleInputChange(inp)
return
}
const ta = t2.closest('textarea')
if (ta && ta instanceof HTMLTextAreaElement) {
handleTextareaChange(ta)
return
}
const sel = t2.closest('select')
if (sel && sel instanceof HTMLSelectElement) {
handleSelectChange(sel)
}
}
switch (schema.type) {
case 'simple': {
renderSimplePanel(grid, schema)
break
}
case 'tabs': {
renderTabsPanel(grid, schema.tabs)
break
}
}
panel.addEventListener('click', onPanelClick)
panel.addEventListener('change', onPanelChange)
const outerHeader = c('div', { className: 'outer-header' })
const outerTitle = c('label', {
className: 'outer-title',
text: schema.title,
})
const topCloseBtn = c('button', {
className: 'btn-ghost icon close-btn',
text: '\xD7',
attrs: { 'aria-label': '\u5173\u95ED' },
})
outerHeader.append(outerTitle)
outerHeader.append(topCloseBtn)
try {
outerHeader.addEventListener('click', (e) => {
const t2 = e.target
if (t2 === topCloseBtn) {
closeSettingsPanel()
}
})
} catch (e) {}
panel.append(grid)
const footer = c('div', { className: 'footer' })
const issueLink = c('a', {
className: 'issue-link',
text: 'Report an Issue\u2026',
attrs: {
href:
(options == null ? void 0 : options.issuesUrl) ||
'https://github.com/utags/userscripts/issues',
target: '_blank',
rel: 'noopener noreferrer',
},
})
const brand = c('a', {
className: 'brand',
text: 'Made with \u2764\uFE0F by Pipecraft',
attrs: {
href: 'https://www.pipecraft.net/',
target: '_blank',
rel: 'noopener noreferrer',
},
})
footer.append(issueLink)
footer.append(brand)
panel.append(footer)
const stickyThreshold = 22
let stickyTimer
const stickyDebounceMs = 80
function updateHeaderStickyCore() {
try {
const sc = panel.scrollTop || 0
const stuck = sc > stickyThreshold
if (stuck) {
panel.classList.add('panel-stuck')
outerHeader.classList.add('stuck')
} else {
panel.classList.remove('panel-stuck')
outerHeader.classList.remove('stuck')
}
} catch (e) {}
}
function updateHeaderSticky() {
try {
if (stickyTimer !== void 0) globalThis.clearTimeout(stickyTimer)
stickyTimer = globalThis.setTimeout(
updateHeaderStickyCore,
stickyDebounceMs
)
} catch (e) {}
}
try {
panel.addEventListener('scroll', updateHeaderSticky)
updateHeaderStickyCore()
} catch (e) {}
wrap.append(outerHeader)
wrap.append(panel)
root.append(wrap)
wireStoreChange(store, fillers)
void refreshAll()
globalThis.addEventListener('keydown', onKeyDown, true)
}
function createObjectSettingsStore(rootKey, defaults) {
let cache
let initPromise
const changeCbs = []
let listenerRegistered = false
function registerValueChangeListener() {
if (listenerRegistered) return
try {
void addValueChangeListener(rootKey, (n, ov, nv, remote) => {
try {
if (nv && typeof nv === 'object') {
const merged = __spreadValues({}, defaults)
Object.assign(merged, nv)
cache = merged
} else {
cache = __spreadValues({}, defaults)
}
for (const f of changeCbs) {
f({ key: '*', oldValue: ov, newValue: nv, remote })
}
} catch (e) {}
})
listenerRegistered = true
} catch (e) {}
}
registerValueChangeListener()
async function ensure() {
if (cache) return cache
if (initPromise) return initPromise
initPromise = (async () => {
let obj
try {
obj = await getValue(rootKey, defaults)
} catch (e) {}
cache = __spreadValues({}, defaults)
if (obj && typeof obj === 'object') Object.assign(cache, obj)
initPromise = void 0
return cache
})()
return initPromise
}
return {
async get(key) {
var _a
const obj = await ensure()
return (_a = obj[key]) != null ? _a : defaults[key]
},
async getAll() {
const obj = await ensure()
const out = __spreadValues({}, obj)
return out
},
async set(...args) {
let obj
try {
obj = await getValue(rootKey, {})
} catch (e) {}
if (typeof args[0] === 'string') {
const key = args[0]
const value = args[1]
const dv = defaults[key]
setOrDelete(obj, key, value, dv)
} else {
const kvs = args[0]
for (const k of Object.keys(kvs)) {
const v = kvs[k]
const dv = defaults[k]
setOrDelete(obj, k, v, dv)
}
}
cache = __spreadValues({}, defaults)
if (obj && typeof obj === 'object') Object.assign(cache, obj)
try {
await setValue(rootKey, obj)
} catch (e) {}
},
defaults() {
return __spreadValues({}, defaults)
},
onChange(cb) {
changeCbs.push(cb)
},
}
}
var CONFIG = {
REPOSITORIES: [
{
id: 'greasy_fork',
name: 'Greasy Fork',
domainSearchUrl:
'https://greasyfork.org/scripts/by-site/{domain}?filter_locale=0',
domainSearchEnabled: true,
keywordSearchUrl:
'https://greasyfork.org/scripts?filter_locale=0&q={keyword}',
keywordSearchEnabled: true,
icon: '\u{1F374}',
},
{
id: 'openuserjs',
name: 'OpenUserJS',
keywordSearchUrl: 'https://openuserjs.org/?q={keyword}',
keywordSearchEnabled: true,
icon: '\u{1F4DC}',
},
{
id: 'scriptcat',
name: 'ScriptCat',
domainSearchUrl: 'https://scriptcat.org/search?domain={domain}',
domainSearchEnabled: true,
keywordSearchUrl: 'https://scriptcat.org/search?keyword={keyword}',
keywordSearchEnabled: true,
icon: '\u{1F431}',
},
{
id: 'github',
name: 'GitHub',
keywordSearchUrl:
'https://github.com/search?type=code&q=language%3AJavaScript+%22%3D%3DUserScript%3D%3D%22+{keyword}',
keywordSearchEnabled: true,
icon: '\u{1F419}',
},
{
id: 'github_gist',
name: 'GitHub Gist',
keywordSearchUrl:
'https://gist.github.com/search?l=JavaScript&q=%22%3D%3DUserScript%3D%3D%22+{keyword}',
keywordSearchEnabled: true,
icon: '\u{1F4DD}',
},
{
id: 'sleazy_fork',
name: 'Sleazy Fork',
domainSearchUrl:
'https://sleazyfork.org/scripts/by-site/{domain}?filter_locale=0',
domainSearchEnabled: false,
keywordSearchUrl:
'https://sleazyfork.org/scripts?filter_locale=0&q={keyword}',
keywordSearchEnabled: false,
icon: '\u{1F51E}',
},
],
DEBUG: false,
SETTINGS_KEY: 'find_scripts_settings',
}
var I18N = {
en: {
menu_domain: '{icon} Find scripts by domain on {name}',
menu_keyword: '{icon} Find scripts by keyword on {name}',
title_settings: 'Repository Settings',
btn_save: 'Save',
btn_cancel: 'Cancel',
title_domain: 'Domain Search',
title_keyword: 'Keyword Search',
menu_settings: '\u2699\uFE0F Settings',
},
'zh-CN': {
menu_domain:
'{icon} \u5728 {name} \u4E0A\u6309\u57DF\u540D\u67E5\u627E\u811A\u672C',
menu_keyword:
'{icon} \u5728 {name} \u4E0A\u6309\u5173\u952E\u5B57\u67E5\u627E\u811A\u672C',
title_settings: '\u4ED3\u5E93\u8BBE\u7F6E',
btn_save: '\u4FDD\u5B58',
btn_cancel: '\u53D6\u6D88',
title_domain: '\u57DF\u540D\u641C\u7D22',
title_keyword: '\u5173\u952E\u5B57\u641C\u7D22',
menu_settings: '\u2699\uFE0F \u8BBE\u7F6E',
},
'zh-TW': {
menu_domain:
'{icon} \u5728 {name} \u4E0A\u6309\u57DF\u540D\u67E5\u627E\u8173\u672C',
menu_keyword:
'{icon} \u5728 {name} \u4E0A\u6309\u95DC\u9375\u5B57\u67E5\u627E\u8173\u672C',
title_settings: '\u5009\u5EAB\u8A2D\u7F6E',
btn_save: '\u4FDD\u5B58',
btn_cancel: '\u53D6\u6D88',
title_domain: '\u57DF\u540D\u641C\u7D22',
title_keyword: '\u95DC\u9375\u5B57\u641C\u7D22',
menu_settings: '\u2699\uFE0F \u8A2D\u7F6E',
},
ja: {
menu_domain:
'{icon} {name} \u3067\u30C9\u30E1\u30A4\u30F3\u304B\u3089\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u63A2\u3059',
menu_keyword:
'{icon} {name} \u3067\u30AD\u30FC\u30EF\u30FC\u30C9\u304B\u3089\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u63A2\u3059',
title_settings: '\u30EA\u30DD\u30B8\u30C8\u30EA\u8A2D\u5B9A',
btn_save: '\u4FDD\u5B58',
btn_cancel: '\u30AD\u30E3\u30F3\u30BB\u30EB',
title_domain: '\u30C9\u30E1\u30A4\u30F3\u691C\u7D22',
title_keyword: '\u30AD\u30FC\u30EF\u30FC\u30C9\u691C\u7D22',
menu_settings: '\u2699\uFE0F \u8A2D\u5B9A',
},
ko: {
menu_domain:
'{icon} {name}\uC5D0\uC11C \uB3C4\uBA54\uC778\uC73C\uB85C \uC2A4\uD06C\uB9BD\uD2B8 \uCC3E\uAE30',
menu_keyword:
'{icon} {name}\uC5D0\uC11C \uD0A4\uC6CC\uB4DC\uB85C \uC2A4\uD06C\uB9BD\uD2B8 \uCC3E\uAE30',
title_settings: '\uC800\uC7A5\uC18C \uC124\uC815',
btn_save: '\uC800\uC7A5',
btn_cancel: '\uCDE8\uC18C',
title_domain: '\uB3C4\uBA54\uC778 \uAC80\uC0C9',
title_keyword: '\uD0A4\uC6CC\uB4DC \uAC80\uC0C9',
menu_settings: '\u2699\uFE0F \uC124\uC815',
},
es: {
menu_domain: '{icon} Buscar scripts por dominio en {name}',
menu_keyword: '{icon} Buscar scripts por palabra clave en {name}',
title_settings: 'Configuraci\xF3n de repositorios',
btn_save: 'Guardar',
btn_cancel: 'Cancelar',
title_domain: 'B\xFAsqueda por dominio',
title_keyword: 'B\xFAsqueda por palabra clave',
menu_settings: '\u2699\uFE0F Configuraci\xF3n',
},
fr: {
menu_domain: '{icon} Trouver des scripts par domaine sur {name}',
menu_keyword: '{icon} Trouver des scripts par mot-cl\xE9 sur {name}',
title_settings: 'Param\xE8tres des d\xE9p\xF4ts',
btn_save: 'Enregistrer',
btn_cancel: 'Annuler',
title_domain: 'Recherche par domaine',
title_keyword: 'Recherche par mot-cl\xE9',
menu_settings: '\u2699\uFE0F Param\xE8tres',
},
de: {
menu_domain: '{icon} Skripte nach Domain auf {name} finden',
menu_keyword: '{icon} Skripte nach Stichwort auf {name} finden',
title_settings: 'Repository-Einstellungen',
btn_save: 'Speichern',
btn_cancel: 'Abbrechen',
title_domain: 'Domain-Suche',
title_keyword: 'Stichwortsuche',
menu_settings: '\u2699\uFE0F Einstellungen',
},
ru: {
menu_domain:
'{icon} \u041D\u0430\u0439\u0442\u0438 \u0441\u043A\u0440\u0438\u043F\u0442\u044B \u043F\u043E \u0434\u043E\u043C\u0435\u043D\u0443 \u043D\u0430 {name}',
menu_keyword:
'{icon} \u041D\u0430\u0439\u0442\u0438 \u0441\u043A\u0440\u0438\u043F\u0442\u044B \u043F\u043E \u043A\u043B\u044E\u0447\u0435\u0432\u043E\u043C\u0443 \u0441\u043B\u043E\u0432\u0443 \u043D\u0430 {name}',
title_settings:
'\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0435\u0432',
btn_save: '\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C',
btn_cancel: '\u041E\u0442\u043C\u0435\u043D\u0430',
title_domain:
'\u041F\u043E\u0438\u0441\u043A \u043F\u043E \u0434\u043E\u043C\u0435\u043D\u0443',
title_keyword:
'\u041F\u043E\u0438\u0441\u043A \u043F\u043E \u043A\u043B\u044E\u0447\u0435\u0432\u043E\u043C\u0443 \u0441\u043B\u043E\u0432\u0443',
menu_settings:
'\u2699\uFE0F \u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438',
},
}
var USER_LANG = detectLanguage()
var LANG_MAP =
USER_LANG === 'en'
? I18N.en
: __spreadValues(__spreadValues({}, I18N.en), I18N[USER_LANG])
function t(key) {
return LANG_MAP[key]
}
function detectLanguage() {
try {
const browserLang = (
navigator.language ||
navigator.userLanguage ||
'en'
).toLowerCase()
const supportedLangs = Object.keys(I18N)
if (supportedLangs.includes(browserLang)) {
return browserLang
}
const langBase = browserLang.split('-')[0]
const matchingLang = supportedLangs.find((lang) =>
lang.startsWith(langBase + '-')
)
if (matchingLang) {
return matchingLang
}
return 'en'
} catch (error) {
debugLog('Error detecting language:', error)
return 'en'
}
}
function debugLog(message, data = null) {
if (CONFIG.DEBUG) {
console.log('[Find Scripts] '.concat(message), data || '')
}
}
function extractDomain() {
try {
const hostname = globalThis.location.hostname
let domain = hostname.replace(/^www\./, '')
const parts = domain.split('.')
if (parts.length > 2) {
const secondLevelDomains = [
'co',
'com',
'org',
'net',
'edu',
'gov',
'mil',
]
const thirdLevelDomain = parts[parts.length - 2]
domain =
parts.length > 3 && secondLevelDomains.includes(thirdLevelDomain)
? parts.slice(-3).join('.')
: parts.slice(-2).join('.')
}
debugLog('Extracted domain:', domain)
return domain
} catch (error) {
debugLog('Error extracting domain:', error)
return globalThis.location.hostname
}
}
function getLocalizedMenuText(repo, isKeywordSearch = false) {
const key = isKeywordSearch ? 'menu_keyword' : 'menu_domain'
const template = t(key)
return template.replace('{icon}', repo.icon).replace('{name}', repo.name)
}
var MENU_IDS = []
var SETTINGS_MENU_ID
function clearMenus() {
for (const id of MENU_IDS) {
unregisterMenu(id)
}
MENU_IDS = []
if (SETTINGS_MENU_ID) {
unregisterMenu(SETTINGS_MENU_ID)
SETTINGS_MENU_ID = void 0
}
}
function registerAllMenus() {
const domain = extractDomain()
registerMenuCommands(domain)
registerSettingsMenu()
}
function registerMenuCommands(domain) {
for (const repo of CONFIG.REPOSITORIES) {
const domainEnabled = Boolean(CURRENT_SETTINGS['domain_'.concat(repo.id)])
if (repo.domainSearchUrl && domainEnabled) {
const url = repo.domainSearchUrl.replace('{domain}', domain)
const menuText = getLocalizedMenuText(repo)
const id = registerMenu(menuText, () => {
debugLog('Opening '.concat(repo.name, ' for domain:'), domain)
openInTab(url, { active: true, insert: true })
})
MENU_IDS.push(id)
}
const keywordEnabled = Boolean(
CURRENT_SETTINGS['keyword_'.concat(repo.id)]
)
if (repo.keywordSearchUrl && keywordEnabled) {
const keywordUrl = repo.keywordSearchUrl.replace('{keyword}', domain)
const keywordMenuText = getLocalizedMenuText(repo, true)
const id = registerMenu(keywordMenuText, () => {
debugLog('Opening '.concat(repo.name, ' for keyword search:'), domain)
openInTab(keywordUrl, { active: true, insert: true })
})
MENU_IDS.push(id)
}
}
}
var CURRENT_SETTINGS = {}
function buildDefaults() {
var _a, _b
const out = {}
for (const repo of CONFIG.REPOSITORIES) {
if (repo.domainSearchUrl)
out['domain_'.concat(repo.id)] =
(_a = repo.domainSearchEnabled) != null ? _a : false
if (repo.keywordSearchUrl)
out['keyword_'.concat(repo.id)] =
(_b = repo.keywordSearchEnabled) != null ? _b : false
}
return out
}
var SETTINGS_STORE = createObjectSettingsStore(
CONFIG.SETTINGS_KEY,
buildDefaults()
)
async function loadSettings() {
try {
const all = await SETTINGS_STORE.getAll()
CURRENT_SETTINGS = all
debugLog('Settings loaded:', all)
} catch (error) {
debugLog('Error loading settings:', error)
}
}
function listenSettings() {
var _a
try {
;(_a = SETTINGS_STORE.onChange) == null
? void 0
: _a.call(SETTINGS_STORE, () => {
void (async () => {
await loadSettings()
clearMenus()
registerAllMenus()
})()
})
} catch (e) {}
}
function showSettingsDialog() {
const groupDomain = []
const groupKeyword = []
for (const repo of CONFIG.REPOSITORIES) {
if (repo.domainSearchUrl) {
groupDomain.push({
type: 'toggle',
key: 'domain_'.concat(repo.id),
label: ''.concat(repo.icon, ' ').concat(repo.name),
})
}
if (repo.keywordSearchUrl) {
groupKeyword.push({
type: 'toggle',
key: 'keyword_'.concat(repo.id),
label: ''.concat(repo.icon, ' ').concat(repo.name),
})
}
}
const schema = {
type: 'simple',
title: t('title_settings'),
groups: [
{ id: 'domain', title: t('title_domain'), fields: groupDomain },
{ id: 'keyword', title: t('title_keyword'), fields: groupKeyword },
],
}
const store = SETTINGS_STORE
openSettingsPanel(schema, store, {
hostDatasetKey: 'fsftsHost',
hostDatasetValue: 'find-scripts-settings',
theme: {
activeBg: '#7c3aed',
activeFg: '#ffffff',
colorRing: '#7c3aed',
toggleOnBg: '#7c3aed',
},
})
}
function registerSettingsMenu() {
const menuText = t('menu_settings')
SETTINGS_MENU_ID = registerMenu(menuText, showSettingsDialog)
}
async function initialize() {
await loadSettings()
registerAllMenus()
listenSettings()
}
void initialize()
})()