您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
JM / 18Comic 车牌号划词查询工具
// ==UserScript== // @name 18Comic 之路 // @namespace https://github.com/zyf722 // @version 1.0 // @author zyf722 // @description JM / 18Comic 车牌号划词查询工具 // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=18comic.vip // @match *://weibo.com/* // @match *://*.weibo.com/* // @match *://*.weibo.cn/* // @match *://tieba.baidu.com/* // @match *://*.bilibili.com/ // @match *://*.bilibili.com/* // @require https://cdn.jsdelivr.net/npm/[email protected]/crypto-js.js // @grant GM_addStyle // @grant GM_registerMenuCommand // @grant GM_xmlhttpRequest // ==/UserScript== (o=>{if(typeof GM_addStyle=="function"){GM_addStyle(o);return}const e=document.createElement("style");e.textContent=o,document.head.append(e)})(" .jm-select-none,.jm-select-none *{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.jm-overflow{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#jm-popup{position:absolute;background-color:#fff;padding:10px;margin-top:10px;border:1px solid #ddd;box-shadow:0 4px 8px #0003;z-index:999999999999;display:none;max-width:25%;column-gap:10px;align-items:center}.jm-title{max-width:100%;font-size:14px;grid-column:1;grid-row:2}#jm-title-text{display:none}#jm-number-container{max-width:100%;grid-column:1;grid-row:1;display:flex;align-items:center}#jm-number{font-size:18px;font-weight:700}#jm-number-icon{width:16px;height:16px;margin-right:5px}#jm-copy{border:none;background-color:#fff;width:32px;height:32px;font-size:16px;cursor:pointer;grid-column:2;grid-row:1 / 3;transition:background-color .3s;display:flex;align-items:center;justify-content:center}#jm-copy:hover:not(:disabled){background-color:#f6f6f6}#jm-copy:active:not(:disabled){background-color:#e6e6e6}#jm-copy-icon{width:16px;height:16px;transition:opacity .25s}.jm-copy-icon-hide{opacity:0}#jm-details-container{grid-column:1 / span 2;grid-row:3;display:grid;gap:5px;font-size:12px;margin-top:10px;border-top:1px solid #eee;padding-top:10px}.jm-detail-row{display:contents}.jm-detail-row>span{padding:2px 0}.jm-detail-label{font-weight:700;color:#555;white-space:nowrap}.jm-detail-value{color:#333}.jm-tags-container{display:flex;flex-wrap:wrap;gap:4px}.jm-tag-item{vertical-align:middle;background:#00000012;color:#777;font-size:12px;line-height:16px;display:inline-block;padding:0 3px;margin:-2px 0 0 2px;border-radius:2px;letter-spacing:-.6px;bottom:0}#rt18-config-dialog-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;display:flex;justify-content:center;align-items:center;z-index:9999}#rt18-config-dialog{background-color:#fff;padding:20px;border-radius:8px;box-shadow:0 4px 12px #00000026;width:500px;max-width:90%;position:relative}.rt18-config-close-button{position:absolute;top:10px;right:10px;background:none;border:none;font-size:1.5em;cursor:pointer}.rt18-config-section{margin-top:10px;margin-bottom:10px;display:flex;flex-direction:column;gap:10px}#rt18-source-list{list-style:none;padding:0;max-height:200px;overflow-y:auto;border:1px solid #ddd;border-radius:4px}#rt18-source-list li{padding:8px 12px;border-bottom:1px solid #eee;display:flex;justify-content:space-between;align-items:center}.rt18-source-text{flex-grow:1;margin-right:10px}.rt18-source-controls{display:flex;align-items:center}.rt18-source-button{margin-left:5px;padding:4px 8px;font-size:.9em;cursor:pointer;border:1px solid #ccc;border-radius:3px;background-color:#f0f0f0;display:inline-flex;align-items:center;justify-content:center;min-width:20px;text-align:center}.rt18-source-button:hover{background-color:#e0e0e0}.rt18-source-button-delete{background-color:#f8d7da;color:#721c24;border-color:#f5c6cb}.rt18-source-button-delete:hover{background-color:#f1b0b7}.rt18-button-disabled{opacity:.5;cursor:not-allowed;background-color:#e9ecef}.rt18-button-disabled:hover{background-color:#e9ecef}.rt18-add-source-container{display:flex;margin-top:10px}#rt18-add-source-input{flex-grow:1;padding:8px;border:1px solid #ccc;border-radius:4px 0 0 4px}#rt18-add-source-btn{padding:8px 15px;border:1px solid #ccc;border-left:none;background-color:#007bff;color:#fff;cursor:pointer;border-radius:0 4px 4px 0;display:inline-flex;align-items:center;justify-content:center}#rt18-add-source-btn:hover{background-color:#0056b3}.rt18-config-input{width:100%;padding:8px;border:1px solid #ccc;border-radius:4px;box-sizing:border-box}.rt18-config-description{font-size:.9em;color:#666;margin-top:0} "); (function (CryptoJS) { 'use strict'; const loadingIcon = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M512%20170.666667a341.333333%20341.333333%200%201%200%200%20682.666666%20341.333333%20341.333333%200%200%200%200-682.666666zM85.333333%20512C85.333333%20276.352%20276.352%2085.333333%20512%2085.333333s426.666667%20191.018667%20426.666667%20426.666667-191.018667%20426.666667-426.666667%20426.666667S85.333333%20747.648%2085.333333%20512z%20m426.666667-256a42.666667%2042.666667%200%200%201%2042.666667%2042.666667v195.669333l115.498666%20115.498667a42.666667%2042.666667%200%200%201-60.330666%2060.330666l-128-128A42.666667%2042.666667%200%200%201%20469.333333%20512V298.666667a42.666667%2042.666667%200%200%201%2042.666667-42.666667z'%20fill='currentColor'/%3e%3c/svg%3e"; const failIcon = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M512%2097.52381c228.912762%200%20414.47619%20185.563429%20414.47619%20414.47619s-185.563429%20414.47619-414.47619%20414.47619S97.52381%20740.912762%2097.52381%20512%20283.087238%2097.52381%20512%2097.52381z%20m0%2073.142857C323.486476%20170.666667%20170.666667%20323.486476%20170.666667%20512s152.81981%20341.333333%20341.333333%20341.333333%20341.333333-152.81981%20341.333333-341.333333S700.513524%20170.666667%20512%20170.666667z%20m129.29219%20160.304762l51.736381%2051.736381L563.687619%20512l129.316571%20129.29219-51.73638%2051.736381L512%20563.687619l-129.29219%20129.316571-51.736381-51.73638L460.312381%20512l-129.316571-129.26781%2051.73638-51.73638L512%20460.263619l129.26781-129.29219z'%20fill='currentColor'/%3e%3c/svg%3e"; const successIcon = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M512%2097.52381c228.912762%200%20414.47619%20185.563429%20414.47619%20414.47619s-185.563429%20414.47619-414.47619%20414.47619S97.52381%20740.912762%2097.52381%20512%20283.087238%2097.52381%20512%2097.52381z%20m0%2073.142857C323.486476%20170.666667%20170.666667%20323.486476%20170.666667%20512s152.81981%20341.333333%20341.333333%20341.333333%20341.333333-152.81981%20341.333333-341.333333S700.513524%20170.666667%20512%20170.666667z%20m193.194667%20145.188571l52.467809%2050.956191-310.662095%20319.683047-156.379429-162.230857%2052.662858-50.761143%20103.936%20107.812572%20257.974857-265.45981z'%20fill='currentColor'/%3e%3c/svg%3e"; const warningIcon = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M545.718857%20130.608762c11.337143%206.265905%2020.699429%2015.555048%2026.989714%2026.819048l345.014858%20617.667047a68.87619%2068.87619%200%200%201-26.989715%2093.915429c-10.313143%205.705143-21.942857%208.704-33.718857%208.704H166.985143A69.266286%2069.266286%200%200%201%2097.52381%20808.643048c0-11.751619%202.998857-23.28381%208.752761-33.548191l344.990477-617.642667a69.656381%2069.656381%200%200%201%2094.451809-26.819047zM512%20191.000381L166.985143%20808.643048H856.990476L512%20191.000381zM546.718476%20670.47619v69.071239h-69.461333V670.47619h69.485714z%20m0-298.374095v252.318476h-69.461333V372.102095h69.485714z'%20fill='currentColor'/%3e%3c/svg%3e"; const doneIcon = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M512%2016C238.066%2016%2016%20238.066%2016%20512s222.066%20496%20496%20496%20496-222.066%20496-496S785.934%2016%20512%2016z%20m0%2096c221.064%200%20400%20178.902%20400%20400%200%20221.064-178.902%20400-400%20400-221.064%200-400-178.902-400-400%200-221.064%20178.902-400%20400-400m280.408%20260.534l-45.072-45.436c-9.334-9.41-24.53-9.472-33.94-0.136L430.692%20607.394l-119.584-120.554c-9.334-9.41-24.53-9.472-33.94-0.138l-45.438%2045.072c-9.41%209.334-9.472%2024.53-0.136%2033.942l181.562%20183.032c9.334%209.41%2024.53%209.472%2033.94%200.136l345.178-342.408c9.408-9.336%209.468-24.532%200.134-33.942z'%20fill='currentColor'/%3e%3c/svg%3e"; const copyIcon = "data:image/svg+xml,%3csvg%20viewBox='0%200%201024%201024'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M931.882%20131.882l-103.764-103.764A96%2096%200%200%200%20760.236%200H416c-53.02%200-96%2042.98-96%2096v96H160c-53.02%200-96%2042.98-96%2096v640c0%2053.02%2042.98%2096%2096%2096h448c53.02%200%2096-42.98%2096-96v-96h160c53.02%200%2096-42.98%2096-96V199.764a96%2096%200%200%200-28.118-67.882zM596%20928H172a12%2012%200%200%201-12-12V300a12%2012%200%200%201%2012-12h148v448c0%2053.02%2042.98%2096%2096%2096h192v84a12%2012%200%200%201-12%2012z%20m256-192H428a12%2012%200%200%201-12-12V108a12%2012%200%200%201%2012-12h212v176c0%2026.51%2021.49%2048%2048%2048h176v404a12%2012%200%200%201-12%2012z%20m12-512h-128V96h19.264c3.182%200%206.234%201.264%208.486%203.514l96.736%2096.736a12%2012%200%200%201%203.514%208.486V224z'%20fill='currentColor'/%3e%3c/svg%3e"; const uiHtml = '<div id="jm-popup" class="jm-select-none" style="display: none;">\r\n <div id="jm-number-container">\r\n <div id="jm-number-icon"></div>\r\n <div id="jm-number" class="jm-overflow"></div>\r\n </div>\r\n <a id="jm-title-text" class="jm-overflow jm-title" target="_blank" rel="noopener noreferrer" style="display: none;"></a>\r\n <div id="jm-title-loading" class="jm-title">加载中...</div>\r\n <div id="jm-details-container" style="display: none;"></div>\r\n <button id="jm-copy" title="复制漫画名" disabled>\r\n <div id="jm-copy-icon"></div>\r\n </button>\r\n</div>\r\n'; var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)(); var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); const configHtml = '<div id="rt18-config-dialog-overlay">\r\n <div id="rt18-config-dialog">\r\n <h2>18Comic 之路配置</h2>\r\n <button id="rt18-config-close-btn" class="rt18-config-close-button">×</button>\r\n <div class="rt18-config-section">\r\n <h3>API 线路配置</h3>\r\n <ul id="rt18-source-list"></ul>\r\n <div class="rt18-add-source-container">\r\n <input type="text" id="rt18-add-source-input" placeholder="输入新线路域名">\r\n <div id="rt18-add-source-btn" class="rt18-config-button">添加线路</div>\r\n </div>\r\n <p class="rt18-config-description">脚本运行时将按照配置的 API 线路顺序获取车牌对应信息,直到成功获取为止。</p>\r\n </div>\r\n <div class="rt18-config-section">\r\n <h3>API 请求超时配置</h3>\r\n <input type="number" id="rt18-config-timeout-input" class="rt18-config-input" min="1000" step="1000">\r\n <p class="rt18-config-description">网络请求的超时时间,单位为毫秒。</p>\r\n </div>\r\n <div class="rt18-config-section">\r\n <h3>JM 网站线路</h3>\r\n <input type="url" id="rt18-config-jm-url-input" class="rt18-config-input" placeholder="例如: https://18comic.vip">\r\n <p class="rt18-config-description">用于拼接最终跳转的 18Comic / JM 网站地址。可访问 <a href="https://jmcomic-fb.vip" target="_blank" rel="noopener noreferrer">jmcomic-fb.vip</a> 获取最新线路。</p>\r\n </div>\r\n <div class="rt18-config-section">\r\n <h3>布局选择</h3>\r\n <select id="rt18-config-layout-select" class="rt18-config-input">\r\n <option value="details">详细布局(显示漫画详细信息)</option>\r\n <option value="compact">紧凑布局(旧版布局,仅显示漫画名称)</option>\r\n </select>\r\n <p class="rt18-config-description">漫画浮窗窗口的布局样式。</p>\r\n </div>\r\n </div>\r\n</div>\r\n'; const defaultConfig = { sources: ["www.cdnmhwscc.vip", "www.cdnblackmyth.club", "www.cdnmhws.cc", "www.cdnuc.vip"], timeout: 5e3, jmWebsiteUrl: "https://18comic.vip", layout: "details" }; const loadConfig = () => { const configString = localStorage.getItem("rt18_config"); if (configString) { const parsedConfig = JSON.parse(configString); return { ...defaultConfig, ...parsedConfig }; } return { ...defaultConfig }; }; const config = loadConfig(); let isConfigDialogOpen = false; const saveConfig = () => { localStorage.setItem("rt18_config", JSON.stringify(config)); }; const resetConfig = () => { if (confirm("确定要重置所有配置吗?")) { localStorage.removeItem("rt18_config"); alert("配置已重置为默认值,请刷新页面以应用更改。"); } }; const openConfigDialog$1 = () => { const dialogContainerId = "rt18-config-dialog-container"; let dialogContainer = document.getElementById(dialogContainerId); if (dialogContainer) { dialogContainer.style.display = "flex"; return; } dialogContainer = document.createElement("div"); dialogContainer.id = dialogContainerId; dialogContainer.innerHTML = configHtml; document.body.appendChild(dialogContainer); isConfigDialogOpen = true; const closeButton = document.getElementById("rt18-config-close-btn"); const sourceList = document.getElementById("rt18-source-list"); const addSourceInput = document.getElementById("rt18-add-source-input"); const addSourceButton = document.getElementById("rt18-add-source-btn"); const timeoutInput = document.getElementById("rt18-config-timeout-input"); const jmWebsiteUrlInput = document.getElementById("rt18-config-jm-url-input"); const layoutSelect = document.getElementById("rt18-config-layout-select"); if (timeoutInput) { timeoutInput.value = String(config.timeout); timeoutInput.addEventListener("change", () => { const newTimeout = parseInt(timeoutInput.value, 10); if (!isNaN(newTimeout) && newTimeout > 0) { config.timeout = newTimeout; localStorage.setItem("rt18_config", JSON.stringify(config)); config.timeout = newTimeout; } else { timeoutInput.value = String(config.timeout); alert("请输入有效的超时毫秒数。"); } }); } if (jmWebsiteUrlInput) { jmWebsiteUrlInput.value = config.jmWebsiteUrl; jmWebsiteUrlInput.addEventListener("change", () => { const newUrl = jmWebsiteUrlInput.value.trim(); if (newUrl) { try { new URL(newUrl); config.jmWebsiteUrl = newUrl; localStorage.setItem("rt18_config", JSON.stringify(config)); } catch (e) { jmWebsiteUrlInput.value = config.jmWebsiteUrl; alert("请输入有效的 URL。"); } } else { jmWebsiteUrlInput.value = config.jmWebsiteUrl; alert("URL 不能为空。"); } }); } if (layoutSelect) { layoutSelect.value = config.layout; layoutSelect.addEventListener("change", () => { const newLayout = layoutSelect.value; if (newLayout === "compact" || newLayout === "details") { config.layout = newLayout; localStorage.setItem("rt18_config", JSON.stringify(config)); } else { layoutSelect.value = config.layout; } }); } const renderSourceList = () => { sourceList.innerHTML = ""; config.sources.forEach((source, index) => { const listItem = document.createElement("li"); listItem.className = "rt18-source-list-item"; const sourceText = document.createElement("span"); sourceText.className = "rt18-source-text"; sourceText.textContent = source; listItem.appendChild(sourceText); const controlsContainer = document.createElement("div"); controlsContainer.className = "rt18-source-controls"; const upButton = document.createElement("div"); upButton.className = "rt18-source-button rt18-source-button-up"; upButton.innerHTML = "<span>↑</span>"; if (index === 0) { upButton.classList.add("rt18-button-disabled"); } else { upButton.addEventListener("click", () => { const temp = config.sources[index]; config.sources[index] = config.sources[index - 1]; config.sources[index - 1] = temp; saveConfig(); renderSourceList(); }); } const downButton = document.createElement("div"); downButton.className = "rt18-source-button rt18-source-button-down"; downButton.innerHTML = "<span>↓</span>"; if (index === config.sources.length - 1) { downButton.classList.add("rt18-button-disabled"); } else { downButton.addEventListener("click", () => { const temp = config.sources[index]; config.sources[index] = config.sources[index + 1]; config.sources[index + 1] = temp; saveConfig(); renderSourceList(); }); } const deleteButton = document.createElement("div"); deleteButton.className = "rt18-source-button rt18-source-button-delete"; deleteButton.textContent = "删除"; deleteButton.addEventListener("click", () => { if (confirm(`确定删除源 "${source}" 吗?`)) { config.sources.splice(index, 1); saveConfig(); renderSourceList(); } }); controlsContainer.appendChild(upButton); controlsContainer.appendChild(downButton); controlsContainer.appendChild(deleteButton); listItem.appendChild(controlsContainer); sourceList.appendChild(listItem); }); }; addSourceButton.addEventListener("click", () => { const newSource = addSourceInput.value.trim(); if (newSource && !config.sources.includes(newSource)) { config.sources.push(newSource); saveConfig(); config.sources = [...config.sources]; renderSourceList(); addSourceInput.value = ""; } }); renderSourceList(); closeButton.addEventListener("click", () => { if (dialogContainer) { dialogContainer.style.display = "none"; dialogContainer.remove(); isConfigDialogOpen = false; } }); }; const APP_TOKEN_SECRET = "18comicAPP"; const APP_DATA_SECRET = "185Hcomic3PAPP7R"; const APP_VERSION = "1.7.9"; const getTokenWithTokenparam = (ts, ver = APP_VERSION, secret = APP_TOKEN_SECRET) => { const tokenparam = `${ts},${ver}`; const token = CryptoJS.MD5(`${ts}${secret}`).toString(); return { token, tokenparam }; }; const decodeData = (data, ts, secret = APP_DATA_SECRET) => { const dataWordArray = CryptoJS.enc.Base64.parse(data); const token = CryptoJS.MD5(`${ts}${secret}`).toString(); const tokenWordArray = CryptoJS.enc.Utf8.parse(token); const encrypted = CryptoJS.lib.CipherParams.create({ ciphertext: dataWordArray }); const decrypted = CryptoJS.AES.decrypt(encrypted, tokenWordArray, { mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7 }); return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8)); }; const JMFetchAlbumInfo = (jmSite, jmId, callback) => { const timestamp = Math.floor(Date.now() / 1e3); _GM_xmlhttpRequest({ method: "GET", url: `https://${jmSite}/album?id=${jmId}`, timeout: config.timeout, headers: { ...getTokenWithTokenparam(timestamp), "Accept-Encoding": "gzip, deflate", "User-Agent": navigator.userAgent }, onload: (gmResponse) => { try { const resp = JSON.parse(gmResponse.responseText); const album = decodeData(resp.data, timestamp); callback(album); } catch (error) { callback(null); } }, onerror: () => callback(null), ontimeout: () => callback(null) }); }; const openConfigDialog = () => { var _a; (_a = window.getSelection()) == null ? void 0 : _a.empty(); if (popupWindow.checkVisibility()) { popupWindow.style.display = "none"; } openConfigDialog$1(); }; _GM_registerMenuCommand("⚙ 打开配置菜单", openConfigDialog); _GM_registerMenuCommand("⚠ 重置配置", resetConfig); const setSVGWithColor = (wrapper, svgUrl, color) => { wrapper.style.backgroundColor = color; wrapper.style.mask = `url("${svgUrl}") no-repeat center`; wrapper.style.webkitMask = `url("${svgUrl}") no-repeat center`; }; const uiContainer = document.createElement("div"); uiContainer.innerHTML = uiHtml; document.body.appendChild(uiContainer); const popupWindow = document.getElementById("jm-popup"); const numberIcon = document.getElementById("jm-number-icon"); const numberText = document.getElementById("jm-number"); const titleText = document.getElementById("jm-title-text"); const titleLoadingText = document.getElementById("jm-title-loading"); const copyBtn = document.getElementById("jm-copy"); const copyBtnIcon = document.getElementById("jm-copy-icon"); const detailsContainer = document.getElementById("jm-details-container"); setSVGWithColor(numberIcon, loadingIcon, "black"); const populateDetails = (album) => { detailsContainer.innerHTML = ""; const createDetailRow = (field, value, isHtml = false) => { const isValueArray = Array.isArray(value); if (!value || isValueArray && value.length === 0) return; const row = document.createElement("div"); row.className = "jm-detail-row"; const labelSpan = document.createElement("span"); labelSpan.className = "jm-detail-label"; labelSpan.textContent = `${field}:`; row.appendChild(labelSpan); const valueSpan = document.createElement("span"); valueSpan.className = "jm-detail-value"; if (isHtml) { valueSpan.innerHTML = isValueArray ? value.join(", ") : value; } else { valueSpan.textContent = isValueArray ? value.join(", ") : value; } if (isValueArray) { valueSpan.classList.add("jm-tags-container"); valueSpan.innerHTML = ""; value.forEach((tag) => { const tagSpan = document.createElement("span"); tagSpan.className = "jm-tag-item"; tagSpan.textContent = tag; valueSpan.appendChild(tagSpan); }); } row.appendChild(valueSpan); detailsContainer.appendChild(row); }; if (config.layout === "details") { createDetailRow("作者", album.author); createDetailRow("标签", album.tags); createDetailRow("系列", album.works); createDetailRow("角色", album.actors); createDetailRow( "统计", `浏览: ${album.total_views || 0} / 喜欢: ${album.likes || 0} / 评论: ${album.comment_total || 0}` ); if (album.addtime) { const date = new Date(parseInt(album.addtime) * 1e3); createDetailRow("上传于", date.toLocaleString()); } detailsContainer.style.display = "grid"; } else { detailsContainer.style.display = "none"; } }; const toggleLoading = async (status, albumOrMessage, link) => { let numberIconUrl = loadingIcon; let numberTextColor = "black"; let titleTextColor = "gray"; detailsContainer.style.display = "none"; if (status === "fail") { numberIconUrl = failIcon; numberTextColor = "red"; titleText.innerHTML = titleText.title = typeof albumOrMessage === "string" ? albumOrMessage : "获取信息失败"; } else if (status === "done" && albumOrMessage && typeof albumOrMessage !== "string") { const album = albumOrMessage; numberIconUrl = successIcon; numberTextColor = "green"; titleTextColor = null; titleText.innerHTML = titleText.title = album.name; populateDetails(album); } else if (status === "warning") { numberIconUrl = warningIcon; numberTextColor = "orange"; titleText.innerHTML = titleText.title = typeof albumOrMessage === "string" ? albumOrMessage : "发生错误"; } else if (status === "loading") { titleText.innerHTML = titleText.title = "加载中..."; } setSVGWithColor(numberIcon, numberIconUrl, numberTextColor); numberText.style.color = numberTextColor; const isLoading = status === "loading"; titleLoadingText.style.display = isLoading ? "inline" : "none"; titleText.style.display = !isLoading ? "inline" : "none"; titleText.style.color = titleTextColor || ""; if (link) { titleText.href = link; } }; setSVGWithColor(copyBtnIcon, copyIcon, "dodgerblue"); const disableCopyBtn = (status) => { copyBtn.disabled = status; copyBtn.style.pointerEvents = status ? "none" : "auto"; copyBtnIcon.style.backgroundColor = status ? "gray" : "dodgerblue"; }; disableCopyBtn(true); const copyToClipboard = () => { navigator.clipboard.writeText(titleText.innerText); copyBtn.style.pointerEvents = "none"; copyBtnIcon.classList.toggle("jm-copy-icon-hide"); setTimeout(() => { copyBtnIcon.classList.toggle("jm-copy-icon-hide"); setSVGWithColor(copyBtnIcon, doneIcon, "dodgerblue"); }, 250); setTimeout(() => { copyBtnIcon.classList.toggle("jm-copy-icon-hide"); setTimeout(() => { setSVGWithColor(copyBtnIcon, copyIcon, "dodgerblue"); copyBtnIcon.classList.toggle("jm-copy-icon-hide"); copyBtn.style.pointerEvents = "auto"; }, 250); }, 1500); }; copyBtn.addEventListener("click", copyToClipboard); const showPopup = (event) => { const selectedText = window.getSelection(); if (!event.target || !event.target.closest("#jm-popup")) { popupWindow.style.display = "none"; disableCopyBtn(true); } if (!isConfigDialogOpen && selectedText && selectedText.toString().trim() !== "") { const number = parseInt(selectedText.toString().replace(/\D/g, "")); if (popupWindow.style.display !== "grid" && !Number.isNaN(number)) { const range = selectedText.getRangeAt(0); const activeEl = document.activeElement; const rect = activeEl.tagName === "TEXTAREA" || activeEl.tagName === "INPUT" ? activeEl.getBoundingClientRect() : range.getBoundingClientRect(); const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; let top = Math.floor(scrollTop + rect.top + rect.height); const left = Math.floor(rect.left); if (top === 0 && left === 0 && rect.width === 0 && rect.height === 0) return; popupWindow.style.left = `${left}px`; popupWindow.style.top = `${top}px`; numberText.innerHTML = number.toString(); numberText.style.color = ""; popupWindow.style.display = "grid"; const nbnhhsh = document.getElementsByClassName( "nbnhhsh-box nbnhhsh-box-pop" )[0]; const originalNbnhhshTop = parseInt(nbnhhsh.style.top); const nbnhhshAdjust = () => { if (nbnhhsh) { const popupHeight = popupWindow.offsetHeight; const offset = popupHeight > 80 ? popupHeight + 10 : 80; if (!isNaN(originalNbnhhshTop)) { nbnhhsh.style.top = `${originalNbnhhshTop + offset}px`; } else { const rectNbnhhsh = nbnhhsh.getBoundingClientRect(); const scrollTopNbnhhsh = document.documentElement.scrollTop || document.body.scrollTop; nbnhhsh.style.top = `${scrollTopNbnhhsh + rectNbnhhsh.top + offset}px`; } } }; const configuredSources = config.sources; if (!configuredSources || configuredSources.length === 0) { toggleLoading("warning", "无可用线路,请先配置"); disableCopyBtn(true); nbnhhshAdjust(); return; } let sourceIndex = 0; toggleLoading("loading"); nbnhhshAdjust(); const tryNextSource = () => { if (sourceIndex >= configuredSources.length) { toggleLoading("fail", "获取信息失败或未找到车牌"); disableCopyBtn(true); nbnhhshAdjust(); return; } const currentSite = configuredSources[sourceIndex]; JMFetchAlbumInfo(currentSite, number, (albumData) => { if (!albumData || albumData.id === 0 || !albumData.name) { sourceIndex++; tryNextSource(); return; } toggleLoading("done", albumData, `${config.jmWebsiteUrl}/album/${albumData.id}`); disableCopyBtn(false); nbnhhshAdjust(); }); }; tryNextSource(); } } }; const _showPopup = (event) => { setTimeout(() => { showPopup(event); }, 1); }; document.addEventListener("mouseup", _showPopup); document.addEventListener("keyup", _showPopup); })(CryptoJS);
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址