您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Marks F95Zone threads for future reference
当前为
// ==UserScript== // @name F95zone marker // @namespace http://tampermonkey.net/ // @version 0.1.4 // @description Marks F95Zone threads for future reference // @author agreg // @license MIT // @match https://f95zone.to/* // @icon https://www.google.com/s2/favicons?domain=f95zone.to // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // ==/UserScript== /* jshint esversion: 6 */ (function() { 'use strict'; const THREADS = /^(https:\/\/f95zone.to)?\/threads\//; const OP = '.message-threadStarterPost'; const OP_ICONS = `${OP} header .message-attribution-opposite`; let urlId = s => (!THREADS.test(s) ? null : s.replace(THREADS, '').match(/^([^\/]+\.)?([0-9]+)/)[2]); let $find = (s, e=document) => e.querySelector(s); let $find_ = (s, e=document) => Array.from( e.querySelectorAll(s) ); let $parent = (e, check=()=>true) => (check(e.parentNode) ? e.parentNode : $parent(e.parentNode, check)); let $e = (tag, options={}, ...children) => {var e = Object.assign(document.createElement(tag), options); children.forEach(x => e.append(x)); return e} let $assign = (o, vals) => Object.assign(o, ...Object.entries(vals).map(([k, v]) => ({[k]: v||undefined}))); let $updData = (id, e, data=GM_getValue(id), upd={}) => {if (data) { GM_setValue(id, $assign(data, upd)); e.classList[data.fade ? 'add' : 'remove']('-marker-fade'); e.classList[data.mark ? 'add' : 'remove']('-marker-mark'); e.title = data.info || ""; } else { GM_deleteValue(id); e.classList.remove('-marker-fade', '-marker-mark'); e.title = ""; }}; let $editIcon = (id, e) => { var icon = $e('i', {className: "fas fa-star"}); var data = GM_getValue(id), edit = null; let _$updData = (upd={}) => {$updData(id, e, data, upd); icon.classList.add(`-marker-${data ? "" : "un"}marked`); icon.classList.remove(`-marker-${data ? "un" : ""}marked`)} let $deleteMark = () => {if (confirm("Delete mark?")) { $toggleEdit(); data = null; _$updData(); }}; let $toggleEdit = () => {if (edit) { edit.remove(); edit = null; } else { data = data || {}; document.body.append(edit = $e('div', {className: '-marker-dialog'}, $e('textarea', {placeholder: "Tooltip", value: data.info||"", oninput () {_$updData({info: this.value})}}), $e('div', {className: '-marker-row'}, $e('label', {}, $e('input', {type: 'checkbox', checked: data.fade, onchange () {_$updData({fade: this.checked})}}), $e('span', {innerText: "Fade"})), $e('label', {}, $e('input', {type: 'checkbox', checked: data.mark, onchange () {_$updData({mark: this.checked})}}), $e('span', {innerText: "Mark"}))), $e('div', {className: '-marker-row'}, $e('button', {innerText: "OK", onclick: $toggleEdit}), $e('button', {innerText: "Delete", onclick: $deleteMark})))); }}; _$updData(); return $e('a', {href: location.href, onclick () {$toggleEdit(); return false}}, icon); }; GM_addStyle(`.-marker-unmarked {opacity: 0.5; color: rgb(147, 152, 160)} .-marker-marked {color: rgb(193, 88, 88)} .-marker-fade:not(:hover) {opacity: 0.25} .-marker-fade:hover {outline: 2px solid black} .-marker-mark {outline: 2px solid grey} .-marker-dialog {position: fixed; top: 30%; left: 30%; width: 40%; background: rgb(29, 31, 33); border-radius: 5px; z-index:1000} .-marker-dialog > * {margin: 1em} .-marker-dialog textarea {width: calc(100% - 2em)} .-marker-dialog .-marker-row > * {margin-left: .5em; margin-right: .5em}`); $find_(".structItem-title").forEach(e => { // forum, similar threads let _id = urlId(e.getAttribute('uix-data-href')||""); _id && $updData(_id, $parent(e, x => x.classList.contains('structItem--thread'))); }); if (location.pathname.startsWith('/search/')) { // search results $find_(".contentRow-title a").forEach(e => { let _id = urlId(e.href||""); console.log(e.href, _id) _id && $updData(_id, $parent(e, x => /^li$/i.test(x.tagName))); }); } if (['/latest', '/sam/latest_alpha'].some(s => location.pathname.startsWith(s))) { // latest updates new MutationObserver(mutations => mutations.forEach(m => Array.from(m.addedNodes).filter(e => e.tagName).forEach(node => { console.warn(node, node.children); $find_("a.resource-tile_link", node).forEach(e => { let _id = urlId(e.href||""); console.log(e.href, _id) _id && $updData(_id, e); }); }))).observe(document.body, {subtree: true, childList: true}); } if (location.pathname === '/account/bookmarks') { $find_("li.block-row").forEach(e => { let _id = urlId($find(".contentRow-title a", e).href||""); if (_id) { let toolbar = $find(".contentRow-extra", e); toolbar.insertBefore($editIcon(_id, e), toolbar.firstChild); } }); } if (location.pathname.startsWith('/threads/') && $find(OP)) { // first page of a thread var icons = $find(OP_ICONS); if ( $find_('a', icons).some(e => e.innerText == "#1") ) { icons.insertBefore($e('li', {}, $editIcon(urlId(location.href), $find(OP))), icons.firstChild); } } })();