您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
i,j,k 키를 눌러보세요
// ==UserScript== // @name 토끼 뷰어 // @name:ko 토끼 뷰어 // @name:en toki viewer // @description i,j,k 키를 눌러보세요 // @description:ko i,j,k 키를 눌러보세요 // @description:en press i to open // @version 250524154400 // @match https://*.net/bbs/* // @match https://*.net/comic/* // @match https://*.com/webtoon/* // @match https://*.com/novel/* // @author nanikit // @namespace https://gf.qytechs.cn/ko/users/713014-nanikit // @license MIT // @connect * // @grant GM.addValueChangeListener // @grant GM.getResourceText // @grant GM.getValue // @grant GM.removeValueChangeListener // @grant GM.setValue // @grant GM.xmlHttpRequest // @grant unsafeWindow // @require https://cdn.jsdelivr.net/npm/[email protected]/require.js // @resource link:@headlessui/react https://cdn.jsdelivr.net/npm/@headlessui/[email protected]/dist/headlessui.prod.cjs // @resource link:@stitches/react https://cdn.jsdelivr.net/npm/@stitches/[email protected]/dist/index.cjs // @resource link:clsx https://cdn.jsdelivr.net/npm/[email protected]/dist/clsx.js // @resource link:fflate https://cdn.jsdelivr.net/npm/[email protected]/lib/browser.cjs // @resource link:jotai https://cdn.jsdelivr.net/npm/[email protected]/index.js // @resource link:jotai-cache https://cdn.jsdelivr.net/npm/[email protected]/dist/cjs/atomWithCache.js // @resource link:jotai/react https://cdn.jsdelivr.net/npm/[email protected]/react.js // @resource link:jotai/react/utils https://cdn.jsdelivr.net/npm/[email protected]/react/utils.js // @resource link:jotai/utils https://cdn.jsdelivr.net/npm/[email protected]/utils.js // @resource link:jotai/vanilla https://cdn.jsdelivr.net/npm/[email protected]/vanilla.js // @resource link:jotai/vanilla/utils https://cdn.jsdelivr.net/npm/[email protected]/vanilla/utils.js // @resource link:overlayscrollbars https://cdn.jsdelivr.net/npm/[email protected]/overlayscrollbars.cjs // @resource link:overlayscrollbars-react https://cdn.jsdelivr.net/npm/[email protected]/overlayscrollbars-react.cjs.js // @resource link:react https://cdn.jsdelivr.net/npm/[email protected]/cjs/react.production.js // @resource link:react-dom https://cdn.jsdelivr.net/npm/[email protected]/cjs/react-dom.production.js // @resource link:react-dom/client https://cdn.jsdelivr.net/npm/[email protected]/cjs/react-dom-client.production.js // @resource link:react-toastify https://cdn.jsdelivr.net/npm/[email protected]/dist/react-toastify.js // @resource link:react/jsx-runtime https://cdn.jsdelivr.net/npm/[email protected]/cjs/react-jsx-runtime.production.js // @resource link:scheduler https://cdn.jsdelivr.net/npm/[email protected]/cjs/scheduler.production.min.js // @resource link:vcv-inject-node-env data:,unsafeWindow.process=%7Benv:%7BNODE_ENV:%22production%22%7D%7D // @resource link:vim_comic_viewer https://update.gf.qytechs.cn/scripts/417893/1595153/vim%20comic%20viewer.js // @resource overlayscrollbars-css https://cdn.jsdelivr.net/npm/[email protected]/styles/overlayscrollbars.min.css // @resource react-toastify-css https://cdn.jsdelivr.net/npm/[email protected]/dist/ReactToastify.css // ==/UserScript== "use strict"; define("main", (require, exports, module) => { var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); const vim_comic_viewer = __toESM(require("vim_comic_viewer")); async function main() { const origin = getOrigin(); if (origin === "unknown") return; markVisitedLinks(); registerEpisodeNavigator(); const buttons = duplicateViewerButton(); const source = await comicSource(); const controller = await (0, vim_comic_viewer.initialize)({ source: () => source, onPreviousSeries: goPreviousEpisode, onNextSeries: goNextEpisode }); controller.setScriptPreferences({ manualPreset: origin, preferences: { pageDirection: origin === "manatoki" ? "rightToLeft" : "leftToRight" } }); for (const button of buttons) button.addEventListener("click", async () => { await controller.setImmersive(true); }); } function getOrigin() { const allowedOrigins = [ "manatoki", "newtoki", "booktoki" ]; return allowedOrigins.find(originIncludes) ?? "unknown"; } function originIncludes(str) { return location.origin.includes(str); } function duplicateViewerButton() { const template = document.createElement("template"); template.innerHTML = `<a class="show_viewer" alt="뷰어로 보기"> <i class="ion-ios-book at-tip" aria-hidden="true" style="color: blue;"></i> </a>`; const templateButton = template.content.firstElementChild; const buttons = []; const divs = document.querySelectorAll(".toon-nav"); for (const div of divs) { const button = templateButton.cloneNode(true); div.prepend(button); buttons.push(button); } return buttons; } async function comicSource() { while (true) { const urls = getUrls(); if (urls.length) return urls; await vim_comic_viewer.utils.timeout(200); } } function goPreviousEpisode() { document.getElementById("goPrevBtn")?.click?.(); } function goNextEpisode() { document.getElementById("goNextBtn")?.click?.(); } function registerEpisodeNavigator() { addEventListener("keydown", (event) => { const { ctrlKey, shiftKey, altKey } = event; if (ctrlKey || shiftKey || altKey || vim_comic_viewer.utils.isTyping(event)) return; switch (event.key) { case "t": document.getElementById("sticky-wrapper")?.scrollIntoView({ block: "center" }); break; case "m": document.querySelector(".view-good")?.scrollIntoView({ block: "center" }); break; } }); } function getUrls() { const imgs = document.querySelectorAll("div.view-padding img"); return [...imgs].flatMap(getUrl); } function getUrl(image) { if (image.offsetParent === null) return []; const data = Object.values(image.dataset); return data.length ? data : [image.src]; } async function markVisitedLinks() { const links = document.querySelectorAll(".post-row a"); const visitedLinks = new Set(await GM.getValue("visitedPaths", [])); for (const link of links) { const url = link.getAttribute("href"); if (!url) return; const path = new URL(url).pathname; if (visitedLinks.has(path)) link.style.color = "#e2e2e2"; link.addEventListener("click", async () => { visitedLinks.add(path); await GM.setValue("visitedPaths", [...visitedLinks]); }); } } main(); }); define("tampermonkey_grants", function() { Object.assign(this.window, { GM, unsafeWindow }); }); requirejs.config({ deps: ["tampermonkey_grants"] }); load() async function load() { const links = GM.info.script.resources.filter(x => x.name.startsWith("link:")); await Promise.all(links.map(async ({ name }) => { const script = await GM.getResourceText(name) define(name.replace("link:", ""), Function("require", "exports", "module", script)) })); require(["main"], () => {}, console.error); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址