🏷️ 小鱼标签 (UTags) - 为链接添加用户标签

这是个超实用的工具,能给用户、帖子、视频等链接添加自定义标签和备注信息。比如,可以给论坛的用户或帖子添加标签,易于识别他们或屏蔽他们的帖子和回复。支持 V2EX, X, Reddit, Greasy Fork, GitHub, B站, 抖音, 小红书, 知乎, 掘金, 豆瓣, 吾爱破解, pixiv, LINUX DO, 小众软件, NGA, BOSS直聘等网站。

目前为 2025-03-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 🏷️ UTags - Add usertags to links
  3. // @name:zh-CN 🏷️ 小鱼标签 (UTags) - 为链接添加用户标签
  4. // @namespace https://utags.pipecraft.net/
  5. // @homepageURL https://github.com/utags/utags#readme
  6. // @supportURL https://github.com/utags/utags/issues
  7. // @version 0.12.10
  8. // @description Add custom tags or notes to links such as users, posts and videos. For example, tags can be added to users or posts on a forum, making it easy to identify them or block their posts and replies. It works on X (Twitter), Reddit, Facebook, Threads, Instagram, Youtube, TikTok, GitHub, Greasy Fork, Hacker News, pixiv and numerous other websites.
  9. // @description:zh-CN 这是个超实用的工具,能给用户、帖子、视频等链接添加自定义标签和备注信息。比如,可以给论坛的用户或帖子添加标签,易于识别他们或屏蔽他们的帖子和回复。支持 V2EX, X, Reddit, Greasy Fork, GitHub, B站, 抖音, 小红书, 知乎, 掘金, 豆瓣, 吾爱破解, pixiv, LINUX DO, 小众软件, NGA, BOSS直聘等网站。
  10. // @icon data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23ff6361' class='bi bi-tags-fill' viewBox='0 0 16 16'%3E %3Cpath d='M2 2a1 1 0 0 1 1-1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 2 6.586V2zm3.5 4a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z'/%3E %3Cpath d='M1.293 7.793A1 1 0 0 1 1 7.086V2a1 1 0 0 0-1 1v4.586a1 1 0 0 0 .293.707l7 7a1 1 0 0 0 1.414 0l.043-.043-7.457-7.457z'/%3E %3C/svg%3E
  11. // @author Pipecraft
  12. // @license MIT
  13. // @match https://x.com/*
  14. // @match https://twitter.com/*
  15. // @match https://github.com/*
  16. // @match https://www.reddit.com/*
  17. // @match https://www.instagram.com/*
  18. // @match https://www.threads.net/*
  19. // @match https://*.facebook.com/*
  20. // @match https://*.youtube.com/*
  21. // @match https://www.tiktok.com/*
  22. // @match https://*.bilibili.com/*
  23. // @match https://*.biligame.com/*
  24. // @match https://greasyfork.org/*
  25. // @match https://lobste.rs/*
  26. // @match https://news.ycombinator.com/*
  27. // @match https://*.v2ex.com/*
  28. // @match https://*.v2ex.co/*
  29. // @match https://*.zhihu.com/*
  30. // @match https://*.weibo.com/*
  31. // @match https://*.weibo.cn/*
  32. // @match https://*.douban.com/*
  33. // @match https://www.52pojie.cn/*
  34. // @match https://juejin.cn/*
  35. // @match https://mp.weixin.qq.com/*
  36. // @match https://www.xiaohongshu.com/*
  37. // @match https://sspai.com/*
  38. // @match https://www.douyin.com/*
  39. // @match https://podcasts.google.com/*
  40. // @match https://sleazyfork.org/*
  41. // @match https://tilde.news/*
  42. // @match https://www.journalduhacker.net/*
  43. // @match https://rebang.today/*
  44. // @match https://myanimelist.net/*
  45. // @match https://www.pixiv.net/*
  46. // @match https://meta.discourse.org/*
  47. // @match https://linux.do/*
  48. // @match https://meta.appinn.net/*
  49. // @match https://community.openai.com/*
  50. // @match https://community.cloudflare.com/*
  51. // @match https://community.wanikani.com/*
  52. // @match https://forum.cursor.com/*
  53. // @match https://bbs.nga.cn/*
  54. // @match https://nga.178.com/*
  55. // @match https://ngabbs.com/*
  56. // @match https://www.dlsite.com/*
  57. // @match https://keylol.com/*
  58. // @match https://kemono.su/*
  59. // @match https://coomer.su/*
  60. // @match https://nekohouse.su/*
  61. // @match https://rule34video.com/*
  62. // @match https://rule34gen.com/*
  63. // @match https://panda.chaika.moe/*
  64. // @match https://bbs.tampermonkey.net.cn/*
  65. // @match https://discuss.flarum.org/*
  66. // @match https://discuss.flarum.org.cn/*
  67. // @match https://www.nodeloc.com/*
  68. // @match https://freesmth.net/*
  69. // @match https://freesmth.uk/*
  70. // @match https://veryfb.com/*
  71. // @match https://www.nodeseek.com/*
  72. // @match https://*.inoreader.com/*
  73. // @match https://kater.me/*
  74. // @match https://bbs.viva-la-vita.org/*
  75. // @match https://www.zhipin.com/*
  76. // @match https://v2hot.pipecraft.net/*
  77. // @match https://utags.pipecraft.net/*
  78. // @match https://*.pipecraft.net/*
  79. // @run-at document-start
  80. // @grant GM.getValue
  81. // @grant GM.setValue
  82. // @grant GM_addValueChangeListener
  83. // @grant GM_removeValueChangeListener
  84. // @grant GM_addElement
  85. // @grant GM.registerMenuCommand
  86. // ==/UserScript==
  87. //
  88. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. //// The Official Installation URLs ////
  90. //// 官方安装网址 ////
  91. //// ////
  92. //// * https://greasyfork.org/scripts/460718-utags-add-usertags-to-links ////
  93. //// ** downloadURL https://update.greasyfork.org/scripts/460718/%F0%9F%8F%B7%EF%B8%8F%20UTags%20-%20Add%20usertags%20to%20links.user.js ////
  94. //// * https://scriptcat.org/script-show-page/2784 ////
  95. //// ** downloadURL https://scriptcat.org/scripts/code/2784/%F0%9F%8F%B7%EF%B8%8F+UTags+-+Add+usertags+to+links.user.js ////
  96. //// * https://github.com/utags/utags ////
  97. //// ** downloadURL https://github.com/utags/utags/raw/main/build/userscript-prod/utags.user.js ////
  98. //// * https://gist.github.com/PipecraftNet/38d90a567ff04660f2a1b5430af9ae96 ////
  99. //// ** downloadURL https://gist.github.com/PipecraftNet/38d90a567ff04660f2a1b5430af9ae96/raw/utags.user.js ////
  100. //// ////
  101. //// ////
  102. //// Extension Version ////
  103. //// 浏览器扩展版本 ////
  104. //// * Chrome Web Store - https://chromewebstore.google.com/detail/utags-add-usertags-to-lin/kofjcnaphffjoookgahgjidofbdplgig ////
  105. //// * Edge Add-ons - https://microsoftedge.microsoft.com/addons/detail/utags-add-usertags-to-l/bhlbflbehfoccjjenpekilgabbjjnphe ////
  106. //// * Firefox Addon Store - https://addons.mozilla.org/firefox/addon/utags/ ////
  107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  108. //
  109. ;(() => {
  110. "use strict"
  111. var listeners = {}
  112. var getValue = async (key) => {
  113. const value = await GM.getValue(key)
  114. return value && value !== "undefined" ? JSON.parse(value) : void 0
  115. }
  116. var setValue = async (key, value) => {
  117. if (value !== void 0) {
  118. const newValue = JSON.stringify(value)
  119. if (listeners[key]) {
  120. const oldValue = await GM.getValue(key)
  121. await GM.setValue(key, newValue)
  122. if (newValue !== oldValue) {
  123. for (const func of listeners[key]) {
  124. func(key, oldValue, newValue)
  125. }
  126. }
  127. } else {
  128. await GM.setValue(key, newValue)
  129. }
  130. }
  131. }
  132. var _addValueChangeListener = (key, func) => {
  133. listeners[key] = listeners[key] || []
  134. listeners[key].push(func)
  135. return () => {
  136. if (listeners[key] && listeners[key].length > 0) {
  137. for (let i3 = listeners[key].length - 1; i3 >= 0; i3--) {
  138. if (listeners[key][i3] === func) {
  139. listeners[key].splice(i3, 1)
  140. }
  141. }
  142. }
  143. }
  144. }
  145. var addValueChangeListener = (key, func) => {
  146. if (typeof GM_addValueChangeListener !== "function") {
  147. console.warn("Do not support GM_addValueChangeListener!")
  148. return _addValueChangeListener(key, func)
  149. }
  150. const listenerId = GM_addValueChangeListener(key, func)
  151. return () => {
  152. GM_removeValueChangeListener(listenerId)
  153. }
  154. }
  155. var doc = document
  156. var win = window
  157. var uniq = (array) => [...new Set(array)]
  158. if (typeof String.prototype.replaceAll !== "function") {
  159. String.prototype.replaceAll = String.prototype.replace
  160. }
  161. var $ = (selectors, element) => (element || doc).querySelector(selectors)
  162. var $$ = (selectors, element) => [
  163. ...(element || doc).querySelectorAll(selectors),
  164. ]
  165. var getRootElement = (type) =>
  166. type === 1
  167. ? doc.head || doc.body || doc.documentElement
  168. : type === 2
  169. ? doc.body || doc.documentElement
  170. : doc.documentElement
  171. var createElement = (tagName, attributes) =>
  172. setAttributes(doc.createElement(tagName), attributes)
  173. var addElement = (parentNode, tagName, attributes) => {
  174. if (typeof parentNode === "string") {
  175. return addElement(null, parentNode, tagName)
  176. }
  177. if (!tagName) {
  178. return
  179. }
  180. if (!parentNode) {
  181. parentNode = /^(script|link|style|meta)$/.test(tagName)
  182. ? getRootElement(1)
  183. : getRootElement(2)
  184. }
  185. if (typeof tagName === "string") {
  186. const element = createElement(tagName, attributes)
  187. parentNode.append(element)
  188. return element
  189. }
  190. setAttributes(tagName, attributes)
  191. parentNode.append(tagName)
  192. return tagName
  193. }
  194. var addEventListener = (element, type, listener, options) => {
  195. if (!element) {
  196. return
  197. }
  198. if (typeof type === "object") {
  199. for (const type1 in type) {
  200. if (Object.hasOwn(type, type1)) {
  201. element.addEventListener(type1, type[type1])
  202. }
  203. }
  204. } else if (typeof type === "string" && typeof listener === "function") {
  205. element.addEventListener(type, listener, options)
  206. }
  207. }
  208. var removeEventListener = (element, type, listener, options) => {
  209. if (!element) {
  210. return
  211. }
  212. if (typeof type === "object") {
  213. for (const type1 in type) {
  214. if (Object.hasOwn(type, type1)) {
  215. element.removeEventListener(type1, type[type1])
  216. }
  217. }
  218. } else if (typeof type === "string" && typeof listener === "function") {
  219. element.removeEventListener(type, listener, options)
  220. }
  221. }
  222. var getAttribute = (element, name) =>
  223. element && element.getAttribute ? element.getAttribute(name) : null
  224. var setAttribute = (element, name, value) =>
  225. element && element.setAttribute ? element.setAttribute(name, value) : void 0
  226. var setAttributes = (element, attributes) => {
  227. if (element && attributes) {
  228. for (const name in attributes) {
  229. if (Object.hasOwn(attributes, name)) {
  230. const value = attributes[name]
  231. if (value === void 0) {
  232. continue
  233. }
  234. if (/^(value|textContent|innerText)$/.test(name)) {
  235. element[name] = value
  236. } else if (/^(innerHTML)$/.test(name)) {
  237. element[name] = createHTML(value)
  238. } else if (name === "style") {
  239. setStyle(element, value, true)
  240. } else if (/on\w+/.test(name)) {
  241. const type = name.slice(2)
  242. addEventListener(element, type, value)
  243. } else {
  244. setAttribute(element, name, value)
  245. }
  246. }
  247. }
  248. }
  249. return element
  250. }
  251. var addClass = (element, className) => {
  252. if (!element || !element.classList) {
  253. return
  254. }
  255. element.classList.add(className)
  256. }
  257. var removeClass = (element, className) => {
  258. if (!element || !element.classList) {
  259. return
  260. }
  261. element.classList.remove(className)
  262. }
  263. var hasClass = (element, className) => {
  264. if (!element || !element.classList) {
  265. return false
  266. }
  267. return element.classList.contains(className)
  268. }
  269. var setStyle = (element, values, overwrite) => {
  270. if (!element) {
  271. return
  272. }
  273. const style = element.style
  274. if (typeof values === "string") {
  275. style.cssText = overwrite ? values : style.cssText + ";" + values
  276. return
  277. }
  278. if (overwrite) {
  279. style.cssText = ""
  280. }
  281. for (const key in values) {
  282. if (Object.hasOwn(values, key)) {
  283. style[key] = values[key].replace("!important", "")
  284. }
  285. }
  286. }
  287. var isUrl = (text) => /^https?:\/\//.test(text)
  288. var throttle = (func, interval) => {
  289. let timeoutId = null
  290. let next = false
  291. const handler = (...args) => {
  292. if (timeoutId) {
  293. next = true
  294. } else {
  295. func.apply(void 0, args)
  296. timeoutId = setTimeout(() => {
  297. timeoutId = null
  298. if (next) {
  299. next = false
  300. handler()
  301. }
  302. }, interval)
  303. }
  304. }
  305. return handler
  306. }
  307. if (typeof Object.hasOwn !== "function") {
  308. Object.hasOwn = (instance, prop) =>
  309. Object.prototype.hasOwnProperty.call(instance, prop)
  310. }
  311. var extendHistoryApi = () => {
  312. const pushState = history.pushState
  313. const replaceState = history.replaceState
  314. history.pushState = function () {
  315. pushState.apply(history, arguments)
  316. window.dispatchEvent(new Event("pushstate"))
  317. window.dispatchEvent(new Event("locationchange"))
  318. }
  319. history.replaceState = function () {
  320. replaceState.apply(history, arguments)
  321. window.dispatchEvent(new Event("replacestate"))
  322. window.dispatchEvent(new Event("locationchange"))
  323. }
  324. window.addEventListener("popstate", function () {
  325. window.dispatchEvent(new Event("locationchange"))
  326. })
  327. }
  328. var getOffsetPosition = (element, referElement) => {
  329. const position = { top: 0, left: 0 }
  330. referElement = referElement || doc.body
  331. while (element && element !== referElement) {
  332. position.top += element.offsetTop
  333. position.left += element.offsetLeft
  334. element = element.offsetParent
  335. }
  336. return position
  337. }
  338. var parseInt10 = (number, defaultValue) => {
  339. if (typeof number === "number" && !Number.isNaN(number)) {
  340. return number
  341. }
  342. if (typeof defaultValue !== "number") {
  343. defaultValue = Number.NaN
  344. }
  345. if (!number) {
  346. return defaultValue
  347. }
  348. const result = Number.parseInt(number, 10)
  349. return Number.isNaN(result) ? defaultValue : result
  350. }
  351. var rootFuncArray = []
  352. var headFuncArray = []
  353. var bodyFuncArray = []
  354. var headBodyObserver
  355. var startObserveHeadBodyExists = () => {
  356. if (headBodyObserver) {
  357. return
  358. }
  359. headBodyObserver = new MutationObserver(() => {
  360. if (doc.head && doc.body) {
  361. headBodyObserver.disconnect()
  362. }
  363. if (doc.documentElement && rootFuncArray.length > 0) {
  364. for (const func of rootFuncArray) {
  365. func()
  366. }
  367. rootFuncArray.length = 0
  368. }
  369. if (doc.head && headFuncArray.length > 0) {
  370. for (const func of headFuncArray) {
  371. func()
  372. }
  373. headFuncArray.length = 0
  374. }
  375. if (doc.body && bodyFuncArray.length > 0) {
  376. for (const func of bodyFuncArray) {
  377. func()
  378. }
  379. bodyFuncArray.length = 0
  380. }
  381. })
  382. headBodyObserver.observe(doc, {
  383. childList: true,
  384. subtree: true,
  385. })
  386. }
  387. var runWhenHeadExists = (func) => {
  388. if (!doc.head) {
  389. headFuncArray.push(func)
  390. startObserveHeadBodyExists()
  391. return
  392. }
  393. func()
  394. }
  395. var runWhenDomReady = (func) => {
  396. if (doc.readyState === "interactive" || doc.readyState === "complete") {
  397. return func()
  398. }
  399. const handler = () => {
  400. if (doc.readyState === "interactive" || doc.readyState === "complete") {
  401. func()
  402. removeEventListener(doc, "readystatechange", handler)
  403. }
  404. }
  405. addEventListener(doc, "readystatechange", handler)
  406. }
  407. var isVisible = (element) => {
  408. if (typeof element.checkVisibility === "function") {
  409. return element.checkVisibility()
  410. }
  411. return element.offsetParent !== null
  412. }
  413. var isTouchScreen = () => "ontouchstart" in win
  414. var escapeHTMLPolicy =
  415. typeof trustedTypes !== "undefined" &&
  416. typeof trustedTypes.createPolicy === "function"
  417. ? trustedTypes.createPolicy("beuEscapePolicy", {
  418. createHTML: (string) => string,
  419. })
  420. : void 0
  421. var createHTML = (html) => {
  422. return escapeHTMLPolicy ? escapeHTMLPolicy.createHTML(html) : html
  423. }
  424. var addElement2 =
  425. typeof GM_addElement === "function"
  426. ? (parentNode, tagName, attributes) => {
  427. if (typeof parentNode === "string") {
  428. return addElement2(null, parentNode, tagName)
  429. }
  430. if (!tagName) {
  431. return
  432. }
  433. if (!parentNode) {
  434. parentNode = /^(script|link|style|meta)$/.test(tagName)
  435. ? getRootElement(1)
  436. : getRootElement(2)
  437. }
  438. if (typeof tagName === "string") {
  439. let attributes2
  440. if (attributes) {
  441. const entries1 = []
  442. const entries2 = []
  443. for (const entry of Object.entries(attributes)) {
  444. if (/^(on\w+|innerHTML)$/.test(entry[0])) {
  445. entries2.push(entry)
  446. } else {
  447. entries1.push(entry)
  448. }
  449. }
  450. attributes = Object.fromEntries(entries1)
  451. attributes2 = Object.fromEntries(entries2)
  452. }
  453. const element = GM_addElement(null, tagName, attributes)
  454. setAttributes(element, attributes2)
  455. parentNode.append(element)
  456. return element
  457. }
  458. setAttributes(tagName, attributes)
  459. parentNode.append(tagName)
  460. return tagName
  461. }
  462. : addElement
  463. var addStyle = (styleText) =>
  464. addElement2(null, "style", { textContent: styleText })
  465. var registerMenuCommand = (name, callback, accessKey) => {
  466. if (window !== top) {
  467. return
  468. }
  469. if (typeof GM.registerMenuCommand !== "function") {
  470. console.warn("Do not support GM.registerMenuCommand!")
  471. return
  472. }
  473. GM.registerMenuCommand(name, callback, accessKey)
  474. }
  475. var style_default =
  476. '#browser_extension_settings_container{--browser-extension-settings-background-color: #f2f2f7;--browser-extension-settings-text-color: #444444;--browser-extension-settings-link-color: #217dfc;--sb-track-color: #00000000;--sb-thumb-color: #33334480;--sb-size: 2px;--font-family: "helvetica neue", "microsoft yahei", arial, sans-serif;position:fixed;top:10px;right:30px;max-height:90%;height:600px;overflow:hidden;display:none;z-index:100000;border-radius:5px;-webkit-box-shadow:0px 10px 39px 10px rgba(62,66,66,.22);-moz-box-shadow:0px 10px 39px 10px rgba(62,66,66,.22);box-shadow:0px 10px 39px 10px rgba(62,66,66,.22) !important}#browser_extension_settings_container .browser_extension_settings_wrapper{display:flex;height:100%;overflow:hidden;background-color:var(--browser-extension-settings-background-color);font-family:var(--font-family)}#browser_extension_settings_container .browser_extension_settings_wrapper h1,#browser_extension_settings_container .browser_extension_settings_wrapper h2{border:none;color:var(--browser-extension-settings-text-color);padding:0;font-family:var(--font-family);line-height:normal;letter-spacing:normal}#browser_extension_settings_container .browser_extension_settings_wrapper h1{font-size:26px;font-weight:800;margin:18px 0}#browser_extension_settings_container .browser_extension_settings_wrapper h2{font-size:18px;font-weight:600;margin:14px 0}#browser_extension_settings_container .browser_extension_settings_wrapper footer{display:flex;justify-content:center;flex-direction:column;font-size:11px;margin:10px auto 0px;background-color:var(--browser-extension-settings-background-color);color:var(--browser-extension-settings-text-color);font-family:var(--font-family)}#browser_extension_settings_container .browser_extension_settings_wrapper footer a{color:var(--browser-extension-settings-link-color) !important;font-family:var(--font-family);text-decoration:none;padding:0}#browser_extension_settings_container .browser_extension_settings_wrapper footer p{text-align:center;padding:0;margin:2px;line-height:13px;font-size:11px;color:var(--browser-extension-settings-text-color);font-family:var(--font-family)}#browser_extension_settings_container .browser_extension_settings_wrapper a.navigation_go_previous{color:var(--browser-extension-settings-link-color);cursor:pointer;display:none}#browser_extension_settings_container .browser_extension_settings_wrapper a.navigation_go_previous::before{content:"< "}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container{overflow-x:auto;box-sizing:border-box;padding:10px 15px;background-color:var(--browser-extension-settings-background-color);color:var(--browser-extension-settings-text-color)}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div{background-color:#fff;font-size:14px;border-top:1px solid #ccc;padding:6px 15px 6px 15px}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div a,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div a:visited,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div a,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div a:visited{display:flex;justify-content:space-between;align-items:center;cursor:pointer;text-decoration:none;color:var(--browser-extension-settings-text-color);font-family:var(--font-family)}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div a:hover,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div a:visited:hover,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div a:hover,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div a:visited:hover{text-decoration:none;color:var(--browser-extension-settings-text-color)}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div a span,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div a:visited span,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div a span,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div a:visited span{margin-right:10px;line-height:24px;font-family:var(--font-family)}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div.active,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div:hover,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div.active,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div:hover{background-color:#e4e4e6}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div.active a,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div.active a{cursor:default}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div:first-of-type,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div:first-of-type{border-top:none;border-top-right-radius:10px;border-top-left-radius:10px}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .installed_extension_list div:last-of-type,#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container .related_extension_list div:last-of-type{border-bottom-right-radius:10px;border-bottom-left-radius:10px}#browser_extension_settings_container .thin_scrollbar{scrollbar-color:var(--sb-thumb-color) var(--sb-track-color);scrollbar-width:thin}#browser_extension_settings_container .thin_scrollbar::-webkit-scrollbar{width:var(--sb-size)}#browser_extension_settings_container .thin_scrollbar::-webkit-scrollbar-track{background:var(--sb-track-color);border-radius:10px}#browser_extension_settings_container .thin_scrollbar::-webkit-scrollbar-thumb{background:var(--sb-thumb-color);border-radius:10px}#browser_extension_settings_main{min-width:250px;overflow-y:auto;overflow-x:hidden;box-sizing:border-box;padding:10px 15px;background-color:var(--browser-extension-settings-background-color);color:var(--browser-extension-settings-text-color);font-family:var(--font-family)}#browser_extension_settings_main h2{text-align:center;margin:5px 0 0}#browser_extension_settings_main .option_groups{background-color:#fff;padding:6px 15px 6px 15px;border-radius:10px;display:flex;flex-direction:column;margin:10px 0 0}#browser_extension_settings_main .option_groups .action{font-size:14px;padding:6px 0 6px 0;color:var(--browser-extension-settings-link-color);cursor:pointer}#browser_extension_settings_main .bes_external_link{font-size:14px;padding:6px 0 6px 0}#browser_extension_settings_main .bes_external_link a,#browser_extension_settings_main .bes_external_link a:visited,#browser_extension_settings_main .bes_external_link a:hover{color:var(--browser-extension-settings-link-color);font-family:var(--font-family);text-decoration:none;cursor:pointer}#browser_extension_settings_main .option_groups textarea{font-size:12px;margin:10px 0 10px 0;height:100px;width:100%;border:1px solid #a9a9a9;border-radius:4px;box-sizing:border-box}#browser_extension_settings_main .switch_option,#browser_extension_settings_main .select_option{display:flex;justify-content:space-between;align-items:center;padding:6px 0 6px 0;font-size:14px}#browser_extension_settings_main .option_groups>*{border-top:1px solid #ccc}#browser_extension_settings_main .option_groups>*:first-child{border-top:none}#browser_extension_settings_main .bes_option>.bes_icon{width:24px;height:24px;margin-right:10px}#browser_extension_settings_main .bes_option>.bes_title{margin-right:10px;flex-grow:1}#browser_extension_settings_main .bes_option>.bes_select{box-sizing:border-box;background-color:#fff;height:24px;padding:0 2px 0 2px;margin:0;border-radius:6px;border:1px solid #ccc}#browser_extension_settings_main .option_groups .bes_tip{position:relative;margin:0;padding:0 15px 0 0;border:none;max-width:none;font-size:14px}#browser_extension_settings_main .option_groups .bes_tip .bes_tip_anchor{cursor:help;text-decoration:underline}#browser_extension_settings_main .option_groups .bes_tip .bes_tip_content{position:absolute;bottom:15px;left:0;background-color:#fff;color:var(--browser-extension-settings-text-color);text-align:left;padding:10px;display:none;border-radius:5px;-webkit-box-shadow:0px 10px 39px 10px rgba(62,66,66,.22);-moz-box-shadow:0px 10px 39px 10px rgba(62,66,66,.22);box-shadow:0px 10px 39px 10px rgba(62,66,66,.22) !important}#browser_extension_settings_main .option_groups .bes_tip .bes_tip_anchor:hover+.bes_tip_content,#browser_extension_settings_main .option_groups .bes_tip .bes_tip_content:hover{display:block}#browser_extension_settings_main .option_groups .bes_tip p,#browser_extension_settings_main .option_groups .bes_tip pre{margin:revert;padding:revert}#browser_extension_settings_main .option_groups .bes_tip pre{font-family:Consolas,panic sans,bitstream vera sans mono,Menlo,microsoft yahei,monospace;font-size:13px;letter-spacing:.015em;line-height:120%;white-space:pre;overflow:auto;background-color:#f5f5f5;word-break:normal;overflow-wrap:normal;padding:.5em;border:none}#browser_extension_settings_main .bes_switch_container{--button-width: 51px;--button-height: 24px;--toggle-diameter: 20px;--color-off: #e9e9eb;--color-on: #34c759;width:var(--button-width);height:var(--button-height);position:relative;padding:0;margin:0;flex:none;user-select:none}#browser_extension_settings_main input[type=checkbox]{opacity:0;width:0;height:0;position:absolute}#browser_extension_settings_main .bes_switch{width:100%;height:100%;display:block;background-color:var(--color-off);border-radius:calc(var(--button-height)/2);border:none;cursor:pointer;transition:all .2s ease-out}#browser_extension_settings_main .bes_switch::before{display:none}#browser_extension_settings_main .bes_slider{width:var(--toggle-diameter);height:var(--toggle-diameter);position:absolute;left:2px;top:calc(50% - var(--toggle-diameter)/2);border-radius:50%;background:#fff;box-shadow:0px 3px 8px rgba(0,0,0,.15),0px 3px 1px rgba(0,0,0,.06);transition:all .2s ease-out;cursor:pointer}#browser_extension_settings_main input[type=checkbox]:checked+.bes_switch{background-color:var(--color-on)}#browser_extension_settings_main input[type=checkbox]:checked+.bes_switch .bes_slider{left:calc(var(--button-width) - var(--toggle-diameter) - 2px)}#browser_extension_side_menu{min-height:80px;width:30px;opacity:0;position:fixed;top:80px;right:0;padding-top:20px;z-index:10000}#browser_extension_side_menu:hover{opacity:1}#browser_extension_side_menu button{cursor:pointer;width:24px;height:24px;padding:0;border:none;background-color:rgba(0,0,0,0);background-image:none}#browser_extension_side_menu button svg{width:24px;height:24px}#browser_extension_side_menu button:hover{opacity:70%}#browser_extension_side_menu button:active{opacity:100%}@media(max-width: 500px){#browser_extension_settings_container{right:10px}#browser_extension_settings_container .browser_extension_settings_wrapper a.navigation_go_previous{display:block}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container{display:none}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container.bes_active{display:block}#browser_extension_settings_container .browser_extension_settings_wrapper .extension_list_container.bes_active+div{display:none}}'
  477. function createSwitch(options = {}) {
  478. const container = createElement("label", { class: "bes_switch_container" })
  479. const checkbox = createElement(
  480. "input",
  481. options.checked ? { type: "checkbox", checked: "" } : { type: "checkbox" }
  482. )
  483. addElement2(container, checkbox)
  484. const switchElm = createElement("span", { class: "bes_switch" })
  485. addElement2(switchElm, "span", { class: "bes_slider" })
  486. addElement2(container, switchElm)
  487. if (options.onchange) {
  488. addEventListener(checkbox, "change", options.onchange)
  489. }
  490. return container
  491. }
  492. function createSwitchOption(icon, text, options) {
  493. if (typeof text !== "string") {
  494. return createSwitchOption(void 0, icon, text)
  495. }
  496. const div = createElement("div", { class: "switch_option bes_option" })
  497. if (icon) {
  498. addElement2(div, "img", { src: icon, class: "bes_icon" })
  499. }
  500. addElement2(div, "span", { textContent: text, class: "bes_title" })
  501. div.append(createSwitch(options))
  502. return div
  503. }
  504. var besVersion = 55
  505. var openButton =
  506. '<svg viewBox="0 0 60.2601318359375 84.8134765625" version="1.1" xmlns="http://www.w3.org/2000/svg" class=" glyph-box" style="height: 9.62969px; width: 6.84191px;"><g transform="matrix(1 0 0 1 -6.194965820312518 77.63671875)"><path d="M66.4551-35.2539C66.4551-36.4746 65.9668-37.5977 65.0391-38.4766L26.3672-76.3672C25.4883-77.1973 24.4141-77.6367 23.1445-77.6367C20.6543-77.6367 18.7012-75.7324 18.7012-73.1934C18.7012-71.9727 19.1895-70.8496 19.9707-70.0195L55.5176-35.2539L19.9707-0.488281C19.1895 0.341797 18.7012 1.41602 18.7012 2.68555C18.7012 5.22461 20.6543 7.12891 23.1445 7.12891C24.4141 7.12891 25.4883 6.68945 26.3672 5.81055L65.0391-32.0312C65.9668-32.959 66.4551-34.0332 66.4551-35.2539Z"></path></g></svg>'
  507. var openInNewTabButton =
  508. '<svg viewBox="0 0 72.127685546875 72.2177734375" version="1.1" xmlns="http://www.w3.org/2000/svg" class=" glyph-box" style="height: 8.19958px; width: 8.18935px;"><g transform="matrix(1 0 0 1 -12.451127929687573 71.3388671875)"><path d="M84.5703-17.334L84.5215-66.4551C84.5215-69.2383 82.7148-71.1914 79.7852-71.1914L30.6641-71.1914C27.9297-71.1914 26.0742-69.0918 26.0742-66.748C26.0742-64.4043 28.1738-62.4023 30.4688-62.4023L47.4609-62.4023L71.2891-63.1836L62.207-55.2246L13.8184-6.73828C12.9395-5.85938 12.4512-4.73633 12.4512-3.66211C12.4512-1.31836 14.5508 0.878906 16.9922 0.878906C18.1152 0.878906 19.1895 0.488281 20.0684-0.439453L68.5547-48.877L76.6113-58.0078L75.7324-35.2051L75.7324-17.1387C75.7324-14.8438 77.7344-12.6953 80.127-12.6953C82.4707-12.6953 84.5703-14.6973 84.5703-17.334Z"></path></g></svg>'
  509. var settingButton =
  510. '<svg viewBox="0 0 16 16" version="1.1">\n<path d="M8 0a8.2 8.2 0 0 1 .701.031C9.444.095 9.99.645 10.16 1.29l.288 1.107c.018.066.079.158.212.224.231.114.454.243.668.386.123.082.233.09.299.071l1.103-.303c.644-.176 1.392.021 1.82.63.27.385.506.792.704 1.218.315.675.111 1.422-.364 1.891l-.814.806c-.049.048-.098.147-.088.294.016.257.016.515 0 .772-.01.147.038.246.088.294l.814.806c.475.469.679 1.216.364 1.891a7.977 7.977 0 0 1-.704 1.217c-.428.61-1.176.807-1.82.63l-1.102-.302c-.067-.019-.177-.011-.3.071a5.909 5.909 0 0 1-.668.386c-.133.066-.194.158-.211.224l-.29 1.106c-.168.646-.715 1.196-1.458 1.26a8.006 8.006 0 0 1-1.402 0c-.743-.064-1.289-.614-1.458-1.26l-.289-1.106c-.018-.066-.079-.158-.212-.224a5.738 5.738 0 0 1-.668-.386c-.123-.082-.233-.09-.299-.071l-1.103.303c-.644.176-1.392-.021-1.82-.63a8.12 8.12 0 0 1-.704-1.218c-.315-.675-.111-1.422.363-1.891l.815-.806c.05-.048.098-.147.088-.294a6.214 6.214 0 0 1 0-.772c.01-.147-.038-.246-.088-.294l-.815-.806C.635 6.045.431 5.298.746 4.623a7.92 7.92 0 0 1 .704-1.217c.428-.61 1.176-.807 1.82-.63l1.102.302c.067.019.177.011.3-.071.214-.143.437-.272.668-.386.133-.066.194-.158.211-.224l.29-1.106C6.009.645 6.556.095 7.299.03 7.53.01 7.764 0 8 0Zm-.571 1.525c-.036.003-.108.036-.137.146l-.289 1.105c-.147.561-.549.967-.998 1.189-.173.086-.34.183-.5.29-.417.278-.97.423-1.529.27l-1.103-.303c-.109-.03-.175.016-.195.045-.22.312-.412.644-.573.99-.014.031-.021.11.059.19l.815.806c.411.406.562.957.53 1.456a4.709 4.709 0 0 0 0 .582c.032.499-.119 1.05-.53 1.456l-.815.806c-.081.08-.073.159-.059.19.162.346.353.677.573.989.02.03.085.076.195.046l1.102-.303c.56-.153 1.113-.008 1.53.27.161.107.328.204.501.29.447.222.85.629.997 1.189l.289 1.105c.029.109.101.143.137.146a6.6 6.6 0 0 0 1.142 0c.036-.003.108-.036.137-.146l.289-1.105c.147-.561.549-.967.998-1.189.173-.086.34-.183.5-.29.417-.278.97-.423 1.529-.27l1.103.303c.109.029.175-.016.195-.045.22-.313.411-.644.573-.99.014-.031.021-.11-.059-.19l-.815-.806c-.411-.406-.562-.957-.53-1.456a4.709 4.709 0 0 0 0-.582c-.032-.499.119-1.05.53-1.456l.815-.806c.081-.08.073-.159.059-.19a6.464 6.464 0 0 0-.573-.989c-.02-.03-.085-.076-.195-.046l-1.102.303c-.56.153-1.113.008-1.53-.27a4.44 4.44 0 0 0-.501-.29c-.447-.222-.85-.629-.997-1.189l-.289-1.105c-.029-.11-.101-.143-.137-.146a6.6 6.6 0 0 0-1.142 0ZM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0ZM9.5 8a1.5 1.5 0 1 0-3.001.001A1.5 1.5 0 0 0 9.5 8Z"></path>\n</svg>'
  511. function initI18n(messageMaps, language) {
  512. language = (language || navigator.language).toLowerCase()
  513. const language2 = language.slice(0, 2)
  514. let messagesDefault
  515. let messagesLocal
  516. for (const entry of Object.entries(messageMaps)) {
  517. const langs = new Set(
  518. entry[0]
  519. .toLowerCase()
  520. .split(",")
  521. .map((v) => v.trim())
  522. )
  523. const value = entry[1]
  524. if (langs.has(language)) {
  525. messagesLocal = value
  526. }
  527. if (langs.has(language2) && !messagesLocal) {
  528. messagesLocal = value
  529. }
  530. if (langs.has("en")) {
  531. messagesDefault = value
  532. }
  533. if (langs.has("en-us") && !messagesDefault) {
  534. messagesDefault = value
  535. }
  536. }
  537. if (!messagesLocal) {
  538. messagesLocal = {}
  539. }
  540. if (!messagesDefault || messagesDefault === messagesLocal) {
  541. messagesDefault = {}
  542. }
  543. return function (key, ...parameters) {
  544. let text = messagesLocal[key] || messagesDefault[key] || key
  545. if (parameters && parameters.length > 0 && text !== key) {
  546. for (let i3 = 0; i3 < parameters.length; i3++) {
  547. text = text.replaceAll(
  548. new RegExp("\\{".concat(i3 + 1, "\\}"), "g"),
  549. String(parameters[i3])
  550. )
  551. }
  552. }
  553. return text
  554. }
  555. }
  556. var messages = {
  557. "settings.title": "Settings",
  558. "settings.otherExtensions": "Other Extensions",
  559. "settings.displaySettingsButtonInSideMenu":
  560. "Display Settings Button in Side Menu",
  561. "settings.menu.settings": "\u2699\uFE0F Settings",
  562. "settings.extensions.utags.title":
  563. "\u{1F3F7}\uFE0F UTags - Add usertags to links",
  564. "settings.extensions.links-helper.title": "\u{1F517} Links Helper",
  565. "settings.extensions.v2ex.rep.title":
  566. "V2EX.REP - \u4E13\u6CE8\u63D0\u5347 V2EX \u4E3B\u9898\u56DE\u590D\u6D4F\u89C8\u4F53\u9A8C",
  567. "settings.extensions.v2ex.min.title":
  568. "v2ex.min - V2EX Minimalist (\u6781\u7B80\u98CE\u683C)",
  569. "settings.extensions.replace-ugly-avatars.title": "Replace Ugly Avatars",
  570. "settings.extensions.more-by-pipecraft.title":
  571. "Find more useful userscripts",
  572. }
  573. var en_default = messages
  574. var messages2 = {
  575. "settings.title": "\u8BBE\u7F6E",
  576. "settings.otherExtensions": "\u5176\u4ED6\u6269\u5C55",
  577. "settings.displaySettingsButtonInSideMenu":
  578. "\u5728\u4FA7\u8FB9\u680F\u83DC\u5355\u4E2D\u663E\u793A\u8BBE\u7F6E\u6309\u94AE",
  579. "settings.menu.settings": "\u2699\uFE0F \u8BBE\u7F6E",
  580. "settings.extensions.utags.title":
  581. "\u{1F3F7}\uFE0F \u5C0F\u9C7C\u6807\u7B7E (UTags) - \u4E3A\u94FE\u63A5\u6DFB\u52A0\u7528\u6237\u6807\u7B7E",
  582. "settings.extensions.links-helper.title":
  583. "\u{1F517} \u94FE\u63A5\u52A9\u624B",
  584. "settings.extensions.v2ex.rep.title":
  585. "V2EX.REP - \u4E13\u6CE8\u63D0\u5347 V2EX \u4E3B\u9898\u56DE\u590D\u6D4F\u89C8\u4F53\u9A8C",
  586. "settings.extensions.v2ex.min.title":
  587. "v2ex.min - V2EX \u6781\u7B80\u98CE\u683C",
  588. "settings.extensions.replace-ugly-avatars.title":
  589. "\u8D50\u4F60\u4E2A\u5934\u50CF\u5427",
  590. "settings.extensions.more-by-pipecraft.title":
  591. "\u66F4\u591A\u6709\u8DA3\u7684\u811A\u672C",
  592. }
  593. var zh_cn_default = messages2
  594. var i = initI18n({
  595. "en,en-US": en_default,
  596. "zh,zh-CN": zh_cn_default,
  597. })
  598. var lang = navigator.language
  599. var locale
  600. if (lang === "zh-TW" || lang === "zh-HK") {
  601. locale = "zh-TW"
  602. } else if (lang.includes("zh")) {
  603. locale = "zh-CN"
  604. } else {
  605. locale = "en"
  606. }
  607. var relatedExtensions = [
  608. {
  609. id: "utags",
  610. title: i("settings.extensions.utags.title"),
  611. url: "https://greasyfork.org/".concat(
  612. locale,
  613. "/scripts/460718-utags-add-usertags-to-links"
  614. ),
  615. },
  616. {
  617. id: "links-helper",
  618. title: i("settings.extensions.links-helper.title"),
  619. description:
  620. "\u5728\u65B0\u6807\u7B7E\u9875\u4E2D\u6253\u5F00\u7B2C\u4E09\u65B9\u7F51\u7AD9\u94FE\u63A5\uFF0C\u56FE\u7247\u94FE\u63A5\u8F6C\u56FE\u7247\u6807\u7B7E\u7B49",
  621. url: "https://greasyfork.org/".concat(
  622. locale,
  623. "/scripts/464541-links-helper"
  624. ),
  625. },
  626. {
  627. id: "v2ex.rep",
  628. title: i("settings.extensions.v2ex.rep.title"),
  629. url: "https://greasyfork.org/".concat(
  630. locale,
  631. "/scripts/466589-v2ex-rep-%E4%B8%93%E6%B3%A8%E6%8F%90%E5%8D%87-v2ex-%E4%B8%BB%E9%A2%98%E5%9B%9E%E5%A4%8D%E6%B5%8F%E8%A7%88%E4%BD%93%E9%AA%8C"
  632. ),
  633. },
  634. {
  635. id: "v2ex.min",
  636. title: i("settings.extensions.v2ex.min.title"),
  637. url: "https://greasyfork.org/".concat(
  638. locale,
  639. "/scripts/463552-v2ex-min-v2ex-%E6%9E%81%E7%AE%80%E9%A3%8E%E6%A0%BC"
  640. ),
  641. },
  642. {
  643. id: "replace-ugly-avatars",
  644. title: i("settings.extensions.replace-ugly-avatars.title"),
  645. url: "https://greasyfork.org/".concat(
  646. locale,
  647. "/scripts/472616-replace-ugly-avatars"
  648. ),
  649. },
  650. {
  651. id: "more-by-pipecraft",
  652. title: i("settings.extensions.more-by-pipecraft.title"),
  653. url: "https://greasyfork.org/".concat(locale, "/users/1030884-pipecraft"),
  654. },
  655. ]
  656. var getInstalledExtesionList = () => {
  657. return $(".extension_list_container .installed_extension_list")
  658. }
  659. var getRelatedExtesionList = () => {
  660. return $(".extension_list_container .related_extension_list")
  661. }
  662. var isInstalledExtension = (id) => {
  663. const list = getInstalledExtesionList()
  664. if (!list) {
  665. return false
  666. }
  667. const installed = $('[data-extension-id="'.concat(id, '"]'), list)
  668. return Boolean(installed)
  669. }
  670. var addCurrentExtension = (extension) => {
  671. const list = getInstalledExtesionList()
  672. if (!list) {
  673. return
  674. }
  675. if (isInstalledExtension(extension.id)) {
  676. return
  677. }
  678. const element = createInstalledExtension(extension)
  679. list.append(element)
  680. const list2 = getRelatedExtesionList()
  681. if (list2) {
  682. updateRelatedExtensions(list2)
  683. }
  684. }
  685. var activeExtension = (id) => {
  686. const list = getInstalledExtesionList()
  687. if (!list) {
  688. return false
  689. }
  690. for (const element of $$(".active", list)) {
  691. removeClass(element, "active")
  692. }
  693. const installed = $('[data-extension-id="'.concat(id, '"]'), list)
  694. if (installed) {
  695. addClass(installed, "active")
  696. }
  697. }
  698. var activeExtensionList = () => {
  699. const extensionListContainer = $(".extension_list_container")
  700. if (extensionListContainer) {
  701. addClass(extensionListContainer, "bes_active")
  702. }
  703. }
  704. var deactiveExtensionList = () => {
  705. const extensionListContainer = $(".extension_list_container")
  706. if (extensionListContainer) {
  707. removeClass(extensionListContainer, "bes_active")
  708. }
  709. }
  710. var createInstalledExtension = (installedExtension) => {
  711. const div = createElement("div", {
  712. class: "installed_extension",
  713. "data-extension-id": installedExtension.id,
  714. })
  715. const a = addElement2(div, "a", {
  716. onclick: installedExtension.onclick,
  717. })
  718. addElement2(a, "span", {
  719. textContent: installedExtension.title,
  720. })
  721. const svg = addElement2(a, "svg")
  722. svg.outerHTML = createHTML(openButton)
  723. return div
  724. }
  725. var updateRelatedExtensions = (container) => {
  726. const relatedExtensionElements = $$("[data-extension-id]", container)
  727. if (relatedExtensionElements.length > 0) {
  728. for (const relatedExtensionElement of relatedExtensionElements) {
  729. if (
  730. isInstalledExtension(
  731. relatedExtensionElement.dataset.extensionId || "noid"
  732. )
  733. ) {
  734. relatedExtensionElement.remove()
  735. }
  736. }
  737. } else {
  738. container.innerHTML = createHTML("")
  739. }
  740. for (const relatedExtension of relatedExtensions) {
  741. if (
  742. isInstalledExtension(relatedExtension.id) ||
  743. $('[data-extension-id="'.concat(relatedExtension.id, '"]'), container)
  744. ) {
  745. continue
  746. }
  747. if ($$("[data-extension-id]", container).length >= 4) {
  748. return
  749. }
  750. const div4 = addElement2(container, "div", {
  751. class: "related_extension",
  752. "data-extension-id": relatedExtension.id,
  753. })
  754. const a = addElement2(div4, "a", {
  755. href: relatedExtension.url,
  756. target: "_blank",
  757. })
  758. addElement2(a, "span", {
  759. textContent: relatedExtension.title,
  760. })
  761. const svg = addElement2(a, "svg")
  762. svg.outerHTML = createHTML(openInNewTabButton)
  763. }
  764. }
  765. function createExtensionList(installedExtensions) {
  766. const div = createElement("div", {
  767. class: "extension_list_container thin_scrollbar",
  768. })
  769. addElement2(div, "h1", { textContent: i("settings.title") })
  770. const div2 = addElement2(div, "div", {
  771. class: "installed_extension_list",
  772. })
  773. for (const installedExtension of installedExtensions) {
  774. if (isInstalledExtension(installedExtension.id)) {
  775. continue
  776. }
  777. const element = createInstalledExtension(installedExtension)
  778. div2.append(element)
  779. }
  780. addElement2(div, "h2", { textContent: i("settings.otherExtensions") })
  781. const div3 = addElement2(div, "div", {
  782. class: "related_extension_list",
  783. })
  784. updateRelatedExtensions(div3)
  785. return div
  786. }
  787. var prefix = "browser_extension_settings_"
  788. var randomId = String(Math.round(Math.random() * 1e4))
  789. var settingsContainerId = prefix + "container_" + randomId
  790. var settingsElementId = prefix + "main_" + randomId
  791. var getSettingsElement = () => $("#" + settingsElementId)
  792. var getSettingsStyle = () =>
  793. style_default
  794. .replaceAll(/browser_extension_settings_container/gm, settingsContainerId)
  795. .replaceAll(/browser_extension_settings_main/gm, settingsElementId)
  796. var storageKey = "settings"
  797. var settingsOptions
  798. var settingsTable = {}
  799. var settings = {}
  800. async function getSettings() {
  801. var _a
  802. return (_a = await getValue(storageKey)) != null ? _a : {}
  803. }
  804. async function saveSettingsValue(key, value) {
  805. const settings2 = await getSettings()
  806. settings2[key] =
  807. settingsTable[key] && settingsTable[key].defaultValue === value
  808. ? void 0
  809. : value
  810. await setValue(storageKey, settings2)
  811. }
  812. function getSettingsValue(key) {
  813. var _a
  814. return Object.hasOwn(settings, key)
  815. ? settings[key]
  816. : (_a = settingsTable[key]) == null
  817. ? void 0
  818. : _a.defaultValue
  819. }
  820. var closeModal = () => {
  821. const settingsContainer = getSettingsContainer()
  822. if (settingsContainer) {
  823. settingsContainer.style.display = "none"
  824. }
  825. removeEventListener(document, "click", onDocumentClick, true)
  826. removeEventListener(document, "keydown", onDocumentKeyDown, true)
  827. }
  828. var onDocumentClick = (event) => {
  829. const target = event.target
  830. if (
  831. target == null ? void 0 : target.closest(".".concat(prefix, "container"))
  832. ) {
  833. return
  834. }
  835. closeModal()
  836. }
  837. var onDocumentKeyDown = (event) => {
  838. if (event.defaultPrevented) {
  839. return
  840. }
  841. if (event.key === "Escape") {
  842. closeModal()
  843. event.preventDefault()
  844. }
  845. }
  846. async function updateOptions() {
  847. if (!getSettingsElement()) {
  848. return
  849. }
  850. for (const key in settingsTable) {
  851. if (Object.hasOwn(settingsTable, key)) {
  852. const item = settingsTable[key]
  853. const type = item.type || "switch"
  854. switch (type) {
  855. case "switch": {
  856. const checkbox = $(
  857. "#"
  858. .concat(
  859. settingsElementId,
  860. ' .option_groups .switch_option[data-key="'
  861. )
  862. .concat(key, '"] input')
  863. )
  864. if (checkbox) {
  865. checkbox.checked = getSettingsValue(key)
  866. }
  867. break
  868. }
  869. case "select": {
  870. const options = $$(
  871. "#"
  872. .concat(
  873. settingsElementId,
  874. ' .option_groups .select_option[data-key="'
  875. )
  876. .concat(key, '"] .bes_select option')
  877. )
  878. for (const option of options) {
  879. option.selected = option.value === String(getSettingsValue(key))
  880. }
  881. break
  882. }
  883. case "textarea": {
  884. const textArea = $(
  885. "#"
  886. .concat(
  887. settingsElementId,
  888. ' .option_groups textarea[data-key="'
  889. )
  890. .concat(key, '"]')
  891. )
  892. if (textArea) {
  893. textArea.value = getSettingsValue(key)
  894. }
  895. break
  896. }
  897. default: {
  898. break
  899. }
  900. }
  901. }
  902. }
  903. if (typeof settingsOptions.onViewUpdate === "function") {
  904. const settingsMain = createSettingsElement()
  905. settingsOptions.onViewUpdate(settingsMain)
  906. }
  907. }
  908. function getSettingsContainer() {
  909. const container = $(".".concat(prefix, "container"))
  910. if (container) {
  911. const theVersion = parseInt10(container.dataset.besVersion, 0)
  912. if (theVersion < besVersion) {
  913. container.id = settingsContainerId
  914. container.dataset.besVersion = String(besVersion)
  915. }
  916. return container
  917. }
  918. return addElement2(doc.body, "div", {
  919. id: settingsContainerId,
  920. class: "".concat(prefix, "container"),
  921. "data-bes-version": besVersion,
  922. style: "display: none;",
  923. })
  924. }
  925. function getSettingsWrapper() {
  926. const container = getSettingsContainer()
  927. return (
  928. $(".".concat(prefix, "wrapper"), container) ||
  929. addElement2(container, "div", {
  930. class: "".concat(prefix, "wrapper"),
  931. })
  932. )
  933. }
  934. function initExtensionList() {
  935. const wrapper = getSettingsWrapper()
  936. if (!$(".extension_list_container", wrapper)) {
  937. const list = createExtensionList([])
  938. wrapper.append(list)
  939. }
  940. addCurrentExtension({
  941. id: settingsOptions.id,
  942. title: settingsOptions.title,
  943. onclick: showSettings,
  944. })
  945. }
  946. function createSettingsElement() {
  947. let settingsMain = getSettingsElement()
  948. if (!settingsMain) {
  949. const wrapper = getSettingsWrapper()
  950. for (const element of $$(".".concat(prefix, "main"))) {
  951. element.remove()
  952. }
  953. settingsMain = addElement2(wrapper, "div", {
  954. id: settingsElementId,
  955. class: "".concat(prefix, "main thin_scrollbar"),
  956. })
  957. addElement2(settingsMain, "a", {
  958. textContent: "Settings",
  959. class: "navigation_go_previous",
  960. onclick() {
  961. activeExtensionList()
  962. },
  963. })
  964. if (settingsOptions.title) {
  965. addElement2(settingsMain, "h2", { textContent: settingsOptions.title })
  966. }
  967. const optionGroups = []
  968. const getOptionGroup = (index) => {
  969. if (index > optionGroups.length) {
  970. for (let i3 = optionGroups.length; i3 < index; i3++) {
  971. optionGroups.push(
  972. addElement2(settingsMain, "div", {
  973. class: "option_groups",
  974. })
  975. )
  976. }
  977. }
  978. return optionGroups[index - 1]
  979. }
  980. for (const key in settingsTable) {
  981. if (Object.hasOwn(settingsTable, key)) {
  982. const item = settingsTable[key]
  983. const type = item.type || "switch"
  984. const group = item.group || 1
  985. const optionGroup = getOptionGroup(group)
  986. switch (type) {
  987. case "switch": {
  988. const switchOption = createSwitchOption(item.icon, item.title, {
  989. async onchange(event) {
  990. const checkbox = event.target
  991. if (checkbox) {
  992. let result = true
  993. if (typeof item.onConfirmChange === "function") {
  994. result = item.onConfirmChange(checkbox.checked)
  995. }
  996. if (result) {
  997. await saveSettingsValue(key, checkbox.checked)
  998. } else {
  999. checkbox.checked = !checkbox.checked
  1000. }
  1001. }
  1002. },
  1003. })
  1004. switchOption.dataset.key = key
  1005. addElement2(optionGroup, switchOption)
  1006. break
  1007. }
  1008. case "textarea": {
  1009. let timeoutId
  1010. const div = addElement2(optionGroup, "div", {
  1011. class: "bes_textarea",
  1012. })
  1013. addElement2(div, "textarea", {
  1014. "data-key": key,
  1015. placeholder: item.placeholder || "",
  1016. onkeyup(event) {
  1017. const textArea = event.target
  1018. if (timeoutId) {
  1019. clearTimeout(timeoutId)
  1020. timeoutId = void 0
  1021. }
  1022. timeoutId = setTimeout(async () => {
  1023. if (textArea) {
  1024. await saveSettingsValue(key, textArea.value.trim())
  1025. }
  1026. }, 100)
  1027. },
  1028. })
  1029. break
  1030. }
  1031. case "action": {
  1032. addElement2(optionGroup, "a", {
  1033. class: "action",
  1034. textContent: item.title,
  1035. onclick: item.onclick,
  1036. })
  1037. break
  1038. }
  1039. case "externalLink": {
  1040. const div4 = addElement2(optionGroup, "div", {
  1041. class: "bes_external_link",
  1042. })
  1043. addElement2(div4, "a", {
  1044. textContent: item.title,
  1045. href: item.url,
  1046. target: "_blank",
  1047. })
  1048. break
  1049. }
  1050. case "select": {
  1051. const div = addElement2(optionGroup, "div", {
  1052. class: "select_option bes_option",
  1053. "data-key": key,
  1054. })
  1055. if (item.icon) {
  1056. addElement2(div, "img", { src: item.icon, class: "bes_icon" })
  1057. }
  1058. addElement2(div, "span", {
  1059. textContent: item.title,
  1060. class: "bes_title",
  1061. })
  1062. const select = addElement2(div, "select", {
  1063. class: "bes_select",
  1064. async onchange() {
  1065. await saveSettingsValue(key, select.value)
  1066. },
  1067. })
  1068. for (const option of Object.entries(item.options)) {
  1069. addElement2(select, "option", {
  1070. textContent: option[0],
  1071. value: option[1],
  1072. })
  1073. }
  1074. break
  1075. }
  1076. case "tip": {
  1077. const tip = addElement2(optionGroup, "div", {
  1078. class: "bes_tip",
  1079. })
  1080. addElement2(tip, "a", {
  1081. class: "bes_tip_anchor",
  1082. textContent: item.title,
  1083. })
  1084. const tipContent = addElement2(tip, "div", {
  1085. class: "bes_tip_content",
  1086. innerHTML: createHTML(item.tipContent),
  1087. })
  1088. break
  1089. }
  1090. }
  1091. }
  1092. }
  1093. if (settingsOptions.footer) {
  1094. const footer = addElement2(settingsMain, "footer")
  1095. footer.innerHTML = createHTML(
  1096. typeof settingsOptions.footer === "string"
  1097. ? settingsOptions.footer
  1098. : '<p>Made with \u2764\uFE0F by\n <a href="https://www.pipecraft.net/" target="_blank">\n Pipecraft\n </a></p>'
  1099. )
  1100. }
  1101. }
  1102. return settingsMain
  1103. }
  1104. function addSideMenu() {
  1105. if (!getSettingsValue("displaySettingsButtonInSideMenu")) {
  1106. return
  1107. }
  1108. const menu =
  1109. $("#browser_extension_side_menu") ||
  1110. addElement2(doc.body, "div", {
  1111. id: "browser_extension_side_menu",
  1112. "data-bes-version": besVersion,
  1113. })
  1114. const button = $("button[data-bes-version]", menu)
  1115. if (button) {
  1116. const theVersion = parseInt10(button.dataset.besVersion, 0)
  1117. if (theVersion >= besVersion) {
  1118. return
  1119. }
  1120. button.remove()
  1121. }
  1122. addElement2(menu, "button", {
  1123. type: "button",
  1124. "data-bes-version": besVersion,
  1125. title: i("settings.menu.settings"),
  1126. onclick() {
  1127. setTimeout(showSettings, 1)
  1128. },
  1129. innerHTML: settingButton,
  1130. })
  1131. }
  1132. function addCommonSettings(settingsTable3) {
  1133. let maxGroup = 0
  1134. for (const key in settingsTable3) {
  1135. if (Object.hasOwn(settingsTable3, key)) {
  1136. const item = settingsTable3[key]
  1137. const group = item.group || 1
  1138. if (group > maxGroup) {
  1139. maxGroup = group
  1140. }
  1141. }
  1142. }
  1143. settingsTable3.displaySettingsButtonInSideMenu = {
  1144. title: i("settings.displaySettingsButtonInSideMenu"),
  1145. defaultValue: !(
  1146. typeof GM === "object" && typeof GM.registerMenuCommand === "function"
  1147. ),
  1148. group: maxGroup + 1,
  1149. }
  1150. }
  1151. function handleShowSettingsUrl() {
  1152. if (location.hash === "#bes-show-settings") {
  1153. setTimeout(showSettings, 100)
  1154. }
  1155. }
  1156. async function showSettings() {
  1157. const settingsContainer = getSettingsContainer()
  1158. const settingsMain = createSettingsElement()
  1159. await updateOptions()
  1160. settingsContainer.style.display = "block"
  1161. addEventListener(document, "click", onDocumentClick, true)
  1162. addEventListener(document, "keydown", onDocumentKeyDown, true)
  1163. activeExtension(settingsOptions.id)
  1164. deactiveExtensionList()
  1165. }
  1166. var initSettings = async (options) => {
  1167. settingsOptions = options
  1168. settingsTable = options.settingsTable || {}
  1169. addCommonSettings(settingsTable)
  1170. addValueChangeListener(storageKey, async () => {
  1171. settings = await getSettings()
  1172. await updateOptions()
  1173. addSideMenu()
  1174. if (typeof options.onValueChange === "function") {
  1175. options.onValueChange()
  1176. }
  1177. })
  1178. settings = await getSettings()
  1179. runWhenHeadExists(() => {
  1180. addStyle(getSettingsStyle())
  1181. })
  1182. runWhenDomReady(() => {
  1183. initExtensionList()
  1184. addSideMenu()
  1185. })
  1186. registerMenuCommand(i("settings.menu.settings"), showSettings, "o")
  1187. handleShowSettingsUrl()
  1188. }
  1189. var content_default =
  1190. '\uFEFF#TOFIX_uFEFF{display:block}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul:not(.utags_ul)[data-utags_key],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ol:not(.utags_ul)[data-utags_key]{display:none !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity)[data-utags=off] .utags_ul{display:none !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul{box-sizing:border-box !important;display:inline-flex !important;flex-direction:row !important;flex-wrap:wrap !important;align-content:flex-start;justify-content:flex-start;overflow:visible;white-space:normal;list-style-type:none !important;margin:0 !important;padding:0 !important;vertical-align:text-bottom !important;line-height:normal !important;background-color:rgba(0,0,0,0);border:none !important;box-shadow:none !important;max-width:100% !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul>li{box-sizing:border-box !important;display:inline-flex !important;align-items:center !important;float:none !important;overflow:visible;width:unset !important;height:unset !important;border:none !important;padding:0 !important;margin:0 !important;vertical-align:top !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul>li:first-child .utags_text_tag{margin-left:3px !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul>li:last-child .utags_text_tag{margin-right:3px !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul>li::before,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul>li::after{content:none}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_text_tag{box-sizing:border-box !important;display:block !important;border:var(--utags-text-tag-border-width) solid var(--utags-text-tag-border-color);color:var(--utags-text-tag-color) !important;border-radius:3px !important;padding:1px 3px !important;margin:0 1px !important;font-size:var(--utags-text-tag-font-size) !important;font-family:var(--utags-text-tag-font-family) !important;letter-spacing:0 !important;line-height:1 !important;height:unset !important;width:unset !important;font-weight:normal !important;text-decoration:none !important;text-align:center !important;text-shadow:none !important;min-width:unset !important;min-height:unset !important;max-width:unset !important;max-height:unset !important;background:unset !important;background-color:var(--utags-text-tag-background-color) !important;cursor:pointer;z-index:0;pointer-events:auto}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_text_tag:link{cursor:pointer}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_text_tag[data-utags_tag]::before{content:attr(data-utags_tag);display:block;font-size:var(--utags-text-tag-font-size);line-height:1;height:unset;width:unset;max-width:var(--utags-text-tag-max-width);white-space:var(--utags-text-tag-white-space);overflow:hidden;text-overflow:ellipsis;border-radius:unset;border:unset;background:unset;margin:unset;padding:unset}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_text_tag[data-utags_tag=":visited"]{height:var(--utags-visited-tag-size) !important;width:var(--utags-visited-tag-size) !important;border-radius:var(--utags-visited-tag-size) !important;--utags-text-tag-background-color: var( --utags-visited-tag-background-color );--utags-text-tag-border-color: var(--utags-visited-tag-background-color);--utags-text-tag-border-width: 0px;margin-left:2px !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_text_tag[data-utags_tag=":visited"]::before{display:none}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_emoji_tag{--utags-text-tag-background-color: var( --utags-emoji-tag-background-color );--utags-text-tag-font-size: var(--utags-emoji-tag-font-size);--utags-text-tag-font-family: var(--utags-emoji-tag-font-family);--utags-text-tag-border-width: var(--utags-emoji-tag-border-width);--utags-text-tag-border-color: var(--utags-emoji-tag-border-color)}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag2{width:var(--utags-captain-tag-size) !important;height:var(--utags-captain-tag-size) !important;padding:1px 0 0 1px !important;background:none !important;color:var(--utags-captain-tag-color) !important;border:none !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag::before,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag2::before{content:none !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag svg,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag2 svg{fill:currentColor !important;vertical-align:-3px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag *,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag2 *{color:inherit !important;fill:currentColor !important;width:unset;height:unset}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag{opacity:1%;position:absolute;top:var(--utags-notag-captain-tag-top, 0);left:var(--utags-notag-captain-tag-left, 0);padding:0 !important;margin:0 !important;width:4px !important;height:4px !important;font-size:1px !important;background-color:var(--utags-captain-tag-background-color) !important;transition:all 0s .3s !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag:hover,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag:focus,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag2:hover,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul .utags_captain_tag2:focus{color:var(--utags-captain-tag-hover-color) !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul.utags_ul_0{margin:0 !important;display:var(--utags-notag-ul-disply, inline) !important;float:var(--utags-notag-ul-float, none);height:var(--utags-notag-ul-height, unset);width:var(--utags-notag-ul-width, unset) !important;position:var(--utags-notag-ul-position, unset);top:var(--utags-notag-ul-top, unset)}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul.utags_ul_0>li{position:relative !important;height:var(--utags-captain-tag-size) !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_captain_tag:focus,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) *:hover+.utags_ul .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_fit_content]:hover .utags_ul .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_ul:hover .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_show_all .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) :not(a):not([data-utags_node_type=link])+.utags_ul .utags_captain_tag{opacity:100%;width:calc(var(--utags-captain-tag-size) + 8px) !important;height:calc(var(--utags-captain-tag-size) + 8px) !important;padding:5px 4px 4px 5px !important;transition:all 0s .1s !important;z-index:90}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_hide_all .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_show_all .utags_captain_tag{transition:unset !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal{position:fixed;top:0;left:0;height:0;width:0;z-index:200000}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_modal_wrapper{position:fixed;display:flex;align-items:flex-start;justify-content:center;width:100%;inset:0px;padding-top:5vh;background-color:rgba(255,255,255,.1);z-index:200000}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_modal_content{box-sizing:border-box;display:flex;flex-direction:column;max-width:94%;max-height:100%;overflow:hidden;overflow:auto;color:#000;background-color:#fff;border-radius:5px;padding:14px;margin:0 auto;-webkit-box-shadow:0px 10px 39px 10px rgba(62,66,66,.22);-moz-box-shadow:0px 10px 39px 10px rgba(62,66,66,.22);box-shadow:0px 10px 39px 10px rgba(62,66,66,.22)}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_title{display:block;color:#000;margin-bottom:10px;font-size:14px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_buttons_wrapper{display:flex;flex-direction:row;justify-content:end;padding:10px 0 10px 0}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_buttons_wrapper button{font-size:14px;height:32px;min-width:80px;font-weight:600;padding:0 8px;border-radius:2px;color:var(--utags-button-text-color);border:1px solid var(--utags-button-border-color);background-color:var(--utags-button-bg-color);text-shadow:none;text-align:center;font-family:revert}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_buttons_wrapper button:hover{background-color:var(--utags-button-hover-bg-color);border-color:var(--utags-button-hover-border-color)}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_buttons_wrapper button:not(:first-child){margin-left:10px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_buttons_wrapper button.utags_primary{--utags-button-text-color: var(--utags-action-button-text-color);--utags-button-bg-color: var(--utags-action-button-bg-color);--utags-button-border-color: var(--utags-action-button-border-color);--utags-button-hover-bg-color: var( --utags-action-button-hover-bg-color );--utags-button-hover-border-color: var( --utags-action-button-hover-border-color )}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_prompt input{-webkit-appearance:none;background-color:var(--utags-button-hover-bg-color);border:none;border-bottom:2px solid var(--utags-button-hover-bg-color);border-radius:4px;box-sizing:border-box;caret-color:var(--cr-input-focus-color);color:var(--cr-input-color);font-family:var(--utags-text-tag-font-family) !important;font-weight:inherit;line-height:inherit;min-height:var(--cr-input-min-height, auto);outline:0;padding-bottom:var(--cr-input-padding-bottom, 6px);padding-inline-end:var(--cr-input-padding-end, 8px);padding-inline-start:var(--cr-input-padding-start, 8px);padding-top:var(--cr-input-padding-top, 6px);text-align:left;text-overflow:ellipsis;width:100%;margin:0;font-size:12px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_prompt input:focus,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_prompt input:focus-visible{outline:0;border-bottom:2px solid var(--utags-action-button-hover-border-color)}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_modal .utags_prompt .utags_link_settings{font-size:12px;text-decoration:underline;cursor:pointer;color:#374151}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_current_tags_wrapper{display:flex;justify-content:space-between}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_current_tags_wrapper .utags_button_copy{cursor:pointer;font-size:10px;line-height:1;height:18px;padding:0 6px;border-radius:2px;color:var(--utags-action-button-text-color);background-color:var(--utags-action-button-bg-color);border:1px solid var(--utags-action-button-border-color);text-shadow:none;text-align:center;font-family:revert}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_current_tags{list-style-type:none;margin:0;padding:0 0 10px 0 !important;display:flex !important;flex-direction:row;flex-wrap:wrap}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_current_tags:empty,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_current_tags:empty+button{display:none !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_current_tags li .utags_text_tag:hover{--utags-text-tag-color: #000;--utags-text-tag-border-color: #000;--utags-text-tag-background-color: unset;opacity:.5;text-decoration:line-through !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_current_tags li .utags_text_tag[data-utags_tag=":visited"]:hover{--utags-text-tag-background-color: var( --utags-visited-tag-background-color );--utags-text-tag-border-color: var(--utags-visited-tag-background-color);opacity:.3}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) .utags_list_wrapper{display:flex;justify-content:space-between;max-height:200px;overflow-y:auto}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list{flex-grow:1;list-style-type:none;margin:0;padding:10px 0 10px 0}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list:empty{display:none !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list:not(:first-child){margin-left:4px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list::before{content:attr(data-utags_list_name);position:sticky;top:0;display:block;font-size:12px;font-weight:600;text-align:left;padding:0 2px 0 8px;cursor:default;background-color:#f8fafe}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list li{box-sizing:border-box;cursor:pointer;font-size:12px;height:16px;display:flex;align-items:center;padding:0 2px 0 8px;margin:0;max-width:150px;overflow:hidden;text-overflow:ellipsis}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list li.utags_active,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list li.utags_active2{background-color:#fef2f2}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) ul.utags_select_list li span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:var(--utags-text-tag-font-family) !important;font-size:12px;line-height:1}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) textarea[data-key=customStyleValue]{height:250px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) textarea[data-key^=customStyleValue_]{height:250px}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u6807\u9898\u515A,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u63A8\u5E7F,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u65E0\u804A,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u5FFD\u7565,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",ignore,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",clickbait,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",promotion,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",sb,"]{opacity:10%}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u5DF2\u9605,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u5DF2\u8BFB,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u65B0\u7528\u6237,"]{opacity:50%}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",hide,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u9690\u85CF,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u5C4F\u853D,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u4E0D\u518D\u663E\u793A,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",block,"]{opacity:5%;display:none}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u70ED\u95E8,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u6536\u85CF,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u91CD\u8981,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u5173\u6CE8,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u7A0D\u540E\u9605\u8BFB,"]{background-image:linear-gradient(to right, rgba(255, 255, 255, 0), #fefce8) !important;opacity:100% !important;display:var(--utags-list-node-display) !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u70ED\u95E8,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u6536\u85CF,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u91CD\u8981,"],:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node*=",\u5173\u6CE8,"]{background-image:linear-gradient(to right, rgba(255, 255, 255, 0), #fef2f2) !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_list_node]:hover{opacity:99.99% !important}:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_other="1"]+ul.utags_ul .utags_captain_tag,:not(#utags_should_has_higher_specificity):not(#utags_should_has_higher_specificity) [data-utags_other="1"]+ul.utags_ul .utags_captain_tag2{color:#ff0 !important}[data-utags_display-effect-of-the-visited-content="4"] [data-utags_list_node*=",:visited,"] [data-utags_condition_node][data-utags_visited="1"]{color:var(--utags-visited-title-color)}[data-utags_display-effect-of-the-visited-content="2"] [data-utags_list_node*=",:visited,"]{opacity:var(--utags-visited-opacity)}[data-utags_display-effect-of-the-visited-content="3"] [data-utags_list_node*=",:visited,"]{opacity:5%;display:none}.utags_no_hide [data-utags_list_node*=","]{display:var(--utags-list-node-display) !important}.utags_no_opacity_effect [data-utags_list_node*=","]{opacity:100% !important}textarea[data-key=emojiTags]{font-family:var(--utags-text-tag-font-family)}:root{--utags-list-node-display: block;--utags-captain-tag-background-color: #ffffffb3;--utags-captain-tag-background-color-overlap: #ffffffdd;--utags-captain-tag-color: #ff6361;--utags-captain-tag-hover-color: #256cf1;--utags-captain-tag-size: 14px;--utags-text-tag-color: red;--utags-text-tag-border-color: red;--utags-text-tag-background-color: unset;--utags-text-tag-font-size: 10px;--utags-text-tag-border-width: 1px;--utags-text-tag-max-width: 90px;--utags-text-tag-white-space: nowrap;--utags-text-tag-font-family: "helvetica neue", "Helvetica", "microsoft yahei", "Arial", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "noto color emoji", "android emoji", "emojisymbols", "emojione mozilla", "twemoji mozilla", "Segoe UI", "Noto Sans";--utags-emoji-tag-border-color: #fff0;--utags-emoji-tag-background-color: #fff0;--utags-emoji-tag-font-size: 12px;--utags-emoji-tag-border-width: 0;--utags-emoji-tag-font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "noto color emoji", "android emoji", "emojisymbols", "emojione mozilla", "twemoji mozilla", "Segoe UI", "Noto Sans";--utags-visited-tag-background-color: #bdbdbd;--utags-visited-tag-size: 11px;--utags-visited-title-color: #aaa;--utags-visited-opacity: 10%;--utags-button-text-color: #1a73e8;--utags-button-bg-color: #ffffff;--utags-button-border-color: #dadce0;--utags-button-hover-bg-color: #4285f40a;--utags-button-hover-border-color: #d2e3fc;--utags-action-button-text-color: #ffffff;--utags-action-button-bg-color: #1a73e8;--utags-action-button-border-color: #1a73e8;--utags-action-button-hover-bg-color: #1a73e8e6;--utags-action-button-hover-border-color: #1a73e8e6;--utags-notag-ul-disply-1: inline;--utags-notag-ul-float-1: none;--utags-notag-ul-height-1: unset;--utags-notag-ul-width-1: unset;--utags-notag-ul-position-1: unset;--utags-notag-ul-top-1: unset;--utags-notag-captain-tag-top-1: 0;--utags-notag-captain-tag-left-1: 0;--utags-notag-ul-disply-2: block;--utags-notag-ul-height-2: 0;--utags-notag-ul-width-2: 0;--utags-notag-ul-position-2: unset;--utags-notag-ul-top-2: unset;--utags-notag-captain-tag-top-2: -22px;--utags-notag-captain-tag-left-2: -4px;--utags-notag-ul-disply-3: block;--utags-notag-ul-height-3: 0;--utags-notag-ul-width-3: 0;--utags-notag-ul-position-3: absolute;--utags-notag-ul-top-3: 0;--utags-notag-captain-tag-top-3: 0;--utags-notag-captain-tag-left-3: -4px;--utags-notag-ul-disply-4: block;--utags-notag-ul-height-4: 0;--utags-notag-ul-width-4: 0;--utags-notag-ul-position-4: absolute;--utags-notag-ul-top-4: unset;--utags-notag-captain-tag-top-4: 0;--utags-notag-captain-tag-left-4: -4px;--utags-notag-ul-disply-5: block;--utags-notag-ul-height-5: 0;--utags-notag-ul-width-5: 0;--utags-notag-ul-position-5: absolute;--utags-notag-ul-top-5: -9999px;--utags-notag-captain-tag-top-5: 0;--utags-notag-captain-tag-left-5: -4px;--utags-notag-ul-disply: var(--utags-notag-ul-disply-1);--utags-notag-ul-float: var(--utags-notag-ul-float-1);--utags-notag-ul-height: var(--utags-notag-ul-height-1);--utags-notag-ul-width: var(--utags-notag-ul-width-1);--utags-notag-ul-position: var(--utags-notag-ul-position-1);--utags-notag-ul-top: var(--utags-notag-ul-top-1);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-1);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-1)}[data-utags_darkmode="1"]{--utags-visited-title-color: #666}'
  1191. function createTag(tagName, options) {
  1192. const a = createElement("a", {
  1193. title: tagName,
  1194. class: options.isEmoji
  1195. ? "utags_text_tag utags_emoji_tag"
  1196. : "utags_text_tag",
  1197. })
  1198. if (options.enableSelect) {
  1199. a.textContent = tagName
  1200. } else {
  1201. a.dataset.utags_tag = tagName
  1202. }
  1203. if (!options.noLink) {
  1204. a.setAttribute(
  1205. "href",
  1206. "https://utags.pipecraft.net/tags/#" + encodeURIComponent(tagName)
  1207. )
  1208. a.setAttribute("target", "_blank")
  1209. }
  1210. return a
  1211. }
  1212. var messages3 = {
  1213. "settings.enableCurrentSite": "Enable UTags on the current website",
  1214. "settings.showHidedItems": "Show hidden items (tags with 'block', 'hide')",
  1215. "settings.noOpacityEffect":
  1216. "No opacity mask effect (tags with 'ignore', 'clickbait', 'promotion')",
  1217. "settings.useVisitedFunction":
  1218. "Enable browsing content tagging on the current website",
  1219. "settings.displayEffectOfTheVisitedContent":
  1220. "The display effect of the browsed content",
  1221. "settings.displayEffectOfTheVisitedContent.recordingonly":
  1222. "Save records only, no mark display",
  1223. "settings.displayEffectOfTheVisitedContent.showtagonly":
  1224. "Only display marks",
  1225. "settings.displayEffectOfTheVisitedContent.changecolor":
  1226. "Change the title color",
  1227. "settings.displayEffectOfTheVisitedContent.translucent": "Translucent",
  1228. "settings.displayEffectOfTheVisitedContent.hide": "Hide",
  1229. "settings.pinnedTags": "Add the tags you want to pin, separated by commas.",
  1230. "settings.pinnedTagsDefaultValue":
  1231. "block, hide, ignore, clickbait, promotion",
  1232. "settings.pinnedTagsPlaceholder": "foo, bar",
  1233. "settings.emojiTags": "Add the emoji tags, separated by commas",
  1234. "settings.customStyle": "Enable custom style for all websites",
  1235. "settings.customStyleCurrentSite":
  1236. "Enable custom style for the current website",
  1237. "settings.customStyleDefaultValue":
  1238. "/* Custom style */\nbody {\n /* Tag text color */\n --utags-text-tag-color: white;\n /* Tag border color */\n --utags-text-tag-border-color: red;\n /* Tag background color */\n --utags-text-tag-background-color: red;\n}\n\n/* The tag style for the tag with the label 'TEST' */\n.utags_text_tag[data-utags_tag=\"TEST\"] {\n /* Tag text color */\n --utags-text-tag-color: white;\n /* Tag border color */\n --utags-text-tag-border-color: orange;\n /* Tag background color */\n --utags-text-tag-background-color: orange;\n}",
  1239. "settings.customStyleExamples": "Examples",
  1240. "settings.customStyleExamplesContent":
  1241. '<p>Custom style examples</p>\n <p>\n <pre>/* Custom style */\nbody {\n /* Tag text color */\n --utags-text-tag-color: white;\n /* Tag border color */\n --utags-text-tag-border-color: red;\n /* Tag background color */\n --utags-text-tag-background-color: red;\n}\n\n/* The tag style for the tag with the label \'TEST\' */\n.utags_text_tag[data-utags_tag="TEST"] {\n /* Tag text color */\n --utags-text-tag-color: white;\n /* Tag border color */\n --utags-text-tag-border-color: orange;\n /* Tag background color */\n --utags-text-tag-background-color: orange;\n}\n\ndata-utags_list_node*=",bar,"] {\n /* The background color of the entries\n in the list that contain the \'bar\' tag */\n background-color: aqua;\n}\n\nbody {\n /* The title color of viewed posts */\n --utags-visited-title-color: red;\n}\n\n/* Dark mode */\n[data-utags_darkmode="1"] body {\n /* The title color of viewed posts */\n --utags-visited-title-color: yellow;\n}\n</pre>\n </p>\n <p><a href="https://github.com/utags/utags/tree/main/custom-style-examples">More examples</a></p>\n ',
  1242. "settings.useSimplePrompt": "Use simple prompt method to add tags",
  1243. "settings.openTagsPage": "Open the tag list page",
  1244. "settings.openDataPage": "Open the import data/export data page",
  1245. "settings.title": "\u{1F3F7}\uFE0F UTags - Add usertags to links",
  1246. "settings.information":
  1247. "After changing the settings, reload the page to take effect",
  1248. "settings.report": "Report and Issue...",
  1249. "prompt.addTags":
  1250. "[UTags] Please enter tags, multiple tags are separated by commas",
  1251. "prompt.pinnedTags": "Pinned",
  1252. "prompt.mostUsedTags": "Recently commonly used",
  1253. "prompt.recentAddedTags": "Newly added",
  1254. "prompt.emojiTags": "Emoji",
  1255. "prompt.copy": "Copy",
  1256. "prompt.cancel": "Cancle",
  1257. "prompt.ok": "OK",
  1258. "prompt.settings": "Settings",
  1259. }
  1260. var en_default2 = messages3
  1261. var messages4 = {
  1262. "settings.enableCurrentSite":
  1263. "\u5728\u5F53\u524D\u7F51\u7AD9\u542F\u7528\u5C0F\u9C7C\u6807\u7B7E",
  1264. "settings.showHidedItems":
  1265. "\u663E\u793A\u88AB\u9690\u85CF\u7684\u5185\u5BB9 (\u6DFB\u52A0\u4E86 'block', 'hide', '\u9690\u85CF'\u7B49\u6807\u7B7E\u7684\u5185\u5BB9)",
  1266. "settings.noOpacityEffect":
  1267. "\u53BB\u9664\u534A\u900F\u660E\u6548\u679C (\u6DFB\u52A0\u4E86 'sb', '\u5FFD\u7565', '\u6807\u9898\u515A'\u7B49\u6807\u7B7E\u7684\u5185\u5BB9)",
  1268. "settings.useVisitedFunction":
  1269. "\u5728\u5F53\u524D\u7F51\u7AD9\u542F\u7528\u6D4F\u89C8\u5185\u5BB9\u6807\u8BB0\u529F\u80FD",
  1270. "settings.displayEffectOfTheVisitedContent":
  1271. "\u5F53\u524D\u7F51\u7AD9\u7684\u5DF2\u6D4F\u89C8\u5185\u5BB9\u7684\u5C55\u793A\u6548\u679C",
  1272. "settings.displayEffectOfTheVisitedContent.recordingonly":
  1273. "\u53EA\u4FDD\u5B58\u8BB0\u5F55\uFF0C\u4E0D\u663E\u793A\u6807\u8BB0",
  1274. "settings.displayEffectOfTheVisitedContent.showtagonly":
  1275. "\u53EA\u663E\u793A\u6807\u8BB0",
  1276. "settings.displayEffectOfTheVisitedContent.changecolor":
  1277. "\u66F4\u6539\u6807\u9898\u989C\u8272",
  1278. "settings.displayEffectOfTheVisitedContent.translucent":
  1279. "\u534A\u900F\u660E",
  1280. "settings.displayEffectOfTheVisitedContent.hide": "\u9690\u85CF",
  1281. "settings.pinnedTags":
  1282. "\u5728\u4E0B\u9762\u6DFB\u52A0\u8981\u7F6E\u9876\u7684\u6807\u7B7E\uFF0C\u4EE5\u9017\u53F7\u5206\u9694",
  1283. "settings.pinnedTagsDefaultValue":
  1284. "\u6536\u85CF, block, sb, \u5C4F\u853D, \u9690\u85CF, \u5DF2\u9605, \u5FFD\u7565, \u6807\u9898\u515A, \u63A8\u5E7F, \u5173\u6CE8",
  1285. "settings.pinnedTagsPlaceholder": "foo, bar",
  1286. "settings.emojiTags":
  1287. "\u5728\u4E0B\u9762\u6DFB\u52A0\u8868\u60C5\u7B26\u53F7\u6807\u7B7E\uFF0C\u4EE5\u9017\u53F7\u5206\u9694",
  1288. "settings.customStyle":
  1289. "\u542F\u7528\u5168\u5C40\u81EA\u5B9A\u4E49\u6837\u5F0F",
  1290. "settings.customStyleCurrentSite":
  1291. "\u542F\u7528\u5F53\u524D\u7F51\u7AD9\u7684\u81EA\u5B9A\u4E49\u6837\u5F0F",
  1292. "settings.customStyleDefaultValue":
  1293. "/* \u81EA\u5B9A\u4E49\u6837\u5F0F */\nbody {\n /* \u6807\u7B7E\u6587\u5B57\u989C\u8272 */\n --utags-text-tag-color: white;\n /* \u6807\u7B7E\u8FB9\u6846\u989C\u8272 */\n --utags-text-tag-border-color: red;\n /* \u6807\u7B7E\u80CC\u666F\u989C\u8272 */\n --utags-text-tag-background-color: red;\n}\n\n/* \u6807\u7B7E\u4E3A 'TEST' \u7684\u6807\u7B7E\u6837\u5F0F */\n.utags_text_tag[data-utags_tag=\"TEST\"] {\n /* \u6807\u7B7E\u6587\u5B57\u989C\u8272 */\n --utags-text-tag-color: white;\n /* \u6807\u7B7E\u8FB9\u6846\u989C\u8272 */\n --utags-text-tag-border-color: orange;\n /* \u6807\u7B7E\u80CC\u666F\u989C\u8272 */\n --utags-text-tag-background-color: orange;\n}",
  1294. "settings.customStyleExamples": "\u793A\u4F8B",
  1295. "settings.customStyleExamplesContent":
  1296. '<p>\u81EA\u5B9A\u4E49\u6837\u5F0F\u793A\u4F8B</p>\n <p>\n <pre>/* \u81EA\u5B9A\u4E49\u6837\u5F0F */\nbody {\n /* \u6807\u7B7E\u6587\u5B57\u989C\u8272 */\n --utags-text-tag-color: white;\n /* \u6807\u7B7E\u8FB9\u6846\u989C\u8272 */\n --utags-text-tag-border-color: red;\n /* \u6807\u7B7E\u80CC\u666F\u989C\u8272 */\n --utags-text-tag-background-color: red;\n}\n\n/* \u6807\u7B7E\u4E3A \'TEST\' \u7684\u6807\u7B7E\u6837\u5F0F */\n.utags_text_tag[data-utags_tag="TEST"] {\n /* \u6807\u7B7E\u6587\u5B57\u989C\u8272 */\n --utags-text-tag-color: white;\n /* \u6807\u7B7E\u8FB9\u6846\u989C\u8272 */\n --utags-text-tag-border-color: orange;\n /* \u6807\u7B7E\u80CC\u666F\u989C\u8272 */\n --utags-text-tag-background-color: orange;\n}\n\ndata-utags_list_node*=",bar,"] {\n /* \u5217\u8868\u4E2D\u542B\u6709 \'bar\' \u6807\u7B7E\u7684\u6761\u76EE\u7684\u80CC\u666F\u8272 */\n background-color: aqua;\n}\n\nbody {\n /* \u6D4F\u89C8\u8FC7\u7684\u5E16\u5B50\u7684\u6807\u9898\u989C\u8272 */\n --utags-visited-title-color: red;\n}\n\n/* \u6DF1\u8272\u6A21\u5F0F */\n[data-utags_darkmode="1"] body {\n /* \u6D4F\u89C8\u8FC7\u7684\u5E16\u5B50\u7684\u6807\u9898\u989C\u8272 */\n --utags-visited-title-color: yellow;\n}\n</pre>\n </p>\n <p><a href="https://github.com/utags/utags/tree/main/custom-style-examples">\u66F4\u591A\u793A\u4F8B</a></p>\n ',
  1297. "settings.useSimplePrompt":
  1298. "\u4F7F\u7528\u7B80\u5355\u65B9\u5F0F\u6DFB\u52A0\u6807\u7B7E",
  1299. "settings.openTagsPage": "\u6807\u7B7E\u5217\u8868",
  1300. "settings.openDataPage":
  1301. "\u5BFC\u51FA\u6570\u636E/\u5BFC\u5165\u6570\u636E",
  1302. "settings.title":
  1303. "\u{1F3F7}\uFE0F \u5C0F\u9C7C\u6807\u7B7E (UTags) - \u4E3A\u94FE\u63A5\u6DFB\u52A0\u7528\u6237\u6807\u7B7E",
  1304. "settings.information":
  1305. "\u66F4\u6539\u8BBE\u7F6E\u540E\uFF0C\u91CD\u65B0\u52A0\u8F7D\u9875\u9762\u5373\u53EF\u751F\u6548",
  1306. "settings.report": "\u53CD\u9988\u95EE\u9898",
  1307. "prompt.addTags":
  1308. "[UTags] \u8BF7\u8F93\u5165\u6807\u7B7E\uFF0C\u591A\u4E2A\u6807\u7B7E\u4EE5\u9017\u53F7\u5206\u9694",
  1309. "prompt.pinnedTags": "\u7F6E\u9876",
  1310. "prompt.mostUsedTags": "\u6700\u8FD1\u5E38\u7528",
  1311. "prompt.recentAddedTags": "\u6700\u65B0\u6DFB\u52A0",
  1312. "prompt.emojiTags": "\u7B26\u53F7",
  1313. "prompt.copy": "\u590D\u5236",
  1314. "prompt.cancel": "\u53D6\u6D88",
  1315. "prompt.ok": "\u786E\u8BA4",
  1316. "prompt.settings": "\u8BBE\u7F6E",
  1317. }
  1318. var zh_cn_default2 = messages4
  1319. var i2 = initI18n({
  1320. "en,en-US": en_default2,
  1321. "zh,zh-CN": zh_cn_default2,
  1322. })
  1323. function getFirstHeadElement(tagName = "h1") {
  1324. for (const element of $$(tagName)) {
  1325. if (element.closest(".browser_extension_settings_container")) {
  1326. continue
  1327. }
  1328. return element
  1329. }
  1330. return void 0
  1331. }
  1332. function trimTitle(title) {
  1333. return title ? title.replaceAll(/\s+/gm, " ").trim() : ""
  1334. }
  1335. function getTrimmedTitle(element) {
  1336. return trimTitle(element.textContent)
  1337. }
  1338. function splitTags(text) {
  1339. if (!text) {
  1340. return []
  1341. }
  1342. return text
  1343. .trim()
  1344. .replaceAll(/[\n\r\t]/gm, " ")
  1345. .split(/\s*[,,]\s*/)
  1346. }
  1347. function sortTags(tags, privilegedTags) {
  1348. return tags.sort((a, b) => {
  1349. const pA = privilegedTags.includes(a)
  1350. const pB = privilegedTags.includes(b)
  1351. if (pA && pB) {
  1352. return 0
  1353. }
  1354. if (pA) {
  1355. return -1
  1356. }
  1357. if (pB) {
  1358. return 1
  1359. }
  1360. return 0
  1361. })
  1362. }
  1363. function filterTags(tags, removed) {
  1364. if (typeof removed === "string") {
  1365. removed = [removed]
  1366. }
  1367. if (removed.length === 0) {
  1368. return tags
  1369. }
  1370. return tags.filter((value) => {
  1371. return !removed.includes(value)
  1372. })
  1373. }
  1374. async function copyText(data) {
  1375. const textArea = createElement("textarea", {
  1376. style: "position: absolute; left: -100%;",
  1377. contentEditable: "true",
  1378. })
  1379. textArea.value = data.replaceAll("\xA0", " ")
  1380. document.body.append(textArea)
  1381. textArea.select()
  1382. await navigator.clipboard.writeText(textArea.value)
  1383. textArea.remove()
  1384. }
  1385. function deleteUrlParameters(urlString, keys, excepts) {
  1386. const url = new URL(urlString)
  1387. if (keys === "*") {
  1388. if (excepts && excepts.length > 0) {
  1389. const parameters2 = new URLSearchParams(url.search)
  1390. keys = []
  1391. for (const key of parameters2.keys()) {
  1392. if (!excepts.includes(key)) {
  1393. keys.push(key)
  1394. }
  1395. }
  1396. } else {
  1397. url.search = ""
  1398. return url.toString()
  1399. }
  1400. }
  1401. if (typeof keys === "string") {
  1402. keys = [keys]
  1403. }
  1404. const parameters = new URLSearchParams(url.search)
  1405. for (const key of keys) {
  1406. parameters.delete(key)
  1407. }
  1408. url.search = parameters.size === 0 ? "" : "?" + parameters.toString()
  1409. return url.toString()
  1410. }
  1411. function getUrlParameters(urlString, keys, allowEmpty = false) {
  1412. const url = new URL(urlString)
  1413. if (typeof keys === "string") {
  1414. keys = [keys]
  1415. }
  1416. const result = {}
  1417. const parameters = new URLSearchParams(url.search)
  1418. for (const key of keys) {
  1419. if (key) {
  1420. const value = parameters.get(key)
  1421. if (
  1422. (allowEmpty && value !== void 0 && value !== null) ||
  1423. (!allowEmpty && value)
  1424. ) {
  1425. result[key] = value
  1426. }
  1427. }
  1428. }
  1429. return result
  1430. }
  1431. var extensionVersion = "0.8.0"
  1432. var databaseVersion = 2
  1433. var storageKey2 = "extension.utags.urlmap"
  1434. var storageKeyRecentTags = "extension.utags.recenttags"
  1435. var storageKeyMostUsedTags = "extension.utags.mostusedtags"
  1436. var storageKeyRecentAddedTags = "extension.utags.recentaddedtags"
  1437. var cachedUrlMap
  1438. async function getUrlMap() {
  1439. return (await getValue(storageKey2)) || {}
  1440. }
  1441. async function getUrlMapVesion1() {
  1442. return getValue("plugin.utags.tags.v1")
  1443. }
  1444. async function getCachedUrlMap() {
  1445. if (!cachedUrlMap) {
  1446. cachedUrlMap = await getUrlMap()
  1447. }
  1448. return cachedUrlMap
  1449. }
  1450. function getTags(key) {
  1451. return (cachedUrlMap && cachedUrlMap[key]) || { tags: [] }
  1452. }
  1453. async function saveTags(key, tags, meta) {
  1454. const urlMap = await getUrlMap()
  1455. urlMap.meta = Object.assign({}, urlMap.meta, {
  1456. extensionVersion,
  1457. databaseVersion,
  1458. })
  1459. const newTags = mergeTags(tags, [])
  1460. let oldTags = []
  1461. if (newTags.length === 0) {
  1462. delete urlMap[key]
  1463. } else {
  1464. const now = Date.now()
  1465. const data = urlMap[key] || {}
  1466. oldTags = data.tags
  1467. const newMeta = Object.assign({}, data.meta, meta, {
  1468. updated: now,
  1469. })
  1470. newMeta.created = newMeta.created || now
  1471. urlMap[key] = {
  1472. tags: newTags,
  1473. meta: newMeta,
  1474. }
  1475. }
  1476. await setValue(storageKey2, urlMap)
  1477. await addRecentTags(newTags, oldTags)
  1478. }
  1479. function getScore(weight = 1) {
  1480. return (Math.floor(Date.now() / 1e3) / 1e9) * weight
  1481. }
  1482. async function addRecentTags(newTags, oldTags) {
  1483. if (newTags.length === 0) {
  1484. return
  1485. }
  1486. newTags =
  1487. oldTags && oldTags.length > 0
  1488. ? newTags.filter((v) => !oldTags.includes(v))
  1489. : newTags
  1490. if (newTags.length > 0) {
  1491. const recentTags = (await getValue(storageKeyRecentTags)) || []
  1492. const score = getScore()
  1493. for (const tag of newTags) {
  1494. recentTags.push({
  1495. tag,
  1496. score,
  1497. })
  1498. }
  1499. if (recentTags.length > 1e3) {
  1500. recentTags.splice(0, 100)
  1501. }
  1502. await setValue(storageKeyRecentTags, recentTags)
  1503. await generateMostUsedAndRecentAddedTags(recentTags)
  1504. }
  1505. }
  1506. async function generateMostUsedAndRecentAddedTags(recentTags) {
  1507. const mostUsed = {}
  1508. for (const recentTag of recentTags) {
  1509. if (!recentTag.tag) {
  1510. continue
  1511. }
  1512. if (mostUsed[recentTag.tag]) {
  1513. mostUsed[recentTag.tag].score += recentTag.score
  1514. } else if (recentTag.tag) {
  1515. mostUsed[recentTag.tag] = {
  1516. tag: recentTag.tag,
  1517. score: recentTag.score,
  1518. }
  1519. }
  1520. }
  1521. const mostUsedTags2 = Object.values(mostUsed)
  1522. .filter((v) => v.score > getScore(1.5))
  1523. .sort((a, b) => {
  1524. return b.score - a.score
  1525. })
  1526. .map((v) => v.tag)
  1527. .slice(0, 200)
  1528. const uniqSet = /* @__PURE__ */ new Set()
  1529. const recentAddedTags2 = recentTags
  1530. .map((v) => v.tag)
  1531. .reverse()
  1532. .filter((v) => v && !uniqSet.has(v) && uniqSet.add(v))
  1533. .slice(0, 200)
  1534. await setValue(storageKeyMostUsedTags, mostUsedTags2)
  1535. await setValue(storageKeyRecentAddedTags, recentAddedTags2)
  1536. }
  1537. async function getMostUsedTags() {
  1538. return (await getValue(storageKeyMostUsedTags)) || []
  1539. }
  1540. async function getRecentAddedTags() {
  1541. return (await getValue(storageKeyRecentAddedTags)) || []
  1542. }
  1543. async function getPinnedTags() {
  1544. return splitTags(getSettingsValue("pinnedTags") || "")
  1545. }
  1546. async function getEmojiTags() {
  1547. return splitTags(getSettingsValue("emojiTags") || "")
  1548. }
  1549. function addTagsValueChangeListener(func) {
  1550. addValueChangeListener(storageKey2, func)
  1551. }
  1552. addTagsValueChangeListener(async () => {
  1553. cachedUrlMap = void 0
  1554. await checkVersion()
  1555. })
  1556. async function reload() {
  1557. console.log("Current extionsion is outdated, need reload page")
  1558. const urlMap = await getUrlMap()
  1559. urlMap.meta = urlMap.meta || {}
  1560. await setValue(storageKey2, urlMap)
  1561. location.reload()
  1562. }
  1563. async function checkVersion() {
  1564. cachedUrlMap = await getUrlMap()
  1565. const meta = cachedUrlMap.meta || {}
  1566. if (meta.extensionVersion !== extensionVersion) {
  1567. console.log(
  1568. "Previous extension version:",
  1569. meta.extensionVersion,
  1570. "current extension version:",
  1571. extensionVersion
  1572. )
  1573. if (meta.extensionVersion > extensionVersion) {
  1574. }
  1575. }
  1576. if (meta.databaseVersion !== databaseVersion) {
  1577. console.log(
  1578. "Previous database version:",
  1579. meta.databaseVersion,
  1580. "current database version:",
  1581. databaseVersion
  1582. )
  1583. if (meta.databaseVersion > databaseVersion) {
  1584. await reload()
  1585. return false
  1586. }
  1587. }
  1588. return true
  1589. }
  1590. function isValidKey(key) {
  1591. return isUrl(key)
  1592. }
  1593. function isValidTags(tags) {
  1594. return Array.isArray(tags)
  1595. }
  1596. function mergeTags(tags, tags2) {
  1597. tags = tags || []
  1598. tags2 = tags2 || []
  1599. return uniq(
  1600. tags
  1601. .concat(tags2)
  1602. .map((v) => (v ? String(v).trim() : v))
  1603. .filter(Boolean)
  1604. )
  1605. }
  1606. async function migrationData(urlMap) {
  1607. console.log("Before migration", JSON.stringify(urlMap))
  1608. const meta = urlMap.meta || {}
  1609. const now = Date.now()
  1610. const meta2 = { created: now, updated: now }
  1611. if (!meta.databaseVersion) {
  1612. meta.databaseVersion = 1
  1613. }
  1614. if (meta.databaseVersion === 1) {
  1615. for (const key in urlMap) {
  1616. if (!Object.hasOwn(urlMap, key)) {
  1617. continue
  1618. }
  1619. if (!isValidKey(key)) {
  1620. continue
  1621. }
  1622. const tags = urlMap[key]
  1623. if (!isValidTags(tags)) {
  1624. throw new Error("Invaid data format.")
  1625. }
  1626. const newTags = mergeTags(tags, [])
  1627. if (newTags.length > 0) {
  1628. urlMap[key] = { tags: newTags, meta: meta2 }
  1629. } else {
  1630. delete urlMap[key]
  1631. }
  1632. }
  1633. meta.databaseVersion = 2
  1634. }
  1635. if (meta.databaseVersion === 2) {
  1636. }
  1637. urlMap.meta = meta
  1638. console.log("After migration", JSON.stringify(urlMap))
  1639. return urlMap
  1640. }
  1641. async function mergeData(urlMapNew) {
  1642. if (typeof urlMapNew !== "object") {
  1643. throw new TypeError("Invalid data format")
  1644. }
  1645. let numberOfLinks = 0
  1646. let numberOfTags = 0
  1647. const urlMap = await getUrlMap()
  1648. if (
  1649. !urlMapNew.meta ||
  1650. urlMapNew.meta.databaseVersion !== urlMap.meta.databaseVersion
  1651. ) {
  1652. urlMapNew = await migrationData(urlMapNew)
  1653. }
  1654. if (urlMapNew.meta.databaseVersion !== urlMap.meta.databaseVersion) {
  1655. throw new Error("Invalid database version")
  1656. }
  1657. for (const key in urlMapNew) {
  1658. if (!Object.hasOwn(urlMapNew, key)) {
  1659. continue
  1660. }
  1661. if (!isValidKey(key)) {
  1662. continue
  1663. }
  1664. const tags = urlMapNew[key].tags || []
  1665. const meta = urlMapNew[key].meta || {}
  1666. if (!isValidTags(tags)) {
  1667. throw new Error("Invaid data format.")
  1668. }
  1669. const orgData = urlMap[key] || { tags: [] }
  1670. const orgTags = orgData.tags || []
  1671. const newTags = mergeTags(orgTags, tags)
  1672. const now = Date.now()
  1673. if (newTags.length > 0) {
  1674. const orgMeta = orgData.meta || {}
  1675. const created = Math.min(orgMeta.created || now, meta.created || now)
  1676. const updated = Math.max(
  1677. orgMeta.updated || 0,
  1678. meta.updated || 0,
  1679. created
  1680. )
  1681. const newMata = Object.assign({}, orgMeta, meta, { created, updated })
  1682. urlMap[key] = Object.assign({}, orgData, {
  1683. tags: newTags,
  1684. meta: newMata,
  1685. })
  1686. numberOfTags += Math.max(newTags.length - orgTags.length, 0)
  1687. if (orgTags.length === 0) {
  1688. numberOfLinks++
  1689. }
  1690. } else {
  1691. delete urlMap[key]
  1692. }
  1693. }
  1694. await setValue(storageKey2, urlMap)
  1695. console.log(
  1696. "\u6570\u636E\u5DF2\u6210\u529F\u5BFC\u5165\uFF0C\u65B0\u589E "
  1697. .concat(numberOfLinks, " \u6761\u94FE\u63A5\uFF0C\u65B0\u589E ")
  1698. .concat(numberOfTags, " \u6761\u6807\u7B7E\u3002")
  1699. )
  1700. return { numberOfLinks, numberOfTags }
  1701. }
  1702. async function migration() {
  1703. const result = await checkVersion()
  1704. if (!result) {
  1705. return
  1706. }
  1707. cachedUrlMap = await getUrlMap()
  1708. const meta = cachedUrlMap.meta || {}
  1709. if (meta.databaseVersion !== databaseVersion) {
  1710. meta.databaseVersion = meta.databaseVersion || 1
  1711. if (meta.databaseVersion < databaseVersion) {
  1712. console.log("Migration start")
  1713. await saveTags("any", [])
  1714. console.log("Migration done")
  1715. }
  1716. }
  1717. const urlMapVer1 = await getUrlMapVesion1()
  1718. if (urlMapVer1) {
  1719. console.log(
  1720. "Migration start: database version 1 to database version",
  1721. databaseVersion
  1722. )
  1723. const result2 = await mergeData(urlMapVer1)
  1724. if (result2) {
  1725. await setValue("plugin.utags.tags.v1", null)
  1726. }
  1727. }
  1728. }
  1729. async function outputData() {
  1730. if (
  1731. /^(utags\.pipecraft\.net|localhost|127\.0\.0\.1)$/.test(location.hostname)
  1732. ) {
  1733. const urlMap = await getUrlMap()
  1734. const textarea = createElement("textarea")
  1735. textarea.id = "utags_output"
  1736. textarea.setAttribute("style", "display:none")
  1737. textarea.value = JSON.stringify(urlMap)
  1738. doc.body.append(textarea)
  1739. textarea.addEventListener("click", async () => {
  1740. if (textarea.dataset.utags_type === "export") {
  1741. const urlMap2 = await getUrlMap()
  1742. textarea.value = JSON.stringify(urlMap2)
  1743. textarea.dataset.utags_type = "export_done"
  1744. textarea.click()
  1745. } else if (textarea.dataset.utags_type === "import") {
  1746. const data = textarea.value
  1747. try {
  1748. const result = await mergeData(JSON.parse(data))
  1749. textarea.value = JSON.stringify(result)
  1750. textarea.dataset.utags_type = "import_done"
  1751. textarea.click()
  1752. } catch (error) {
  1753. console.error(error)
  1754. textarea.value = JSON.stringify(error)
  1755. textarea.dataset.utags_type = "import_failed"
  1756. textarea.click()
  1757. }
  1758. }
  1759. })
  1760. }
  1761. }
  1762. function createModal(attributes) {
  1763. const div = createElement("div", {
  1764. class: "utags_modal",
  1765. })
  1766. const wrapper = addElement2(div, "div", {
  1767. class: "utags_modal_wrapper",
  1768. })
  1769. const content = addElement2(wrapper, "div", attributes)
  1770. addClass(content, "utags_modal_content")
  1771. let removed = false
  1772. return {
  1773. remove() {
  1774. if (!removed) {
  1775. removed = true
  1776. div.remove()
  1777. }
  1778. },
  1779. append(element) {
  1780. ;(element || doc.body).append(div)
  1781. },
  1782. getContentElement() {
  1783. return content
  1784. },
  1785. }
  1786. }
  1787. var pinnedTags
  1788. var mostUsedTags
  1789. var recentAddedTags
  1790. var emojiTags
  1791. var displayedTags = /* @__PURE__ */ new Set()
  1792. var currentTags = /* @__PURE__ */ new Set()
  1793. function onSelect(selected, input) {
  1794. if (selected) {
  1795. input.value = ""
  1796. const tags = splitTags(selected)
  1797. for (const tag of tags) {
  1798. if (tag.trim()) {
  1799. currentTags.add(tag.trim())
  1800. }
  1801. }
  1802. updateLists()
  1803. }
  1804. }
  1805. function removeTag(tag) {
  1806. if (tag) {
  1807. tag = tag.trim()
  1808. currentTags.delete(tag)
  1809. updateLists()
  1810. }
  1811. }
  1812. function updateLists(container) {
  1813. displayedTags = /* @__PURE__ */ new Set()
  1814. const ul1 = $(".utags_modal_content ul.utags_current_tags", container)
  1815. if (ul1) {
  1816. updateCurrentTagList(ul1)
  1817. }
  1818. const ul = $(
  1819. ".utags_modal_content ul.utags_select_list.utags_pined_list",
  1820. container
  1821. )
  1822. if (ul) {
  1823. updateCandidateTagList(ul, pinnedTags)
  1824. }
  1825. const ul4 = $(
  1826. ".utags_modal_content ul.utags_select_list.utags_emoji_list",
  1827. container
  1828. )
  1829. if (ul4) {
  1830. updateCandidateTagList(ul4, emojiTags)
  1831. }
  1832. const ul2 = $(
  1833. ".utags_modal_content ul.utags_select_list.utags_most_used",
  1834. container
  1835. )
  1836. if (ul2) {
  1837. updateCandidateTagList(ul2, mostUsedTags)
  1838. }
  1839. const ul3 = $(
  1840. ".utags_modal_content ul.utags_select_list.utags_recent_added",
  1841. container
  1842. )
  1843. if (ul3) {
  1844. updateCandidateTagList(ul3, recentAddedTags)
  1845. }
  1846. }
  1847. function updateCandidateTagList(ul, candidateTags) {
  1848. ul.textContent = ""
  1849. let index = 0
  1850. for (const text of candidateTags) {
  1851. if (displayedTags.has(text)) {
  1852. continue
  1853. }
  1854. displayedTags.add(text)
  1855. const li = addElement2(ul, "li", {})
  1856. addElement2(li, "span", {
  1857. textContent: text,
  1858. })
  1859. index++
  1860. if (index >= 50) {
  1861. break
  1862. }
  1863. }
  1864. }
  1865. function getNextList(parentElement) {
  1866. let parentNext = parentElement.nextElementSibling
  1867. while (parentNext && parentNext.children.length === 0) {
  1868. parentNext = parentNext.nextElementSibling
  1869. }
  1870. return parentNext
  1871. }
  1872. function getPreviousList(parentElement) {
  1873. let parentPrevious = parentElement.previousElementSibling
  1874. while (parentPrevious && parentPrevious.children.length === 0) {
  1875. parentPrevious = parentPrevious.previousElementSibling
  1876. }
  1877. return parentPrevious
  1878. }
  1879. function updateCurrentTagList(ul) {
  1880. ul.textContent = ""
  1881. const sortedTags = sortTags([...currentTags], emojiTags)
  1882. for (const tag of sortedTags) {
  1883. displayedTags.add(tag)
  1884. const li = addElement2(ul, "li")
  1885. const a = createTag(tag, {
  1886. isEmoji: emojiTags.includes(tag),
  1887. noLink: true,
  1888. })
  1889. li.append(a)
  1890. }
  1891. }
  1892. function removeAllActive(type) {
  1893. if (type !== 2) {
  1894. const selector = ".utags_modal_content ul.utags_select_list .utags_active"
  1895. for (const li of $$(selector)) {
  1896. removeClass(li, "utags_active")
  1897. }
  1898. }
  1899. if (type !== 1) {
  1900. const selector =
  1901. ".utags_modal_content ul.utags_select_list .utags_active2"
  1902. for (const li of $$(selector)) {
  1903. removeClass(li, "utags_active2")
  1904. }
  1905. }
  1906. }
  1907. async function copyCurrentTags(input) {
  1908. const value = sortTags([...currentTags], emojiTags).join(", ")
  1909. await copyText(value)
  1910. input.value = value
  1911. input.focus()
  1912. input.select()
  1913. }
  1914. function stopEventPropagation(event) {
  1915. event.preventDefault()
  1916. event.stopPropagation()
  1917. event.stopImmediatePropagation()
  1918. }
  1919. function createPromptView(message, value, resolve) {
  1920. const modal = createModal({ class: "utags_prompt" })
  1921. const content = modal.getContentElement()
  1922. value = value || ""
  1923. addElement2(content, "span", {
  1924. class: "utags_title",
  1925. textContent: message,
  1926. })
  1927. const currentTagsWrapper = addElement2(content, "div", {
  1928. class: "utags_current_tags_wrapper",
  1929. })
  1930. addElement2(currentTagsWrapper, "span", {
  1931. textContent: "",
  1932. style: "display: none;",
  1933. "data-utags": "",
  1934. })
  1935. addElement2(currentTagsWrapper, "ul", {
  1936. class: "utags_current_tags utags_ul",
  1937. })
  1938. const input = addElement2(content, "input", {
  1939. type: "text",
  1940. placeholder: "foo, bar",
  1941. onblur(event) {
  1942. if (event.relatedTarget) {
  1943. input.focus()
  1944. stopEventPropagation(event)
  1945. }
  1946. setTimeout(() => {
  1947. if (doc.activeElement === doc.body) {
  1948. closeModal2()
  1949. }
  1950. }, 1)
  1951. },
  1952. })
  1953. setTimeout(() => {
  1954. input.focus()
  1955. input.select()
  1956. })
  1957. addElement2(currentTagsWrapper, "button", {
  1958. type: "button",
  1959. class: "utags_button_copy",
  1960. textContent: i2("prompt.copy"),
  1961. async onclick() {
  1962. await copyCurrentTags(input)
  1963. },
  1964. })
  1965. const listWrapper = addElement2(content, "div", {
  1966. class: "utags_list_wrapper",
  1967. })
  1968. addElement2(listWrapper, "ul", {
  1969. class: "utags_select_list utags_pined_list",
  1970. "data-utags_list_name": i2("prompt.pinnedTags"),
  1971. })
  1972. addElement2(listWrapper, "ul", {
  1973. class: "utags_select_list utags_most_used",
  1974. "data-utags_list_name": i2("prompt.mostUsedTags"),
  1975. })
  1976. addElement2(listWrapper, "ul", {
  1977. class: "utags_select_list utags_recent_added",
  1978. "data-utags_list_name": i2("prompt.recentAddedTags"),
  1979. })
  1980. addElement2(listWrapper, "ul", {
  1981. class: "utags_select_list utags_emoji_list",
  1982. "data-utags_list_name": i2("prompt.emojiTags"),
  1983. })
  1984. updateLists(content)
  1985. const buttonWrapper = addElement2(content, "div", {
  1986. class: "utags_buttons_wrapper",
  1987. })
  1988. let closed = false
  1989. const closeModal2 = (value2) => {
  1990. if (closed) {
  1991. return
  1992. }
  1993. closed = true
  1994. removeEventListener(input, "keydown", keydonwHandler, true)
  1995. removeEventListener(doc, "keydown", keydonwHandler, true)
  1996. removeEventListener(doc, "mousedown", mousedownHandler, true)
  1997. removeEventListener(doc, "click", clickHandler, true)
  1998. removeEventListener(doc, "mouseover", mouseoverHandler, true)
  1999. setTimeout(() => {
  2000. modal.remove()
  2001. })
  2002. resolve(value2 == null ? null : value2)
  2003. }
  2004. const okHandler = () => {
  2005. closeModal2(Array.from(currentTags).join(","))
  2006. }
  2007. addElement2(buttonWrapper, "button", {
  2008. type: "button",
  2009. textContent: i2("prompt.cancel"),
  2010. onclick() {
  2011. closeModal2()
  2012. },
  2013. })
  2014. addElement2(buttonWrapper, "button", {
  2015. type: "button",
  2016. class: "utags_primary",
  2017. textContent: i2("prompt.ok"),
  2018. onclick() {
  2019. onSelect(input.value.trim(), input)
  2020. okHandler()
  2021. },
  2022. })
  2023. const keydonwHandler = (event) => {
  2024. if (event.defaultPrevented || !$(".utags_modal_content")) {
  2025. return
  2026. }
  2027. let current = $(".utags_modal_content ul.utags_select_list .utags_active")
  2028. switch (event.key) {
  2029. case "Escape": {
  2030. stopEventPropagation(event)
  2031. closeModal2()
  2032. break
  2033. }
  2034. case "Enter": {
  2035. stopEventPropagation(event)
  2036. input.focus()
  2037. if (current) {
  2038. onSelect(current.textContent, input)
  2039. } else if (input.value.trim()) {
  2040. onSelect(input.value.trim(), input)
  2041. } else {
  2042. okHandler()
  2043. }
  2044. break
  2045. }
  2046. case "Tab": {
  2047. stopEventPropagation(event)
  2048. input.focus()
  2049. break
  2050. }
  2051. case "ArrowDown": {
  2052. stopEventPropagation(event)
  2053. input.focus()
  2054. current = $(
  2055. ".utags_modal_content ul.utags_select_list .utags_active,.utags_modal_content ul.utags_select_list .utags_active2"
  2056. )
  2057. if (current) {
  2058. const next = current.nextElementSibling
  2059. if (next) {
  2060. next.scrollIntoView({ block: "end" })
  2061. removeAllActive()
  2062. addClass(next, "utags_active")
  2063. }
  2064. } else {
  2065. const next = $(".utags_modal_content ul.utags_select_list li")
  2066. if (next) {
  2067. next.scrollIntoView({ block: "end" })
  2068. removeAllActive()
  2069. addClass(next, "utags_active")
  2070. }
  2071. }
  2072. break
  2073. }
  2074. case "ArrowUp": {
  2075. stopEventPropagation(event)
  2076. input.focus()
  2077. current = $(
  2078. ".utags_modal_content ul.utags_select_list .utags_active,.utags_modal_content ul.utags_select_list .utags_active2"
  2079. )
  2080. if (current) {
  2081. const previous = current.previousElementSibling
  2082. if (previous) {
  2083. previous.scrollIntoView({ block: "end" })
  2084. removeAllActive()
  2085. addClass(previous, "utags_active")
  2086. }
  2087. }
  2088. break
  2089. }
  2090. case "ArrowLeft": {
  2091. stopEventPropagation(event)
  2092. input.focus()
  2093. current = $(
  2094. ".utags_modal_content ul.utags_select_list .utags_active,.utags_modal_content ul.utags_select_list .utags_active2"
  2095. )
  2096. if (current) {
  2097. const parentElement = current.parentElement
  2098. const index = Array.prototype.indexOf.call(
  2099. parentElement.children,
  2100. current
  2101. )
  2102. const parentPrevious = getPreviousList(parentElement)
  2103. if (parentPrevious) {
  2104. removeAllActive()
  2105. const newIndex = Math.min(
  2106. parentPrevious.children.length - 1,
  2107. index
  2108. )
  2109. const next = parentPrevious.children[newIndex]
  2110. next.scrollIntoView({ block: "end" })
  2111. addClass(next, "utags_active")
  2112. }
  2113. }
  2114. break
  2115. }
  2116. case "ArrowRight": {
  2117. stopEventPropagation(event)
  2118. input.focus()
  2119. current = $(
  2120. ".utags_modal_content ul.utags_select_list .utags_active,.utags_modal_content ul.utags_select_list .utags_active2"
  2121. )
  2122. if (current) {
  2123. const parentElement = current.parentElement
  2124. const index = Array.prototype.indexOf.call(
  2125. parentElement.children,
  2126. current
  2127. )
  2128. const parentNext = getNextList(parentElement)
  2129. if (parentNext) {
  2130. removeAllActive()
  2131. const newIndex = Math.min(parentNext.children.length - 1, index)
  2132. const next = parentNext.children[newIndex]
  2133. next.scrollIntoView({ block: "end" })
  2134. addClass(next, "utags_active")
  2135. }
  2136. }
  2137. break
  2138. }
  2139. default: {
  2140. removeAllActive()
  2141. break
  2142. }
  2143. }
  2144. }
  2145. addEventListener(input, "keydown", keydonwHandler, true)
  2146. addEventListener(doc, "keydown", keydonwHandler, true)
  2147. const mousedownHandler = (event) => {
  2148. if (event.defaultPrevented || !$(".utags_modal_content")) {
  2149. return
  2150. }
  2151. const target = event.target
  2152. if (!target) {
  2153. return
  2154. }
  2155. if (target.closest(".utags_modal_content")) {
  2156. if (target === input) {
  2157. return
  2158. }
  2159. event.preventDefault()
  2160. input.focus()
  2161. } else {
  2162. event.preventDefault()
  2163. input.focus()
  2164. }
  2165. }
  2166. addEventListener(doc, "mousedown", mousedownHandler, true)
  2167. const clickHandler = (event) => {
  2168. if (event.defaultPrevented || !$(".utags_modal_content")) {
  2169. return
  2170. }
  2171. const target = event.target
  2172. if (!target) {
  2173. return
  2174. }
  2175. if (
  2176. !target.closest(".utags_modal_content button") &&
  2177. !target.closest(".utags_modal_content .utags_footer a")
  2178. ) {
  2179. stopEventPropagation(event)
  2180. }
  2181. if (target.closest(".utags_modal_content")) {
  2182. input.focus()
  2183. if (target.closest(".utags_modal_content ul.utags_select_list li")) {
  2184. onSelect(target.textContent, input)
  2185. }
  2186. if (target.closest(".utags_modal_content ul.utags_current_tags li a")) {
  2187. removeTag(target.dataset.utags_tag)
  2188. }
  2189. } else {
  2190. closeModal2()
  2191. }
  2192. }
  2193. addEventListener(doc, "click", clickHandler, true)
  2194. const mouseoverHandler = (event) => {
  2195. const target = event.target
  2196. if (!(target == null ? void 0 : target.closest(".utags_modal_content"))) {
  2197. return
  2198. }
  2199. const li = target.closest("ul.utags_select_list li")
  2200. if (li) {
  2201. removeAllActive()
  2202. addClass(li, "utags_active2")
  2203. } else {
  2204. removeAllActive(2)
  2205. }
  2206. }
  2207. addEventListener(doc, "mousemove", mouseoverHandler, true)
  2208. const footer = addElement2(content, "div", {
  2209. class: "utags_footer",
  2210. })
  2211. addElement2(footer, "a", {
  2212. class: "utags_link_settings",
  2213. textContent: i2("prompt.settings"),
  2214. async onclick() {
  2215. closeModal2()
  2216. setTimeout(showSettings, 1)
  2217. },
  2218. })
  2219. modal.append()
  2220. }
  2221. async function advancedPrompt(message, value) {
  2222. pinnedTags = await getPinnedTags()
  2223. mostUsedTags = await getMostUsedTags()
  2224. recentAddedTags = await getRecentAddedTags()
  2225. emojiTags = await getEmojiTags()
  2226. currentTags = new Set(splitTags(value))
  2227. return new Promise((resolve) => {
  2228. createPromptView(message, value, resolve)
  2229. })
  2230. }
  2231. async function simplePrompt(message, value) {
  2232. return prompt(message, value)
  2233. }
  2234. var prefix2 = location.origin + "/"
  2235. var host = location.host
  2236. var useVisitedFunction = false
  2237. var displayMark = false
  2238. var isAvailable = false
  2239. var cache = {}
  2240. function setPrefix(newPrefix) {
  2241. prefix2 = newPrefix
  2242. }
  2243. function isAvailableOnCurrentSite() {
  2244. return isAvailable
  2245. }
  2246. function setVisitedAvailable(value) {
  2247. isAvailable = value
  2248. }
  2249. function onSettingsChange() {
  2250. useVisitedFunction = getSettingsValue("useVisitedFunction_".concat(host))
  2251. displayMark =
  2252. getSettingsValue("displayEffectOfTheVisitedContent_".concat(host)) !== "0"
  2253. }
  2254. function getVisitedLinks() {
  2255. if (!useVisitedFunction) {
  2256. return []
  2257. }
  2258. return JSON.parse(localStorage.getItem("utags_visited") || "[]") || []
  2259. }
  2260. function saveVisitedLinks(newVisitedLinks) {
  2261. if (useVisitedFunction) {
  2262. localStorage.setItem("utags_visited", JSON.stringify(newVisitedLinks))
  2263. }
  2264. }
  2265. function convertKey(url) {
  2266. if (url.includes(prefix2)) {
  2267. return url.slice(prefix2.length)
  2268. }
  2269. return url
  2270. }
  2271. var TAG_VISITED = ":visited"
  2272. function addVisited(key) {
  2273. if (key && !cache[key]) {
  2274. cache[key] = 1
  2275. } else {
  2276. return
  2277. }
  2278. key = convertKey(key)
  2279. const visitedLinks = getVisitedLinks()
  2280. if (!visitedLinks.includes(key)) {
  2281. visitedLinks.push(key)
  2282. saveVisitedLinks(visitedLinks)
  2283. }
  2284. }
  2285. function removeVisited(key) {
  2286. key = convertKey(key)
  2287. const visitedLinks = getVisitedLinks()
  2288. if (visitedLinks.includes(key)) {
  2289. const newVisitedLinks = visitedLinks.filter((value) => {
  2290. return value !== key
  2291. })
  2292. saveVisitedLinks(newVisitedLinks)
  2293. }
  2294. }
  2295. function isVisited(key) {
  2296. if (!displayMark) {
  2297. return false
  2298. }
  2299. key = convertKey(key)
  2300. const visitedLinks = getVisitedLinks()
  2301. return visitedLinks.includes(key)
  2302. }
  2303. function markElementWhetherVisited(key, element) {
  2304. if (isVisited(key)) {
  2305. element.dataset.utags_visited = "1"
  2306. } else if (element.dataset.utags_visited === "1") {
  2307. delete element.dataset.utags_visited
  2308. }
  2309. }
  2310. var numberLimitOfShowAllUtagsInArea = 10
  2311. var lastShownArea
  2312. var isPromptShown = false
  2313. function hideAllUtagsInArea(target) {
  2314. const element = $(".utags_show_all")
  2315. if (!element) {
  2316. return
  2317. }
  2318. if (element === target || element.contains(target)) {
  2319. return
  2320. }
  2321. if (!target) {
  2322. lastShownArea = void 0
  2323. }
  2324. for (const element2 of $$(".utags_show_all")) {
  2325. addClass(element2, "utags_hide_all")
  2326. removeClass(element2, "utags_show_all")
  2327. setTimeout(() => {
  2328. removeClass(element2, "utags_hide_all")
  2329. })
  2330. }
  2331. }
  2332. function showAllUtagsInArea(element) {
  2333. if (!element) {
  2334. return false
  2335. }
  2336. const utags = $$(".utags_ul", element)
  2337. if (utags.length > 0 && utags.length <= numberLimitOfShowAllUtagsInArea) {
  2338. addClass(element, "utags_show_all")
  2339. return true
  2340. }
  2341. return false
  2342. }
  2343. function findElementToShowAllUtags(target) {
  2344. hideAllUtagsInArea(target)
  2345. if (!target) {
  2346. return
  2347. }
  2348. const targets = []
  2349. let width
  2350. let height
  2351. do {
  2352. targets.push(target)
  2353. const tagName = target.tagName
  2354. const style = getComputedStyle(target)
  2355. if (
  2356. style.position === "fixed" ||
  2357. style.position === "sticky" ||
  2358. /^(BODY|TABLE|UL|OL|NAV|ARTICLE|SECTION|ASIDE)$/.test(tagName)
  2359. ) {
  2360. break
  2361. }
  2362. target = target.parentElement
  2363. if (target) {
  2364. width = target.offsetWidth || target.clientWidth
  2365. height = target.offsetHeight || target.clientHeight
  2366. } else {
  2367. width = 0
  2368. height = 0
  2369. }
  2370. } while (targets.length < 8 && target && width > 20 && height > 10)
  2371. while (targets.length > 0) {
  2372. const area = targets.pop()
  2373. if (showAllUtagsInArea(area)) {
  2374. if (lastShownArea === area) {
  2375. hideAllUtagsInArea()
  2376. return
  2377. }
  2378. lastShownArea = area
  2379. return
  2380. }
  2381. }
  2382. hideAllUtagsInArea()
  2383. lastShownArea = void 0
  2384. }
  2385. function bindDocumentEvents() {
  2386. const eventType = isTouchScreen() ? "touchstart" : "click"
  2387. addEventListener(
  2388. doc,
  2389. eventType,
  2390. (event) => {
  2391. const target = event.target
  2392. if (!target) {
  2393. return
  2394. }
  2395. if (target.closest(".utags_prompt")) {
  2396. return
  2397. }
  2398. if (target.closest(".utags_ul")) {
  2399. const captainTag = target.closest(
  2400. ".utags_captain_tag,.utags_captain_tag2"
  2401. )
  2402. const textTag = target.closest(".utags_text_tag")
  2403. if (captainTag) {
  2404. event.preventDefault()
  2405. event.stopPropagation()
  2406. event.stopImmediatePropagation()
  2407. if (!captainTag.dataset.utags_key || isPromptShown) {
  2408. return
  2409. }
  2410. isPromptShown = true
  2411. setTimeout(async () => {
  2412. const key = captainTag.dataset.utags_key
  2413. const tags = captainTag.dataset.utags_tags || ""
  2414. const meta = captainTag.dataset.utags_meta
  2415. ? JSON.parse(captainTag.dataset.utags_meta)
  2416. : void 0
  2417. const myPrompt = getSettingsValue("useSimplePrompt")
  2418. ? simplePrompt
  2419. : advancedPrompt
  2420. const newTags = await myPrompt(i2("prompt.addTags"), tags)
  2421. isPromptShown = false
  2422. captainTag.focus()
  2423. if (key && newTags != void 0) {
  2424. const emojiTags3 = await getEmojiTags()
  2425. const newTagsArray = sortTags(
  2426. filterTags(splitTags(newTags), TAG_VISITED),
  2427. emojiTags3
  2428. )
  2429. if (
  2430. tags.includes(TAG_VISITED) &&
  2431. !newTags.includes(TAG_VISITED)
  2432. ) {
  2433. removeVisited(key)
  2434. } else if (
  2435. !tags.includes(TAG_VISITED) &&
  2436. newTags.includes(TAG_VISITED)
  2437. ) {
  2438. addVisited(key)
  2439. }
  2440. await saveTags(key, newTagsArray, meta)
  2441. }
  2442. })
  2443. } else if (textTag) {
  2444. event.stopPropagation()
  2445. event.stopImmediatePropagation()
  2446. }
  2447. return
  2448. }
  2449. setTimeout(() => {
  2450. findElementToShowAllUtags(target)
  2451. }, 100)
  2452. },
  2453. true
  2454. )
  2455. addEventListener(
  2456. doc,
  2457. "keydown",
  2458. (event) => {
  2459. if (event.defaultPrevented) {
  2460. return
  2461. }
  2462. if (event.key === "Escape" && $(".utags_show_all")) {
  2463. hideAllUtagsInArea()
  2464. event.preventDefault()
  2465. }
  2466. },
  2467. true
  2468. )
  2469. addEventListener(
  2470. doc,
  2471. "mousedown",
  2472. (event) => {
  2473. const target = event.target
  2474. if (target == null ? void 0 : target.closest(".utags_ul")) {
  2475. event.preventDefault()
  2476. event.stopPropagation()
  2477. event.stopImmediatePropagation()
  2478. }
  2479. },
  2480. true
  2481. )
  2482. addEventListener(
  2483. doc,
  2484. "mouseup",
  2485. (event) => {
  2486. const target = event.target
  2487. if (target == null ? void 0 : target.closest(".utags_ul")) {
  2488. event.preventDefault()
  2489. event.stopPropagation()
  2490. event.stopImmediatePropagation()
  2491. }
  2492. },
  2493. true
  2494. )
  2495. }
  2496. function extendHistoryApi2() {
  2497. let url = location.href
  2498. setInterval(() => {
  2499. const url2 = location.href
  2500. if (url !== url2) {
  2501. url = url2
  2502. window.dispatchEvent(new Event("locationchange"))
  2503. }
  2504. }, 100)
  2505. }
  2506. function bindWindowEvents() {
  2507. extendHistoryApi()
  2508. extendHistoryApi2()
  2509. addEventListener(window, "locationchange", function () {
  2510. hideAllUtagsInArea()
  2511. })
  2512. }
  2513. var default_default =
  2514. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:100% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}"
  2515. var default_default2 = (() => {
  2516. return {
  2517. matches: /.*/,
  2518. matchedNodesSelectors: ["a[href]:not(.utags_text_tag)"],
  2519. validate(element) {
  2520. return true
  2521. },
  2522. excludeSelectors: [],
  2523. getCanonicalUrl: (url) =>
  2524. deleteUrlParameters(url, ["utm_campaign", "utm_source", "utm_medium"]),
  2525. getStyle: () => default_default,
  2526. }
  2527. })()
  2528. var v2ex_default =
  2529. ':not(#a):not(#b):not(#c) .header h1+.utags_ul_0{object-position:0% 200%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: 10px;--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5)}:not(#a):not(#b):not(#c) .header h1+.utags_ul_0+.votes{margin-left:24px}:not(#a):not(#b):not(#c) .title .node-breadcrumb[data-utags_fit_content="1"]{display:inline-block !important;max-width:fit-content !important}:not(#a):not(#b):not(#c) .title .node-breadcrumb+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: 2px;--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .title .node-breadcrumb+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px}:not(#a):not(#b):not(#c) .box .header>span[data-utags_flag=tag_page]+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: 2px;--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .box .header>span[data-utags_flag=tag_page]+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px}'
  2530. var v2ex_default2 = (() => {
  2531. function getCanonicalUrl2(url) {
  2532. if (url.startsWith("https://links.pipecraft")) {
  2533. url = url.replace("https://links.pipecraft.net/", "https://")
  2534. }
  2535. if (url.includes("v2ex.com")) {
  2536. return url
  2537. .replace(/[?#].*/, "")
  2538. .replace(/(\w+\.)?v2ex.com/, "www.v2ex.com")
  2539. }
  2540. if (url.includes("v2ex.co")) {
  2541. return url
  2542. .replace(/[?#].*/, "")
  2543. .replace(/(\w+\.)?v2ex.co/, "www.v2ex.com")
  2544. }
  2545. return url
  2546. }
  2547. function cloneWithoutCitedReplies(element) {
  2548. const newElement = element.cloneNode(true)
  2549. for (const cell of $$(".cell", newElement)) {
  2550. cell.remove()
  2551. }
  2552. return newElement
  2553. }
  2554. return {
  2555. matches: /v2ex\.com|v2hot\.|v2ex\.co/,
  2556. preProcess() {
  2557. setVisitedAvailable(true)
  2558. setPrefix("https://www.v2ex.com/")
  2559. },
  2560. listNodesSelectors: [".box .cell", ".my-box .comment"],
  2561. conditionNodesSelectors: [
  2562. ".box .cell .topic-link",
  2563. ".item_hot_topic_title a",
  2564. '.box .cell .topic_info strong:first-of-type a[href*="/member/"]',
  2565. ".box .cell .topic_info .node",
  2566. '.box .cell strong a.dark[href*="/member/"]',
  2567. ".box .cell .ago a",
  2568. ".box .cell .fade.small a",
  2569. ".comment .username",
  2570. ".comment .ago",
  2571. ],
  2572. matchedNodesSelectors: [
  2573. 'a[href*="/t/"]',
  2574. 'a[href*="/member/"]',
  2575. 'a[href*="/go/"]',
  2576. 'a[href^="https://"]:not([href*="v2ex.com"])',
  2577. 'a[href^="http://"]:not([href*="v2ex.com"])',
  2578. ".box .cell .fr .tag",
  2579. ".box .inner .tag",
  2580. ],
  2581. excludeSelectors: [
  2582. ...default_default2.excludeSelectors,
  2583. ".site-nav a",
  2584. ".cell_tabs a",
  2585. ".tab-alt-container a",
  2586. "#SecondaryTabs a",
  2587. "a.page_normal,a.page_current",
  2588. "a.count_livid",
  2589. ".post-item a.post-content",
  2590. ],
  2591. addExtraMatchedNodes(matchedNodesSet) {
  2592. if (location.pathname.includes("/member/")) {
  2593. const profile = $(".content h1")
  2594. if (profile) {
  2595. const username = profile.textContent
  2596. if (username) {
  2597. const key = "https://www.v2ex.com/member/".concat(username)
  2598. const meta = { title: username, type: "user" }
  2599. profile.utags = { key, meta }
  2600. matchedNodesSet.add(profile)
  2601. }
  2602. }
  2603. }
  2604. if (location.pathname.includes("/t/")) {
  2605. const header = $(".header h1")
  2606. if (header) {
  2607. const key = getCanonicalUrl2(
  2608. "https://www.v2ex.com" + location.pathname
  2609. )
  2610. const title = $("h1").textContent
  2611. const meta = { title, type: "topic" }
  2612. header.utags = { key, meta }
  2613. matchedNodesSet.add(header)
  2614. addVisited(key)
  2615. markElementWhetherVisited(key, header)
  2616. }
  2617. const main2 = $("#Main") || $(".content")
  2618. const replyElements = $$(
  2619. '.box .cell[id^="r_"],.box .cell[id^="related_r_"]',
  2620. main2
  2621. )
  2622. for (const reply of replyElements) {
  2623. const replyId = reply.id.replace("related_", "")
  2624. const floorNoElement = $(".no", reply)
  2625. const replyContentElement = $(".reply_content", reply)
  2626. const agoElement = $(".ago,.fade.small", reply)
  2627. if (
  2628. replyId &&
  2629. floorNoElement &&
  2630. replyContentElement &&
  2631. agoElement
  2632. ) {
  2633. let newAgoElement = $("a", agoElement)
  2634. if (!newAgoElement) {
  2635. newAgoElement = createElement("a", {
  2636. textContent: agoElement.textContent,
  2637. href: "#" + replyId,
  2638. })
  2639. agoElement.textContent = ""
  2640. agoElement.append(newAgoElement)
  2641. }
  2642. const floorNo = parseInt10(floorNoElement.textContent, 1)
  2643. const pageNo = Math.floor((floorNo - 1) / 100) + 1
  2644. const key =
  2645. getCanonicalUrl2("https://www.v2ex.com" + location.pathname) +
  2646. "?p=" +
  2647. String(pageNo) +
  2648. "#" +
  2649. replyId
  2650. const title =
  2651. cloneWithoutCitedReplies(replyContentElement).textContent
  2652. const meta = { title, type: "reply" }
  2653. newAgoElement.utags = { key, meta }
  2654. matchedNodesSet.add(newAgoElement)
  2655. }
  2656. }
  2657. }
  2658. if (location.pathname.includes("/go/")) {
  2659. const header = $(".title .node-breadcrumb")
  2660. if (header) {
  2661. const key = getCanonicalUrl2(
  2662. "https://www.v2ex.com" + location.pathname
  2663. )
  2664. const title = header.textContent.replaceAll(/\s+/g, " ").trim()
  2665. const meta = { title, type: "node" }
  2666. header.utags = { key, meta }
  2667. matchedNodesSet.add(header)
  2668. }
  2669. }
  2670. if (location.pathname.includes("/tag/")) {
  2671. const header = $(".box .header > span")
  2672. if (header) {
  2673. const key = getCanonicalUrl2(
  2674. "https://www.v2ex.com" + location.pathname
  2675. )
  2676. const title = header.textContent.replaceAll(/\s+/g, " ").trim()
  2677. const meta = { title, type: "tag" }
  2678. header.utags = { key, meta }
  2679. header.dataset.utags_flag = "tag_page"
  2680. matchedNodesSet.add(header)
  2681. }
  2682. }
  2683. },
  2684. getStyle: () => v2ex_default,
  2685. getCanonicalUrl: getCanonicalUrl2,
  2686. postProcess() {
  2687. for (const element of $$('a[href*="/t/"]')) {
  2688. const key = getCanonicalUrl2(element.href)
  2689. markElementWhetherVisited(key, element)
  2690. }
  2691. },
  2692. }
  2693. })()
  2694. var greasyfork_org_default =
  2695. ":not(#a):not(#b):not(#c) .discussion-title+.utags_ul_0{display:block !important;height:0}:not(#a):not(#b):not(#c) .discussion-title+.utags_ul_0 .utags_captain_tag{top:-26px;background-color:rgba(255,255,255,.8666666667) !important}:not(#a):not(#b):not(#c) .discussion-title+.utags_ul_1{display:block !important;margin-top:-12px !important;margin-bottom:8px !important}:not(#a):not(#b):not(#c) .discussion-meta .script-link+.utags_ul_0{display:block !important;height:0}:not(#a):not(#b):not(#c) .discussion-meta .script-link+.utags_ul_0 .utags_captain_tag{top:-22px;background-color:rgba(255,255,255,.8666666667) !important}"
  2696. var greasyfork_org_default2 = (() => {
  2697. function getScriptUrl(url) {
  2698. return getCanonicalUrl2(url.replace(/(scripts\/\d+)(.*)/, "$1"))
  2699. }
  2700. function getCanonicalUrl2(url) {
  2701. if (/(greasyfork|sleazyfork)\.org/.test(url)) {
  2702. url = url.replace(
  2703. /((greasyfork|sleazyfork)\.org\/)(\w{2}(-\w{2})?)(\/|$)/,
  2704. "$1"
  2705. )
  2706. if (url.includes("/scripts/")) {
  2707. return url.replace(/(scripts\/\d+)([^/]*)/, "$1")
  2708. }
  2709. if (url.includes("/users/")) {
  2710. return url.replace(/(users\/\d+)(.*)/, "$1")
  2711. }
  2712. }
  2713. return url
  2714. }
  2715. return {
  2716. matches: /(greasyfork|sleazyfork)\.org/,
  2717. listNodesSelectors: [".script-list > li", ".discussion-list-container"],
  2718. conditionNodesSelectors: [
  2719. ".script-list li .script-link",
  2720. ".script-list li .script-list-author a",
  2721. ".discussion-list-container .script-link",
  2722. ".discussion-list-container .discussion-title",
  2723. ".discussion-list-container .discussion-meta-item:nth-child(2) > a",
  2724. ],
  2725. excludeSelectors: [
  2726. ...default_default2.excludeSelectors,
  2727. ".sidebar",
  2728. ".pagination",
  2729. ".sign-out-link,.sign-in-link",
  2730. ".with-submenu",
  2731. "#script-links.tabs",
  2732. "#install-area",
  2733. ".history_versions .version-number",
  2734. 'a[href*="show_all_versions"]',
  2735. 'a[href*="/reports/new"]',
  2736. 'a[href*="/conversations/new"]',
  2737. 'a[href*="/discussions/mark_all_read"]',
  2738. 'a[href*="/discussions/new"]',
  2739. "div.sidebarred-main-content > p:nth-child(3) > a",
  2740. ],
  2741. addExtraMatchedNodes(matchedNodesSet) {
  2742. if (location.pathname.includes("/scripts/")) {
  2743. const element = $("#script-info header h2")
  2744. if (element) {
  2745. const title = element.textContent
  2746. if (title) {
  2747. const key = getScriptUrl(location.href)
  2748. const meta = { title }
  2749. element.utags = { key, meta }
  2750. matchedNodesSet.add(element)
  2751. }
  2752. }
  2753. } else if (location.pathname.includes("/users/")) {
  2754. const element = $("#about-user h2")
  2755. if (element) {
  2756. const title = element.textContent
  2757. if (title) {
  2758. const key = getCanonicalUrl2(location.href)
  2759. const meta = { title }
  2760. element.utags = { key, meta }
  2761. matchedNodesSet.add(element)
  2762. }
  2763. }
  2764. }
  2765. },
  2766. getCanonicalUrl: getCanonicalUrl2,
  2767. getStyle: () => greasyfork_org_default,
  2768. }
  2769. })()
  2770. var news_ycombinator_com_default = (() => {
  2771. function cloneComment(element) {
  2772. const newElement = element.cloneNode(true)
  2773. for (const node of $$(".reply", newElement)) {
  2774. node.remove()
  2775. }
  2776. return newElement
  2777. }
  2778. return {
  2779. matches: /news\.ycombinator\.com/,
  2780. listNodesSelectors: [".script-list li", ".discussion-list-container"],
  2781. conditionNodesSelectors: [],
  2782. excludeSelectors: [
  2783. ...default_default2.excludeSelectors,
  2784. ".pagetop",
  2785. ".morelink",
  2786. ".hnpast",
  2787. ".clicky",
  2788. ".navs > a",
  2789. 'a[href^="login"]',
  2790. 'a[href^="logout"]',
  2791. 'a[href^="forgot"]',
  2792. 'a[href^="vote"]',
  2793. 'a[href^="submit"]',
  2794. 'a[href^="hide"]',
  2795. 'a[href^="fave"]',
  2796. 'a[href^="reply"]',
  2797. 'a[href^="context"]',
  2798. 'a[href^="newcomments"]',
  2799. 'a[href^="#"]',
  2800. '.subline > a[href^="item"]',
  2801. ],
  2802. addExtraMatchedNodes(matchedNodesSet) {
  2803. if (location.pathname === "/item") {
  2804. const comments = $$(".comment-tree .comtr[id]")
  2805. for (const comment of comments) {
  2806. const commentText = $(".commtext", comment)
  2807. const target = $(".age a", comment)
  2808. if (commentText && target) {
  2809. const key = target.href
  2810. const title = cloneComment(commentText).textContent
  2811. if (key && title) {
  2812. const meta = { title, type: "comment" }
  2813. target.utags = { key, meta }
  2814. matchedNodesSet.add(target)
  2815. }
  2816. }
  2817. }
  2818. const fatitem = $(".fatitem")
  2819. if (fatitem) {
  2820. const titleElement = $(".titleline a", fatitem)
  2821. const commentText = titleElement || $(".commtext", fatitem)
  2822. const type = titleElement ? "topic" : "comment"
  2823. const target = $(".age a", fatitem)
  2824. if (commentText && target) {
  2825. const key = target.href
  2826. const title = cloneComment(commentText).textContent
  2827. if (key && title) {
  2828. const meta = { title, type }
  2829. target.utags = { key, meta }
  2830. matchedNodesSet.add(target)
  2831. }
  2832. }
  2833. }
  2834. } else if (location.pathname === "/newcomments") {
  2835. const comments = $$(".athing[id]")
  2836. for (const comment of comments) {
  2837. const commentText = $(".commtext", comment)
  2838. const target = $(".age a", comment)
  2839. if (commentText && target) {
  2840. const key = target.href
  2841. const title = cloneComment(commentText).textContent
  2842. if (key && title) {
  2843. const meta = { title, type: "comment" }
  2844. target.utags = { key, meta }
  2845. matchedNodesSet.add(target)
  2846. }
  2847. }
  2848. }
  2849. } else {
  2850. const topics = $$(".athing[id]")
  2851. for (const topic of topics) {
  2852. const titleElement = $(".titleline a", topic)
  2853. const subtext = topic.nextElementSibling
  2854. if (subtext) {
  2855. const target = $(".age a", subtext)
  2856. if (titleElement && target) {
  2857. const key = target.href
  2858. const title = titleElement.textContent
  2859. if (key && title) {
  2860. const meta = { title, type: "topic" }
  2861. target.utags = { key, meta }
  2862. matchedNodesSet.add(target)
  2863. }
  2864. }
  2865. }
  2866. }
  2867. }
  2868. },
  2869. }
  2870. })()
  2871. var lobste_rs_default = (() => {
  2872. return {
  2873. matches:
  2874. /lobste\.rs|dto\.pipecraft\.net|tilde\.news|journalduhacker\.net/,
  2875. listNodesSelectors: [],
  2876. conditionNodesSelectors: [],
  2877. excludeSelectors: [
  2878. ...default_default2.excludeSelectors,
  2879. "#nav",
  2880. "#header",
  2881. "#subnav",
  2882. ".mobile_comments",
  2883. ".description_present",
  2884. ".morelink",
  2885. ".user_tree",
  2886. ".dropdown_parent",
  2887. 'a[href^="/login"]',
  2888. 'a[href^="/logout"]',
  2889. 'a[href^="/u#"]',
  2890. 'a[href$="/save"]',
  2891. 'a[href$="/hide"]',
  2892. 'a[href$="/suggest"]',
  2893. ],
  2894. }
  2895. })()
  2896. var github_com_default =
  2897. ':not(#a):not(#b):not(#c) .search-title .utags_ul_0,:not(#a):not(#b):not(#c) .d-flex.flex-justify-between a[href^="/topics/"]+.utags_ul_0,:not(#a):not(#b):not(#c) .d-md-flex.flex-justify-between a[href^="/topics/"].d-flex+.utags_ul_0,:not(#a):not(#b):not(#c) [id=user-starred-repos] a[href^="/topics/"].flex-items-center+.utags_ul_0,:not(#a):not(#b):not(#c) ul.f4 a[href^="/topics/"].d-flex+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-4);--utags-notag-ul-height: var(--utags-notag-ul-height-4);--utags-notag-ul-position: var(--utags-notag-ul-position-4);--utags-notag-ul-top: var(--utags-notag-ul-top-4);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-4);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-4);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .search-title .utags_ul_0{--utags-notag-captain-tag-top: -10px}:not(#a):not(#b):not(#c) .d-flex.flex-justify-between a[href^="/topics/"]+.utags_ul_0{--utags-notag-captain-tag-top: 6px;--utags-notag-captain-tag-left: 76px}:not(#a):not(#b):not(#c) .d-md-flex.flex-justify-between a[href^="/topics/"].d-flex+.utags_ul_0{--utags-notag-captain-tag-top: 20px;--utags-notag-captain-tag-left: 76px}:not(#a):not(#b):not(#c) ul.f4 a[href^="/topics/"].d-flex+.utags_ul_0{--utags-notag-captain-tag-top: -24px;--utags-notag-captain-tag-left: -2px}:not(#a):not(#b):not(#c) div[id=repo-title-component] strong[itemprop=name] a+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-4);--utags-notag-ul-height: var(--utags-notag-ul-height-4);--utags-notag-ul-position: var(--utags-notag-ul-position-4);--utags-notag-ul-top: var(--utags-notag-ul-top-4);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-4);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-4)}'
  2898. var github_com_default2 = (() => {
  2899. const noneUsers = /* @__PURE__ */ new Set([
  2900. "about",
  2901. "pricing",
  2902. "security",
  2903. "login",
  2904. "logout",
  2905. "signup",
  2906. "explore",
  2907. "topics",
  2908. "trending",
  2909. "collections",
  2910. "events",
  2911. "sponsors",
  2912. "features",
  2913. "enterprise",
  2914. "team",
  2915. "customer-stories",
  2916. "readme",
  2917. "premium-support",
  2918. "sitemap",
  2919. "git-guides",
  2920. "open-source",
  2921. "marketplace",
  2922. "codespaces",
  2923. "issues",
  2924. "pulls",
  2925. "discussions",
  2926. "dashboard",
  2927. "account",
  2928. "new",
  2929. "notifications",
  2930. "settings",
  2931. "feedback",
  2932. "organizations",
  2933. "github-copilot",
  2934. "search",
  2935. ])
  2936. const prefix3 = "https://github.com/"
  2937. function getUserProfileUrl(href) {
  2938. if (href.startsWith(prefix3)) {
  2939. const href2 = href.slice(19)
  2940. let username = ""
  2941. if (/^[\w-]+$/.test(href2)) {
  2942. username = /^([\w-]+)$/.exec(href2)[1]
  2943. }
  2944. if (/(author%3A|author=)[\w-]+/.test(href2)) {
  2945. username = /(author%3A|author=)([\w-]+)/.exec(href2)[2]
  2946. }
  2947. if (username && !noneUsers.has(username)) {
  2948. return prefix3 + username
  2949. }
  2950. }
  2951. return void 0
  2952. }
  2953. function getRepoUrl(href) {
  2954. if (href.startsWith(prefix3)) {
  2955. const href2 = href.slice(19)
  2956. if (/^[\w-]+\/[\w-.]+(\?.*)?$/.test(href2)) {
  2957. const username = /^([\w-]+)/.exec(href2)[1]
  2958. if (username && !noneUsers.has(username)) {
  2959. return prefix3 + href2.replace(/(^[\w-]+\/[\w-.]+).*/, "$1")
  2960. }
  2961. }
  2962. }
  2963. return void 0
  2964. }
  2965. function getTopicsUrl(href) {
  2966. if (href.startsWith(prefix3)) {
  2967. const href2 = href.slice(19)
  2968. if (/^topics\/[\w-.]+(\?.*)?$/.test(href2)) {
  2969. return prefix3 + href2.replace(/(^topics\/[\w-.]+).*/, "$1")
  2970. }
  2971. }
  2972. return void 0
  2973. }
  2974. function getIssuesUrl(href) {
  2975. if (href.startsWith(prefix3)) {
  2976. const href2 = href.slice(19)
  2977. if (
  2978. /^[\w-]+\/[\w-.]+\/(issues|pull|discussions)\/\d+(\?.*)?$/.test(href2)
  2979. ) {
  2980. const username = /^([\w-]+)/.exec(href2)[1]
  2981. if (username && !noneUsers.has(username)) {
  2982. return (
  2983. prefix3 +
  2984. href2.replace(
  2985. /(^[\w-]+\/[\w-.]+\/(issues|pull|discussions)\/\d+).*/,
  2986. "$1"
  2987. )
  2988. )
  2989. }
  2990. }
  2991. }
  2992. return void 0
  2993. }
  2994. return {
  2995. matches: /github\.com/,
  2996. listNodesSelectors: [],
  2997. conditionNodesSelectors: [],
  2998. validate(element) {
  2999. const href = element.href
  3000. if (href.startsWith(prefix3)) {
  3001. if (/since|until/.test(href)) {
  3002. return false
  3003. }
  3004. let key = getUserProfileUrl(href)
  3005. if (key) {
  3006. const username = /^https:\/\/github\.com\/([\w-]+)$/.exec(key)[1]
  3007. const title = username
  3008. const meta = { title, type: "user" }
  3009. element.utags = { key, meta }
  3010. return true
  3011. }
  3012. key = getRepoUrl(href)
  3013. if (key) {
  3014. const title = key.replace(prefix3, "")
  3015. const meta = { title, type: "repo" }
  3016. element.utags = { key, meta }
  3017. return true
  3018. }
  3019. key = getTopicsUrl(href)
  3020. if (key) {
  3021. const text = element.textContent.trim()
  3022. if (text === "#") {
  3023. return false
  3024. }
  3025. const title = "#" + key.replace(prefix3 + "topics/", "")
  3026. const meta = { title, type: "topic" }
  3027. element.utags = { key, meta }
  3028. return true
  3029. }
  3030. key = getIssuesUrl(href)
  3031. if (key) {
  3032. const meta = { type: "issue" }
  3033. element.utags = { key, meta }
  3034. return true
  3035. }
  3036. return false
  3037. }
  3038. return true
  3039. },
  3040. excludeSelectors: [
  3041. ...default_default2.excludeSelectors,
  3042. 'section[aria-label~="User"] .Link--secondary',
  3043. ".Popover-message .Link--secondary",
  3044. ".IssueLabel",
  3045. ".subnav-links",
  3046. ".btn",
  3047. ".filter-item",
  3048. ".js-github-dev-shortcut",
  3049. ".js-github-dev-new-tab-shortcut",
  3050. ".js-skip-to-content",
  3051. ],
  3052. validMediaSelectors: ["svg.octicon-repo"],
  3053. getStyle: () => github_com_default,
  3054. }
  3055. })()
  3056. var reddit_com_default =
  3057. '\uFEFF#TOFIX_uFEFF{display:block}:not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) shreddit-comment [slot=commentMeta]{position:relative}:not(#a):not(#b):not(#c) [data-testid=user-hover-card]{position:relative}:not(#a):not(#b):not(#c) div[slot=content]{position:relative}:not(#a):not(#b):not(#c) div[slot=comment]{position:relative}:not(#a):not(#b):not(#c) article:hover a[slot=title]+.utags_ul .utags_captain_tag,:not(#a):not(#b):not(#c) [slot=post-media-container]:hover a+.utags_ul .utags_captain_tag{opacity:100%;width:calc(var(--utags-captain-tag-size) + 8px) !important;height:calc(var(--utags-captain-tag-size) + 8px) !important;padding:5px 4px 4px 5px !important;transition:all 0s .1s !important;z-index:0}:not(#a):not(#b):not(#c) article a[slot=title][data-utags_fit_content="1"],:not(#a):not(#b):not(#c) recent-posts a[data-utags_fit_content="1"]{min-width:unset !important;width:fit-content !important}:not(#a):not(#b):not(#c) article a[slot=title][data-utags_fit_content="1"] *:not(svg),:not(#a):not(#b):not(#c) recent-posts a[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) article a[slot=title]+.utags_ul_0,:not(#a):not(#b):not(#c) recent-posts a+.utags_ul_0{object-position:100% 50%}:not(#a):not(#b):not(#c) article a[slot=title]+.utags_ul_1,:not(#a):not(#b):not(#c) recent-posts a+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:-4px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) h1[slot=title][data-utags_fit_content="1"]{min-width:unset !important;width:fit-content !important}:not(#a):not(#b):not(#c) h1[slot=title][data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) h1[slot=title]+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) h1[slot=title]+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) [data-utags_list_node*=",hide,"],:not(#a):not(#b):not(#c) [data-utags_list_node*=",\u9690\u85CF,"],:not(#a):not(#b):not(#c) [data-utags_list_node*=",\u5C4F\u853D,"],:not(#a):not(#b):not(#c) [data-utags_list_node*=",\u4E0D\u518D\u663E\u793A,"],:not(#a):not(#b):not(#c) [data-utags_list_node*=",block,"]{opacity:1%;display:block !important}'
  3058. var reddit_com_default2 = (() => {
  3059. const prefix3 = "https://www.reddit.com/"
  3060. function getCanonicalUrl2(url) {
  3061. if (url.startsWith(prefix3)) {
  3062. let href2 = getUserProfileUrl(url, true)
  3063. if (href2) {
  3064. return href2
  3065. }
  3066. href2 = getCommunityUrl(url, true)
  3067. if (href2) {
  3068. return href2
  3069. }
  3070. href2 = getCommentsUrl(url, true)
  3071. if (href2) {
  3072. return href2
  3073. }
  3074. }
  3075. return url
  3076. }
  3077. function getUserProfileUrl(url, exact = false) {
  3078. if (url.startsWith(prefix3)) {
  3079. const href2 = url.slice(prefix3.length)
  3080. if (exact) {
  3081. if (/^(user|u)\/[\w-]+\/?([?#].*)?$/.test(href2)) {
  3082. return (
  3083. prefix3 +
  3084. "user/" +
  3085. href2.replace(/^(user|u)\/([\w-]+).*/, "$2") +
  3086. "/"
  3087. )
  3088. }
  3089. } else if (/^(user|u)\/[\w-]+/.test(href2)) {
  3090. return (
  3091. prefix3 +
  3092. "user/" +
  3093. href2.replace(/^(user|u)\/([\w-]+).*/, "$2") +
  3094. "/"
  3095. )
  3096. }
  3097. }
  3098. return void 0
  3099. }
  3100. function getCommunityUrl(url, exact = false) {
  3101. if (url.startsWith(prefix3)) {
  3102. const href2 = url.slice(prefix3.length)
  3103. if (exact) {
  3104. if (/^r\/\w+\/?(#.*)?$/.test(href2)) {
  3105. return prefix3 + href2.replace(/^(r\/\w+).*/, "$1") + "/"
  3106. }
  3107. } else if (/^r\/\w+/.test(href2)) {
  3108. return prefix3 + href2.replace(/^(r\/\w+).*/, "$1") + "/"
  3109. }
  3110. }
  3111. return void 0
  3112. }
  3113. function getCommentsUrl(url, exact = false) {
  3114. if (url.startsWith(prefix3)) {
  3115. const href2 = url.slice(prefix3.length)
  3116. if (exact) {
  3117. if (/^(r\/\w+\/comments\/\w+(\/([^/]*\/?)?)?)$/.test(href2)) {
  3118. return (
  3119. prefix3 +
  3120. href2.replace(/^(r\/\w+\/comments\/\w+(\/([^/]*)?)?).*/, "$1") +
  3121. "/"
  3122. )
  3123. }
  3124. } else if (/^(r\/\w+\/comments\/\w+(\/([^/]*)?)?).*/.test(href2)) {
  3125. return (
  3126. prefix3 +
  3127. href2.replace(/^(r\/\w+\/comments\/\w+(\/([^/]*)?)?).*/, "$1") +
  3128. "/"
  3129. )
  3130. }
  3131. }
  3132. return void 0
  3133. }
  3134. return {
  3135. matches: /reddit\.com/,
  3136. listNodesSelectors: [
  3137. "shreddit-feed article",
  3138. "shreddit-feed shreddit-ad-post",
  3139. "shreddit-comment",
  3140. ],
  3141. conditionNodesSelectors: [
  3142. 'shreddit-feed article a[data-testid="subreddit-name"]',
  3143. 'shreddit-feed article a[slot="title"]',
  3144. 'shreddit-feed article [slot="authorName"] a',
  3145. "shreddit-feed shreddit-ad-post a",
  3146. "shreddit-comment faceplate-hovercard a",
  3147. ],
  3148. validate(element) {
  3149. const href = element.href
  3150. if (!href.startsWith(prefix3)) {
  3151. return true
  3152. }
  3153. if ($("time,faceplate-number", element)) {
  3154. return false
  3155. }
  3156. let key = getUserProfileUrl(href, true)
  3157. if (key) {
  3158. const title = element.textContent.trim()
  3159. if (!title) {
  3160. return false
  3161. }
  3162. const meta = { type: "user", title }
  3163. element.utags = { key, meta }
  3164. element.dataset.utags = element.dataset.utags || ""
  3165. return true
  3166. }
  3167. key = getCommunityUrl(href, true)
  3168. if (key) {
  3169. const title = element.textContent.trim()
  3170. if (!title) {
  3171. return false
  3172. }
  3173. const meta = { type: "community", title }
  3174. element.utags = { key, meta }
  3175. element.dataset.utags = element.dataset.utags || ""
  3176. return true
  3177. }
  3178. key = getCommentsUrl(href, true)
  3179. if (key) {
  3180. const title = element.textContent.trim()
  3181. if (!title) {
  3182. return false
  3183. }
  3184. const meta = { type: "comments", title }
  3185. element.utags = { key, meta }
  3186. element.dataset.utags = element.dataset.utags || ""
  3187. return true
  3188. }
  3189. return true
  3190. },
  3191. excludeSelectors: [
  3192. ...default_default2.excludeSelectors,
  3193. 'a[data-testid="comment_author_icon"]',
  3194. "#shreddit-skip-link",
  3195. 'a[slot="text-body"]',
  3196. 'a[slot="full-post-link"]',
  3197. '[slot="post-media-container"] a.inset-0',
  3198. '[bundlename="shreddit_sort_dropdown"]',
  3199. '[slot="tabs"]',
  3200. ],
  3201. addExtraMatchedNodes(matchedNodesSet) {
  3202. let element = $('[data-testid="profile-main"] .w-full p')
  3203. if (element) {
  3204. const title = element.textContent.trim()
  3205. const key = getUserProfileUrl(location.href)
  3206. if (title && key) {
  3207. const meta = { title, type: "user" }
  3208. element.utags = { key, meta }
  3209. matchedNodesSet.add(element)
  3210. }
  3211. }
  3212. element = $(".w-full h1")
  3213. if (element) {
  3214. const title = element.textContent.trim()
  3215. const key = getCommunityUrl(location.href)
  3216. if (title && key) {
  3217. const meta = { title, type: "community" }
  3218. element.utags = { key, meta }
  3219. matchedNodesSet.add(element)
  3220. }
  3221. }
  3222. element = $('h1[slot="title"]')
  3223. if (element) {
  3224. const title = element.textContent.trim()
  3225. const key = getCommentsUrl(location.href, true)
  3226. if (title && key) {
  3227. const meta = { title, type: "comments" }
  3228. element.utags = { key, meta }
  3229. matchedNodesSet.add(element)
  3230. }
  3231. }
  3232. },
  3233. getStyle: () => reddit_com_default,
  3234. postProcess() {
  3235. setTimeout(() => {
  3236. for (const element of $$(
  3237. '[data-utags_list_node*=",hide,"],\n [data-utags_list_node*=",\u9690\u85CF,"],\n [data-utags_list_node*=",\u5C4F\u853D,"],\n [data-utags_list_node*=",\u4E0D\u518D\u663E\u793A,"],\n [data-utags_list_node*=",block,"]'
  3238. )) {
  3239. element.setAttribute("collapsed", "")
  3240. }
  3241. }, 1e3)
  3242. },
  3243. getCanonicalUrl: getCanonicalUrl2,
  3244. }
  3245. })()
  3246. var twitter_com_default =
  3247. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .css-175oi2r.r-xoduu5:hover{z-index:2 !important}:not(#a):not(#b):not(#c) [data-testid=User-Name]:hover .utags_ul .utags_captain_tag,:not(#a):not(#b):not(#c) [data-testid=HoverCard]:hover .utags_ul .utags_captain_tag,:not(#a):not(#b):not(#c) [data-testid=UserCell]:hover .utags_ul .utags_captain_tag{opacity:100%;width:calc(var(--utags-captain-tag-size) + 8px) !important;height:calc(var(--utags-captain-tag-size) + 8px) !important;padding:5px 4px 4px 5px !important;transition:all 0s .1s !important;z-index:0}"
  3248. var twitter_com_default2 = (() => {
  3249. const prefix3 = "https://x.com/"
  3250. const prefix22 = "https://twitter.com/"
  3251. return {
  3252. matches: /x\.com|twitter\.com/,
  3253. listNodesSelectors: ['[data-testid="cellInnerDiv"]'],
  3254. conditionNodesSelectors: [
  3255. '[data-testid="cellInnerDiv"] [data-testid="User-Name"] a',
  3256. ],
  3257. validate(element) {
  3258. const href = element.href
  3259. if (href.startsWith(prefix3) || href.startsWith(prefix22)) {
  3260. const href2 = href.startsWith(prefix22)
  3261. ? href.slice(20)
  3262. : href.slice(14)
  3263. if (/^\w+$/.test(href2)) {
  3264. if (
  3265. /^(home|explore|notifications|messages|tos|privacy)$/.test(href2)
  3266. ) {
  3267. return false
  3268. }
  3269. const textContent = element.textContent || ""
  3270. if (!textContent.startsWith("@")) {
  3271. return false
  3272. }
  3273. const parent = element.parentElement
  3274. setStyle(parent, { zIndex: "1" })
  3275. const meta = { type: "user" }
  3276. element.utags = { meta }
  3277. return true
  3278. }
  3279. }
  3280. return false
  3281. },
  3282. addExtraMatchedNodes(matchedNodesSet) {
  3283. const elements = $$('[data-testid="UserName"] span')
  3284. for (const element of elements) {
  3285. const title = element.textContent.trim()
  3286. if (!title || !title.startsWith("@")) {
  3287. continue
  3288. }
  3289. const key = prefix3 + title.slice(1)
  3290. const meta = { title, type: "user" }
  3291. element.utags = { key, meta }
  3292. matchedNodesSet.add(element)
  3293. }
  3294. },
  3295. getStyle: () => twitter_com_default,
  3296. }
  3297. })()
  3298. var mp_weixin_qq_com_default = (() => {
  3299. function getCanonicalUrl2(url) {
  3300. if (url.startsWith("http://mp.weixin.qq.com")) {
  3301. url = url.replace(/^http:/, "https:")
  3302. }
  3303. if (url.startsWith("https://mp.weixin.qq.com/s/")) {
  3304. url = url.replace(/(\/s\/[\w-]+).*/, "$1")
  3305. }
  3306. if (url.startsWith("https://mp.weixin.qq.com/") && url.includes("#")) {
  3307. url = url.replace(/#.*/, "")
  3308. }
  3309. return url
  3310. }
  3311. return {
  3312. matches: /mp\.weixin\.qq\.com/,
  3313. addExtraMatchedNodes(matchedNodesSet) {
  3314. const element = $("h1.rich_media_title")
  3315. if (element) {
  3316. const title = element.textContent.trim()
  3317. if (title) {
  3318. const key = getCanonicalUrl2(location.href)
  3319. const meta = { title }
  3320. element.utags = { key, meta }
  3321. matchedNodesSet.add(element)
  3322. }
  3323. }
  3324. },
  3325. getCanonicalUrl: getCanonicalUrl2,
  3326. }
  3327. })()
  3328. var instagram_com_default =
  3329. ":not(#a):not(#b):not(#c) [data-utags_node_type=notag_relative]+.utags_ul_0 .utags_captain_tag{position:relative !important;width:14px !important;height:14px !important;padding:1px 0 0 1px !important}"
  3330. var instagram_com_default2 = (() => {
  3331. return {
  3332. matches: /instagram\.com/,
  3333. validate(element) {
  3334. const href = element.href
  3335. if (href.startsWith("https://www.instagram.com/")) {
  3336. const href2 = href.slice(26)
  3337. if (/^[\w.]+\/$/.test(href2)) {
  3338. if (/^(explore|reels)\/$/.test(href2)) {
  3339. return false
  3340. }
  3341. if ($("div span", element)) {
  3342. element.dataset.utags_node_type = "notag_relative"
  3343. }
  3344. const meta = { type: "user" }
  3345. element.utags = { meta }
  3346. return true
  3347. }
  3348. }
  3349. return false
  3350. },
  3351. excludeSelectors: [...default_default2.excludeSelectors],
  3352. getStyle: () => instagram_com_default,
  3353. }
  3354. })()
  3355. var threads_net_default =
  3356. ':not(#a):not(#b):not(#c) a[href^="/@"][data-utags]+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-4);--utags-notag-ul-height: var(--utags-notag-ul-height-4);--utags-notag-ul-position: var(--utags-notag-ul-position-4);--utags-notag-ul-top: var(--utags-notag-ul-top-4);--utags-notag-captain-tag-top: -22px;--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-4)}'
  3357. var threads_net_default2 = (() => {
  3358. function getUserProfileUrl(url) {
  3359. if (url.startsWith("https://www.threads.net/")) {
  3360. const href2 = url.slice(24)
  3361. if (/^@[\w.]+/.test(href2)) {
  3362. return (
  3363. "https://www.threads.net/" +
  3364. href2.replace(/(^@[\w.]+).*/, "$1").toLowerCase()
  3365. )
  3366. }
  3367. }
  3368. return void 0
  3369. }
  3370. return {
  3371. matches: /threads\.net/,
  3372. validate(element) {
  3373. const href = element.href
  3374. if (href.startsWith("https://www.threads.net/")) {
  3375. const href2 = href.slice(24)
  3376. if (/^@[\w.]+$/.test(href2)) {
  3377. const meta = { type: "user" }
  3378. element.utags = { meta }
  3379. return true
  3380. }
  3381. }
  3382. return false
  3383. },
  3384. excludeSelectors: [
  3385. ...default_default2.excludeSelectors,
  3386. '[role="tablist"]',
  3387. ],
  3388. addExtraMatchedNodes(matchedNodesSet) {
  3389. const element = $("h1+div>div>span,h2+div>div>span")
  3390. if (element) {
  3391. const title = element.textContent.trim()
  3392. const key = getUserProfileUrl(location.href)
  3393. if (title && key && key === "https://www.threads.net/@" + title) {
  3394. const meta = { title, type: "user" }
  3395. element.utags = { key, meta }
  3396. matchedNodesSet.add(element)
  3397. }
  3398. }
  3399. },
  3400. getStyle: () => threads_net_default,
  3401. }
  3402. })()
  3403. var facebook_com_default =
  3404. ":not(#a):not(#b):not(#c) a[data-utags_flag=username_with_avatar]+.utags_ul_0{object-position:0% 100%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: -2px;--utags-notag-captain-tag-left: 0px;--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) h1+ul.utags_ul{margin-bottom:16px !important;display:inline-flex !important}"
  3405. var facebook_com_default2 = (() => {
  3406. const prefix3 = location.origin + "/"
  3407. function getUserProfileUrl(href, exact = false) {
  3408. if (href.startsWith(prefix3)) {
  3409. const href2 = href.slice(prefix3.length).toLowerCase()
  3410. if (href2.startsWith("profile.php")) {
  3411. const parameters = getUrlParameters(href, ["id", "sk"])
  3412. if (parameters.id && !parameters.sk) {
  3413. return "https://www.facebook.com/profile.php?id=" + parameters.id
  3414. }
  3415. } else if (/^\d+\/?([?#].*)?$/.test(href2)) {
  3416. return (
  3417. "https://www.facebook.com/profile.php?id=" +
  3418. href2.replace(/^(\d+).*/, "$1")
  3419. )
  3420. } else if (/^messages\/t\/\d+\/?([?#].*)?$/.test(href2)) {
  3421. return (
  3422. "https://www.facebook.com/profile.php?id=" +
  3423. href2.replace(/^messages\/t\/(\d+).*/, "$1")
  3424. )
  3425. } else if (
  3426. href2.startsWith("friends/requests/?profile_id=") ||
  3427. href2.startsWith("friends/suggestions/?profile_id=")
  3428. ) {
  3429. const parameters = getUrlParameters(href, ["profile_id"])
  3430. if (parameters.profile_id) {
  3431. return (
  3432. "https://www.facebook.com/profile.php?id=" + parameters.profile_id
  3433. )
  3434. }
  3435. } else if (
  3436. ((exact && /^[\w.]+([?#].*)?$/.test(href2)) ||
  3437. (!exact && /^[\w.]+/.test(href2))) &&
  3438. !/^(policies|events|ads|business|privacy|help|friends|messages|profile\.php|permalink\.php|photo\.php|\w+\.php)\b/.test(
  3439. href2
  3440. )
  3441. ) {
  3442. return (
  3443. "https://www.facebook.com/" + href2.replace(/(^[\w.]+).*/, "$1")
  3444. )
  3445. }
  3446. }
  3447. return void 0
  3448. }
  3449. return {
  3450. matches: /^(www|m)\.facebook\.com$/,
  3451. validate(element) {
  3452. const href = element.href
  3453. if (
  3454. !href.startsWith("https://www.facebook.com/") &&
  3455. !href.startsWith("https://m.facebook.com/") &&
  3456. !href.startsWith("https://l.facebook.com/")
  3457. ) {
  3458. return true
  3459. }
  3460. const key = getUserProfileUrl(href, true)
  3461. if (key) {
  3462. const title = element.textContent.trim()
  3463. if (!title) {
  3464. return false
  3465. }
  3466. if ($("svg,img", element)) {
  3467. element.dataset.utags_flag = "username_with_avatar"
  3468. }
  3469. const meta = { type: "user", title }
  3470. element.utags = { key, meta }
  3471. element.dataset.utags = element.dataset.utags || ""
  3472. return true
  3473. }
  3474. return false
  3475. },
  3476. excludeSelectors: [
  3477. ...default_default2.excludeSelectors,
  3478. 'div[data-pagelet="ProfileTabs"]',
  3479. ],
  3480. addExtraMatchedNodes(matchedNodesSet) {
  3481. const element = getFirstHeadElement('div[role="main"] h1')
  3482. if (element) {
  3483. const title = element.textContent.trim()
  3484. const key = getUserProfileUrl(location.href)
  3485. if (title && key) {
  3486. const meta = { title, type: "user" }
  3487. element.utags = { key, meta }
  3488. matchedNodesSet.add(element)
  3489. }
  3490. }
  3491. },
  3492. getStyle: () => facebook_com_default,
  3493. }
  3494. })()
  3495. var youtube_com_default =
  3496. ":not(#a):not(#b):not(#c) ytd-rich-item-renderer h3.ytd-rich-grid-media .utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-2);--utags-notag-ul-height: var(--utags-notag-ul-height-2);--utags-notag-ul-position: var(--utags-notag-ul-position-2);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-2);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-2);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) ytd-rich-item-renderer yt-formatted-string[ellipsis-truncate-styling] .utags_ul_0 .utags_captain_tag{left:-20px}:not(#a):not(#b):not(#c) ytd-video-renderer.ytd-item-section-renderer h3 .utags_ul_0,:not(#a):not(#b):not(#c) ytd-video-renderer.ytd-vertical-list-renderer h3 .utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-2);--utags-notag-ul-height: var(--utags-notag-ul-height-2);--utags-notag-ul-position: var(--utags-notag-ul-position-2);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-2);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-2);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) ytd-video-renderer.ytd-item-section-renderer yt-formatted-string.ytd-channel-name .utags_ul_0 .utags_captain_tag,:not(#a):not(#b):not(#c) ytd-video-renderer.ytd-vertical-list-renderer yt-formatted-string.ytd-channel-name .utags_ul_0 .utags_captain_tag{left:-20px}:not(#a):not(#b):not(#c) .watch-active-metadata ytd-channel-name yt-formatted-string .utags_ul_0,:not(#a):not(#b):not(#c) ytd-comment-thread-renderer h3.ytd-comment-renderer .utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-2);--utags-notag-ul-height: var(--utags-notag-ul-height-2);--utags-notag-ul-position: var(--utags-notag-ul-position-2);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-2);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-2);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .ytd-shorts ytd-reel-video-renderer ytd-channel-name yt-formatted-string .utags_ul_0 .utags_captain_tag{left:-24px}:not(#a):not(#b):not(#c) [hidden]+.utags_ul{display:none !important}"
  3497. var youtube_com_default2 = (() => {
  3498. const prefix3 = "https://www.youtube.com/"
  3499. const prefix22 = "https://m.youtube.com/"
  3500. function getUserProfileUrl(href) {
  3501. if (href.startsWith(prefix3) || href.startsWith(prefix22)) {
  3502. const href2 = href.startsWith(prefix22)
  3503. ? href.slice(22)
  3504. : href.slice(24)
  3505. if (/^@[\w-]+/.test(href2)) {
  3506. return prefix3 + href2.replace(/(^@[\w-]+).*/, "$1")
  3507. }
  3508. if (/^channel\/[\w-]+/.test(href2)) {
  3509. return prefix3 + href2.replace(/(^channel\/[\w-]+).*/, "$1")
  3510. }
  3511. }
  3512. return void 0
  3513. }
  3514. function getVideoUrl(href) {
  3515. if (href.startsWith(prefix3) || href.startsWith(prefix22)) {
  3516. const href2 = href.startsWith(prefix22)
  3517. ? href.slice(22)
  3518. : href.slice(24)
  3519. if (href2.includes("&lc=")) {
  3520. return void 0
  3521. }
  3522. if (/^watch\?v=[\w-]+/.test(href2)) {
  3523. return prefix3 + href2.replace(/(watch\?v=[\w-]+).*/, "$1")
  3524. }
  3525. if (/^shorts\/[\w-]+/.test(href2)) {
  3526. return prefix3 + href2.replace(/(^shorts\/[\w-]+).*/, "$1")
  3527. }
  3528. }
  3529. return void 0
  3530. }
  3531. return {
  3532. matches: /youtube\.com/,
  3533. validate(element) {
  3534. const hrefAttr = getAttribute(element, "href")
  3535. if (!hrefAttr || hrefAttr === "null" || hrefAttr === "#") {
  3536. return false
  3537. }
  3538. const href = element.href
  3539. if (href.startsWith(prefix3) || href.startsWith(prefix22)) {
  3540. const pathname = element.pathname
  3541. if (/^\/@[\w-]+$/.test(pathname)) {
  3542. const key2 = prefix3 + pathname.slice(1)
  3543. const meta = { type: "user" }
  3544. element.utags = { key: key2, meta }
  3545. return true
  3546. }
  3547. if (/^\/channel\/[\w-]+$/.test(pathname)) {
  3548. const key2 = prefix3 + pathname.slice(1)
  3549. const meta = { type: "channel" }
  3550. element.utags = { key: key2, meta }
  3551. return true
  3552. }
  3553. const key = getVideoUrl(href)
  3554. if (key) {
  3555. let title
  3556. const titleElement = $("#video-title", element)
  3557. if (titleElement) {
  3558. title = titleElement.textContent
  3559. }
  3560. const meta = title ? { title, type: "video" } : { type: "video" }
  3561. element.utags = { key, meta }
  3562. return true
  3563. }
  3564. }
  3565. return false
  3566. },
  3567. excludeSelectors: [...default_default2.excludeSelectors],
  3568. addExtraMatchedNodes(matchedNodesSet) {
  3569. let key = getUserProfileUrl(location.href)
  3570. if (key) {
  3571. const element = $(
  3572. "#inner-header-container #container.ytd-channel-name #text"
  3573. )
  3574. if (element) {
  3575. const title = element.textContent.trim()
  3576. if (title) {
  3577. const meta = { title }
  3578. element.utags = { key, meta }
  3579. matchedNodesSet.add(element)
  3580. }
  3581. }
  3582. }
  3583. key = getVideoUrl(location.href)
  3584. if (key) {
  3585. const element = $(
  3586. "#title h1.ytd-watch-metadata,ytd-reel-video-renderer[is-active] h2.title"
  3587. )
  3588. if (element) {
  3589. const title = element.textContent.trim()
  3590. if (title) {
  3591. const meta = { title, type: "video" }
  3592. element.utags = { key, meta }
  3593. matchedNodesSet.add(element)
  3594. }
  3595. }
  3596. }
  3597. },
  3598. getStyle: () => youtube_com_default,
  3599. }
  3600. })()
  3601. var bilibili_com_default =
  3602. ':not(#a):not(#b):not(#c) .bili-video-card__info--right a[href*="/video/"]+.utags_ul_0,:not(#a):not(#b):not(#c) .bili-video-card__info--right h3.bili-video-card__info--tit+.utags_ul_0,:not(#a):not(#b):not(#c) .video-page-card-small a[href*="/video/"]+.utags_ul_0,:not(#a):not(#b):not(#c) .video-page-card-small h3.bili-video-card__info--tit+.utags_ul_0,:not(#a):not(#b):not(#c) .video-page-operator-card-small a[href*="/video/"]+.utags_ul_0,:not(#a):not(#b):not(#c) .video-page-operator-card-small h3.bili-video-card__info--tit+.utags_ul_0{display:block !important;height:0}:not(#a):not(#b):not(#c) .bili-video-card__info--right a[href*="/video/"]+.utags_ul_0 .utags_captain_tag,:not(#a):not(#b):not(#c) .bili-video-card__info--right h3.bili-video-card__info--tit+.utags_ul_0 .utags_captain_tag,:not(#a):not(#b):not(#c) .video-page-card-small a[href*="/video/"]+.utags_ul_0 .utags_captain_tag,:not(#a):not(#b):not(#c) .video-page-card-small h3.bili-video-card__info--tit+.utags_ul_0 .utags_captain_tag,:not(#a):not(#b):not(#c) .video-page-operator-card-small a[href*="/video/"]+.utags_ul_0 .utags_captain_tag,:not(#a):not(#b):not(#c) .video-page-operator-card-small h3.bili-video-card__info--tit+.utags_ul_0 .utags_captain_tag{top:-22px;background-color:rgba(255,255,255,.8666666667) !important}'
  3603. var bilibili_com_default2 = (() => {
  3604. const prefix3 = "https://www.bilibili.com/"
  3605. const prefix22 = "https://space.bilibili.com/"
  3606. const prefix32 = "https://m.bilibili.com/"
  3607. function getUserProfileUrl(href) {
  3608. if (href.startsWith(prefix22)) {
  3609. const href2 = href.slice(27)
  3610. if (/^\d+/.test(href2)) {
  3611. return prefix22 + href2.replace(/(^\d+).*/, "$1")
  3612. }
  3613. }
  3614. if (href.startsWith(prefix32 + "space/")) {
  3615. const href2 = href.slice(29)
  3616. if (/^\d+/.test(href2)) {
  3617. return prefix22 + href2.replace(/(^\d+).*/, "$1")
  3618. }
  3619. }
  3620. return void 0
  3621. }
  3622. function getVideoUrl(href) {
  3623. if (
  3624. href.startsWith(prefix3 + "video/") ||
  3625. href.startsWith(prefix32 + "video/")
  3626. ) {
  3627. const href2 = href.startsWith(prefix32)
  3628. ? href.slice(23)
  3629. : href.slice(25)
  3630. if (/^video\/\w+/.test(href2)) {
  3631. return prefix3 + href2.replace(/^(video\/\w+).*/, "$1")
  3632. }
  3633. }
  3634. return void 0
  3635. }
  3636. return {
  3637. matches: /bilibili\.com|biligame\.com/,
  3638. excludeSelectors: ["*"],
  3639. addExtraMatchedNodes(matchedNodesSet) {
  3640. if (location.href.startsWith(prefix3 + "video/")) {
  3641. if ($(".bpx-state-loading")) {
  3642. return
  3643. }
  3644. const img = $(".bpx-player-follow-face")
  3645. const img2 = $("img.video-capture-img")
  3646. if (
  3647. !(img == null ? void 0 : img.src) ||
  3648. !(img2 == null ? void 0 : img2.src)
  3649. ) {
  3650. return
  3651. }
  3652. }
  3653. const elements = $$(
  3654. ".user-name[data-user-id],.sub-user-name[data-user-id],.jump-link.user[data-user-id]"
  3655. )
  3656. for (const element2 of elements) {
  3657. const userId = element2.dataset.userId
  3658. if (!userId) {
  3659. return false
  3660. }
  3661. const title = element2.textContent.trim()
  3662. const key = prefix22 + userId
  3663. const meta = { title, type: "user" }
  3664. element2.utags = { key, meta }
  3665. element2.dataset.utags_node_type = "link"
  3666. matchedNodesSet.add(element2)
  3667. }
  3668. const elements2 = $$(".upname a,a.bili-video-card__info--owner")
  3669. for (const element2 of elements2) {
  3670. const href = element2.href
  3671. if (href.startsWith(prefix22)) {
  3672. const key = getUserProfileUrl(href)
  3673. if (key) {
  3674. const nameElement = $(
  3675. ".name,.bili-video-card__info--author",
  3676. element2
  3677. )
  3678. if (nameElement) {
  3679. const title = nameElement.textContent
  3680. const meta = { title, type: "user" }
  3681. nameElement.utags = { key, meta }
  3682. nameElement.dataset.utags_node_type = "link"
  3683. matchedNodesSet.add(nameElement)
  3684. }
  3685. }
  3686. }
  3687. }
  3688. const elements3 = $$(
  3689. [
  3690. "a.up-name",
  3691. "a.card-user-name",
  3692. ".usercard-wrap .user .name",
  3693. ".comment-list .user .name",
  3694. ".user-card .user .name",
  3695. "a[data-usercard-mid]",
  3696. "a.user-name",
  3697. ".user-name a",
  3698. 'a[href^="https://space.bilibili.com/"]',
  3699. "a.staff-name",
  3700. ].join(",")
  3701. )
  3702. for (const element2 of elements3) {
  3703. const href = element2.href
  3704. if (href.startsWith(prefix22)) {
  3705. const key = getUserProfileUrl(href)
  3706. if (key) {
  3707. let title = element2.textContent.trim()
  3708. if (title) {
  3709. title = title.replace(/^@/, "")
  3710. const meta = { title, type: "user" }
  3711. element2.utags = { key, meta }
  3712. matchedNodesSet.add(element2)
  3713. }
  3714. }
  3715. }
  3716. }
  3717. if (
  3718. location.href.startsWith(prefix22) ||
  3719. location.href.startsWith(prefix32 + "space/")
  3720. ) {
  3721. const element2 = $("#h-name,.m-space-info .name")
  3722. if (element2) {
  3723. const title = element2.textContent.trim()
  3724. const key = getUserProfileUrl(location.href)
  3725. if (title && key) {
  3726. const meta = { title, type: "user" }
  3727. element2.utags = { key, meta }
  3728. matchedNodesSet.add(element2)
  3729. }
  3730. }
  3731. }
  3732. const element = $("h1.video-title,h1.title-text")
  3733. if (element) {
  3734. const title = element.textContent.trim()
  3735. const key = getVideoUrl(location.href)
  3736. if (title && key) {
  3737. const meta = { title, type: "video" }
  3738. element.utags = { key, meta }
  3739. matchedNodesSet.add(element)
  3740. }
  3741. }
  3742. const elements4 = $$(
  3743. ".bili-video-card__info--right a,.video-page-card-small .info a,.video-page-operator-card-small .info a"
  3744. )
  3745. for (const element2 of elements4) {
  3746. const key = getVideoUrl(element2.href)
  3747. if (key) {
  3748. const title = element2.textContent.trim()
  3749. const target =
  3750. element2.parentElement.tagName === "H3"
  3751. ? element2.parentElement
  3752. : element2
  3753. if (title) {
  3754. const meta = { title, type: "video" }
  3755. target.utags = { key, meta }
  3756. target.dataset.utags_node_type = "link"
  3757. matchedNodesSet.add(target)
  3758. }
  3759. }
  3760. }
  3761. },
  3762. getStyle: () => bilibili_com_default,
  3763. }
  3764. })()
  3765. var tiktok_com_default =
  3766. ':not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) .css-e2j6y6-StyledLink+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -4px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .css-e2j6y6-StyledLink+.utags_ul_1{position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .css-1gstnae-DivCommentItemWrapper{--utags-list-node-display: flex}:not(#a):not(#b):not(#c) .css-1gstnae-DivCommentItemWrapper a[href^="/@"] p{display:inline}:not(#a):not(#b):not(#c) .css-ulyotp-DivCommentContentContainer{--utags-list-node-display: flex}:not(#a):not(#b):not(#c) .css-1asahzr-DivBroadcastTitleWrapper a[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .css-1asahzr-DivBroadcastTitleWrapper a[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .css-1asahzr-DivBroadcastTitleWrapper a+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .css-c5ejjw-DivProfileContainer[data-e2e=user-profile-card] a[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .css-c5ejjw-DivProfileContainer[data-e2e=user-profile-card] a[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .css-8c0sl4-AName[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important;height:fit-content !important}:not(#a):not(#b):not(#c) .css-8c0sl4-AName[data-utags_fit_content="1"] *:not(svg){width:fit-content !important;height:fit-content !important}:not(#a):not(#b):not(#c) .css-8c0sl4-AName+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -4px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .css-8c0sl4-AName+.utags_ul_1{position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) [data-e2e=recommend-card] a+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -2px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) [data-e2e=recommend-card] a+.utags_ul_1{position:absolute;top:-9999px;margin-top:2px !important;margin-left:0px !important}'
  3767. var tiktok_com_default2 = (() => {
  3768. const prefix3 = "https://www.tiktok.com/"
  3769. function getUserProfileUrl(url, exact = false) {
  3770. if (url.startsWith(prefix3)) {
  3771. const href2 = url.slice(23)
  3772. if (exact) {
  3773. if (/^@[\w.-]+([?#].*)?$/.test(href2)) {
  3774. return prefix3 + href2.replace(/(^@[\w.-]+).*/, "$1")
  3775. }
  3776. } else if (/^@[\w.-]+/.test(href2)) {
  3777. return prefix3 + href2.replace(/(^@[\w.-]+).*/, "$1")
  3778. }
  3779. }
  3780. return void 0
  3781. }
  3782. return {
  3783. matches: /tiktok\.com/,
  3784. listNodesSelectors: [
  3785. ".css-ulyotp-DivCommentContentContainer",
  3786. ".css-1gstnae-DivCommentItemWrapper",
  3787. ".css-x6y88p-DivItemContainerV2",
  3788. ],
  3789. conditionNodesSelectors: [
  3790. '.css-ulyotp-DivCommentContentContainer a[href^="/@"]',
  3791. '.css-1gstnae-DivCommentItemWrapper a[href^="/@"]',
  3792. '.css-x6y88p-DivItemContainerV2 a[href^="/@"]',
  3793. ],
  3794. validate(element) {
  3795. const href = element.href
  3796. if (!href.startsWith(prefix3)) {
  3797. return true
  3798. }
  3799. const key = getUserProfileUrl(href, true)
  3800. if (key) {
  3801. const titleElement = $('h3,[data-e2e="browse-username"]', element)
  3802. const title = titleElement
  3803. ? titleElement.textContent.trim()
  3804. : element.textContent.trim()
  3805. if (!title) {
  3806. return false
  3807. }
  3808. const meta = { type: "user", title }
  3809. element.utags = { key, meta }
  3810. return true
  3811. }
  3812. return false
  3813. },
  3814. excludeSelectors: [
  3815. ...default_default2.excludeSelectors,
  3816. ".avatar-anchor",
  3817. '[data-e2e*="avatar"]',
  3818. '[data-e2e="user-card-nickname"]',
  3819. ],
  3820. validMediaSelectors: [
  3821. '[data-e2e="browse-bluev"]',
  3822. '[data-e2e="recommend-card"]',
  3823. ],
  3824. addExtraMatchedNodes(matchedNodesSet) {
  3825. const element = $('h1[data-e2e="user-title"]')
  3826. if (element) {
  3827. const title = element.textContent.trim()
  3828. const key = getUserProfileUrl(location.href)
  3829. if (title && key) {
  3830. const meta = { title, type: "user" }
  3831. element.utags = { key, meta }
  3832. matchedNodesSet.add(element)
  3833. }
  3834. }
  3835. },
  3836. getStyle: () => tiktok_com_default,
  3837. }
  3838. })()
  3839. var pojie_cn_default =
  3840. ".fl cite,.tl cite{white-space:break-spaces}.favatar .pi .authi a{line-height:16px}.favatar .pi{height:auto}"
  3841. var pojie_cn_default2 = (() => {
  3842. return {
  3843. matches: /52pojie\.cn/,
  3844. matchedNodesSelectors: [
  3845. 'a[href*="home.php?mod=space&uid="]',
  3846. 'a[href*="home.php?mod=space&username="]',
  3847. ],
  3848. excludeSelectors: [
  3849. ...default_default2.excludeSelectors,
  3850. "#hd",
  3851. "#pt",
  3852. "#pgt",
  3853. "#jz52top",
  3854. ],
  3855. getStyle: () => pojie_cn_default,
  3856. }
  3857. })()
  3858. var juejin_cn_default = (() => {
  3859. const prefix3 = "https://juejin.cn/"
  3860. function getUserProfileUrl(url) {
  3861. if (url.startsWith(prefix3)) {
  3862. const href2 = url.slice(18)
  3863. if (/^user\/\d+/.test(href2)) {
  3864. return prefix3 + href2.replace(/^(user\/\d+).*/, "$1")
  3865. }
  3866. }
  3867. return void 0
  3868. }
  3869. return {
  3870. matches: /juejin\.cn/,
  3871. validate(element) {
  3872. if ($(".avatar", element)) {
  3873. return false
  3874. }
  3875. const href = element.href
  3876. if (href.startsWith(prefix3)) {
  3877. const key = getUserProfileUrl(href)
  3878. if (key) {
  3879. const titleElement = $(".name", element)
  3880. let title
  3881. if (titleElement) {
  3882. title = titleElement.textContent
  3883. }
  3884. const meta = { type: "user" }
  3885. if (title) {
  3886. meta.title = title
  3887. }
  3888. element.utags = { key, meta }
  3889. element.dataset.utags = element.dataset.utags || ""
  3890. return true
  3891. }
  3892. }
  3893. return false
  3894. },
  3895. excludeSelectors: [
  3896. ...default_default2.excludeSelectors,
  3897. ".list-header",
  3898. ".sub-header",
  3899. ".next-page",
  3900. ".follow-item",
  3901. ".more-item",
  3902. ],
  3903. addExtraMatchedNodes(matchedNodesSet) {
  3904. const key = getUserProfileUrl(location.href)
  3905. if (key) {
  3906. const element2 = $("h1.username")
  3907. if (element2) {
  3908. const title = element2.textContent.trim()
  3909. if (title) {
  3910. const meta = { title, type: "user" }
  3911. element2.utags = { key, meta }
  3912. matchedNodesSet.add(element2)
  3913. }
  3914. }
  3915. }
  3916. const element = $(".sidebar-block.author-block a .username")
  3917. if (element) {
  3918. const anchor = element.closest("a")
  3919. if (anchor) {
  3920. const key2 = getUserProfileUrl(anchor.href)
  3921. if (key2) {
  3922. const titleElement = $(".name", element)
  3923. const title = titleElement
  3924. ? titleElement.textContent
  3925. : element.textContent
  3926. if (title) {
  3927. const meta = { title, type: "user" }
  3928. element.utags = { key: key2, meta }
  3929. matchedNodesSet.add(element)
  3930. }
  3931. }
  3932. }
  3933. }
  3934. },
  3935. }
  3936. })()
  3937. var zhihu_com_default = (() => {
  3938. const prefix3 = "https://www.zhihu.com/"
  3939. function getUserProfileUrl(url, exact = false) {
  3940. if (url.startsWith(prefix3)) {
  3941. const href2 = url.slice(22)
  3942. if (exact) {
  3943. if (/^people\/[\w-]+(\?.*)?$/.test(href2)) {
  3944. return prefix3 + href2.replace(/^(people\/[\w-]+).*/, "$1")
  3945. }
  3946. } else if (/^people\/[\w-]+/.test(href2)) {
  3947. return prefix3 + href2.replace(/^(people\/[\w-]+).*/, "$1")
  3948. }
  3949. }
  3950. return void 0
  3951. }
  3952. return {
  3953. matches: /zhihu\.com/,
  3954. validate(element) {
  3955. if ($(".avatar", element)) {
  3956. return false
  3957. }
  3958. const href = element.href
  3959. if (!href.includes("zhihu.com")) {
  3960. return true
  3961. }
  3962. if (href.startsWith(prefix3 + "people/")) {
  3963. const key = getUserProfileUrl(href, true)
  3964. if (key) {
  3965. const titleElement = $(".name", element)
  3966. let title
  3967. if (titleElement) {
  3968. title = titleElement.textContent
  3969. }
  3970. const meta = { type: "user" }
  3971. if (title) {
  3972. meta.title = title
  3973. }
  3974. element.utags = { key, meta }
  3975. return true
  3976. }
  3977. }
  3978. return false
  3979. },
  3980. excludeSelectors: [
  3981. ...default_default2.excludeSelectors,
  3982. ".NumberBoard",
  3983. ".ProfileMain-tabs",
  3984. ".Profile-lightList",
  3985. ],
  3986. addExtraMatchedNodes(matchedNodesSet) {
  3987. const key = getUserProfileUrl(location.href)
  3988. if (key) {
  3989. const element = $("h1.ProfileHeader-title .ProfileHeader-name")
  3990. if (element) {
  3991. const title = element.textContent.trim()
  3992. if (title) {
  3993. const meta = { title, type: "user" }
  3994. element.utags = { key, meta }
  3995. matchedNodesSet.add(element)
  3996. }
  3997. }
  3998. }
  3999. },
  4000. }
  4001. })()
  4002. var xiaohongshu_com_default =
  4003. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:0% 100%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 100%;background-color:var(--utags-captain-tag-background-color) !important;border-radius:3px !important}:not(#a):not(#b):not(#c) .author-container .author-wrapper .name+.utags_ul_0{--utags-notag-captain-tag-top: 6px;--utags-notag-captain-tag-left: 8px}:not(#a):not(#b):not(#c) .author-container .author-wrapper .name+.utags_ul_1{position:absolute;top:-9999px;margin-top:4px !important;margin-left:8px !important}:not(#a):not(#b):not(#c) .note-text{position:relative}:not(#a):not(#b):not(#c) .note-text .utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-1);--utags-notag-ul-height: var(--utags-notag-ul-height-1);--utags-notag-ul-position: var(--utags-notag-ul-position-1);--utags-notag-ul-top: var(--utags-notag-ul-top-1);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-1);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-1);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .comments-container .author-wrapper .author{align-items:flex-start;flex-direction:column}:not(#a):not(#b):not(#c) .comments-container .author-wrapper .author .name+.utags_ul_0{object-position:200% 50%}:not(#a):not(#b):not(#c) .note-content-user+.utags_ul_0{--utags-notag-captain-tag-top: 0px;--utags-notag-captain-tag-left: 20px}:not(#a):not(#b):not(#c) .tooltip-content .user-content .avatar-info+.utags_ul_0{--utags-notag-captain-tag-top: 6px;--utags-notag-captain-tag-left: 46px}:not(#a):not(#b):not(#c) .tooltip-content .user-content .avatar-info+.utags_ul_1{position:absolute;top:-9999px;margin-top:6px !important;margin-left:46px !important}:not(#a):not(#b):not(#c) .note-item .cover+.utags_ul_0{--utags-notag-captain-tag-top: 18px;--utags-notag-captain-tag-left: -8px}:not(#a):not(#b):not(#c) .note-item .cover+.utags_ul_1{position:absolute;top:-9999px;margin-top:14px !important;margin-left:-4px !important}:not(#a):not(#b):not(#c) .note-item .author-wrapper .author+.utags_ul_0{--utags-notag-captain-tag-top: 16px;--utags-notag-captain-tag-left: 20px}:not(#a):not(#b):not(#c) .note-item .author-wrapper .author+.utags_ul_1{position:absolute;top:-9999px;margin-top:12px !important;margin-left:22px !important}:not(#a):not(#b):not(#c) #userPageContainer .user-info .user-nickname{align-items:flex-start;flex-direction:column}:not(#a):not(#b):not(#c) #userPageContainer .user-info .user-nickname .user-name+.utags_ul_0{object-position:0% 200%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: 0px;--utags-notag-captain-tag-left: 0px}"
  4004. var xiaohongshu_com_default2 = (() => {
  4005. const prefix3 = "https://www.xiaohongshu.com/"
  4006. function getCanonicalUrl2(url) {
  4007. if (url.startsWith(prefix3)) {
  4008. const href2 = url.slice(prefix3.length)
  4009. if (href2.startsWith("search_result") && href2.includes("keyword")) {
  4010. return (
  4011. prefix3 +
  4012. "search_result/?" +
  4013. href2.replace(/.*?(keyword=[^&]*).*/, "$1") +
  4014. "&type=54"
  4015. )
  4016. }
  4017. }
  4018. return url
  4019. }
  4020. function getUserProfileUrl(url, exact = false) {
  4021. if (url.startsWith(prefix3)) {
  4022. const href2 = url.slice(28)
  4023. if (exact) {
  4024. if (/^user\/profile\/\w+(\?.*)?$/.test(href2)) {
  4025. return prefix3 + href2.replace(/^(user\/profile\/\w+).*/, "$1")
  4026. }
  4027. } else if (/^user\/profile\/\w+/.test(href2)) {
  4028. return prefix3 + href2.replace(/^(user\/profile\/\w+).*/, "$1")
  4029. }
  4030. }
  4031. return void 0
  4032. }
  4033. function getPostUrl(url) {
  4034. if (url.startsWith(prefix3)) {
  4035. const href2 = url.slice(28)
  4036. if (/^explore\/\w+/.test(href2)) {
  4037. return prefix3 + href2.replace(/^(explore\/\w+).*/, "$1")
  4038. }
  4039. if (/^user\/profile\/\w+\/\w+/.test(href2)) {
  4040. return (
  4041. prefix3 +
  4042. "explore/" +
  4043. href2.replace(/^user\/profile\/\w+\/(\w+).*/, "$1")
  4044. )
  4045. }
  4046. if (/^search_result\/\w+/.test(href2)) {
  4047. return (
  4048. prefix3 +
  4049. "explore/" +
  4050. href2.replace(/^search_result\/(\w+).*/, "$1")
  4051. )
  4052. }
  4053. }
  4054. return void 0
  4055. }
  4056. return {
  4057. matches: /www\.xiaohongshu\.com/,
  4058. listNodesSelectors: [".feeds-container section", ".comment-item"],
  4059. conditionNodesSelectors: [
  4060. ".feeds-container section .author-wrapper .author",
  4061. ".feeds-container section .cover",
  4062. ".comment-item .author-wrapper .author a",
  4063. ],
  4064. validate(element) {
  4065. const href = element.href
  4066. if (!href.startsWith(prefix3)) {
  4067. return true
  4068. }
  4069. let key = getUserProfileUrl(href, true)
  4070. if (key) {
  4071. const titleElement =
  4072. (hasClass(element, "name") ? element : $(".name", element)) ||
  4073. element
  4074. let title
  4075. if (titleElement) {
  4076. title = titleElement.textContent.trim()
  4077. }
  4078. if (!title) {
  4079. return false
  4080. }
  4081. const meta = { type: "user", title }
  4082. element.utags = { key, meta }
  4083. element.dataset.utags = element.dataset.utags || ""
  4084. return true
  4085. }
  4086. key = getPostUrl(href)
  4087. if (key) {
  4088. const meta = { type: "post" }
  4089. if (hasClass(element, "cover")) {
  4090. const sibling = element.nextElementSibling
  4091. if (sibling && hasClass(sibling, "footer")) {
  4092. const titleElement = $(".title span", sibling)
  4093. if (titleElement) {
  4094. const title = titleElement.textContent.trim()
  4095. if (title) {
  4096. meta.title = title
  4097. }
  4098. }
  4099. element.dataset.utags = element.dataset.utags || ""
  4100. }
  4101. }
  4102. element.utags = { key, meta }
  4103. return true
  4104. }
  4105. return true
  4106. },
  4107. excludeSelectors: [
  4108. ...default_default2.excludeSelectors,
  4109. ".side-bar",
  4110. ".dropdown-nav",
  4111. ".dropdown-container",
  4112. ".interaction-info",
  4113. ],
  4114. addExtraMatchedNodes(matchedNodesSet) {
  4115. let key = getUserProfileUrl(location.href)
  4116. if (key) {
  4117. const element = $(".user-info .user-name")
  4118. if (element) {
  4119. const title = element.textContent.trim()
  4120. if (title) {
  4121. const meta = { title, type: "user" }
  4122. element.utags = { key, meta }
  4123. element.dataset.utags_node_type = "link"
  4124. matchedNodesSet.add(element)
  4125. }
  4126. }
  4127. }
  4128. key = getPostUrl(location.href)
  4129. if (key) {
  4130. const element = $(".note-content .title")
  4131. if (element) {
  4132. const title = element.textContent.trim()
  4133. if (title) {
  4134. const meta = { title, type: "post" }
  4135. element.utags = { key, meta }
  4136. matchedNodesSet.add(element)
  4137. }
  4138. }
  4139. }
  4140. },
  4141. getCanonicalUrl: getCanonicalUrl2,
  4142. getStyle: () => xiaohongshu_com_default,
  4143. }
  4144. })()
  4145. var weibo_com_default = (() => {
  4146. const prefix3 = "https://weibo.com/"
  4147. const prefix22 = "https://m.weibo.cn/"
  4148. function getCanonicalUrl2(url) {
  4149. if (url.startsWith(prefix3) || url.startsWith(prefix22)) {
  4150. const href2 = getUserProfileUrl(url, true)
  4151. if (href2) {
  4152. return href2
  4153. }
  4154. }
  4155. return url
  4156. }
  4157. function getUserProfileUrl(url, exact = false) {
  4158. if (url.startsWith(prefix3) || url.startsWith(prefix22)) {
  4159. const href2 = url.startsWith(prefix22) ? url.slice(19) : url.slice(18)
  4160. if (exact) {
  4161. if (/^u\/\d+(\?.*)?$/.test(href2)) {
  4162. return prefix3 + href2.replace(/^(u\/\d+).*/, "$1")
  4163. }
  4164. if (/^profile\/\d+(\?.*)?$/.test(href2)) {
  4165. return prefix3 + "u/" + href2.replace(/^profile\/(\d+).*/, "$1")
  4166. }
  4167. if (/^\d+(\?.*)?$/.test(href2)) {
  4168. return prefix3 + "u/" + href2.replace(/^(\d+).*/, "$1")
  4169. }
  4170. } else {
  4171. if (/^u\/\d+/.test(href2)) {
  4172. return prefix3 + href2.replace(/^(u\/\d+).*/, "$1")
  4173. }
  4174. if (/^profile\/\d+/.test(href2)) {
  4175. return prefix3 + "u/" + href2.replace(/^profile\/(\d+).*/, "$1")
  4176. }
  4177. if (/^\d+/.test(href2)) {
  4178. return prefix3 + "u/" + href2.replace(/^(\d+).*/, "$1")
  4179. }
  4180. }
  4181. }
  4182. return void 0
  4183. }
  4184. return {
  4185. matches: /weibo\.com|weibo\.cn/,
  4186. validate(element) {
  4187. const href = element.href
  4188. if (!href.includes("weibo.com") && !href.includes("weibo.cn")) {
  4189. return true
  4190. }
  4191. const key = getUserProfileUrl(href, true)
  4192. if (key) {
  4193. const meta = { type: "user" }
  4194. element.utags = { key, meta }
  4195. if ($(".m-icon.vipicon", element)) {
  4196. element.dataset.utags = element.dataset.utags || ""
  4197. }
  4198. return true
  4199. }
  4200. return true
  4201. },
  4202. excludeSelectors: [
  4203. ...default_default2.excludeSelectors,
  4204. '[class^="Frame_side_"]',
  4205. 'a[href*="promote.biz.weibo.cn"]',
  4206. ],
  4207. addExtraMatchedNodes(matchedNodesSet) {
  4208. const key = getUserProfileUrl(location.href)
  4209. if (key) {
  4210. const element = $(
  4211. '[class^="ProfileHeader_name_"],.profile-cover .mod-fil-name .txt-shadow'
  4212. )
  4213. if (element) {
  4214. const title = element.textContent.trim()
  4215. if (title) {
  4216. const meta = { title, type: "user" }
  4217. element.utags = { key, meta }
  4218. matchedNodesSet.add(element)
  4219. }
  4220. }
  4221. }
  4222. },
  4223. getCanonicalUrl: getCanonicalUrl2,
  4224. }
  4225. })()
  4226. var sspai_com_default =
  4227. ":not(#a):not(#b):not(#c) #article-title+.utags_ul{display:block !important;margin-top:-30px !important;margin-bottom:20px !important}:not(#a):not(#b):not(#c) .user__info__card__center .utags_ul{display:block !important;margin-bottom:5px !important}:not(#a):not(#b):not(#c) .pai_title .utags_ul{float:left}"
  4228. var sspai_com_default2 = (() => {
  4229. const prefix3 = "https://sspai.com/"
  4230. const excludeLinks = [
  4231. "https://sspai.com/prime",
  4232. "https://sspai.com/matrix",
  4233. "https://sspai.com/page/about-us",
  4234. "https://sspai.com/page/agreement",
  4235. "https://sspai.com/page/bussiness",
  4236. "https://sspai.com/post/37793",
  4237. "https://sspai.com/page/client",
  4238. "https://sspai.com/s/J71e",
  4239. "https://sspai.com/mall",
  4240. ]
  4241. function getCanonicalUrl2(url) {
  4242. if (url.startsWith(prefix3)) {
  4243. const href = url.slice(18)
  4244. if (href.startsWith("u/")) {
  4245. return prefix3 + href.replace(/^(u\/\w+).*/, "$1")
  4246. }
  4247. }
  4248. return url
  4249. }
  4250. function getUserProfileUrl(url) {
  4251. if (url.startsWith(prefix3)) {
  4252. const href2 = url.slice(18)
  4253. if (/^u\/\w+/.test(href2)) {
  4254. return prefix3 + href2.replace(/^(u\/\w+).*/, "$1")
  4255. }
  4256. }
  4257. return void 0
  4258. }
  4259. function getPostUrl(url) {
  4260. if (url.startsWith(prefix3)) {
  4261. const href2 = url.slice(18)
  4262. if (/^post\/\d+/.test(href2)) {
  4263. return prefix3 + href2.replace(/^(post\/\d+).*/, "$1")
  4264. }
  4265. }
  4266. return void 0
  4267. }
  4268. return {
  4269. matches: /sspai\.com/,
  4270. validate(element) {
  4271. const href = element.href
  4272. for (const link of excludeLinks) {
  4273. if (href.includes(link)) {
  4274. return false
  4275. }
  4276. }
  4277. if (
  4278. hasClass(element, "ss__user__nickname__wrapper") ||
  4279. element.closest('.card_bottom > a[href^="/u/"]')
  4280. ) {
  4281. element.dataset.utags = element.dataset.utags || ""
  4282. return true
  4283. }
  4284. return true
  4285. },
  4286. excludeSelectors: [
  4287. ...default_default2.excludeSelectors,
  4288. "header",
  4289. "footer",
  4290. ".pai_abstract",
  4291. ".pai_title .link",
  4292. ],
  4293. addExtraMatchedNodes(matchedNodesSet) {
  4294. let key = getPostUrl(location.href)
  4295. if (key) {
  4296. const element = $(".article-header .title")
  4297. if (element && !element.closest(".pai_title")) {
  4298. const title = element.textContent.trim()
  4299. if (title) {
  4300. const meta = { title, type: "post" }
  4301. element.utags = { key, meta }
  4302. matchedNodesSet.add(element)
  4303. }
  4304. }
  4305. }
  4306. key = getUserProfileUrl(location.href)
  4307. if (key) {
  4308. const element = $(
  4309. ".user_content .user__info__card .ss__user__card__nickname"
  4310. )
  4311. if (element) {
  4312. const title = element.textContent.trim()
  4313. if (title) {
  4314. const meta = { title, type: "user" }
  4315. element.utags = { key, meta }
  4316. matchedNodesSet.add(element)
  4317. }
  4318. }
  4319. }
  4320. },
  4321. getCanonicalUrl: getCanonicalUrl2,
  4322. getStyle: () => sspai_com_default,
  4323. }
  4324. })()
  4325. var douyin_com_default =
  4326. ':not(#a):not(#b):not(#c) [data-e2e=comment-item] .utags_ul_0 .utags_captain_tag{left:-26px}:not(#a):not(#b):not(#c) [data-e2e=detail-video-info] .utags_ul[data-utags_key*="/video/"]{display:block !important;margin-top:0px !important;margin-bottom:2px !important}:not(#a):not(#b):not(#c) [data-e2e=detail-video-info] .utags_ul[data-utags_key*="/video/"].utags_ul_0{height:0}:not(#a):not(#b):not(#c) [data-e2e=detail-video-info] .utags_ul[data-utags_key*="/video/"].utags_ul_0 .utags_captain_tag{top:-26px;background-color:rgba(255,255,255,.8666666667) !important}:not(#a):not(#b):not(#c) [data-e2e=related-video] .utags_ul_0[data-utags_key*="/video/"]{display:block !important;height:0}:not(#a):not(#b):not(#c) [data-e2e=related-video] .utags_ul_0[data-utags_key*="/video/"] .utags_captain_tag{top:-26px;background-color:rgba(255,255,255,.8666666667) !important}:not(#a):not(#b):not(#c) [data-e2e=related-video] .utags_ul_0[data-utags_key*="/user/"]{display:block !important;height:0px;width:0px}:not(#a):not(#b):not(#c) [data-e2e=related-video] .utags_ul_0[data-utags_key*="/user/"] .utags_captain_tag{top:-22px;background-color:rgba(255,255,255,.8666666667) !important}:not(#a):not(#b):not(#c) [data-e2e=user-info] a+.utags_ul_0[data-utags_key*="/user/"]{display:block !important;height:0px;width:0px}:not(#a):not(#b):not(#c) [data-e2e=user-info] a+.utags_ul_0[data-utags_key*="/user/"] .utags_captain_tag{top:-22px;background-color:rgba(255,255,255,.8666666667) !important}'
  4327. var douyin_com_default2 = (() => {
  4328. const prefix3 = "https://www.douyin.com/"
  4329. function getUserProfileUrl(url, exact = false) {
  4330. if (url.startsWith(prefix3)) {
  4331. const href2 = url.slice(23)
  4332. if (exact) {
  4333. if (/^user\/[\w-]+(\?.*)?$/.test(href2)) {
  4334. return prefix3 + href2.replace(/^(user\/[\w-]+).*/, "$1")
  4335. }
  4336. } else if (/^user\/[\w-]+/.test(href2)) {
  4337. return prefix3 + href2.replace(/^(user\/[\w-]+).*/, "$1")
  4338. }
  4339. }
  4340. return void 0
  4341. }
  4342. function getVideoUrl(url) {
  4343. if (url.startsWith(prefix3)) {
  4344. const href2 = url.slice(23)
  4345. if (/^video\/\w+/.test(href2)) {
  4346. return prefix3 + href2.replace(/^(video\/\w+).*/, "$1")
  4347. }
  4348. }
  4349. return void 0
  4350. }
  4351. function getNoteUrl(url) {
  4352. if (url.startsWith(prefix3)) {
  4353. const href2 = url.slice(23)
  4354. if (/^note\/\w+/.test(href2)) {
  4355. return prefix3 + href2.replace(/^(note\/\w+).*/, "$1")
  4356. }
  4357. }
  4358. return void 0
  4359. }
  4360. return {
  4361. matches: /www\.douyin\.com/,
  4362. validate(element) {
  4363. const href = element.href
  4364. if (!href.includes("www.douyin.com")) {
  4365. return true
  4366. }
  4367. let key = getUserProfileUrl(href, true)
  4368. if (key) {
  4369. const meta = { type: "user" }
  4370. element.utags = { key, meta }
  4371. return true
  4372. }
  4373. key = getVideoUrl(href)
  4374. if (key) {
  4375. const meta = { type: "video" }
  4376. element.utags = { key, meta }
  4377. return true
  4378. }
  4379. key = getNoteUrl(href)
  4380. if (key) {
  4381. const meta = { type: "post" }
  4382. element.utags = { key, meta }
  4383. return true
  4384. }
  4385. return true
  4386. },
  4387. excludeSelectors: [
  4388. ...default_default2.excludeSelectors,
  4389. '[data-e2e="douyin-navigation"]',
  4390. ],
  4391. validMediaSelectors: ['img[src*="twemoji"]'],
  4392. addExtraMatchedNodes(matchedNodesSet) {
  4393. let key = getUserProfileUrl(location.href)
  4394. if (key) {
  4395. const element = getFirstHeadElement("h1")
  4396. if (element) {
  4397. const title = element.textContent.trim()
  4398. if (title) {
  4399. const meta = { title, type: "user" }
  4400. element.utags = { key, meta }
  4401. matchedNodesSet.add(element)
  4402. }
  4403. }
  4404. }
  4405. key = getVideoUrl(location.href)
  4406. if (key) {
  4407. const element = getFirstHeadElement("h1")
  4408. if (element) {
  4409. const title = element.textContent.trim()
  4410. const target = element.parentElement.parentElement
  4411. if (title) {
  4412. const meta = { title, type: "video" }
  4413. target.utags = { key, meta }
  4414. target.dataset.utags_node_type = "link"
  4415. matchedNodesSet.add(target)
  4416. }
  4417. }
  4418. }
  4419. key = getNoteUrl(location.href)
  4420. if (key) {
  4421. const element = getFirstHeadElement("h1")
  4422. if (element) {
  4423. const title = element.textContent.trim()
  4424. if (title) {
  4425. const meta = { title, type: "post" }
  4426. element.utags = { key, meta }
  4427. matchedNodesSet.add(element)
  4428. }
  4429. }
  4430. }
  4431. },
  4432. getStyle: () => douyin_com_default,
  4433. }
  4434. })()
  4435. var podcasts_google_com_default = ""
  4436. var podcasts_google_com_default2 = (() => {
  4437. const prefix3 = "https://podcasts.google.com/"
  4438. function getEpisodeUrl(url, exact = false) {
  4439. if (url.startsWith(prefix3)) {
  4440. const href2 = url.slice(28)
  4441. if (exact) {
  4442. if (/^feed\/\w+\/episode\/\w+(\?.*)?$/.test(href2)) {
  4443. return prefix3 + href2.replace(/^(feed\/\w+\/episode\/\w+).*/, "$1")
  4444. }
  4445. } else if (/^feed\/\w+\/episode\/\w+/.test(href2)) {
  4446. return prefix3 + href2.replace(/^(feed\/\w+\/episode\/\w+).*/, "$1")
  4447. }
  4448. }
  4449. return void 0
  4450. }
  4451. function getFeedUrl(url) {
  4452. if (url.startsWith(prefix3)) {
  4453. const href2 = url.slice(28)
  4454. if (/^feed\/\w+(\?.*)?$/.test(href2)) {
  4455. return prefix3 + href2.replace(/^(feed\/\w+).*/, "$1")
  4456. }
  4457. }
  4458. return void 0
  4459. }
  4460. function getCanonicalUrl2(url) {
  4461. if (url.startsWith(prefix3)) {
  4462. let url2 = getFeedUrl(url)
  4463. if (url2) {
  4464. return url2
  4465. }
  4466. url2 = getEpisodeUrl(url)
  4467. if (url2) {
  4468. return url2
  4469. }
  4470. }
  4471. return url
  4472. }
  4473. return {
  4474. matches: /podcasts\.google\.com/,
  4475. excludeSelectors: [
  4476. ...default_default2.excludeSelectors,
  4477. "header",
  4478. "gm-coplanar-drawer",
  4479. ],
  4480. addExtraMatchedNodes(matchedNodesSet) {
  4481. let key = getEpisodeUrl(location.href)
  4482. if (key) {
  4483. const element = $("h5")
  4484. if (element) {
  4485. const title = element.textContent.trim()
  4486. if (title) {
  4487. const meta = { title, type: "episode" }
  4488. element.utags = { key, meta }
  4489. matchedNodesSet.add(element)
  4490. }
  4491. }
  4492. }
  4493. key = getFeedUrl(location.href)
  4494. if (key) {
  4495. for (const container of $$("[data-encoded-feed]")) {
  4496. if (isVisible(container)) {
  4497. const element = $(
  4498. "div:first-child > div:first-child > div:first-child > div:first-child",
  4499. container
  4500. )
  4501. if (element) {
  4502. const title = element.textContent.trim()
  4503. if (title) {
  4504. const meta = { title, type: "feed" }
  4505. element.utags = { key, meta }
  4506. matchedNodesSet.add(element)
  4507. }
  4508. }
  4509. }
  4510. }
  4511. }
  4512. for (const element of $$('a[role="listitem"]')) {
  4513. const key2 = getEpisodeUrl(element.href)
  4514. const titleElement = $(
  4515. 'div[role="navigation"] div div[role="presentation"]',
  4516. element
  4517. )
  4518. if (key2 && titleElement) {
  4519. const title = titleElement.textContent
  4520. const meta = { title, type: "episode" }
  4521. titleElement.utags = { key: key2, meta }
  4522. titleElement.dataset.utags_node_type = "link"
  4523. matchedNodesSet.add(titleElement)
  4524. }
  4525. }
  4526. for (const element of $$(
  4527. 'a[href^="./feed/"]:not(a[href*="/episode/"])'
  4528. )) {
  4529. if (!isVisible(element)) {
  4530. continue
  4531. }
  4532. const key2 = getFeedUrl(element.href)
  4533. const titleElement = $("div > div", element)
  4534. if (titleElement) {
  4535. const title = titleElement.textContent
  4536. const meta = { title, type: "feed" }
  4537. titleElement.utags = { key: key2, meta }
  4538. titleElement.dataset.utags_node_type = "link"
  4539. matchedNodesSet.add(titleElement)
  4540. }
  4541. }
  4542. },
  4543. getCanonicalUrl: getCanonicalUrl2,
  4544. getStyle: () => podcasts_google_com_default,
  4545. }
  4546. })()
  4547. var rebang_today_default =
  4548. ":not(#a):not(#b):not(#c) .w-screen ul{--utags-list-node-display: flex}:not(#a):not(#b):not(#c) .w-screen ul .flex-1:not(.relative)>.utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul .flex.flex-col.relative .flex-1 .utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul .relative>.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-3);--utags-notag-ul-height: var(--utags-notag-ul-height-3);--utags-notag-ul-position: var(--utags-notag-ul-position-3);--utags-notag-ul-top: var(--utags-notag-ul-top-3);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-3);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-3);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .w-screen ul .flex.flex-col.relative .flex-1 .utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul .flex-1:not(.relative)>.utags_ul_0{--utags-notag-captain-tag-top: 18px}:not(#a):not(#b):not(#c) .w-screen ul .text-base .block+.utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul h1 .utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul li>div.overflow-hidden:nth-of-type(2):not(.relative)>a+.utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul li>a+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-2);--utags-notag-ul-height: var(--utags-notag-ul-height-2);--utags-notag-ul-position: var(--utags-notag-ul-position-2);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-2);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-2);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .w-screen ul .text-base .block+.utags_ul_0{--utags-notag-captain-tag-top: -24px}:not(#a):not(#b):not(#c) .w-screen ul h1 .utags_ul_0{--utags-notag-captain-tag-top: -28px}:not(#a):not(#b):not(#c) .w-screen ul li>a+.utags_ul_0{--utags-notag-captain-tag-left: 26px}:not(#a):not(#b):not(#c) .w-screen ul .flex.flex-col .text-base+.utags_ul_0,:not(#a):not(#b):not(#c) .w-screen ul li>a.text-base+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-4);--utags-notag-ul-height: var(--utags-notag-ul-height-4);--utags-notag-ul-position: var(--utags-notag-ul-position-4);--utags-notag-ul-top: var(--utags-notag-ul-top-4);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-4);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-4);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .w-screen ul li>a.text-base+.utags_ul_0{--utags-notag-captain-tag-top: -10px;--utags-notag-captain-tag-left: 14px}:not(#a):not(#b):not(#c) .w-screen ul .truncate .utags_ul_0{--utags-notag-captain-tag-left: -22px}:not(#a):not(#b):not(#c) aside{--utags-list-node-display: flex}:not(#a):not(#b):not(#c) aside .select-none .utags_ul_0{--utags-notag-captain-tag-left: -22px}:not(#a):not(#b):not(#c) aside .select-none .arco-tag .utags_ul_0{--utags-notag-captain-tag-left: -6px}:not(#a):not(#b):not(#c) #markdown-body.markdown-body a+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-1);--utags-notag-ul-height: var(--utags-notag-ul-height-1);--utags-notag-ul-width: var(--utags-notag-ul-width-1);--utags-notag-ul-position: var(--utags-notag-ul-position-1);--utags-notag-ul-top: var(--utags-notag-ul-top-1);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-1);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-1)}"
  4549. var rebang_today_default2 = (() => {
  4550. const nodeNameMap = {
  4551. 知乎: "zhihu",
  4552. 微博: "weibo",
  4553. IT之家: "ithome",
  4554. 虎扑: "hupu",
  4555. 豆瓣社区: "douban-community",
  4556. 虎嗅: "huxiu",
  4557. 少数派: "sspai",
  4558. 网易新闻: "ne-news",
  4559. 澎湃新闻: "thepaper",
  4560. 小红书: "xiaohongshu",
  4561. "36\u6C2A": "36kr",
  4562. 今日头条: "toutiao",
  4563. 爱范儿: "ifanr",
  4564. 豆瓣书影音: "douban-media",
  4565. 什么值得买: "smzdm",
  4566. 百度: "baidu",
  4567. 百度贴吧: "baidu-tieba",
  4568. 吾爱破解: "52pojie",
  4569. 观风闻: "guancha-user",
  4570. 雪球: "xueqiu",
  4571. 东方财富: "eastmoney",
  4572. 新浪财经: "sina-fin",
  4573. 蓝点网: "landian",
  4574. 小众软件: "appinn",
  4575. 反斗限免: "apprcn",
  4576. NGA社区: "nga",
  4577. 游民星空: "gamersky",
  4578. 喷嚏网: "penti",
  4579. 沙雕新闻: "shadiao-news",
  4580. 抖音: "douyin",
  4581. 哔哩哔哩: "bilibili",
  4582. 直播吧: "zhibo8",
  4583. 掘金: "juejin",
  4584. 技术期刊: "journal-tech",
  4585. 开发者头条: "toutiaoio",
  4586. GitHub: "github",
  4587. AcFun: "acfun",
  4588. 宽带山: "kds",
  4589. V2EX: "v2ex",
  4590. 格隆汇: "gelonghui",
  4591. 第一财经: "diyicaijing",
  4592. InfoQ: "infoq",
  4593. CSDN: "csdn",
  4594. }
  4595. return {
  4596. matches: /rebang\.today/,
  4597. preProcess() {
  4598. const nodes = $$(":not(a) > .arco-tag-content")
  4599. for (const node of nodes) {
  4600. const name = node.textContent
  4601. if (name && !node.closest("a")) {
  4602. const nodeId = nodeNameMap[name]
  4603. if (nodeId) {
  4604. const a = createElement("a", {
  4605. href: "https://rebang.today/home?tab=" + nodeId,
  4606. })
  4607. node.after(a)
  4608. a.append(node)
  4609. }
  4610. }
  4611. }
  4612. },
  4613. listNodesSelectors: [
  4614. ".w-screen ul:not(.utags_ul) > li",
  4615. "aside .w-full .select-none",
  4616. ],
  4617. conditionNodesSelectors: [
  4618. '[data-utags_list_node] [data-utags]:not([href^="https://www.v2ex.com/member/"])',
  4619. '[data-utags_list_node] a[href^="https://www.v2ex.com/member/"][data-utags].hidden',
  4620. ],
  4621. excludeSelectors: [
  4622. ...default_default2.excludeSelectors,
  4623. "header",
  4624. ".absolute.rounded-xl",
  4625. "ul li h1 + p a",
  4626. ],
  4627. validMediaSelectors: [
  4628. ".text-text-100",
  4629. ".items-center .rounded-full",
  4630. 'a[href^="https://github.com/"] svg',
  4631. 'a[href^="https://space.bilibili.com/"] img',
  4632. 'a[href^="https://toutiao.io/subjects/"] img',
  4633. "svg.arco-icon",
  4634. ],
  4635. getStyle: () => rebang_today_default,
  4636. }
  4637. })()
  4638. var myanimelist_net_default =
  4639. ":not(#a):not(#b):not(#c) tbody.list-item td.title{--utags-notag-captain-tag-top: -6px;--utags-notag-captain-tag-left: -24px}"
  4640. var myanimelist_net_default2 = (() => {
  4641. return {
  4642. matches: /myanimelist\.net/,
  4643. listNodesSelectors: [],
  4644. conditionNodesSelectors: [],
  4645. excludeSelectors: [
  4646. ...default_default2.excludeSelectors,
  4647. "#headerSmall",
  4648. "#menu",
  4649. "#nav",
  4650. ".header",
  4651. "#status-menu",
  4652. 'a[href^="/sns/register/"]',
  4653. 'a[href^="/logout"]',
  4654. 'a[href*="/membership?"]',
  4655. 'a[href*="/login.php"]',
  4656. 'a[href*="/register.php"]',
  4657. 'a[href*="/dbchanges.php"]',
  4658. 'a[href*="/editprofile.php"]',
  4659. 'a[href*="go=write"]',
  4660. 'a[href^="/ownlist/anime/add?"]',
  4661. '[class*="btn-"]',
  4662. '[class*="icon-"]',
  4663. '[rel*="sponsored"]',
  4664. ],
  4665. getStyle: () => myanimelist_net_default,
  4666. }
  4667. })()
  4668. var douban_com_default = (() => {
  4669. function getCanonicalUrl2(url) {
  4670. if (url.includes("douban.com")) {
  4671. return deleteUrlParameters(url, [
  4672. "ref",
  4673. "dcs",
  4674. "dcm",
  4675. "from",
  4676. "from_",
  4677. "dt_time_source",
  4678. "target_user_id",
  4679. "_dtcc",
  4680. "_i",
  4681. ])
  4682. }
  4683. return url
  4684. }
  4685. return {
  4686. matches: /douban\.com/,
  4687. listNodesSelectors: [],
  4688. conditionNodesSelectors: [],
  4689. excludeSelectors: [
  4690. ...default_default2.excludeSelectors,
  4691. ".tabs",
  4692. 'a[href*="/accounts/login?"]',
  4693. 'a[href*="/passport/login?"]',
  4694. 'a[href*="/register?"]',
  4695. ],
  4696. getCanonicalUrl: getCanonicalUrl2,
  4697. }
  4698. })()
  4699. var pixiv_net_default = ""
  4700. var pixiv_net_default2 = (() => {
  4701. const prefix3 = "https://www.pixiv.net/"
  4702. function getUserProfileUrl(url, exact = false) {
  4703. if (url.startsWith(prefix3)) {
  4704. let href2 = url.slice(22)
  4705. if (href2.startsWith("en/")) {
  4706. href2 = href2.slice(3)
  4707. }
  4708. if (exact) {
  4709. if (/^users\/\d+([?#].*)?$/.test(href2)) {
  4710. return prefix3 + href2.replace(/^(users\/\d+).*/, "$1")
  4711. }
  4712. } else if (/^users\/\d+/.test(href2)) {
  4713. return prefix3 + href2.replace(/^(users\/\d+).*/, "$1")
  4714. }
  4715. }
  4716. return void 0
  4717. }
  4718. return {
  4719. matches: /pixiv\.net/,
  4720. validate(element) {
  4721. const href = element.href
  4722. if (!href.includes("www.pixiv.net")) {
  4723. return true
  4724. }
  4725. const key = getUserProfileUrl(href, true)
  4726. if (key) {
  4727. const title = element.textContent
  4728. if (
  4729. !title ||
  4730. /プロフィールを見る|View Profile|프로필 보기|查看个人资料|查看個人資料|ホーム|Home|홈|主页|首頁/.test(
  4731. title
  4732. )
  4733. ) {
  4734. return false
  4735. }
  4736. const meta = { type: "user", title }
  4737. element.utags = { key, meta }
  4738. element.dataset.utags = element.dataset.utags || ""
  4739. return true
  4740. }
  4741. return false
  4742. },
  4743. addExtraMatchedNodes(matchedNodesSet) {
  4744. const key = getUserProfileUrl(location.href)
  4745. if (key) {
  4746. const element = $("h1")
  4747. if (element) {
  4748. const title = element.textContent.trim()
  4749. if (title) {
  4750. const meta = { title, type: "user" }
  4751. element.utags = { key, meta }
  4752. matchedNodesSet.add(element)
  4753. }
  4754. }
  4755. }
  4756. },
  4757. getStyle: () => pixiv_net_default,
  4758. }
  4759. })()
  4760. var discourse_default =
  4761. ':not(#a):not(#b):not(#c) *+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) *+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) .topic-list{--utags-list-node-display: table-row}:not(#a):not(#b):not(#c) .topic-list .main-link a.title+.utags_ul_1{margin-bottom:4px !important}:not(#a):not(#b):not(#c) .topic-list .discourse-tag+.utags_ul_0{--utags-notag-captain-tag-top: 1px}:not(#a):not(#b):not(#c) .topic-list .discourse-tag+.utags_ul_1{margin-top:3px !important}:not(#a):not(#b):not(#c) .topic-list .posters a:first-of-type+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-left: -6px}:not(#a):not(#b):not(#c) .topic-list .posters a:first-of-type+.utags_ul_1{position:absolute;top:-9999px;margin-top:4px !important;margin-left:-2px !important}:not(#a):not(#b):not(#c) header .header-title a.topic-link+.utags_ul_1{object-position:100% 200%;position:absolute;top:-9999px;margin-bottom:4px !important}:not(#a):not(#b):not(#c) header .header-title a.topic-link[data-utags_flag=inline]+.utags_ul_1{position:unset;margin-bottom:4px !important}:not(#a):not(#b):not(#c) header .badge-category__wrapper+.utags_ul_1{margin-top:2px !important}:not(#a):not(#b):not(#c) #topic-title a.fancy-title+.utags_ul_1{margin-bottom:8px !important}:not(#a):not(#b):not(#c) #topic-title .discourse-tag+.utags_ul_1{margin-top:5px !important}:not(#a):not(#b):not(#c) .topic-body .topic-meta-data .names[data-utags_fit_content="1"]{max-width:max-content !important}:not(#a):not(#b):not(#c) .topic-body .topic-meta-data .names[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .topic-body .topic-meta-data .names a+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;z-index:100}:not(#a):not(#b):not(#c) .post-links-container .post-links .track-link[data-utags_fit_content="1"]{max-width:max-content !important;max-height:max-content !important}:not(#a):not(#b):not(#c) .user-card .names[data-utags_fit_content="1"]{max-width:max-content !important;max-height:max-content !important}:not(#a):not(#b):not(#c) .user-card .names a.user-profile-link+.utags_ul_0{object-position:200% 0%;margin-top:6px !important}:not(#a):not(#b):not(#c) .user-card .names a.user-profile-link+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-left:16px !important}:not(#a):not(#b):not(#c) .column .category-list .category-title-link+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px}:not(#a):not(#b):not(#c) .column .latest-topic-list .main-link .title+.utags_ul_1{margin-bottom:4px !important}:not(#a):not(#b):not(#c) .column .latest-topic-list .main-link .badge-category__wrapper+.utags_ul_1{padding-top:3px !important}:not(#a):not(#b):not(#c) .column .latest-topic-list .main-link .discourse-tag+.utags_ul_1{margin-top:4px !important}:not(#a):not(#b):not(#c) .column .latest-topic-list .topic-poster a+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: 13px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .column .latest-topic-list .topic-poster a+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:17px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .search-container{--utags-list-node-display: flex}:not(#a):not(#b):not(#c) .search-container .search-link[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .search-container .search-link[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .search-container .search-link+.utags_ul_1{object-position:0% 0%;position:absolute;top:-9999px;margin-top:-14px !important}:not(#a):not(#b):not(#c) .search-container .search-results .author a+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: 13px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .search-container .search-results .author a+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:17px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .user-info .user-detail .name-line a[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .user-info .user-detail .name-line a[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .bookmark-list.topic-list tr a.avatar+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: 6px}:not(#a):not(#b):not(#c) .bookmark-list.topic-list tr a.avatar+.utags_ul_1{position:absolute;top:-9999px;margin-top:10px !important}:not(#a):not(#b):not(#c) .user-content .user-stream-item__header a.avatar-link+.utags_ul_0,:not(#a):not(#b):not(#c) .user-content .filter-1 .post-list-item .post-list-item__header a.avatar-link+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -4px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .user-content .user-stream-item__header a.avatar-link+.utags_ul_1,:not(#a):not(#b):not(#c) .user-content .filter-1 .post-list-item .post-list-item__header a.avatar-link+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:2px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .search-menu .results{position:relative}:not(#a):not(#b):not(#c) .search-menu .results .search-link+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -14px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .user-profile-names [data-utags][data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .user-profile-names [data-utags][data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .leaderboard .winner{padding-bottom:50px}:not(#a):not(#b):not(#c) .leaderboard .winner .winner__avatar[data-user-card]+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -56px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .leaderboard .winner .winner__avatar[data-user-card]+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:-56px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .notification a[data-utags_fit_content="1"]{display:inline-flex !important;width:fit-content !important}:not(#a):not(#b):not(#c) .notification a[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) .notification a+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:-6px !important;margin-left:42px !important}:not(#a):not(#b):not(#c) [data-utags_list_node]:last-of-type{display:var(--utags-list-node-display) !important}:not(#a):not(#b):not(#c) .user-menu.revamped .menu-tabs-container{z-index:91;background-color:var(--secondary)}.mobile-view:not(#a):not(#b):not(#c) .topic-list a[data-user-card]+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: 14px;--utags-notag-captain-tag-left: -8px}.mobile-view:not(#a):not(#b):not(#c) .topic-list a[data-user-card]+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:18px !important;margin-left:-4px !important;max-width:58px !important}.mobile-view:not(#a):not(#b):not(#c) .topic-body .topic-meta-data .names a+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -4px;--utags-notag-captain-tag-left: -4px}.mobile-view:not(#a):not(#b):not(#c) .topic-body .topic-meta-data .names a+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;z-index:100}'
  4762. var discourse_default2 = (() => {
  4763. const prefix3 = location.origin + "/"
  4764. const getUserProfileUrl = (url, exact = false) => {
  4765. if (url.startsWith(prefix3)) {
  4766. const href2 = url.slice(prefix3.length).toLowerCase()
  4767. if (exact) {
  4768. if (/^u\/[\w.-]+([?#].*)?$/.test(href2)) {
  4769. return prefix3 + href2.replace(/^(u\/[\w.-]+).*/, "$1")
  4770. }
  4771. } else if (/^u\/[\w.-]+/.test(href2)) {
  4772. return prefix3 + href2.replace(/^(u\/[\w.-]+).*/, "$1")
  4773. }
  4774. }
  4775. return void 0
  4776. }
  4777. function getPostUrl(url, exact = false) {
  4778. if (url.startsWith(prefix3)) {
  4779. const href2 = url.slice(prefix3.length).toLowerCase()
  4780. if (exact) {
  4781. if (/^t\/[^/]+\/\d+(\/\d+)?([?#].*)?$/.test(href2)) {
  4782. return prefix3 + href2.replace(/^(t\/[^/]+\/\d+).*/, "$1")
  4783. }
  4784. } else if (/^t\/[^/]+\/\d+?/.test(href2)) {
  4785. return prefix3 + href2.replace(/^(t\/[^/]+\/\d+).*/, "$1")
  4786. }
  4787. }
  4788. return void 0
  4789. }
  4790. function getCategoryUrl(url, exact = false) {
  4791. if (url.startsWith(prefix3)) {
  4792. const href2 = url.slice(prefix3.length).toLowerCase()
  4793. if (exact) {
  4794. if (/^c\/[\w-]+(\/[\w-]+)?\/\d+([?#].*)?$/.test(href2)) {
  4795. return (
  4796. prefix3 + href2.replace(/^(c\/[\w-]+(\/[\w-]+)?\/\d+).*/, "$1")
  4797. )
  4798. }
  4799. } else if (/^c\/[\w-]+(\/[\w-]+)?\/\d+?/.test(href2)) {
  4800. return prefix3 + href2.replace(/^(c\/[\w-]+(\/[\w-]+)?\/\d+).*/, "$1")
  4801. }
  4802. }
  4803. return void 0
  4804. }
  4805. function getTagUrl(url, exact = false) {
  4806. if (url.startsWith(prefix3)) {
  4807. const href2 = url.slice(prefix3.length).toLowerCase()
  4808. if (exact) {
  4809. if (/^tag\/[^/?#]+([?#].*)?$/.test(href2)) {
  4810. return prefix3 + href2.replace(/^(tag\/[^/?#]+).*/, "$1")
  4811. }
  4812. } else if (/^tag\/[^/?#]+?/.test(href2)) {
  4813. return prefix3 + href2.replace(/^(tag\/[^/?#]+).*/, "$1")
  4814. }
  4815. }
  4816. return void 0
  4817. }
  4818. return {
  4819. matches:
  4820. /meta\.discourse\.org|linux\.do|meta\.appinn\.net|community\.openai\.com|community\.cloudflare\.com|community\.wanikani\.com|forum\.cursor\.com/,
  4821. preProcess() {
  4822. setVisitedAvailable(true)
  4823. },
  4824. listNodesSelectors: [
  4825. ".topic-list .topic-list-body tr",
  4826. ".topic-area .topic-post",
  4827. ".search-results .fps-result",
  4828. ".column .latest-topic-list .latest-topic-list-item",
  4829. ],
  4830. conditionNodesSelectors: [
  4831. ".topic-list .topic-list-body tr .title",
  4832. ".topic-list .topic-list-body tr .badge-category__wrapper",
  4833. ".topic-list .topic-list-body tr .discourse-tag",
  4834. ".topic-list .topic-list-body tr .posters a:first-of-type",
  4835. ".mobile-view .topic-list a[data-user-card]",
  4836. ".topic-area .topic-post:nth-of-type(n+2) .topic-meta-data:not(.embedded-reply) .names a",
  4837. ".search-results .fps-result .search-link",
  4838. ".search-results .fps-result .badge-category__wrapper",
  4839. ".search-results .fps-result .discourse-tag",
  4840. ".column .latest-topic-list .latest-topic-list-item .main-link .title",
  4841. ".column .latest-topic-list .latest-topic-list-item .main-link .badge-category__wrapper",
  4842. ".column .latest-topic-list .latest-topic-list-item .main-link .discourse-tag",
  4843. ],
  4844. validate(element) {
  4845. const href = element.href
  4846. if (!href.startsWith(prefix3)) {
  4847. return true
  4848. }
  4849. let key = getUserProfileUrl(href, true)
  4850. if (key) {
  4851. const titleElement = $("span.username", element)
  4852. const title = getTrimmedTitle(titleElement || element)
  4853. if (
  4854. !title &&
  4855. !element.closest(".topic-list tr .posters a:first-of-type") &&
  4856. !element.closest(".bookmark-list tr a.avatar") && // https://linux.do/u/neo/activity/reactions
  4857. !element.closest(
  4858. ".user-content .user-stream-item__header a.avatar-link"
  4859. ) && // https://linux.do/u/neo/activity/likes-given
  4860. !element.closest(
  4861. ".user-content .filter-1 .post-list-item .post-list-item__header a.avatar-link"
  4862. ) &&
  4863. !element.closest(".column .latest-topic-list .topic-poster a") &&
  4864. !element.closest(".search-results .author a")
  4865. ) {
  4866. return false
  4867. }
  4868. const meta = { type: "user", title }
  4869. element.utags = { key, meta }
  4870. element.dataset.utags = element.dataset.utags || ""
  4871. if (element.closest(".topic-body .names a")) {
  4872. element.dataset.utags_position_selector = ".topic-body .names"
  4873. } else if (element.closest(".user-card .names a")) {
  4874. element.dataset.utags_position_selector = ".user-card .names"
  4875. } else if ($("span.username", element)) {
  4876. element.dataset.utags_position_selector = "span.username"
  4877. }
  4878. return true
  4879. }
  4880. key = getPostUrl(href)
  4881. if (key) {
  4882. const title = element.textContent.trim()
  4883. if (
  4884. element.closest(".mobile-view .topic-list a[data-user-card]") &&
  4885. element.dataset.userCard
  4886. ) {
  4887. const title2 = element.dataset.userCard
  4888. key = prefix3 + "u/" + title2.toLowerCase()
  4889. const meta2 = { type: "user", title: title2 }
  4890. element.utags = { key, meta: meta2 }
  4891. element.dataset.utags = element.dataset.utags || ""
  4892. return true
  4893. }
  4894. if (!title) {
  4895. return false
  4896. }
  4897. if (
  4898. element.closest("header .topic-link") &&
  4899. getComputedStyle(element).display === "inline"
  4900. ) {
  4901. element.dataset.utags_flag = "inline"
  4902. }
  4903. const meta = { type: "post", title }
  4904. element.utags = { key, meta }
  4905. markElementWhetherVisited(key, element)
  4906. element.dataset.utags = element.dataset.utags || ""
  4907. return true
  4908. }
  4909. key = getCategoryUrl(href)
  4910. if (key) {
  4911. const title = element.textContent.trim()
  4912. if (!title) {
  4913. return false
  4914. }
  4915. const meta = { type: "category", title }
  4916. element.utags = { key, meta }
  4917. if (element.closest(".column .category-list .category-title-link")) {
  4918. element.dataset.utags_position_selector =
  4919. ".category-text-title .category-name"
  4920. }
  4921. return true
  4922. }
  4923. key = getTagUrl(href)
  4924. if (key) {
  4925. const title = element.textContent.trim()
  4926. if (!title) {
  4927. return false
  4928. }
  4929. const meta = { type: "tag", title }
  4930. element.utags = { key, meta }
  4931. return true
  4932. }
  4933. return true
  4934. },
  4935. excludeSelectors: [
  4936. ".topic-map",
  4937. ".names .second",
  4938. ".post-activity",
  4939. ".topic-last-activity",
  4940. ".topic-item-stats .activity",
  4941. ".topic-post-badges",
  4942. ".topic-excerpt",
  4943. ".topic-list-category-expert-tags",
  4944. ".list-vote-count",
  4945. ".post-date",
  4946. ".category__badges",
  4947. ".badge-posts",
  4948. ".topic-timeline",
  4949. ".with-timeline",
  4950. ".sidebar-wrapper",
  4951. ".topic-meta-data .post-link-arrow",
  4952. "#skip-link",
  4953. "#navigation-bar",
  4954. ".user-navigation",
  4955. ".search-menu",
  4956. "footer.category-topics-count",
  4957. '[role="tablist"]',
  4958. ".nav.nav-pills",
  4959. ".btn",
  4960. ".custom-header-links",
  4961. ".chat-time",
  4962. ],
  4963. validMediaSelectors: [
  4964. "a img.emoji",
  4965. "a svg.svg-string",
  4966. ".category-title-link",
  4967. ".topic-list tr .posters a:first-of-type",
  4968. ".search-results .author a .avatar",
  4969. ],
  4970. addExtraMatchedNodes(matchedNodesSet) {
  4971. var _a
  4972. const isDarkMode =
  4973. doc.documentElement.dataset.themeType === "dark" || // linux.do
  4974. ((_a = $("header picture > source")) == null ? void 0 : _a.media) ===
  4975. "all"
  4976. doc.documentElement.dataset.utags_darkmode = isDarkMode ? "1" : "0"
  4977. let key = getUserProfileUrl(location.href)
  4978. if (key) {
  4979. let index = 0
  4980. for (const element2 of $$(
  4981. ".user-profile-names .username,.user-profile-names .user-profile-names__primary,.user-profile-names .user-profile-names__secondary"
  4982. )) {
  4983. index++
  4984. if (key !== element2.dataset.utags_key || index === 2) {
  4985. delete element2.dataset.utags
  4986. delete element2.utags
  4987. }
  4988. }
  4989. const element =
  4990. $(".user-profile-names .username") ||
  4991. $(
  4992. ".user-profile-names .user-profile-names__primary,.user-profile-names .user-profile-names__secondary"
  4993. )
  4994. if (element) {
  4995. const title = element.textContent.trim()
  4996. if (title) {
  4997. const meta = { title, type: "user" }
  4998. element.utags = { key, meta }
  4999. element.dataset.utags_key = key
  5000. matchedNodesSet.add(element)
  5001. }
  5002. }
  5003. }
  5004. key = getPostUrl(location.href)
  5005. if (key) {
  5006. addVisited(key)
  5007. }
  5008. for (const element of $$(".leaderboard div[data-user-card]")) {
  5009. const title = element.dataset.userCard
  5010. if (title) {
  5011. key = prefix3 + "u/" + title.toLowerCase()
  5012. const meta = { type: "user", title }
  5013. element.utags = { key, meta }
  5014. element.dataset.utags = element.dataset.utags || ""
  5015. element.dataset.utags_node_type = "link"
  5016. element.dataset.utags_position_selector = element.closest(".winner")
  5017. ? ".winner"
  5018. : ".user__name"
  5019. matchedNodesSet.add(element)
  5020. }
  5021. }
  5022. for (const element of $$(".chat-message span[data-user-card]")) {
  5023. const title = element.dataset.userCard
  5024. if (title) {
  5025. key = prefix3 + "u/" + title.toLowerCase()
  5026. const meta = { type: "user", title }
  5027. element.utags = { key, meta }
  5028. element.dataset.utags = element.dataset.utags || ""
  5029. element.dataset.utags_node_type = "link"
  5030. matchedNodesSet.add(element)
  5031. }
  5032. }
  5033. },
  5034. getStyle: () => discourse_default,
  5035. }
  5036. })()
  5037. var nga_cn_default = ""
  5038. var nga_cn_default2 = (() => {
  5039. const prefix3 = location.origin + "/"
  5040. function getUserProfileUrl(url) {
  5041. if (url.startsWith(prefix3)) {
  5042. const href2 = url.slice(prefix3.length).toLowerCase()
  5043. if (/^nuke\.php\?func=ucp&uid=\d+/.test(href2)) {
  5044. return (
  5045. prefix3 + href2.replace(/^(nuke\.php\?func=ucp&uid=\d+).*/, "$1")
  5046. )
  5047. }
  5048. }
  5049. return void 0
  5050. }
  5051. return {
  5052. matches: /bbs\.nga\.cn|nga\.178\.com|ngabbs\.com/,
  5053. validate(element) {
  5054. const href = element.href
  5055. if (!href.startsWith(prefix3)) {
  5056. return true
  5057. }
  5058. const key = getUserProfileUrl(href)
  5059. if (key) {
  5060. const title = element.textContent
  5061. if (!title) {
  5062. return false
  5063. }
  5064. const meta = { type: "user", title }
  5065. element.utags = { key, meta }
  5066. element.dataset.utags = element.dataset.utags || ""
  5067. return true
  5068. }
  5069. return false
  5070. },
  5071. excludeSelectors: [
  5072. ...default_default2.excludeSelectors,
  5073. ".xxxxxxxxxx",
  5074. ".xxxxxxxxxx",
  5075. ],
  5076. addExtraMatchedNodes(matchedNodesSet) {
  5077. const key = getUserProfileUrl(location.href)
  5078. if (key) {
  5079. const label = $(
  5080. "#ucpuser_info_blockContent > div > span > div:nth-child(2) > div:nth-child(3) > label"
  5081. )
  5082. if (label) {
  5083. const title = label.textContent.trim()
  5084. if (title === "\u7528\u2002\u6237\u2002\u540D") {
  5085. const element = label.nextElementSibling
  5086. if (element) {
  5087. const title2 = element.textContent.trim()
  5088. if (title2) {
  5089. const meta = { title: title2, type: "user" }
  5090. element.utags = { key, meta }
  5091. matchedNodesSet.add(element)
  5092. }
  5093. }
  5094. }
  5095. }
  5096. }
  5097. },
  5098. getStyle: () => nga_cn_default,
  5099. }
  5100. })()
  5101. var dlsite_com_default =
  5102. ':not(#a):not(#b):not(#c) *+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) *+.utags_ul_1{object-position:0% 200%;background-color:var(--utags-captain-tag-background-color) !important;border-radius:3px !important;--utags-emoji-tag-background-color: #fff0}:not(#a):not(#b):not(#c) .n_worklist a.work_name,:not(#a):not(#b):not(#c) .n_worklist dt.work_name,:not(#a):not(#b):not(#c) .recommend_list a.work_name,:not(#a):not(#b):not(#c) .recommend_list dt.work_name,:not(#a):not(#b):not(#c) .genre_ranking a.work_name,:not(#a):not(#b):not(#c) .genre_ranking dt.work_name{width:fit-content}:not(#a):not(#b):not(#c) .n_worklist a.work_name+.utags_ul_0,:not(#a):not(#b):not(#c) .n_worklist dt.work_name+.utags_ul_0,:not(#a):not(#b):not(#c) .recommend_list a.work_name+.utags_ul_0,:not(#a):not(#b):not(#c) .recommend_list dt.work_name+.utags_ul_0,:not(#a):not(#b):not(#c) .genre_ranking a.work_name+.utags_ul_0,:not(#a):not(#b):not(#c) .genre_ranking dt.work_name+.utags_ul_0{object-position:200% 0%}:not(#a):not(#b):not(#c) .n_worklist .maker_name,:not(#a):not(#b):not(#c) .recommend_list .maker_name,:not(#a):not(#b):not(#c) .genre_ranking .maker_name{white-space:wrap;-webkit-line-clamp:unset;height:unset}:not(#a):not(#b):not(#c) h1#work_name[data-utags_fit_content="1"]{max-width:max-content !important}'
  5103. var dlsite_com_default2 = (() => {
  5104. const prefix3 = "https://www.dlsite.com/"
  5105. function getProductUrl(url) {
  5106. if (url.startsWith(prefix3)) {
  5107. const href2 = url.slice(prefix3.length)
  5108. if (href2.includes("=/product_id/")) {
  5109. return prefix3 + href2.replace(/^(.+\.html).*/, "$1")
  5110. }
  5111. }
  5112. return void 0
  5113. }
  5114. function getMakerUrl(url) {
  5115. if (url.startsWith(prefix3)) {
  5116. const href2 = url.slice(prefix3.length)
  5117. if (href2.includes("/profile/=/maker_id/")) {
  5118. return prefix3 + href2.replace(/^(.+\.html).*/, "$1")
  5119. }
  5120. }
  5121. return void 0
  5122. }
  5123. return {
  5124. matches: /dlsite\.com/,
  5125. validate(element) {
  5126. if (element.tagName !== "A") {
  5127. return true
  5128. }
  5129. const href = element.href
  5130. if (!href.startsWith(prefix3)) {
  5131. return true
  5132. }
  5133. if (href.includes("/=/")) {
  5134. return true
  5135. }
  5136. return false
  5137. },
  5138. map(element) {
  5139. if (
  5140. element.tagName === "A" &&
  5141. element.closest(
  5142. ".n_worklist .work_name,.recommend_list dt.work_name,.genre_ranking .work_name"
  5143. )
  5144. ) {
  5145. const key = getProductUrl(element.href)
  5146. const title = element.textContent.trim()
  5147. if (!key || !title) {
  5148. return
  5149. }
  5150. const parentElement = element.parentElement
  5151. const meta = { title }
  5152. parentElement.utags = { key, meta }
  5153. parentElement.dataset.utags_node_type = "link"
  5154. return parentElement
  5155. }
  5156. },
  5157. excludeSelectors: [
  5158. ...default_default2.excludeSelectors,
  5159. "header",
  5160. "#top_header",
  5161. "#header",
  5162. ".topicpath",
  5163. ".link_dl_ch",
  5164. ".floating_cart_box",
  5165. "#work_buy_box_wrapper",
  5166. ".pagetop_block",
  5167. ".matome_btn",
  5168. ".review_all",
  5169. ".review_report",
  5170. ".work_cart",
  5171. ".work_favorite",
  5172. ".title_01",
  5173. ".search_more",
  5174. ".btn_category_sample",
  5175. ".btn_cart",
  5176. ".btn_favorite",
  5177. ".btn_follow",
  5178. ".btn_default",
  5179. ".btn_sample",
  5180. ".left_module",
  5181. ".more_work_btn",
  5182. ".heading_link",
  5183. ".work_edition",
  5184. ".work_btn_list",
  5185. ".trans_work_btn",
  5186. ".work_feature",
  5187. ".work_review",
  5188. ".work_rating",
  5189. ".work_category",
  5190. ".work_btn_link",
  5191. ".sort_box",
  5192. ".search_condition_box",
  5193. ".global_pagination",
  5194. ".page_bottom_link",
  5195. ".trial_download",
  5196. ".btn_trial",
  5197. ".work_win_only",
  5198. ".cp_overview_btn",
  5199. ".cp_overview_list",
  5200. ".option_tab_item",
  5201. ".dc_work_group_footer",
  5202. ".new_worklist_more",
  5203. "#work_win_only",
  5204. "#index2_header",
  5205. ".floor_link",
  5206. ".floor_link_creator",
  5207. ".floor_guide",
  5208. ".l-header",
  5209. ".hd_drawer",
  5210. ".index_header",
  5211. ".index_footer",
  5212. ".left_module_comipo",
  5213. "div#left",
  5214. ".footer_floor_nav",
  5215. ".prof_label_list",
  5216. ".type_btn",
  5217. ],
  5218. addExtraMatchedNodes(matchedNodesSet) {
  5219. let key = getProductUrl(location.href)
  5220. if (key) {
  5221. const element = $("h1#work_name")
  5222. if (element) {
  5223. const title = element.textContent.trim()
  5224. if (title) {
  5225. const meta = { title }
  5226. element.utags = { key, meta }
  5227. element.dataset.utags_node_type = "link"
  5228. matchedNodesSet.add(element)
  5229. }
  5230. }
  5231. }
  5232. key = getMakerUrl(location.href)
  5233. if (key) {
  5234. const element = $(".prof_maker_name")
  5235. if (element) {
  5236. const title = element.textContent.trim()
  5237. if (title) {
  5238. const meta = { title }
  5239. element.utags = { key, meta }
  5240. element.dataset.utags_node_type = "link"
  5241. matchedNodesSet.add(element)
  5242. }
  5243. }
  5244. }
  5245. },
  5246. getStyle: () => dlsite_com_default,
  5247. }
  5248. })()
  5249. var keylol_com_default =
  5250. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .frame-tab .dxb_bc .module{position:relative}:not(#a):not(#b):not(#c) .favatar .pi{height:unset}:not(#a):not(#b):not(#c) .ratl td:first-of-type{white-space:normal}"
  5251. var keylol_com_default2 = (() => {
  5252. const prefix3 = location.origin + "/"
  5253. function getUserProfileUrl(url, exact = false) {
  5254. if (url.startsWith(prefix3)) {
  5255. const href2 = url.slice(prefix3.length).toLowerCase()
  5256. if (exact) {
  5257. if (/^\?\d+(#.*)?$/.test(href2)) {
  5258. return (
  5259. prefix3 + href2.replace(/^\?(\d+).*/, "home.php?mod=space&uid=$1")
  5260. )
  5261. }
  5262. if (/^suid-\d+(#.*)?$/.test(href2)) {
  5263. return (
  5264. prefix3 +
  5265. href2.replace(/^suid-(\d+).*/, "home.php?mod=space&uid=$1")
  5266. )
  5267. }
  5268. if (/^home\.php\?mod=space&uid=\d+(#.*)?$/.test(href2)) {
  5269. return (
  5270. prefix3 +
  5271. href2.replace(
  5272. /^home\.php\?mod=space&uid=(\d+).*/,
  5273. "home.php?mod=space&uid=$1"
  5274. )
  5275. )
  5276. }
  5277. } else if (/^u\/[\w.-]+/.test(href2)) {
  5278. return prefix3 + href2.replace(/^(u\/[\w.-]+).*/, "$1")
  5279. }
  5280. }
  5281. return void 0
  5282. }
  5283. return {
  5284. matches: /keylol\.com/,
  5285. validate(element) {
  5286. const href = element.href
  5287. if (!href.startsWith(prefix3)) {
  5288. return true
  5289. }
  5290. const key = getUserProfileUrl(href, true)
  5291. if (key) {
  5292. const title = element.textContent
  5293. if (!title) {
  5294. return false
  5295. }
  5296. const meta = { type: "user", title }
  5297. element.utags = { key, meta }
  5298. element.dataset.utags = element.dataset.utags || ""
  5299. return true
  5300. }
  5301. return false
  5302. },
  5303. excludeSelectors: [
  5304. ...default_default2.excludeSelectors,
  5305. "nav",
  5306. "header",
  5307. "#pgt",
  5308. "#fd_page_bottom",
  5309. "#visitedforums",
  5310. "#pt",
  5311. ],
  5312. getStyle: () => keylol_com_default,
  5313. }
  5314. })()
  5315. var tampermonkey_net_cn_default =
  5316. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) .favatar .authi a+.utags_ul_1{position:absolute;top:-9999px;z-index:100;margin-top:0px !important;margin-left:-64px !important}:not(#a):not(#b):not(#c) .comiis_irbox a+.utags_ul_0{object-position:100% 0%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .comiis_irbox a+.utags_ul_1{object-position:0% 0%;position:absolute;top:-9999px;z-index:100;margin-top:18px !important;margin-left:0px !important}"
  5317. var tampermonkey_net_cn_default2 = (() => {
  5318. const prefix3 = "https://bbs.tampermonkey.net.cn/"
  5319. function getCanonicalUrl2(url) {
  5320. if (url.startsWith(prefix3)) {
  5321. let href2 = getUserProfileUrl(url, true)
  5322. if (href2) {
  5323. return href2
  5324. }
  5325. href2 = getPostUrl(url, true)
  5326. if (href2) {
  5327. return href2
  5328. }
  5329. }
  5330. return url
  5331. }
  5332. function getUserProfileUrl(url, exact = false) {
  5333. if (url.startsWith(prefix3)) {
  5334. url = deleteUrlParameters(url, "do")
  5335. const href2 = url.slice(prefix3.length).toLowerCase()
  5336. if (exact) {
  5337. if (/^\?\d+(#.*)?$/.test(href2)) {
  5338. return (
  5339. prefix3 + href2.replace(/^\?(\d+).*/, "home.php?mod=space&uid=$1")
  5340. )
  5341. }
  5342. if (/^space-uid-\d+\.html([?#].*)?$/.test(href2)) {
  5343. return (
  5344. prefix3 +
  5345. href2.replace(/^space-uid-(\d+).*/, "home.php?mod=space&uid=$1")
  5346. )
  5347. }
  5348. if (/^home\.php\?mod=space&uid=\d+(#.*)?$/.test(href2)) {
  5349. return (
  5350. prefix3 +
  5351. href2.replace(
  5352. /^home\.php\?mod=space&uid=(\d+).*/,
  5353. "home.php?mod=space&uid=$1"
  5354. )
  5355. )
  5356. }
  5357. } else if (/^u\/[\w.-]+/.test(href2)) {
  5358. return prefix3 + href2.replace(/^(u\/[\w.-]+).*/, "$1")
  5359. }
  5360. }
  5361. return void 0
  5362. }
  5363. function getPostUrl(url) {
  5364. if (url.startsWith(prefix3)) {
  5365. const href2 = url.slice(prefix3.length).toLowerCase()
  5366. if (/^thread(?:-\d+){3}\.html([?#].*)?$/.test(href2)) {
  5367. return (
  5368. prefix3 +
  5369. href2.replace(/^thread-(\d+).*/, "forum.php?mod=viewthread&tid=$1")
  5370. )
  5371. }
  5372. if (/^forum\.php\?mod=redirect&tid=\d+([&#].*)?$/.test(href2)) {
  5373. return (
  5374. prefix3 +
  5375. href2.replace(
  5376. /^forum\.php\?mod=redirect&tid=(\d+).*/,
  5377. "forum.php?mod=viewthread&tid=$1"
  5378. )
  5379. )
  5380. }
  5381. if (/^forum\.php\?mod=viewthread&tid=\d+(#.*)?$/.test(href2)) {
  5382. return (
  5383. prefix3 +
  5384. href2.replace(
  5385. /^forum\.php\?mod=viewthread&tid=(\d+).*/,
  5386. "forum.php?mod=viewthread&tid=$1"
  5387. )
  5388. )
  5389. }
  5390. }
  5391. return void 0
  5392. }
  5393. return {
  5394. matches: /bbs\.tampermonkey\.net\.cn/,
  5395. preProcess() {
  5396. setVisitedAvailable(true)
  5397. },
  5398. listNodesSelectors: [
  5399. //
  5400. "#threadlist table tbody",
  5401. "#postlist .comiis_vrx",
  5402. ],
  5403. conditionNodesSelectors: [
  5404. //
  5405. "#threadlist table tbody h2 a",
  5406. "#threadlist table tbody .km_user a",
  5407. "#postlist .comiis_vrx .authi a",
  5408. ],
  5409. validate(element) {
  5410. const href = element.href
  5411. if (!href.startsWith(prefix3)) {
  5412. return true
  5413. }
  5414. let key = getUserProfileUrl(href, true)
  5415. if (key) {
  5416. let title2 = element.textContent.trim()
  5417. if (!title2) {
  5418. return false
  5419. }
  5420. if (/^https:\/\/bbs\.tampermonkey\.net\.cn\/\?\d+$/.test(title2)) {
  5421. const titleElement = $("#uhd h2")
  5422. if (titleElement) {
  5423. title2 = titleElement.textContent.trim()
  5424. }
  5425. }
  5426. if (
  5427. /^\d+$/.test(title2) &&
  5428. element.parentElement.parentElement.textContent.includes(
  5429. "\u79EF\u5206"
  5430. )
  5431. ) {
  5432. return false
  5433. }
  5434. const meta =
  5435. href === title2 ? { type: "user" } : { type: "user", title: title2 }
  5436. element.utags = { key, meta }
  5437. element.dataset.utags = element.dataset.utags || ""
  5438. return true
  5439. }
  5440. key = getPostUrl(href)
  5441. if (key) {
  5442. const title2 = element.textContent.trim()
  5443. if (!title2) {
  5444. return false
  5445. }
  5446. if (
  5447. title2 === "New" ||
  5448. title2 === "\u7F6E\u9876" ||
  5449. /^\d+$/.test(title2) ||
  5450. /^\d{4}(?:-\d{1,2}){2} \d{2}:\d{2}$/.test(title2)
  5451. ) {
  5452. return false
  5453. }
  5454. if ($('span[title^="20"]', element)) {
  5455. return false
  5456. }
  5457. if (
  5458. element.parentElement.textContent.includes(
  5459. "\u6700\u540E\u56DE\u590D\u4E8E"
  5460. )
  5461. ) {
  5462. return false
  5463. }
  5464. const meta =
  5465. href === title2 ? { type: "post" } : { type: "post", title: title2 }
  5466. element.utags = { key, meta }
  5467. markElementWhetherVisited(key, element)
  5468. return true
  5469. }
  5470. const title = element.textContent.trim()
  5471. if (!title) {
  5472. return false
  5473. }
  5474. if (
  5475. title === "New" ||
  5476. title === "\u7F6E\u9876" ||
  5477. /^\d+$/.test(title)
  5478. ) {
  5479. return false
  5480. }
  5481. return true
  5482. },
  5483. excludeSelectors: [
  5484. ...default_default2.excludeSelectors,
  5485. "#hd",
  5486. ".comiis_pgs",
  5487. "#scrolltop",
  5488. "#fd_page_bottom",
  5489. "#visitedforums",
  5490. "#pt",
  5491. ".tps",
  5492. ".pgbtn",
  5493. ".pgs",
  5494. "#f_pst",
  5495. 'a[href*="member.php?mod=logging"]',
  5496. 'a[href*="member.php?mod=register"]',
  5497. 'a[href*="login/oauth/"]',
  5498. 'a[href*="mod=spacecp&ac=usergroup"]',
  5499. 'a[href*="home.php?mod=spacecp"]',
  5500. "#gadmin_menu",
  5501. "#guser_menu",
  5502. "#gupgrade_menu",
  5503. "#gmy_menu",
  5504. ".showmenu",
  5505. "ul.tb.cl",
  5506. ".comiis_irbox_tit",
  5507. "#thread_types",
  5508. "#filter_special_menu",
  5509. 'a[title="RSS"]',
  5510. ".fa_fav",
  5511. ".p_pop",
  5512. ".comiis_topinfo",
  5513. ".bm .bm_h .kmfz",
  5514. "td.num a",
  5515. "td.plc .pi",
  5516. "td.plc .po.hin",
  5517. "td.pls .tns",
  5518. "ul.comiis_o",
  5519. 'a[onclick*="showMenu"]',
  5520. 'a[onclick*="showWindow"]',
  5521. ".toplist_7ree",
  5522. ],
  5523. addExtraMatchedNodes(matchedNodesSet) {
  5524. let key = getUserProfileUrl(location.href)
  5525. if (key) {
  5526. const element =
  5527. $(".user-profile-names .username") ||
  5528. $(
  5529. ".user-profile-names .user-profile-names__primary,.user-profile-names .user-profile-names__secondary"
  5530. )
  5531. if (element) {
  5532. const title = element.textContent.trim()
  5533. if (title) {
  5534. const meta = { title, type: "user" }
  5535. element.utags = { key, meta }
  5536. matchedNodesSet.add(element)
  5537. }
  5538. }
  5539. }
  5540. key = getPostUrl(location.href)
  5541. if (key) {
  5542. addVisited(key)
  5543. const element = $("#thread_subject")
  5544. if (element) {
  5545. const title = element.textContent.trim()
  5546. if (title) {
  5547. const meta = { title, type: "post" }
  5548. element.utags = { key, meta }
  5549. matchedNodesSet.add(element)
  5550. }
  5551. }
  5552. }
  5553. },
  5554. getStyle: () => tampermonkey_net_cn_default,
  5555. getCanonicalUrl: getCanonicalUrl2,
  5556. }
  5557. })()
  5558. var flarum_default =
  5559. ':not(#a):not(#b):not(#c) *+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) *+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) a.DiscussionListItem-main+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) a.DiscussionListItem-author+.utags_ul_0{object-position:0% 0%;--utags-notag-captain-tag-top: -22px}:not(#a):not(#b):not(#c) a.DiscussionListItem-author+.utags_ul_1{object-position:0% 0%;position:absolute;top:-9999px;margin-top:-18px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .DiscussionList--searchResults a.DiscussionListItem-main+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -18px}:not(#a):not(#b):not(#c) .DiscussionList--searchResults a.DiscussionListItem-main+.utags_ul_1{object-position:0% 200%;position:absolute;top:-9999px;margin-top:-14px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .TagTiles a.TagTile-info+.utags_ul_0{object-position:0% 0%}:not(#a):not(#b):not(#c) .TagTiles a.TagTile-info+.utags_ul_1{object-position:0% 0%;position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .TagTiles a.TagTile-lastPostedDiscussion+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) h1.Hero-title[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) h1.Hero-title[data-utags_fit_content="1"] *:not(svg){width:fit-content !important}:not(#a):not(#b):not(#c) h1.Hero-title+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) h1.Hero-title+.utags_ul_1{object-position:200% 50%;position:absolute;top:-9999px;margin-top:0px !important;margin-left:0px !important}:not(#a):not(#b):not(#c) .PostStream .PostStream-item[data-index="0"]{display:block !important}:not(#a):not(#b):not(#c) .UserBio .UserBio-content p{position:relative}'
  5560. var flarum_default2 = (() => {
  5561. const prefix3 = location.origin + "/"
  5562. function getUserProfileUrl(url, exact = false) {
  5563. if (url.startsWith(prefix3)) {
  5564. const href2 = url.slice(prefix3.length).toLowerCase()
  5565. if (exact) {
  5566. if (/^u\/[\w-]+([?#].*)?$/.test(href2)) {
  5567. return prefix3 + href2.replace(/^(u\/[\w-]+).*/, "$1")
  5568. }
  5569. } else if (/^u\/[\w-]+/.test(href2)) {
  5570. return prefix3 + href2.replace(/^(u\/[\w-]+).*/, "$1")
  5571. }
  5572. }
  5573. return void 0
  5574. }
  5575. function getPostUrl(url, exact = false) {
  5576. if (url.startsWith(prefix3)) {
  5577. const href2 = url.slice(prefix3.length).toLowerCase()
  5578. if (exact) {
  5579. if (/^d\/\d+(?:-[^/?]+)?(?:\/\d+)?([?#].*)?$/.test(href2)) {
  5580. return prefix3 + href2.replace(/^(d\/\d+).*/, "$1")
  5581. }
  5582. } else if (/^d\/\d+(?:-[^/?]+)?/.test(href2)) {
  5583. return prefix3 + href2.replace(/^(d\/\d+).*/, "$1")
  5584. }
  5585. }
  5586. return void 0
  5587. }
  5588. function getTagUrl(url, exact = false) {
  5589. if (url.startsWith(prefix3)) {
  5590. const href2 = url.slice(prefix3.length).toLowerCase()
  5591. if (exact) {
  5592. if (/^t\/[\w-]+([?#].*)?$/.test(href2)) {
  5593. return prefix3 + href2.replace(/^(t\/[\w-]+).*/, "$1")
  5594. }
  5595. } else if (/^t\/[\w-]+/.test(href2)) {
  5596. return prefix3 + href2.replace(/^(t\/[\w-]+).*/, "$1")
  5597. }
  5598. }
  5599. return void 0
  5600. }
  5601. return {
  5602. matches:
  5603. /discuss\.flarum\.org|discuss\.flarum\.org\.cn|www\.nodeloc\.com|freesmth\.net|freesmth\.uk|veryfb\.com|kater\.me|bbs\.viva-la-vita\.org/,
  5604. preProcess() {
  5605. setVisitedAvailable(true)
  5606. },
  5607. listNodesSelectors: [
  5608. "ul.DiscussionList-discussions li",
  5609. ".hotDiscussion-content ul li",
  5610. ".PostStream .PostStream-item",
  5611. ],
  5612. conditionNodesSelectors: [
  5613. "ul.DiscussionList-discussions li a",
  5614. ".hotDiscussion-content ul li a",
  5615. ".PostStream .PostStream-item .PostUser-name a",
  5616. ],
  5617. validate(element) {
  5618. const href = element.href
  5619. if (!href.startsWith(prefix3)) {
  5620. return true
  5621. }
  5622. let key = getUserProfileUrl(href, true)
  5623. if (key) {
  5624. const titleElement = $(".GroupList-UserList-user .username", element)
  5625. const title = (titleElement || element).textContent.trim()
  5626. const meta = { type: "user", title }
  5627. element.utags = { key, meta }
  5628. element.dataset.utags = element.dataset.utags || ""
  5629. if (titleElement) {
  5630. element.dataset.utags_position_selector =
  5631. ".GroupList-UserList-user .username"
  5632. } else if (element.closest(".PostUser .PostUser-name")) {
  5633. element.dataset.utags_position_selector = ".PostUser"
  5634. }
  5635. return true
  5636. }
  5637. key = getPostUrl(href, true)
  5638. if (key) {
  5639. const titleElement =
  5640. $(".DiscussionListItem-title", element) ||
  5641. $(".TagTile-lastPostedDiscussion-title", element)
  5642. const title = (titleElement || element).textContent.trim()
  5643. if (!title) {
  5644. return false
  5645. }
  5646. const meta = { type: "post", title }
  5647. element.utags = { key, meta }
  5648. element.dataset.utags = element.dataset.utags || ""
  5649. markElementWhetherVisited(key, element)
  5650. if (titleElement) {
  5651. element.dataset.utags_position_selector = hasClass(
  5652. element,
  5653. "TagTile-lastPostedDiscussion"
  5654. )
  5655. ? "time"
  5656. : ".item-terminalPost"
  5657. }
  5658. return true
  5659. }
  5660. key = getTagUrl(href)
  5661. if (key) {
  5662. const title = element.textContent.trim()
  5663. if (!title) {
  5664. return false
  5665. }
  5666. const meta = { type: "tag", title }
  5667. element.utags = { key, meta }
  5668. element.dataset.utags = element.dataset.utags || ""
  5669. return true
  5670. }
  5671. return true
  5672. },
  5673. excludeSelectors: [
  5674. ...default_default2.excludeSelectors,
  5675. "header.App-header",
  5676. ".sideNav",
  5677. ".PostMention",
  5678. ".Post-mentionedBy",
  5679. ".Post-mentionedBy-preview",
  5680. ".PostMention-preview",
  5681. ".Dropdown-menu",
  5682. ".Button",
  5683. ],
  5684. addExtraMatchedNodes(matchedNodesSet) {
  5685. var _a
  5686. const isDarkMode =
  5687. ((_a = $('meta[name="color-scheme"]')) == null
  5688. ? void 0
  5689. : _a.content) === "dark"
  5690. doc.documentElement.dataset.utags_darkmode = isDarkMode ? "1" : "0"
  5691. let key = getPostUrl(location.href)
  5692. if (key) {
  5693. addVisited(key)
  5694. const element = $(".item-title h1")
  5695. if (element) {
  5696. const title = element.textContent.trim()
  5697. if (title) {
  5698. const meta = { title, type: "post" }
  5699. element.utags = { key, meta }
  5700. element.dataset.utags_node_type = "link"
  5701. matchedNodesSet.add(element)
  5702. markElementWhetherVisited(key, element)
  5703. }
  5704. }
  5705. }
  5706. key = getTagUrl(location.href)
  5707. if (key) {
  5708. const element = $("h1.Hero-title")
  5709. if (element) {
  5710. const title = element.textContent.trim()
  5711. if (title) {
  5712. const meta = { title, type: "tag" }
  5713. element.utags = { key, meta }
  5714. element.dataset.utags_node_type = "link"
  5715. matchedNodesSet.add(element)
  5716. }
  5717. }
  5718. }
  5719. },
  5720. getStyle: () => flarum_default,
  5721. }
  5722. })()
  5723. var nodeseek_com_default =
  5724. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) ul.post-list li.post-list-item{--utags-list-node-display: flex}:not(#a):not(#b):not(#c) ul.post-list li.post-list-item a.post-category+.utags_ul_0{object-position:-100% 50%}:not(#a):not(#b):not(#c) ul.post-list li.post-list-item a.post-category+.utags_ul_1{object-position:-100% 50%;position:absolute;top:-9999px}:not(#a):not(#b):not(#c) .nsk-post-wrapper .author-info ul.utags_ul_1{vertical-align:middle !important}:not(#a):not(#b):not(#c) .nsk-post-wrapper .author-info ul.utags_ul_1 a.utags_text_tag{height:15px !important}:not(#a):not(#b):not(#c) .hover-user-card{z-index:100}"
  5725. var nodeseek_com_default2 = (() => {
  5726. const prefix3 = location.origin + "/"
  5727. function getUserProfileUrl(url, exact = false) {
  5728. if (url.startsWith(prefix3)) {
  5729. const href2 = url.slice(prefix3.length).toLowerCase()
  5730. if (exact) {
  5731. if (/^space\/\d+([?#].*)?$/.test(href2)) {
  5732. return prefix3 + href2.replace(/^(space\/\d+).*/, "$1")
  5733. }
  5734. } else if (/^space\/\d+/.test(href2)) {
  5735. return prefix3 + href2.replace(/^(space\/\d+).*/, "$1")
  5736. }
  5737. }
  5738. return void 0
  5739. }
  5740. function getPostUrl(url, exact = false) {
  5741. if (url.startsWith(prefix3)) {
  5742. const href2 = url.slice(prefix3.length).toLowerCase()
  5743. if (exact) {
  5744. if (/^post-\d+-\d+([?#].*)?$/.test(href2)) {
  5745. return prefix3 + href2.replace(/^(post-\d+)-.*/, "$1") + "-1"
  5746. }
  5747. } else if (/^post-\d+-\d+/.test(href2)) {
  5748. return prefix3 + href2.replace(/^(post-\d+)-.*/, "$1") + "-1"
  5749. }
  5750. }
  5751. return void 0
  5752. }
  5753. function getCategoryUrl(url, exact = false) {
  5754. if (url.startsWith(prefix3)) {
  5755. const href2 = url.slice(prefix3.length).toLowerCase()
  5756. if (exact) {
  5757. if (/^categories\/[\w-]+([?#].*)?$/.test(href2)) {
  5758. return prefix3 + href2.replace(/^(categories\/[\w-]+).*/, "$1")
  5759. }
  5760. } else if (/^categories\/[\w-]+/.test(href2)) {
  5761. return prefix3 + href2.replace(/^(categories\/[\w-]+).*/, "$1")
  5762. }
  5763. }
  5764. return void 0
  5765. }
  5766. return {
  5767. matches: /www\.nodeseek\.com/,
  5768. preProcess() {
  5769. setVisitedAvailable(true)
  5770. },
  5771. listNodesSelectors: [
  5772. "ul.post-list li.post-list-item",
  5773. "ul.comments li.content-item",
  5774. ],
  5775. conditionNodesSelectors: [
  5776. "ul.post-list li.post-list-item .post-title a",
  5777. "ul.post-list li.post-list-item .info-author a",
  5778. "ul.post-list li.post-list-item a.post-category",
  5779. "ul.comments li.content-item a.author-name",
  5780. ],
  5781. validate(element) {
  5782. const href = element.href
  5783. if (!href.startsWith(prefix3)) {
  5784. return true
  5785. }
  5786. let key = getUserProfileUrl(href, true)
  5787. if (key) {
  5788. const title = element.textContent.trim()
  5789. if (!title) {
  5790. return false
  5791. }
  5792. const meta = { type: "user", title }
  5793. element.utags = { key, meta }
  5794. return true
  5795. }
  5796. key = getPostUrl(href, true)
  5797. if (key) {
  5798. const title = element.textContent.trim()
  5799. if (!title || /^#\d+$/.test(title)) {
  5800. return false
  5801. }
  5802. const meta = { type: "post", title }
  5803. element.utags = { key, meta }
  5804. markElementWhetherVisited(key, element)
  5805. return true
  5806. }
  5807. key = getCategoryUrl(href)
  5808. if (key) {
  5809. const title = element.textContent.trim()
  5810. if (!title) {
  5811. return false
  5812. }
  5813. const meta = { type: "category", title }
  5814. element.utags = { key, meta }
  5815. return true
  5816. }
  5817. return true
  5818. },
  5819. excludeSelectors: [
  5820. ...default_default2.excludeSelectors,
  5821. "header",
  5822. '[aria-label="pagination"]',
  5823. 'a[href="/signIn.html"]',
  5824. 'a[href="/register.html"]',
  5825. 'a[href^="/notification"]',
  5826. ".info-last-comment-time",
  5827. ".floor-link",
  5828. ".avatar-wrapper",
  5829. ".select-item",
  5830. ".card-item",
  5831. ".nsk-new-member-board",
  5832. ".hover-user-card .user-stat",
  5833. ".btn",
  5834. ],
  5835. validMediaSelectors: ["svg.iconpark-icon"],
  5836. addExtraMatchedNodes(matchedNodesSet) {
  5837. const isDarkMode = hasClass(doc.body, "dark-layout")
  5838. doc.documentElement.dataset.utags_darkmode = isDarkMode ? "1" : "0"
  5839. let key = getUserProfileUrl(location.href)
  5840. if (key) {
  5841. const element = $("h1.username")
  5842. if (element) {
  5843. const title = element.textContent.trim()
  5844. if (title) {
  5845. const meta = { title, type: "user" }
  5846. element.utags = { key, meta }
  5847. matchedNodesSet.add(element)
  5848. }
  5849. }
  5850. }
  5851. key = getPostUrl(location.href)
  5852. if (key) {
  5853. addVisited(key)
  5854. }
  5855. },
  5856. getStyle: () => nodeseek_com_default,
  5857. }
  5858. })()
  5859. var inoreader_com_default =
  5860. ':not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) .article_tile_footer_feed_title a+.utags_ul_1{position:absolute;top:-9999px;margin-top:-4px !important}:not(#a):not(#b):not(#c) .article_tile[data-utags_list_node^=","] .article_tile_content_wraper{position:unset}:not(#a):not(#b):not(#c) .ar .column_view_title a[data-utags_fit_content="1"],:not(#a):not(#b):not(#c) .article_tile a.article_title_link[data-utags_fit_content="1"],:not(#a):not(#b):not(#c) .article_magazine a.article_magazine_title_link[data-utags_fit_content="1"],:not(#a):not(#b):not(#c) .ar.article_card .article-details a.article_title_link[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .article_full_contents div.article_title+.utags_ul_0{object-position:0% -100%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) .article_full_contents div.article_title+.utags_ul_1{object-position:0% -100%;position:absolute;top:-9999px;margin-top:0px !important}:not(#a):not(#b):not(#c) #search_content a.featured_category+.utags_ul_1{position:absolute;top:-9999px;z-index:100;margin-top:2px !important}:not(#a):not(#b):not(#c) #search_content a.search_feed_article+.utags_ul_1{position:absolute;top:-9999px;z-index:100;margin-top:2px !important}'
  5861. var inoreader_com_default2 = (() => {
  5862. const prefix3 = location.origin + "/"
  5863. function getArticleUrl(url) {
  5864. if (url.startsWith(prefix3)) {
  5865. const href2 = url.slice(prefix3.length).toLowerCase()
  5866. if (/^article\/\w+(-[^?#]*)?([?#].*)?$/.test(href2)) {
  5867. return prefix3 + href2.replace(/^(article\/\w+)-.*/, "$1")
  5868. }
  5869. }
  5870. return void 0
  5871. }
  5872. return {
  5873. matches: /\w+\.inoreader\.com/,
  5874. listNodesSelectors: [".ar"],
  5875. conditionNodesSelectors: [
  5876. ".article_tile .article_tile_footer_feed_title a",
  5877. ".article_tile a.article_title_link",
  5878. ".article_magazine .article_magazine_feed_title a",
  5879. ".article_magazine a.article_magazine_title_link",
  5880. ".ar .column_view_title a",
  5881. ".ar .article_title_wrapper a",
  5882. ".ar.article_card .article_sub_title a",
  5883. ".ar.article_card a.article_title_link",
  5884. ],
  5885. validate(element) {
  5886. const href = element.href
  5887. if (!href.startsWith(prefix3)) {
  5888. return true
  5889. }
  5890. if (element.closest("#search_content .featured_category")) {
  5891. element.dataset.utags_position_selector = "span"
  5892. }
  5893. const key = getArticleUrl(href)
  5894. if (key) {
  5895. const title = element.textContent.trim()
  5896. if (!title) {
  5897. return false
  5898. }
  5899. const meta = { type: "article", title }
  5900. element.utags = { key, meta }
  5901. element.dataset.utags = element.dataset.utags || ""
  5902. if (element.closest(".search_feed_article")) {
  5903. element.dataset.utags_position_selector = "h6"
  5904. }
  5905. return true
  5906. }
  5907. return true
  5908. },
  5909. excludeSelectors: [
  5910. ...default_default2.excludeSelectors,
  5911. "#side-nav",
  5912. 'a[href^="/preferences"]',
  5913. 'a[href^="/upgrade"]',
  5914. 'a[href^="/login"]',
  5915. 'a[href^="/signup"]',
  5916. 'a[href^="/sign_up"]',
  5917. 'a[href^="/forgot-password"]',
  5918. "#preference-section-content",
  5919. "#preference-section-settings",
  5920. ".inno_tabs_tab",
  5921. ".profile_checklist",
  5922. ".gadget_overview_feed_title",
  5923. ".header_name",
  5924. ],
  5925. addExtraMatchedNodes(matchedNodesSet) {
  5926. const key = getArticleUrl(location.href)
  5927. if (key) {
  5928. const element = $(".article_full_contents div.article_title")
  5929. if (element) {
  5930. const title = element.textContent.trim()
  5931. if (title) {
  5932. const meta = { title, type: "article" }
  5933. element.utags = { key, meta }
  5934. matchedNodesSet.add(element)
  5935. }
  5936. }
  5937. }
  5938. },
  5939. postProcess() {
  5940. const isDarkMode = hasClass(doc.body, "theme_dark")
  5941. doc.documentElement.dataset.utags_darkmode = isDarkMode ? "1" : "0"
  5942. },
  5943. getStyle: () => inoreader_com_default,
  5944. }
  5945. })()
  5946. var zhipin_com_default =
  5947. ':not(#a):not(#b):not(#c) *+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) *+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) .sub-li a.job-info+.utags_ul_1{position:absolute;top:-9999px}:not(#a):not(#b):not(#c) .sub-li .sub-li-bottom a+.utags_ul_1{position:absolute;top:-9999px;margin-top:-2px !important}:not(#a):not(#b):not(#c) .hot-company-wrapper a.company-info-top+.utags_ul_1{position:absolute;top:-9999px;margin-top:-16px !important;width:inherit}:not(#a):not(#b):not(#c) .hot-company-wrapper .company-job-item a.job-info+.utags_ul_1{position:absolute;top:-9999px;margin-top:0px !important;width:inherit}:not(#a):not(#b):not(#c) .job-recommend-result .job-info .job-title a.job-name[data-utags_fit_content="1"]{display:inline-block !important;max-width:fit-content !important}:not(#a):not(#b):not(#c) .job-recommend-result .job-info .job-title a.job-name+.utags_ul_1{position:absolute;top:-9999px;margin-top:-2px !important}:not(#a):not(#b):not(#c) .job-recommend-result .job-card-footer a.boss-info+.utags_ul_1{position:absolute;top:-9999px;margin-top:-2px !important}:not(#a):not(#b):not(#c) .search-job-result .job-card-body a.job-card-left+.utags_ul_1{position:absolute;top:-9999px;margin-top:34px !important}:not(#a):not(#b):not(#c) .search-job-result .job-card-body .job-card-right .company-name{max-width:290px;height:unset}:not(#a):not(#b):not(#c) .company-search a.company-info h4[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .company-search a.company-info+.utags_ul_1{position:absolute;top:-9999px;margin-top:34px !important;width:194px}:not(#a):not(#b):not(#c) .company-search a.about-info+.utags_ul_1{position:absolute;top:-9999px;margin-top:-14px !important;width:214px}:not(#a):not(#b):not(#c) .job-banner .info-primary .name[data-utags_fit_content="1"],:not(#a):not(#b):not(#c) .smallbanner .company-info .name[data-utags_fit_content="1"]{display:inline-block !important;width:fit-content !important}:not(#a):not(#b):not(#c) .job-sider .sider-company .company-info a+.utags_ul_1{position:absolute;top:-9999px;margin-top:-2px !important;width:194px}:not(#a):not(#b):not(#c) .job-sider .sider-company [ka=job-detail-brandindustry][data-utags_fit_content="1"]{display:inline-flex !important;max-width:fit-content !important}:not(#a):not(#b):not(#c) .job-sider ul.similar-job-list li>a+.utags_ul_1{position:absolute;top:-9999px;margin-top:0px !important;width:260px}:not(#a):not(#b):not(#c) .job-sider ul.similar-job-list li>a .similar-job-attr{flex-wrap:wrap}:not(#a):not(#b):not(#c) .job-sider ul.similar-job-list li>a .similar-job-attr span.similar-job-company[data-url]+.utags_ul_1{width:100%;order:1}:not(#a):not(#b):not(#c) .job-detail .more-job-section ul.look-job-list{display:flex;flex-wrap:wrap}:not(#a):not(#b):not(#c) .job-detail .more-job-section ul.look-job-list li a{height:unset}:not(#a):not(#b):not(#c) .job-detail .more-job-section ul.look-job-list li a+.utags_ul_1{position:absolute;top:-9999px}:not(#a):not(#b):not(#c) .job-detail .more-job-section ul.look-job-list li .info-company{flex-wrap:wrap}:not(#a):not(#b):not(#c) .job-detail .more-job-section ul.look-job-list li .info-company div[data-url]+.utags_ul_1{width:100%;order:1}:not(#a):not(#b):not(#c) .company-new .company-hotjob a+.utags_ul_1{position:absolute;top:-9999px}:not(#a):not(#b):not(#c) .page-company-position ul.position-job-list .job-title{height:unset;flex-wrap:wrap}:not(#a):not(#b):not(#c) .page-company-position ul.position-job-list .job-title .job-name[data-utags_fit_content="1"]{display:inline-flex !important;max-width:fit-content !important}:not(#a):not(#b):not(#c) .page-company-position ul.position-job-list .job-title .job-name+.utags_ul_1{width:100%;order:1}:not(#a):not(#b):not(#c) .page-company-position ul.similar-job-list{display:flex;flex-wrap:wrap}:not(#a):not(#b):not(#c) .page-company-position ul.similar-job-list .company-info{flex-wrap:wrap}:not(#a):not(#b):not(#c) .page-company-position ul.similar-job-list .company-info a.company-logo+.utags_ul_1{width:100%;order:1}:not(#a):not(#b):not(#c) .job-detail-card{z-index:91}:not(#a):not(#b):not(#c) ul li .sub-li{position:relative}'
  5948. var zhipin_com_default2 = (() => {
  5949. const prefix3 = "https://www.zhipin.com/"
  5950. function getCanonicalUrl2(url) {
  5951. if (url.includes(prefix3)) {
  5952. return url.replace(/[?#].*/, "")
  5953. }
  5954. return url
  5955. }
  5956. function getCompanyUrl(url) {
  5957. if (url.startsWith(prefix3)) {
  5958. const href2 = url.slice(prefix3.length)
  5959. if (/^gongsi\/[\w-~]+\.html/.test(href2)) {
  5960. return prefix3 + href2.replace(/^(gongsi\/[\w-~]+\.html).*/, "$1")
  5961. }
  5962. }
  5963. return void 0
  5964. }
  5965. function getJobDetailUrl(url) {
  5966. if (url.startsWith(prefix3)) {
  5967. const href2 = url.slice(prefix3.length)
  5968. if (/^job_detail\/[\w-~]+\.html/.test(href2)) {
  5969. return prefix3 + href2.replace(/^(job_detail\/[\w-~]+\.html).*/, "$1")
  5970. }
  5971. }
  5972. return void 0
  5973. }
  5974. return {
  5975. matches: /www\.zhipin\.com/,
  5976. listNodesSelectors: [
  5977. ".common-tab-box ul li",
  5978. ".hot-company-wrapper ul li",
  5979. ".hot-company-wrapper ul li .company-job-list li",
  5980. ".job-recommend-result .job-card-wrap",
  5981. ".search-job-result .job-card-wrapper",
  5982. ".history-job-list li",
  5983. ".company-search ul li",
  5984. ".company-hotjob ul li",
  5985. ".page-company-position ul.position-job-list li",
  5986. "ul.similar-job-list li",
  5987. "ul.look-job-list li",
  5988. ],
  5989. conditionNodesSelectors: [
  5990. ".common-tab-box ul li .sub-li a.job-info",
  5991. ".common-tab-box ul li .sub-li-bottom a.user-info",
  5992. ".hot-company-wrapper ul li .company-info-top",
  5993. ".hot-company-wrapper ul li .company-job-list li a.job-info",
  5994. ".job-recommend-result .job-card-wrap .job-info .job-title a.job-name",
  5995. ".job-recommend-result .job-card-wrap .job-card-footer .boss-info",
  5996. ".search-job-result .job-card-wrapper a.job-card-left",
  5997. ".search-job-result .job-card-wrapper .job-card-right .company-name a",
  5998. ".history-job-list li a",
  5999. ".company-search ul li a.company-info",
  6000. ".company-hotjob ul li > a",
  6001. ".page-company-position ul.position-job-list li .job-title .job-name",
  6002. "ul.similar-job-list li a.job-info",
  6003. "ul.similar-job-list li > a",
  6004. "ul.similar-job-list li .company-info a.company-logo",
  6005. "ul.similar-job-list li .similar-job-attr span.similar-job-company[data-url]",
  6006. "ul.look-job-list li > a",
  6007. "ul.look-job-list li .info-company div[data-url]",
  6008. ],
  6009. matchedNodesSelectors: [
  6010. ...default_default2.matchedNodesSelectors,
  6011. ".info-company div[data-url]",
  6012. ".similar-job-list .similar-job-company[data-url]",
  6013. ],
  6014. preProcess() {
  6015. setVisitedAvailable(true)
  6016. for (const element of $$(
  6017. ".info-company div[data-url],.similar-job-list .similar-job-company[data-url]"
  6018. )) {
  6019. if (element.dataset.url) {
  6020. element.href =
  6021. location.origin + element.dataset.url.replace("/job/", "/")
  6022. element.dataset.utags_node_type = "link"
  6023. }
  6024. }
  6025. },
  6026. validate(element) {
  6027. const href = element.href
  6028. if (!href) {
  6029. return false
  6030. }
  6031. if (!href.startsWith(prefix3)) {
  6032. return true
  6033. }
  6034. if (element.closest(".common-tab-box")) {
  6035. element.dataset.utags_ul_type = "ol"
  6036. }
  6037. let key = getCompanyUrl(href)
  6038. if (key) {
  6039. const titleElement = $(
  6040. ".name,.company-info-top h3,.card-desc .title,h4",
  6041. element
  6042. )
  6043. const title = getTrimmedTitle(titleElement || element)
  6044. if (!title) {
  6045. return false
  6046. }
  6047. const meta = { type: "company", title }
  6048. element.utags = { key, meta }
  6049. element.dataset.utags = element.dataset.utags || ""
  6050. if (element.closest(".sub-li-bottom a.user-info")) {
  6051. element.dataset.utags_position_selector = "a > p"
  6052. } else if (element.closest(".company-search a.company-info")) {
  6053. element.dataset.utags_position_selector = "h4"
  6054. }
  6055. return true
  6056. }
  6057. key = getJobDetailUrl(href)
  6058. if (key) {
  6059. const titleElement = $(
  6060. ".job-title .job-name,.job-info-top,.info-primary .name b,.info-job,.similar-job-info,.sub-li-top,a.about-info u.h",
  6061. element
  6062. )
  6063. let title = getTrimmedTitle(titleElement || element)
  6064. if (!title) {
  6065. return false
  6066. }
  6067. title = title.replace(" \u5728\u7EBF ", "")
  6068. const meta = { type: "job-detail", title }
  6069. element.utags = { key, meta }
  6070. element.dataset.utags = element.dataset.utags || ""
  6071. element.dataset.utags_position_selector =
  6072. ".job-title .job-name,.info-primary .name b,.info-job,.similar-job-info,.sub-li-top,a.about-info u.h"
  6073. markElementWhetherVisited(key, element)
  6074. return true
  6075. }
  6076. return true
  6077. },
  6078. excludeSelectors: [
  6079. ...default_default2.excludeSelectors,
  6080. "#header",
  6081. ".look-all",
  6082. ".more-job-btn",
  6083. ".look-more",
  6084. ".all-jobs-hot",
  6085. ".view-more",
  6086. ".link-more",
  6087. "h3:not(.company-name):not(.name)",
  6088. ".compare-btn",
  6089. ".job_pk",
  6090. ".search-hot",
  6091. ".filter-box",
  6092. ".sign-form",
  6093. ".login-card-wrapper",
  6094. ".login-entry-page",
  6095. ".btn",
  6096. ".footer-icon",
  6097. ".company-tab",
  6098. ".school-type-box",
  6099. ".search-condition-wrapper",
  6100. ".filter-select-box",
  6101. 'a[href*="/web/geek/job"]',
  6102. ".page",
  6103. ],
  6104. addExtraMatchedNodes(matchedNodesSet) {
  6105. let key = getCompanyUrl(location.href)
  6106. if (key) {
  6107. const element = $(".company-banner h1")
  6108. if (element) {
  6109. const title = element.childNodes[0].textContent.trim()
  6110. if (title) {
  6111. const meta = { title, type: "company" }
  6112. element.utags = { key, meta }
  6113. matchedNodesSet.add(element)
  6114. }
  6115. }
  6116. }
  6117. key = getJobDetailUrl(location.href)
  6118. if (key) {
  6119. addVisited(key)
  6120. let element = $(".job-banner .info-primary .name")
  6121. if (element) {
  6122. const title = getTrimmedTitle(element)
  6123. if (title) {
  6124. const meta = { title, type: "job-detail" }
  6125. element.utags = { key, meta }
  6126. matchedNodesSet.add(element)
  6127. markElementWhetherVisited(key, element)
  6128. }
  6129. }
  6130. element = $(".smallbanner .company-info .name")
  6131. if (element) {
  6132. const title = getTrimmedTitle(element)
  6133. if (title) {
  6134. const meta = { title, type: "job-detail" }
  6135. element.utags = { key, meta }
  6136. matchedNodesSet.add(element)
  6137. markElementWhetherVisited(key, element)
  6138. }
  6139. }
  6140. }
  6141. },
  6142. postProcess() {
  6143. const isDarkMode = hasClass(doc.body, "theme_dark")
  6144. doc.documentElement.dataset.utags_darkmode = isDarkMode ? "1" : "0"
  6145. },
  6146. getStyle: () => zhipin_com_default,
  6147. getCanonicalUrl: getCanonicalUrl2,
  6148. }
  6149. })()
  6150. var pornhub_com_default =
  6151. ':not(#a):not(#b):not(#c) .usernameWrap .utags_ul_0 .utags_captain_tag{left:-20px}:not(#a):not(#b):not(#c) .usernameWrap .utags_ul_1::before{content:"";display:block}:not(#a):not(#b):not(#c) .vidTitleWrapper .title .utags_ul_0{display:block !important;height:0;position:absolute;top:0}:not(#a):not(#b):not(#c) .vidTitleWrapper .title .utags_ul_0 .utags_captain_tag{background-color:rgba(255,255,255,.8666666667) !important}:not(#a):not(#b):not(#c) .vidTitleWrapper .title .utags_ul_1{display:block !important;height:0;position:absolute;bottom:0}:not(#a):not(#b):not(#c) ul.videos .thumbnail-info-wrapper{position:relative}:not(#a):not(#b):not(#c) ul.videos .thumbnail-info-wrapper .title .utags_ul_0{display:block !important;height:0;position:absolute;top:0}:not(#a):not(#b):not(#c) ul.videos .thumbnail-info-wrapper .title .utags_ul_0 .utags_captain_tag{background-color:rgba(255,255,255,.8666666667) !important}:not(#a):not(#b):not(#c) ul.videos .thumbnail-info-wrapper .title .utags_ul_1{display:block !important;height:0;position:absolute;bottom:0}'
  6152. var pornhub_com_default2 = (() => {
  6153. const prefix3 = "https://www.pornhub.com/"
  6154. function getUserProfileUrl(href, exact = false) {
  6155. if (href.includes("pornhub.com")) {
  6156. const index = href.indexOf("pornhub.com") + 12
  6157. const href2 = href.slice(index)
  6158. if (exact) {
  6159. if (/^(model|users)\/[\w-]+(\?.*)?$/.test(href2)) {
  6160. return prefix3 + href2.replace(/(^(model|users)\/[\w-]+).*/, "$1")
  6161. }
  6162. } else if (/^(model|users)\/[\w-]+/.test(href2)) {
  6163. return prefix3 + href2.replace(/(^(model|users)\/[\w-]+).*/, "$1")
  6164. }
  6165. }
  6166. return void 0
  6167. }
  6168. function getChannelUrl(href, exact = false) {
  6169. if (href.includes("pornhub.com")) {
  6170. const index = href.indexOf("pornhub.com") + 12
  6171. const href2 = href.slice(index)
  6172. if (exact) {
  6173. if (/^channels\/[\w-]+(\?.*)?$/.test(href2)) {
  6174. return prefix3 + href2.replace(/(^channels\/[\w-]+).*/, "$1")
  6175. }
  6176. } else if (/^channels\/[\w-]+/.test(href2)) {
  6177. return prefix3 + href2.replace(/(^channels\/[\w-]+).*/, "$1")
  6178. }
  6179. }
  6180. return void 0
  6181. }
  6182. function getVideoUrl(href) {
  6183. if (href.includes("pornhub.com")) {
  6184. const index = href.indexOf("pornhub.com") + 12
  6185. const href2 = href.slice(index)
  6186. if (/^view_video.php\?viewkey=\w+/.test(href2)) {
  6187. return (
  6188. prefix3 + href2.replace(/(view_video.php\?viewkey=\w+).*/, "$1")
  6189. )
  6190. }
  6191. }
  6192. return void 0
  6193. }
  6194. return {
  6195. matches: /pornhub\.com/,
  6196. validate(element) {
  6197. const hrefAttr = getAttribute(element, "href")
  6198. if (!hrefAttr || hrefAttr === "null" || hrefAttr === "#") {
  6199. return false
  6200. }
  6201. const href = element.href
  6202. let key = getChannelUrl(href, true)
  6203. if (key) {
  6204. const meta = { type: "channel" }
  6205. element.utags = { key, meta }
  6206. return true
  6207. }
  6208. key = getUserProfileUrl(href, true)
  6209. if (key) {
  6210. const meta = { type: "user" }
  6211. element.utags = { key, meta }
  6212. return true
  6213. }
  6214. key = getVideoUrl(href)
  6215. if (key) {
  6216. let title
  6217. const titleElement = $("#video-title", element)
  6218. if (titleElement) {
  6219. title = titleElement.textContent
  6220. }
  6221. const meta = title ? { title, type: "video" } : { type: "video" }
  6222. element.utags = { key, meta }
  6223. return true
  6224. }
  6225. return true
  6226. },
  6227. excludeSelectors: [
  6228. ...default_default2.excludeSelectors,
  6229. ".networkBarWrapper",
  6230. "#headerWrapper",
  6231. "#headerMenuContainer",
  6232. "#mainMenuProfile",
  6233. "#mainMenuAmateurModelProfile",
  6234. "#countryRedirectMessage",
  6235. "aside#leftMenu",
  6236. ".profileSubNav",
  6237. ".subFilterList",
  6238. ".greyButton",
  6239. ".orangeButton",
  6240. ],
  6241. addExtraMatchedNodes(matchedNodesSet) {
  6242. let key = getUserProfileUrl(location.href)
  6243. if (key) {
  6244. const element = $(".name h1")
  6245. if (element) {
  6246. const title = element.textContent.trim()
  6247. if (title) {
  6248. const meta = { title, type: "user" }
  6249. element.utags = { key, meta }
  6250. matchedNodesSet.add(element)
  6251. }
  6252. }
  6253. }
  6254. key = getChannelUrl(location.href)
  6255. if (key) {
  6256. const element = $(".title h1")
  6257. if (element && !$("a", element)) {
  6258. const title = element.textContent.trim()
  6259. if (title) {
  6260. const meta = { title, type: "channel" }
  6261. element.utags = { key, meta }
  6262. matchedNodesSet.add(element)
  6263. }
  6264. }
  6265. }
  6266. key = getVideoUrl(location.href)
  6267. if (key) {
  6268. const element = $("h1.title")
  6269. if (element) {
  6270. const title = element.textContent.trim()
  6271. if (title) {
  6272. const meta = { title, type: "video" }
  6273. element.utags = { key, meta }
  6274. matchedNodesSet.add(element)
  6275. }
  6276. }
  6277. }
  6278. },
  6279. getStyle: () => pornhub_com_default,
  6280. }
  6281. })()
  6282. var e_hentai_org_default =
  6283. ":not(#a):not(#b):not(#c) div.gt a+.utags_ul_0,:not(#a):not(#b):not(#c) div.gtl a+.utags_ul_0,:not(#a):not(#b):not(#c) div.gtw a+.utags_ul_0,:not(#a):not(#b):not(#c) div.gl4e.glname .glink+.utags_ul_0,:not(#a):not(#b):not(#c) .gltm .glname a+.utags_ul_0,:not(#a):not(#b):not(#c) .gltc .glname a+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-3);--utags-notag-ul-height: var(--utags-notag-ul-height-3);--utags-notag-ul-position: var(--utags-notag-ul-position-3);--utags-notag-ul-top: var(--utags-notag-ul-top-3);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-3);--utags-notag-captain-tag-left: 24px;--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap );z-index:200}:not(#a):not(#b):not(#c) div.gl1t a+.utags_ul_0{--utags-notag-ul-disply: var(--utags-notag-ul-disply-4);--utags-notag-ul-height: var(--utags-notag-ul-height-4);--utags-notag-ul-position: var(--utags-notag-ul-position-4);--utags-notag-ul-top: var(--utags-notag-ul-top-4);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-4);--utags-notag-captain-tag-left: 24px;--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}"
  6284. var e_hentai_org_default2 = (() => {
  6285. const prefix3 = "https://e-hentai.org/"
  6286. const prefix22 = "https://exhentai.org/"
  6287. function getPostUrl(url) {
  6288. if (url.startsWith(prefix3)) {
  6289. const href2 = url.slice(21)
  6290. if (/^g\/\w+/.test(href2)) {
  6291. return prefix3 + href2.replace(/^(g\/\w+\/\w+\/).*/, "$1")
  6292. }
  6293. }
  6294. if (url.startsWith(prefix22)) {
  6295. const href2 = url.slice(21)
  6296. if (/^g\/\w+/.test(href2)) {
  6297. return prefix22 + href2.replace(/^(g\/\w+\/\w+\/).*/, "$1")
  6298. }
  6299. }
  6300. return void 0
  6301. }
  6302. function isImageViewUrl(url) {
  6303. if (url.startsWith(prefix3)) {
  6304. const href2 = url.slice(21)
  6305. return /^s\/\w+/.test(href2)
  6306. }
  6307. if (url.startsWith(prefix22)) {
  6308. const href2 = url.slice(21)
  6309. return /^s\/\w+/.test(href2)
  6310. }
  6311. return false
  6312. }
  6313. return {
  6314. matches: /e-hentai\.org|exhentai\.org/,
  6315. validate(element) {
  6316. if (element.tagName !== "A") {
  6317. return true
  6318. }
  6319. const href = element.href
  6320. if (href && (href.startsWith(prefix3) || href.startsWith(prefix22))) {
  6321. const key = getPostUrl(href)
  6322. if (key) {
  6323. const titleElement = $(".glink", element)
  6324. let title
  6325. if (titleElement) {
  6326. title = titleElement.textContent
  6327. }
  6328. const meta = { type: "post" }
  6329. if (title) {
  6330. meta.title = title
  6331. }
  6332. element.utags = { key, meta }
  6333. return true
  6334. }
  6335. if (isImageViewUrl(href)) {
  6336. return false
  6337. }
  6338. }
  6339. return true
  6340. },
  6341. map(element) {
  6342. const titleElement = $(".gl4e.glname .glink", element)
  6343. if (titleElement) {
  6344. titleElement.utags = element.utags
  6345. titleElement.dataset.utags = titleElement.dataset.utags || ""
  6346. titleElement.dataset.utags_node_type = "link"
  6347. return titleElement
  6348. }
  6349. return void 0
  6350. },
  6351. excludeSelectors: [
  6352. ...default_default2.excludeSelectors,
  6353. "#nb",
  6354. ".searchnav",
  6355. ".gtb",
  6356. 'a[href*="report=select"]',
  6357. 'a[href*="act=expunge"]',
  6358. ],
  6359. addExtraMatchedNodes(matchedNodesSet) {
  6360. const key = getPostUrl(location.href)
  6361. if (key) {
  6362. const element = getFirstHeadElement()
  6363. if (element) {
  6364. const title = element.textContent.trim()
  6365. if (title) {
  6366. const meta = { title, type: "post" }
  6367. element.utags = { key, meta }
  6368. matchedNodesSet.add(element)
  6369. }
  6370. }
  6371. }
  6372. },
  6373. getStyle: () => e_hentai_org_default,
  6374. }
  6375. })()
  6376. var panda_chaika_moe_default =
  6377. ":not(#a):not(#b):not(#c) h5+.utags_ul{display:block !important;margin-top:-4px !important;margin-bottom:6px !important}"
  6378. var panda_chaika_moe_default2 = (() => {
  6379. const prefix3 = "https://panda.chaika.moe/"
  6380. function getPostUrl(url, exact = false) {
  6381. if (url.startsWith(prefix3)) {
  6382. const href2 = url.slice(25)
  6383. if (exact) {
  6384. if (/^archive\/\d+\/(\?.*)?$/.test(href2)) {
  6385. return prefix3 + href2.replace(/^(archive\/\d+\/).*/, "$1")
  6386. }
  6387. } else if (/^archive\/\d+\//.test(href2)) {
  6388. return prefix3 + href2.replace(/^(archive\/\d+\/).*/, "$1")
  6389. }
  6390. }
  6391. return void 0
  6392. }
  6393. return {
  6394. matches: /panda\.chaika\.moe/,
  6395. excludeSelectors: [
  6396. ...default_default2.excludeSelectors,
  6397. ".navbar",
  6398. "th",
  6399. ".pagination",
  6400. ".btn",
  6401. ".caption",
  6402. ],
  6403. addExtraMatchedNodes(matchedNodesSet) {
  6404. const key = getPostUrl(location.href)
  6405. if (key) {
  6406. const element = $("h5")
  6407. if (element) {
  6408. const title = element.textContent.trim()
  6409. if (title) {
  6410. const meta = { title, type: "post" }
  6411. element.utags = { key, meta }
  6412. matchedNodesSet.add(element)
  6413. }
  6414. }
  6415. }
  6416. for (const element of $$(".gallery a.cover")) {
  6417. const key2 = element.href
  6418. const titleElement = $(".cover-title", element)
  6419. if (titleElement) {
  6420. const title = titleElement.textContent
  6421. const meta = { title, type: "post" }
  6422. titleElement.utags = { key: key2, meta }
  6423. titleElement.dataset.utags_node_type = "link"
  6424. matchedNodesSet.add(titleElement)
  6425. }
  6426. }
  6427. for (const element of $$('.td-extended > a[href^="/archive/"]')) {
  6428. const key2 = element.href
  6429. const titleElement = $("h5", element.parentElement.parentElement)
  6430. if (titleElement) {
  6431. const title = titleElement.textContent
  6432. const meta = { title, type: "post" }
  6433. titleElement.utags = { key: key2, meta }
  6434. titleElement.dataset.utags_node_type = "link"
  6435. matchedNodesSet.add(titleElement)
  6436. }
  6437. }
  6438. },
  6439. getStyle: () => panda_chaika_moe_default,
  6440. }
  6441. })()
  6442. var dmm_co_jp_default =
  6443. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{background-color:var(--utags-captain-tag-background-color) !important;border-radius:3px !important;--utags-emoji-tag-background-color: #fff0}:not(#a):not(#b):not(#c) .mainList__item a+.utags_ul_0{object-position:0% 100%;--utags-notag-captain-tag-top: -90px;--utags-notag-captain-tag-left: 4px}:not(#a):not(#b):not(#c) .mainList__item a+.utags_ul_1{margin-top:6px !important;width:100%}:not(#a):not(#b):not(#c) .pickup .fn-responsiveImg a+.utags_ul_0{object-position:0% 100%;--utags-notag-captain-tag-top: -70px;--utags-notag-captain-tag-left: 4px}:not(#a):not(#b):not(#c) .pickup .fn-responsiveImg a+.utags_ul_1{margin-top:6px !important;width:100%}:not(#a):not(#b):not(#c) .productList .tileListTtl__txt{height:unset}:not(#a):not(#b):not(#c) .productList .tileListTtl__txt--author{white-space:normal}:not(#a):not(#b):not(#c) #l-areaRecommendProduct a+.utags_ul_0{object-position:0% 100%;--utags-notag-captain-tag-top: -80px;--utags-notag-captain-tag-left: 4px}:not(#a):not(#b):not(#c) #l-areaRecommendProduct a+.utags_ul_1{margin-top:6px !important;width:100%}"
  6444. var dmm_co_jp_default2 = (() => {
  6445. const prefix3 = "https://www.dmm.co.jp/"
  6446. function getCanonicalUrl2(url) {
  6447. if (url.startsWith(prefix3)) {
  6448. const href2 = url.slice(prefix3.length)
  6449. if (href2.includes("/=/")) {
  6450. return prefix3 + href2.replace(/\?.*/, "")
  6451. }
  6452. }
  6453. return url
  6454. }
  6455. function getProductUrl(url) {
  6456. if (url.startsWith(prefix3)) {
  6457. const href2 = url.slice(prefix3.length)
  6458. if (href2.includes("/detail/=/cid=")) {
  6459. return prefix3 + href2.replace(/\?.*/, "")
  6460. }
  6461. }
  6462. return void 0
  6463. }
  6464. function getMakerUrl(url) {
  6465. if (url.startsWith(prefix3)) {
  6466. const href2 = url.slice(prefix3.length)
  6467. if (href2.includes("/list/=/article=maker/id=")) {
  6468. return prefix3 + href2.replace(/\?.*/, "")
  6469. }
  6470. }
  6471. return void 0
  6472. }
  6473. return {
  6474. matches: /dmm\.co\.jp/,
  6475. validate(element) {
  6476. const href = element.href
  6477. if (!href.startsWith(prefix3)) {
  6478. return true
  6479. }
  6480. if (href.includes("/=/")) {
  6481. const key = getProductUrl(href)
  6482. if (key) {
  6483. const titleElement = $(
  6484. ".mainListLinkWork__txt,.responsive-name",
  6485. element
  6486. )
  6487. const title = titleElement
  6488. ? getTrimmedTitle(titleElement)
  6489. : getTrimmedTitle(element)
  6490. if (title) {
  6491. const meta = { title, type: "product" }
  6492. element.utags = { key, meta }
  6493. }
  6494. }
  6495. return true
  6496. }
  6497. return false
  6498. },
  6499. excludeSelectors: [
  6500. ...default_default2.excludeSelectors,
  6501. "header",
  6502. ".localNav-list",
  6503. ".m-leftNavigation",
  6504. ".l-areaSideNavColumn",
  6505. ".top-leftcolumn",
  6506. ".top-rightcolumn",
  6507. ".d-btn-xhi-st",
  6508. ".headingTitle__txt--more",
  6509. ".recommendCapt__txt",
  6510. ".circleFanButton__content",
  6511. ".displayFormat",
  6512. ".pageNationList",
  6513. ".nav-text-container",
  6514. ".sub-nav-link",
  6515. ".m-listHeader",
  6516. ".dcd-review__rating_map",
  6517. ".dcd-review_boxpagenation",
  6518. ".sampleButton",
  6519. ".right_navi_link",
  6520. ],
  6521. validMediaSelectors: [
  6522. ".mainList",
  6523. ".pickup .fn-responsiveImg",
  6524. "#l-areaRecommendProduct",
  6525. ],
  6526. addExtraMatchedNodes(matchedNodesSet) {
  6527. let key = getProductUrl(location.href)
  6528. if (key) {
  6529. const element = $("h1.productTitle__txt")
  6530. if (element) {
  6531. const title = element.textContent.trim()
  6532. if (title) {
  6533. const meta = { title }
  6534. element.utags = { key, meta }
  6535. matchedNodesSet.add(element)
  6536. }
  6537. }
  6538. }
  6539. key = getMakerUrl(location.href)
  6540. if (key) {
  6541. const element = $(".circleProfile__name span")
  6542. if (element) {
  6543. const title = element.textContent.trim()
  6544. if (title) {
  6545. const meta = { title }
  6546. element.utags = { key, meta }
  6547. matchedNodesSet.add(element)
  6548. }
  6549. }
  6550. }
  6551. },
  6552. getCanonicalUrl: getCanonicalUrl2,
  6553. getStyle: () => dmm_co_jp_default,
  6554. }
  6555. })()
  6556. var kemono_su_default =
  6557. ":not(#a):not(#b):not(#c) a.user-header__avatar+.utags_ul_0,:not(#a):not(#b):not(#c) a.user-card+.utags_ul_0,:not(#a):not(#b):not(#c) .post-card a+.utags_ul_0{object-position:0% 100%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: -4px;--utags-notag-captain-tag-left: 2px;--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap );transition:top ease .1s,left ease .1s}:not(#a):not(#b):not(#c) a.user-header__avatar+.utags_ul_1,:not(#a):not(#b):not(#c) a.user-card+.utags_ul_1,:not(#a):not(#b):not(#c) .post-card a+.utags_ul_1{object-position:0% 100%;position:absolute;top:-9999px;z-index:100;margin-top:-6px !important;margin-left:4px !important;transition:top ease .1s,left ease .1s}:not(#a):not(#b):not(#c) a.user-header__avatar+.utags_ul_1 .utags_text_tag,:not(#a):not(#b):not(#c) a.user-card+.utags_ul_1 .utags_text_tag,:not(#a):not(#b):not(#c) .post-card a+.utags_ul_1 .utags_text_tag{--utags-text-tag-background-color: yellow}"
  6558. var kemono_su_default2 = (() => {
  6559. const prefix3 = location.origin + "/"
  6560. function getPostUrl(url) {
  6561. if (url.startsWith(prefix3)) {
  6562. const href2 = url.slice(prefix3.length)
  6563. if (/^\w+\/user\/\w+\/post\/\w+/.test(href2)) {
  6564. return prefix3 + href2.replace(/^(\w+\/user\/\w+\/post\/\w+).*/, "$1")
  6565. }
  6566. }
  6567. return void 0
  6568. }
  6569. return {
  6570. matches: /kemono\.su|coomer\.su|nekohouse\.su/,
  6571. validate(element) {
  6572. const hrefAttr = getAttribute(element, "href")
  6573. if (hrefAttr.startsWith("#")) {
  6574. return false
  6575. }
  6576. const href = element.href
  6577. if (!href.startsWith(prefix3)) {
  6578. return true
  6579. }
  6580. if (
  6581. hasClass(element, "user-card") ||
  6582. hasClass(element, "user-header__avatar") ||
  6583. element.closest(".post-card")
  6584. ) {
  6585. element.dataset.utags = element.dataset.utags || ""
  6586. }
  6587. return true
  6588. },
  6589. validMediaSelectors: [
  6590. ".user-header .user-header__avatar",
  6591. ".user-header .user-header__profile",
  6592. ".user-card",
  6593. ".post-card__image",
  6594. ".post-card",
  6595. ],
  6596. excludeSelectors: [
  6597. ...default_default2.excludeSelectors,
  6598. ".global-sidebar",
  6599. ".paginator",
  6600. ".post__nav-links",
  6601. ".scrape__nav-links",
  6602. ".tabs",
  6603. ".user-header__actions",
  6604. ".posts-board__sidebar",
  6605. "#add-new-link",
  6606. 'a[href^="/authentication/"]',
  6607. ],
  6608. addExtraMatchedNodes(matchedNodesSet) {
  6609. const key = getPostUrl(location.href)
  6610. if (key) {
  6611. const element = $("h1.post__title,h1.scrape__title")
  6612. if (element) {
  6613. const title = element.textContent.trim()
  6614. if (title) {
  6615. const meta = { title, type: "post" }
  6616. element.utags = { key, meta }
  6617. matchedNodesSet.add(element)
  6618. }
  6619. }
  6620. }
  6621. },
  6622. getStyle: () => kemono_su_default,
  6623. }
  6624. })()
  6625. var rule34video_com_default =
  6626. ":not(#a):not(#b):not(#c) a+.utags_ul_0{object-position:200% 50%;--utags-notag-ul-disply: var(--utags-notag-ul-disply-5);--utags-notag-ul-height: var(--utags-notag-ul-height-5);--utags-notag-ul-position: var(--utags-notag-ul-position-5);--utags-notag-ul-top: var(--utags-notag-ul-top-5);--utags-notag-captain-tag-top: var(--utags-notag-captain-tag-top-5);--utags-notag-captain-tag-left: var(--utags-notag-captain-tag-left-5);--utags-captain-tag-background-color: var( --utags-captain-tag-background-color-overlap )}:not(#a):not(#b):not(#c) a+.utags_ul_1{object-position:0% 200%}:not(#a):not(#b):not(#c) .thumbs .thumb a+.utags_ul_0{object-position:0% 200%;--utags-notag-captain-tag-top: -2px;--utags-notag-captain-tag-left: -4px}:not(#a):not(#b):not(#c) .list_items .item a.wrap_item+.utags_ul_0,:not(#a):not(#b):not(#c) .aside_wrap a.item+.utags_ul_0{object-position:100% 50%}"
  6627. var rule34video_com_default2 = (() => {
  6628. const prefix3 = location.origin + "/"
  6629. function getModelUrl(url) {
  6630. if (url.startsWith(prefix3)) {
  6631. const href2 = url.slice(prefix3.length)
  6632. if (/^models\/[\w-]+/.test(href2)) {
  6633. return prefix3 + href2.replace(/^(models\/[\w-]+).*/, "$1") + "/"
  6634. }
  6635. }
  6636. return void 0
  6637. }
  6638. function getMemberUrl(url) {
  6639. if (url.startsWith(prefix3)) {
  6640. const href2 = url.slice(prefix3.length)
  6641. if (/^members\/\d+/.test(href2)) {
  6642. return prefix3 + href2.replace(/^(members\/\d+).*/, "$1") + "/"
  6643. }
  6644. }
  6645. return void 0
  6646. }
  6647. function getCategoryUrl(url) {
  6648. if (url.startsWith(prefix3)) {
  6649. const href2 = url.slice(prefix3.length)
  6650. if (/^categories\/[\w-]+/.test(href2)) {
  6651. return prefix3 + href2.replace(/^(categories\/[\w-]+).*/, "$1") + "/"
  6652. }
  6653. }
  6654. return void 0
  6655. }
  6656. function getVideoUrl(url) {
  6657. if (url.startsWith(prefix3)) {
  6658. const href2 = url.slice(prefix3.length)
  6659. if (/^video\/\d+(\/[\w-]+)?/.test(href2)) {
  6660. return (
  6661. prefix3 + href2.replace(/^(video\/\d+(\/[\w-]+)?).*/, "$1") + "/"
  6662. )
  6663. }
  6664. }
  6665. return void 0
  6666. }
  6667. return {
  6668. matches: /rule34video\.com|rule34gen\.com/,
  6669. listNodesSelectors: [
  6670. //
  6671. ".list-comments .item",
  6672. ".thumbs .item",
  6673. ],
  6674. conditionNodesSelectors: [
  6675. //
  6676. ".list-comments .item .comment-info .inner a",
  6677. ".thumbs .item a.th",
  6678. ],
  6679. validate(element) {
  6680. const href = element.href
  6681. if (!href.startsWith(prefix3)) {
  6682. if ($("header", element.parentElement)) {
  6683. const key2 = href.replace(/(https?:\/\/[^/]+\/).*/, "$1")
  6684. const meta = { type: "AD", title: "AD" }
  6685. element.utags = { key: key2, meta }
  6686. element.dataset.utags = element.dataset.utags || ""
  6687. }
  6688. return true
  6689. }
  6690. const key = getVideoUrl(href)
  6691. if (key) {
  6692. const titleElement = $(".thumb_title", element)
  6693. const title = titleElement
  6694. ? titleElement.textContent.trim()
  6695. : element.textContent.trim()
  6696. if (!title) {
  6697. return false
  6698. }
  6699. const meta = { type: "video", title }
  6700. element.utags = { key, meta }
  6701. element.dataset.utags = element.dataset.utags || ""
  6702. return true
  6703. }
  6704. element.dataset.utags = element.dataset.utags || ""
  6705. return true
  6706. },
  6707. excludeSelectors: [
  6708. ...default_default2.excludeSelectors,
  6709. ".header",
  6710. ".btn_more",
  6711. ".tabs-menu",
  6712. ".pagination",
  6713. ".headline",
  6714. ".prev",
  6715. ".next",
  6716. ".btn",
  6717. ".all",
  6718. ".tag_item_suggest",
  6719. 'a[href*="download"]',
  6720. ".list-comments .wrap_image",
  6721. ],
  6722. addExtraMatchedNodes(matchedNodesSet) {
  6723. let key = getModelUrl(location.href)
  6724. if (key) {
  6725. const element = $(".brand_inform .title")
  6726. if (element) {
  6727. const title = element.textContent.trim()
  6728. if (title) {
  6729. const meta = { title, type: "model" }
  6730. element.utags = { key, meta }
  6731. matchedNodesSet.add(element)
  6732. }
  6733. }
  6734. }
  6735. key = getMemberUrl(location.href)
  6736. if (key) {
  6737. const element = $(".channel_logo .title")
  6738. if (element) {
  6739. const title = element.textContent.trim()
  6740. if (title) {
  6741. const meta = { title, type: "user" }
  6742. element.utags = { key, meta }
  6743. matchedNodesSet.add(element)
  6744. }
  6745. }
  6746. }
  6747. key = getCategoryUrl(location.href)
  6748. if (key) {
  6749. const element = $(".brand_inform .title")
  6750. if (element) {
  6751. const title = element.textContent.trim()
  6752. if (title) {
  6753. const meta = { title, type: "category" }
  6754. element.utags = { key, meta }
  6755. matchedNodesSet.add(element)
  6756. }
  6757. }
  6758. }
  6759. key = getVideoUrl(location.href)
  6760. if (key) {
  6761. const element = $("h1.title_video")
  6762. if (element) {
  6763. const title = element.textContent.trim()
  6764. if (title) {
  6765. const meta = { title, type: "video" }
  6766. element.utags = { key, meta }
  6767. matchedNodesSet.add(element)
  6768. }
  6769. }
  6770. }
  6771. },
  6772. getStyle: () => rule34video_com_default,
  6773. }
  6774. })()
  6775. var sites = [
  6776. github_com_default2,
  6777. v2ex_default2,
  6778. twitter_com_default2,
  6779. reddit_com_default2,
  6780. greasyfork_org_default2,
  6781. news_ycombinator_com_default,
  6782. lobste_rs_default,
  6783. mp_weixin_qq_com_default,
  6784. instagram_com_default2,
  6785. threads_net_default2,
  6786. facebook_com_default2,
  6787. youtube_com_default2,
  6788. bilibili_com_default2,
  6789. tiktok_com_default2,
  6790. pojie_cn_default2,
  6791. juejin_cn_default,
  6792. zhihu_com_default,
  6793. xiaohongshu_com_default2,
  6794. weibo_com_default,
  6795. sspai_com_default2,
  6796. douyin_com_default2,
  6797. podcasts_google_com_default2,
  6798. rebang_today_default2,
  6799. myanimelist_net_default2,
  6800. douban_com_default,
  6801. pixiv_net_default2,
  6802. discourse_default2,
  6803. nga_cn_default2,
  6804. keylol_com_default2,
  6805. tampermonkey_net_cn_default2,
  6806. flarum_default2,
  6807. nodeseek_com_default2,
  6808. inoreader_com_default2,
  6809. zhipin_com_default2,
  6810. pornhub_com_default2,
  6811. e_hentai_org_default2,
  6812. panda_chaika_moe_default2,
  6813. dlsite_com_default2,
  6814. dmm_co_jp_default2,
  6815. kemono_su_default2,
  6816. rule34video_com_default2,
  6817. ]
  6818. var getCanonicalUrlFunctionList = [default_default2, ...sites]
  6819. .map((site) => site.getCanonicalUrl)
  6820. .filter((v) => typeof v === "function")
  6821. function matchedSite(hostname2) {
  6822. for (const s of sites) {
  6823. if (s.matches.test(hostname2)) {
  6824. return s
  6825. }
  6826. }
  6827. if (false) {
  6828. return siteForExtensions(hostname2)
  6829. }
  6830. return default_default2
  6831. }
  6832. function joinSelectors(selectors) {
  6833. return selectors ? selectors.join(",") : void 0
  6834. }
  6835. var hostname = location.hostname
  6836. var currentSite = matchedSite(hostname)
  6837. var listNodesSelector = joinSelectors(currentSite.listNodesSelectors)
  6838. var conditionNodesSelector = joinSelectors(
  6839. currentSite.conditionNodesSelectors
  6840. )
  6841. var matchedNodesSelector = joinSelectors(
  6842. currentSite.matchedNodesSelectors ||
  6843. (currentSite.matches ? default_default2.matchedNodesSelectors : void 0)
  6844. )
  6845. var excludeSelector = joinSelectors(currentSite.excludeSelectors)
  6846. var validMediaSelector = joinSelectors(currentSite.validMediaSelectors)
  6847. var validateFunction = currentSite.validate || default_default2.validate
  6848. var mappingFunction =
  6849. typeof currentSite.map === "function" ? currentSite.map : void 0
  6850. function getListNodes() {
  6851. if (typeof currentSite.preProcess === "function") {
  6852. currentSite.preProcess()
  6853. }
  6854. if (typeof currentSite.getStyle === "function" && !$("#utags_site_style")) {
  6855. const styleText = currentSite.getStyle()
  6856. if (styleText) {
  6857. addElement2("style", {
  6858. textContent: styleText,
  6859. id: "utags_site_style",
  6860. })
  6861. }
  6862. }
  6863. return listNodesSelector ? $$(listNodesSelector) : []
  6864. }
  6865. function getConditionNodes() {
  6866. return conditionNodesSelector ? $$(conditionNodesSelector) : []
  6867. }
  6868. function getCanonicalUrl(url) {
  6869. if (!url) {
  6870. return void 0
  6871. }
  6872. for (const getCanonicalUrlFunc of getCanonicalUrlFunctionList) {
  6873. if (getCanonicalUrlFunc) {
  6874. url = getCanonicalUrlFunc(url)
  6875. }
  6876. }
  6877. return url
  6878. }
  6879. var preValidate = (element) => {
  6880. if (!element) {
  6881. return false
  6882. }
  6883. if (element.tagName === "A") {
  6884. let href = getAttribute(element, "href")
  6885. if (!href) {
  6886. return false
  6887. }
  6888. href = href.trim()
  6889. if (href.length === 0 || href === "#") {
  6890. return false
  6891. }
  6892. const protocol = element.protocol
  6893. if (protocol !== "http:" && protocol !== "https:") {
  6894. return false
  6895. }
  6896. }
  6897. if (
  6898. element.closest(
  6899. ".utags_text_tag,.browser_extension_settings_container,a a"
  6900. )
  6901. ) {
  6902. return false
  6903. }
  6904. return true
  6905. }
  6906. var isValidUtagsElement = (element) => {
  6907. if (element.dataset.utags !== void 0) {
  6908. return true
  6909. }
  6910. if (!element.textContent) {
  6911. return false
  6912. }
  6913. if (!element.textContent.trim()) {
  6914. return false
  6915. }
  6916. const media = $(
  6917. 'img,svg,audio,video,button,.icon,[style*="background-image"]',
  6918. element
  6919. )
  6920. if (media) {
  6921. if (!validMediaSelector) {
  6922. return false
  6923. }
  6924. if (!media.closest(validMediaSelector)) {
  6925. return false
  6926. }
  6927. }
  6928. return true
  6929. }
  6930. var isExcludedUtagsElement = (element) => {
  6931. return excludeSelector ? Boolean(element.closest(excludeSelector)) : false
  6932. }
  6933. var addMatchedNodes = (matchedNodesSet) => {
  6934. if (!matchedNodesSelector) {
  6935. return
  6936. }
  6937. const elements = $$(matchedNodesSelector)
  6938. if (elements.length === 0) {
  6939. return
  6940. }
  6941. const process2 = (element) => {
  6942. var _a
  6943. if (!preValidate(element) || !validateFunction(element)) {
  6944. delete element.utags
  6945. return
  6946. }
  6947. if (mappingFunction) {
  6948. const newElement = mappingFunction(element)
  6949. if (newElement && newElement !== element) {
  6950. process2(newElement)
  6951. return
  6952. }
  6953. }
  6954. if (isExcludedUtagsElement(element) || !isValidUtagsElement(element)) {
  6955. delete element.utags
  6956. return
  6957. }
  6958. const utags = element.utags || {}
  6959. const key = utags.key || getCanonicalUrl(element.href)
  6960. if (!key) {
  6961. return
  6962. }
  6963. const title = getTrimmedTitle(element)
  6964. const meta = {}
  6965. if (title && !isUrl(title)) {
  6966. meta.title = title
  6967. }
  6968. if ((_a = utags.meta) == null ? void 0 : _a.title) {
  6969. utags.meta.title = trimTitle(utags.meta.title)
  6970. }
  6971. element.utags = {
  6972. key,
  6973. meta: utags.meta ? Object.assign(meta, utags.meta) : meta,
  6974. }
  6975. matchedNodesSet.add(element)
  6976. }
  6977. for (const element of elements) {
  6978. try {
  6979. process2(element)
  6980. } catch (error) {
  6981. console.error(error)
  6982. }
  6983. }
  6984. }
  6985. function matchedNodes() {
  6986. const matchedNodesSet = /* @__PURE__ */ new Set()
  6987. addMatchedNodes(matchedNodesSet)
  6988. if (typeof currentSite.addExtraMatchedNodes === "function") {
  6989. currentSite.addExtraMatchedNodes(matchedNodesSet)
  6990. }
  6991. if (typeof currentSite.postProcess === "function") {
  6992. currentSite.postProcess()
  6993. }
  6994. return [...matchedNodesSet]
  6995. }
  6996. var config = {
  6997. run_at: "document_start",
  6998. matches: ["https://*/*"],
  6999. all_frames: false,
  7000. }
  7001. var emojiTags2
  7002. var host2 = location.host
  7003. var isEnabledByDefault = () => {
  7004. if (host2.includes("www.bilibili.com")) {
  7005. return false
  7006. }
  7007. return true
  7008. }
  7009. var isTagManager = location.href.includes("utags.pipecraft.net/tags/")
  7010. var groupNumber = 1
  7011. var settingsTable2 = {
  7012. ["enableCurrentSite_".concat(host2)]: {
  7013. title: i2("settings.enableCurrentSite"),
  7014. defaultValue: isEnabledByDefault(),
  7015. },
  7016. showHidedItems: {
  7017. title: i2("settings.showHidedItems"),
  7018. defaultValue: false,
  7019. group: ++groupNumber,
  7020. },
  7021. noOpacityEffect: {
  7022. title: i2("settings.noOpacityEffect"),
  7023. defaultValue: false,
  7024. group: groupNumber,
  7025. },
  7026. ["useVisitedFunction_".concat(host2)]: {
  7027. title: i2("settings.useVisitedFunction"),
  7028. defaultValue: false,
  7029. group: ++groupNumber,
  7030. },
  7031. ["displayEffectOfTheVisitedContent_".concat(host2)]: {
  7032. title: i2("settings.displayEffectOfTheVisitedContent"),
  7033. type: "select",
  7034. defaultValue: "2",
  7035. options: {
  7036. [i2("settings.displayEffectOfTheVisitedContent.recordingonly")]: "0",
  7037. [i2("settings.displayEffectOfTheVisitedContent.showtagonly")]: "1",
  7038. [i2("settings.displayEffectOfTheVisitedContent.changecolor")]: "4",
  7039. [i2("settings.displayEffectOfTheVisitedContent.translucent")]: "2",
  7040. [i2("settings.displayEffectOfTheVisitedContent.hide")]: "3",
  7041. },
  7042. group: groupNumber,
  7043. },
  7044. pinnedTagsTitle: {
  7045. title: i2("settings.pinnedTags"),
  7046. type: "action",
  7047. async onclick() {
  7048. const input = $('textarea[data-key="pinnedTags"]')
  7049. if (input) {
  7050. input.scrollIntoView({ block: "start" })
  7051. input.selectionStart = input.value.length
  7052. input.selectionEnd = input.value.length
  7053. input.focus()
  7054. }
  7055. },
  7056. group: ++groupNumber,
  7057. },
  7058. pinnedTags: {
  7059. title: i2("settings.pinnedTags"),
  7060. defaultValue: i2("settings.pinnedTagsDefaultValue"),
  7061. placeholder: i2("settings.pinnedTagsPlaceholder"),
  7062. type: "textarea",
  7063. group: groupNumber,
  7064. },
  7065. emojiTagsTitle: {
  7066. title: i2("settings.emojiTags"),
  7067. type: "action",
  7068. async onclick() {
  7069. const input = $('textarea[data-key="emojiTags"]')
  7070. if (input) {
  7071. input.scrollIntoView({ block: "start" })
  7072. input.selectionStart = input.value.length
  7073. input.selectionEnd = input.value.length
  7074. input.focus()
  7075. }
  7076. },
  7077. group: groupNumber,
  7078. },
  7079. emojiTags: {
  7080. title: i2("settings.emojiTags"),
  7081. defaultValue:
  7082. "\u{1F44D}, \u{1F44E}, \u2764\uFE0F, \u2B50, \u{1F31F}, \u{1F525}, \u{1F4A9}, \u26A0\uFE0F, \u{1F4AF}, \u{1F44F}, \u{1F437}, \u{1F4CC}, \u{1F4CD}, \u{1F3C6}, \u{1F48E}, \u{1F4A1}, \u{1F916}, \u{1F4D4}, \u{1F4D6}, \u{1F4DA}, \u{1F4DC}, \u{1F4D5}, \u{1F4D7}, \u{1F9F0}, \u26D4, \u{1F6AB}, \u{1F534}, \u{1F7E0}, \u{1F7E1}, \u{1F7E2}, \u{1F535}, \u{1F7E3}, \u2757, \u2753, \u2705, \u274C",
  7083. placeholder: "\u{1F44D}, \u{1F44E}",
  7084. type: "textarea",
  7085. group: groupNumber,
  7086. },
  7087. customStyle: {
  7088. title: i2("settings.customStyle"),
  7089. defaultValue: false,
  7090. group: ++groupNumber,
  7091. },
  7092. customStyleValue: {
  7093. title: "Custom style value",
  7094. defaultValue: i2("settings.customStyleDefaultValue"),
  7095. placeholder: i2("settings.customStyleDefaultValue"),
  7096. type: "textarea",
  7097. group: groupNumber,
  7098. },
  7099. customStyleTip: {
  7100. title: i2("settings.customStyleExamples"),
  7101. type: "tip",
  7102. tipContent: i2("settings.customStyleExamplesContent"),
  7103. group: groupNumber,
  7104. },
  7105. ["customStyle_".concat(host2)]: {
  7106. title: i2("settings.customStyleCurrentSite"),
  7107. defaultValue: false,
  7108. group: ++groupNumber,
  7109. },
  7110. ["customStyleValue_".concat(host2)]: {
  7111. title: "Custom style value",
  7112. defaultValue: "",
  7113. placeholder: i2("settings.customStyleDefaultValue"),
  7114. type: "textarea",
  7115. group: groupNumber,
  7116. },
  7117. useSimplePrompt: {
  7118. title: i2("settings.useSimplePrompt"),
  7119. defaultValue: false,
  7120. group: ++groupNumber,
  7121. },
  7122. openTagsPage: {
  7123. title: i2("settings.openTagsPage"),
  7124. type: "externalLink",
  7125. url: "https://utags.pipecraft.net/tags/",
  7126. group: ++groupNumber,
  7127. },
  7128. openDataPage: {
  7129. title: i2("settings.openDataPage"),
  7130. type: "externalLink",
  7131. url: "https://utags.pipecraft.net/data/",
  7132. group: groupNumber,
  7133. },
  7134. }
  7135. var addUtagsStyle = () => {
  7136. const style = addStyle(content_default)
  7137. style.id = "utags_style"
  7138. }
  7139. function updateCustomStyle() {
  7140. const customStyleValue = getSettingsValue("customStyleValue") || ""
  7141. if (getSettingsValue("customStyle") && customStyleValue) {
  7142. if ($("#utags_custom_style")) {
  7143. $("#utags_custom_style").textContent = customStyleValue
  7144. } else {
  7145. addElement2("style", {
  7146. id: "utags_custom_style",
  7147. textContent: customStyleValue,
  7148. })
  7149. if ($("#utags_custom_style_2")) {
  7150. $("#utags_custom_style_2").remove()
  7151. }
  7152. }
  7153. } else if ($("#utags_custom_style")) {
  7154. $("#utags_custom_style").remove()
  7155. }
  7156. const customStyleValue2 =
  7157. getSettingsValue("customStyleValue_".concat(host2)) || ""
  7158. if (getSettingsValue("customStyle_".concat(host2)) && customStyleValue2) {
  7159. if ($("#utags_custom_style_2")) {
  7160. $("#utags_custom_style_2").textContent = customStyleValue2
  7161. } else {
  7162. addElement2("style", {
  7163. id: "utags_custom_style_2",
  7164. textContent: customStyleValue2,
  7165. })
  7166. }
  7167. } else if ($("#utags_custom_style_2")) {
  7168. $("#utags_custom_style_2").remove()
  7169. }
  7170. }
  7171. function onSettingsChange2() {
  7172. if (getSettingsValue("showHidedItems")) {
  7173. addClass(doc.documentElement, "utags_no_hide")
  7174. } else {
  7175. removeClass(doc.documentElement, "utags_no_hide")
  7176. }
  7177. if (getSettingsValue("noOpacityEffect")) {
  7178. addClass(doc.documentElement, "utags_no_opacity_effect")
  7179. } else {
  7180. removeClass(doc.documentElement, "utags_no_opacity_effect")
  7181. }
  7182. doc.documentElement.dataset.utags_displayEffectOfTheVisitedContent =
  7183. getSettingsValue("displayEffectOfTheVisitedContent_".concat(host2))
  7184. if (getSettingsValue("enableCurrentSite_".concat(host2))) {
  7185. doc.documentElement.dataset.utags = "".concat(host2)
  7186. displayTagsThrottled()
  7187. updateCustomStyle()
  7188. } else {
  7189. doc.documentElement.dataset.utags = "off"
  7190. if ($("#utags_custom_style")) {
  7191. $("#utags_custom_style").remove()
  7192. }
  7193. if ($("#utags_custom_style_2")) {
  7194. $("#utags_custom_style_2").remove()
  7195. }
  7196. if ($("#utags_site_style")) {
  7197. $("#utags_site_style").remove()
  7198. }
  7199. }
  7200. }
  7201. var start = 0
  7202. if (start) {
  7203. start = Date.now()
  7204. }
  7205. function appendTagsToPage(element, key, tags, meta) {
  7206. const utagsUl = element.nextSibling
  7207. if (hasClass(utagsUl, "utags_ul")) {
  7208. if (
  7209. element.dataset.utags === tags.join(",") &&
  7210. key === getAttribute(utagsUl, "data-utags_key")
  7211. ) {
  7212. return
  7213. }
  7214. utagsUl.remove()
  7215. }
  7216. const tagName = element.dataset.utags_ul_type === "ol" ? "ol" : "ul"
  7217. const ul = createElement(tagName, {
  7218. class: tags.length === 0 ? "utags_ul utags_ul_0" : "utags_ul utags_ul_1",
  7219. "data-utags_key": key,
  7220. })
  7221. let li = createElement("li")
  7222. const a = createElement("button", {
  7223. type: "button",
  7224. title: "Add tags",
  7225. "data-utags_tag": "\u{1F3F7}\uFE0F",
  7226. "data-utags_key": key,
  7227. "data-utags_tags": tags.join(", "),
  7228. "data-utags_meta": meta ? JSON.stringify(meta) : "",
  7229. class:
  7230. tags.length === 0
  7231. ? "utags_text_tag utags_captain_tag"
  7232. : "utags_text_tag utags_captain_tag2",
  7233. })
  7234. const svg =
  7235. '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="currentColor" class="bi bi-tags-fill" viewBox="0 0 16 16">\n<path d="M2 2a1 1 0 0 1 1-1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 2 6.586V2zm3.5 4a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3z"/>\n<path d="M1.293 7.793A1 1 0 0 1 1 7.086V2a1 1 0 0 0-1 1v4.586a1 1 0 0 0 .293.707l7 7a1 1 0 0 0 1.414 0l.043-.043-7.457-7.457z"/>\n</svg>\n'
  7236. a.innerHTML = createHTML(svg)
  7237. li.append(a)
  7238. ul.append(li)
  7239. for (const tag of tags) {
  7240. li = createElement("li")
  7241. const a2 = createTag(tag, {
  7242. isEmoji: emojiTags2.includes(tag),
  7243. noLink: isTagManager,
  7244. enableSelect: isTagManager,
  7245. })
  7246. li.append(a2)
  7247. ul.append(li)
  7248. }
  7249. element.after(ul)
  7250. element.dataset.utags = tags.join(",")
  7251. setTimeout(() => {
  7252. const style = getComputedStyle(element)
  7253. const zIndex = style.zIndex
  7254. if (zIndex && zIndex !== "auto") {
  7255. setStyle(ul, { zIndex })
  7256. }
  7257. }, 200)
  7258. }
  7259. function cleanUnusedUtags() {
  7260. const utagsUlList = $$(".utags_ul,ul[data-utags_key],ol[data-utags_key]")
  7261. for (const utagsUl of utagsUlList) {
  7262. const element = utagsUl.previousSibling
  7263. if (element && getAttribute(element, "data-utags") !== null) {
  7264. continue
  7265. }
  7266. utagsUl.remove()
  7267. }
  7268. }
  7269. async function displayTags() {
  7270. if (start) {
  7271. console.error("start of displayTags", Date.now() - start)
  7272. }
  7273. emojiTags2 = await getEmojiTags()
  7274. const listNodes = getListNodes()
  7275. for (const node of listNodes) {
  7276. node.dataset.utags_list_node = ""
  7277. }
  7278. if (start) {
  7279. console.error("before matchedNodes", Date.now() - start)
  7280. }
  7281. const nodes = matchedNodes()
  7282. if (start) {
  7283. console.error("after matchedNodes", Date.now() - start, nodes.length)
  7284. }
  7285. await getCachedUrlMap()
  7286. for (const node of nodes) {
  7287. const utags = node.utags
  7288. if (!utags) {
  7289. continue
  7290. }
  7291. const key = utags.key
  7292. if (!key) {
  7293. continue
  7294. }
  7295. const object = getTags(key)
  7296. const tags = (object.tags || []).slice()
  7297. if (node.dataset.utags_visited === "1") {
  7298. tags.push(TAG_VISITED)
  7299. }
  7300. appendTagsToPage(node, key, tags, utags.meta)
  7301. setTimeout(() => {
  7302. updateTagPosition(node)
  7303. })
  7304. }
  7305. if (start) {
  7306. console.error("after appendTagsToPage", Date.now() - start)
  7307. }
  7308. const conditionNodes = getConditionNodes()
  7309. for (const node of conditionNodes) {
  7310. if (getAttribute(node, "data-utags") !== null) {
  7311. node.dataset.utags_condition_node = ""
  7312. }
  7313. }
  7314. for (const node of listNodes) {
  7315. const conditionNodes2 = $$("[data-utags_condition_node]", node)
  7316. const tagsArray = []
  7317. for (const node2 of conditionNodes2) {
  7318. if (!node2.dataset.utags) {
  7319. continue
  7320. }
  7321. if (node2.closest("[data-utags_list_node]") !== node) {
  7322. continue
  7323. }
  7324. tagsArray.push(node2.dataset.utags)
  7325. }
  7326. if (tagsArray.length === 1) {
  7327. node.dataset.utags_list_node = "," + tagsArray[0] + ","
  7328. } else if (tagsArray.length > 1) {
  7329. node.dataset.utags_list_node =
  7330. "," + uniq(tagsArray.join(",").split(",")).join(",") + ","
  7331. }
  7332. }
  7333. cleanUnusedUtags()
  7334. if (start) {
  7335. console.error("end of displayTags", Date.now() - start)
  7336. }
  7337. }
  7338. var displayTagsThrottled = throttle(displayTags, 500)
  7339. async function initStorage() {
  7340. await migration()
  7341. addTagsValueChangeListener(() => {
  7342. if (!doc.hidden) {
  7343. setTimeout(displayTags)
  7344. }
  7345. })
  7346. }
  7347. var validNodeNames = {
  7348. A: true,
  7349. H1: true,
  7350. H2: true,
  7351. H3: true,
  7352. H4: true,
  7353. H5: true,
  7354. H6: true,
  7355. DIV: true,
  7356. SPAN: true,
  7357. P: true,
  7358. UL: true,
  7359. OL: true,
  7360. LI: true,
  7361. SECTION: true,
  7362. }
  7363. function shouldUpdateUtagsWhenNodeUpdated(nodeList) {
  7364. const length = nodeList.length
  7365. for (let i3 = 0; i3 < length; i3++) {
  7366. const node = nodeList[i3]
  7367. if (
  7368. validNodeNames[node.nodeName] &&
  7369. !hasClass(node, "utags_ul") &&
  7370. !hasClass(node, "utags_modal")
  7371. ) {
  7372. return true
  7373. }
  7374. }
  7375. return false
  7376. }
  7377. function getOutermostOffsetParent(element1, element2) {
  7378. if (
  7379. !(element1 instanceof HTMLElement) ||
  7380. !(element2 instanceof HTMLElement)
  7381. ) {
  7382. throw new TypeError("Both arguments must be valid HTMLElements.")
  7383. }
  7384. const offsetParent1 = element1.offsetParent
  7385. const offsetParent2 = element2.offsetParent
  7386. if (offsetParent1 && offsetParent2) {
  7387. if (offsetParent1.contains(offsetParent2)) {
  7388. return offsetParent1
  7389. }
  7390. if (offsetParent2.contains(offsetParent1)) {
  7391. return offsetParent2
  7392. }
  7393. return void 0
  7394. }
  7395. return offsetParent1 || offsetParent2
  7396. }
  7397. function getMaxOffsetLeft(offsetParent, utags, utagsSizeFix) {
  7398. let maxOffsetRight
  7399. if (offsetParent && offsetParent.offsetWidth > 0) {
  7400. if (offsetParent === utags.offsetParent) {
  7401. maxOffsetRight = offsetParent.offsetWidth
  7402. } else {
  7403. maxOffsetRight =
  7404. offsetParent.offsetWidth -
  7405. getOffsetPosition(utags.offsetParent, offsetParent).left
  7406. }
  7407. } else {
  7408. maxOffsetRight =
  7409. document.body.offsetWidth -
  7410. getOffsetPosition(utags.offsetParent).left -
  7411. 2
  7412. }
  7413. return maxOffsetRight - utags.clientWidth - utagsSizeFix
  7414. }
  7415. function updateTagPosition(element) {
  7416. const utags = element.nextElementSibling
  7417. if (!utags || !hasClass(utags, "utags_ul")) {
  7418. return
  7419. }
  7420. if (!utags.offsetParent && !utags.offsetHeight && !utags.offsetWidth) {
  7421. return
  7422. }
  7423. const style = getComputedStyle(utags)
  7424. if (style.position !== "absolute") {
  7425. return
  7426. }
  7427. if (element.dataset.utags_position_selector) {
  7428. element =
  7429. $(element.dataset.utags_position_selector, element) ||
  7430. element.closest(element.dataset.utags_position_selector) ||
  7431. element
  7432. }
  7433. element.dataset.utags_fit_content = "1"
  7434. const utagsSizeFix = hasClass(utags, "utags_ul_0") ? 22 : 0
  7435. const offsetParent =
  7436. element.offsetParent === utags.offsetParent
  7437. ? element.offsetParent
  7438. : getOutermostOffsetParent(element, utags)
  7439. const offset = getOffsetPosition(element, offsetParent || doc.body)
  7440. if (offsetParent !== utags.offsetParent) {
  7441. const offset2 = getOffsetPosition(
  7442. utags.offsetParent,
  7443. offsetParent || doc.body
  7444. )
  7445. offset.top -= offset2.top
  7446. offset.left -= offset2.left
  7447. }
  7448. if (!element.offsetWidth && !element.clientWidth) {
  7449. return
  7450. }
  7451. const objectPosition = style.objectPosition
  7452. switch (objectPosition) {
  7453. case "-100% 50%": {
  7454. utags.style.left =
  7455. Math.max(offset.left - utags.clientWidth - utagsSizeFix, 0) + "px"
  7456. utags.style.top =
  7457. offset.top +
  7458. ((element.clientHeight || element.offsetHeight) -
  7459. utags.clientHeight -
  7460. utagsSizeFix) /
  7461. 2 +
  7462. "px"
  7463. break
  7464. }
  7465. case "0% -100%": {
  7466. utags.style.left = offset.left + "px"
  7467. utags.style.top = offset.top - utags.clientHeight - utagsSizeFix + "px"
  7468. break
  7469. }
  7470. case "0% 0%": {
  7471. utags.style.left = offset.left + "px"
  7472. utags.style.top = offset.top + "px"
  7473. break
  7474. }
  7475. case "0% 100%": {
  7476. utags.style.left = offset.left + "px"
  7477. utags.style.top =
  7478. offset.top +
  7479. (element.clientHeight || element.offsetHeight) -
  7480. utags.clientHeight -
  7481. utagsSizeFix +
  7482. "px"
  7483. break
  7484. }
  7485. case "0% 200%": {
  7486. utags.style.left = offset.left + "px"
  7487. utags.style.top =
  7488. offset.top + (element.clientHeight || element.offsetHeight) + "px"
  7489. break
  7490. }
  7491. case "100% -100%": {
  7492. utags.style.left =
  7493. offset.left +
  7494. (element.clientWidth || element.offsetWidth) -
  7495. utags.clientWidth -
  7496. utagsSizeFix +
  7497. "px"
  7498. utags.style.top = offset.top - utags.clientHeight - utagsSizeFix + "px"
  7499. break
  7500. }
  7501. case "100% 0%": {
  7502. let offsetLeft =
  7503. (element.clientWidth || element.offsetWidth) -
  7504. utags.clientWidth -
  7505. utagsSizeFix
  7506. if (offsetLeft < 100) {
  7507. offsetLeft = element.clientWidth || element.offsetWidth
  7508. }
  7509. utags.style.left =
  7510. Math.min(
  7511. offset.left + offsetLeft,
  7512. getMaxOffsetLeft(offsetParent, utags, utagsSizeFix)
  7513. ) + "px"
  7514. utags.style.top = offset.top + "px"
  7515. break
  7516. }
  7517. case "100% 50%": {
  7518. let offsetLeft =
  7519. (element.clientWidth || element.offsetWidth) -
  7520. utags.clientWidth -
  7521. utagsSizeFix
  7522. if (offsetLeft < 100) {
  7523. offsetLeft = element.clientWidth || element.offsetWidth
  7524. }
  7525. utags.style.left =
  7526. Math.min(
  7527. offset.left + offsetLeft,
  7528. getMaxOffsetLeft(offsetParent, utags, utagsSizeFix)
  7529. ) + "px"
  7530. utags.style.top =
  7531. offset.top +
  7532. ((element.clientHeight || element.offsetHeight) -
  7533. utags.clientHeight -
  7534. utagsSizeFix) /
  7535. 2 +
  7536. "px"
  7537. break
  7538. }
  7539. case "100% 100%": {
  7540. let offsetLeft =
  7541. (element.clientWidth || element.offsetWidth) -
  7542. utags.clientWidth -
  7543. utagsSizeFix
  7544. if (offsetLeft < 100) {
  7545. offsetLeft = element.clientWidth || element.offsetWidth
  7546. }
  7547. utags.style.left =
  7548. Math.min(
  7549. offset.left + offsetLeft,
  7550. getMaxOffsetLeft(offsetParent, utags, utagsSizeFix)
  7551. ) + "px"
  7552. utags.style.top =
  7553. offset.top +
  7554. (element.clientHeight || element.offsetHeight) -
  7555. utags.clientHeight -
  7556. utagsSizeFix +
  7557. "px"
  7558. break
  7559. }
  7560. case "100% 200%": {
  7561. utags.style.left =
  7562. offset.left +
  7563. (element.clientWidth || element.offsetWidth) -
  7564. utags.clientWidth -
  7565. utagsSizeFix +
  7566. "px"
  7567. utags.style.top =
  7568. offset.top + (element.clientHeight || element.offsetHeight) + "px"
  7569. break
  7570. }
  7571. case "200% 0%": {
  7572. utags.style.left =
  7573. Math.min(
  7574. offset.left + (element.clientWidth || element.offsetWidth),
  7575. getMaxOffsetLeft(offsetParent, utags, utagsSizeFix)
  7576. ) + "px"
  7577. utags.style.top = offset.top + "px"
  7578. break
  7579. }
  7580. case "200% 50%": {
  7581. utags.style.left =
  7582. Math.min(
  7583. offset.left + (element.clientWidth || element.offsetWidth),
  7584. getMaxOffsetLeft(offsetParent, utags, utagsSizeFix)
  7585. ) + "px"
  7586. utags.style.top =
  7587. offset.top +
  7588. ((element.clientHeight || element.offsetHeight) -
  7589. utags.clientHeight -
  7590. utagsSizeFix) /
  7591. 2 +
  7592. "px"
  7593. break
  7594. }
  7595. case "200% 100%": {
  7596. utags.style.left =
  7597. Math.min(
  7598. offset.left + (element.clientWidth || element.offsetWidth),
  7599. getMaxOffsetLeft(offsetParent, utags, utagsSizeFix)
  7600. ) + "px"
  7601. utags.style.top =
  7602. offset.top +
  7603. (element.clientHeight || element.offsetHeight) -
  7604. utags.clientHeight -
  7605. utagsSizeFix +
  7606. "px"
  7607. break
  7608. }
  7609. default: {
  7610. break
  7611. }
  7612. }
  7613. element.dataset.utags_fit_content = "0"
  7614. }
  7615. async function main() {
  7616. addUtagsStyle()
  7617. await initSettings({
  7618. id: "utags",
  7619. title: i2("settings.title"),
  7620. footer: "\n <p>"
  7621. .concat(
  7622. i2("settings.information"),
  7623. '</p>\n <p>\n <a href="https://github.com/utags/utags/issues" target="_blank">\n '
  7624. )
  7625. .concat(
  7626. i2("settings.report"),
  7627. '\n </a></p>\n <p>Made with \u2764\uFE0F by\n <a href="https://www.pipecraft.net/" target="_blank">\n Pipecraft\n </a></p>'
  7628. ),
  7629. settingsTable: settingsTable2,
  7630. async onValueChange() {
  7631. onSettingsChange()
  7632. onSettingsChange2()
  7633. },
  7634. onViewUpdate(settingsMainView) {
  7635. let item = $(
  7636. '[data-key="useVisitedFunction_'.concat(host2, '"]'),
  7637. settingsMainView
  7638. )
  7639. if (!isAvailableOnCurrentSite() && item) {
  7640. item.style.display = "none"
  7641. item.parentElement.style.display = "none"
  7642. }
  7643. item = $(
  7644. '[data-key="displayEffectOfTheVisitedContent_'.concat(host2, '"]'),
  7645. settingsMainView
  7646. )
  7647. if (item) {
  7648. item.style.display = getSettingsValue(
  7649. "useVisitedFunction_".concat(host2)
  7650. )
  7651. ? "flex"
  7652. : "none"
  7653. }
  7654. item = $('[data-key="customStyleValue"]', settingsMainView)
  7655. if (item) {
  7656. item.parentElement.style.display = getSettingsValue("customStyle")
  7657. ? "block"
  7658. : "none"
  7659. }
  7660. item = $(".bes_tip", settingsMainView)
  7661. if (item) {
  7662. item.style.display = getSettingsValue("customStyle")
  7663. ? "block"
  7664. : "none"
  7665. }
  7666. item = $(
  7667. '[data-key="customStyleValue_'.concat(host2, '"]'),
  7668. settingsMainView
  7669. )
  7670. if (item) {
  7671. item.parentElement.style.display = getSettingsValue(
  7672. "customStyle_".concat(host2)
  7673. )
  7674. ? "block"
  7675. : "none"
  7676. }
  7677. },
  7678. })
  7679. if (!getSettingsValue("enableCurrentSite_".concat(host2))) {
  7680. return
  7681. }
  7682. await initStorage()
  7683. setTimeout(outputData, 1)
  7684. onSettingsChange()
  7685. onSettingsChange2()
  7686. await displayTags()
  7687. addEventListener(doc, "visibilitychange", async () => {
  7688. if (!doc.hidden) {
  7689. await displayTags()
  7690. }
  7691. })
  7692. bindDocumentEvents()
  7693. bindWindowEvents()
  7694. const observer = new MutationObserver(async (mutationsList) => {
  7695. let shouldUpdate = false
  7696. for (const mutationRecord of mutationsList) {
  7697. if (shouldUpdateUtagsWhenNodeUpdated(mutationRecord.addedNodes)) {
  7698. shouldUpdate = true
  7699. break
  7700. }
  7701. if (shouldUpdateUtagsWhenNodeUpdated(mutationRecord.removedNodes)) {
  7702. shouldUpdate = true
  7703. break
  7704. }
  7705. }
  7706. if (shouldUpdate) {
  7707. cleanUnusedUtags()
  7708. displayTagsThrottled()
  7709. }
  7710. if ($("#vimiumHintMarkerContainer")) {
  7711. addClass(doc.body, "utags_show_all")
  7712. addClass(doc.documentElement, "utags_vimium_hint")
  7713. } else if (hasClass(doc.documentElement, "utags_vimium_hint")) {
  7714. removeClass(doc.documentElement, "utags_vimium_hint")
  7715. hideAllUtagsInArea()
  7716. }
  7717. })
  7718. observer.observe(doc, {
  7719. childList: true,
  7720. subtree: true,
  7721. })
  7722. addEventListener(doc, "mouseover", (event) => {
  7723. const target = event.target
  7724. if (
  7725. target &&
  7726. (target.tagName === "A" || target.dataset.utags !== void 0)
  7727. ) {
  7728. displayTagsThrottled()
  7729. }
  7730. })
  7731. }
  7732. runWhenHeadExists(async () => {
  7733. if (doc.documentElement.dataset.utags === void 0) {
  7734. doc.documentElement.dataset.utags = "".concat(host2)
  7735. await main()
  7736. }
  7737. })
  7738. })()