ヤフオクで非表示とメモ

q:非表示 w:アンドゥ b:NGワード Shift+Q:NG編集 12:メモを追加 34:自由メモ 56:定型文をメモ Shift+!:メモを編集 Shift+":自動メモのみ全削除 Shift+#:メモを一時非表示 Shift+56:定型文を設定 .:上限価格 t:半透明モード

目前為 2024-06-21 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name ヤフオクで非表示とメモ
  3. // @description q:非表示 w:アンドゥ b:NGワード Shift+Q:NG編集 12:メモを追加 34:自由メモ 56:定型文をメモ Shift+!:メモを編集 Shift+":自動メモのみ全削除 Shift+#:メモを一時非表示 Shift+56:定型文を設定 .:上限価格 t:半透明モード
  4. // @version 0.5.97
  5. // @match *://auctions.yahoo.co.jp/search/*
  6. // @match *://page.auctions.yahoo.co.jp/jp/auction/*
  7. // @match *://auctions.yahoo.co.jp/seller/*
  8. // @match *://auctions.yahoo.co.jp/category/list/*
  9. // @match *://cpu.userbenchmark.com/*
  10. // @match *://webcomics.jp/*
  11. // @match *://www.amazon.co.jp/*
  12. // @exclude *://www.amazon.co.jp/*/cart/*
  13. // @exclude *://www.amazon.co.jp/*/buy/*
  14. // @exclude *://www.amazon.co.jp/*/huc/*
  15. // @exclude *://www.amazon.co.jp/*/css/*
  16. // @exclude *://www.amazon.co.jp/ap/*
  17. // @exclude *://www.amazon.co.jp/gp/*
  18. // @exclude *://www.amazon.co.jp/auto-deliveries*
  19. // @match *://booklive.jp/index/no-charge*3
  20. // @match *://ebookjapan.yahoo.co.jp/free*
  21. // @match *://ebookjapan.yahoo.co.jp/ranking/free/*
  22. // @match *://ebookjapan.yahoo.co.jp/ranking/details/free/*
  23. // @match *://ebookjapan.yahoo.co.jp/viewer*
  24. // @match *://sokuyomi.jp/*
  25. // @match *://csbs.shogakukan.co.jp/free*
  26. // @match *://www.rtings.com/*/tools/table*
  27. // @match *://www.rtings.com/*/reviews/*
  28. // @match *://www.nicovideo.jp/search/*
  29. // @match *://www.nicovideo.jp/tag/*
  30. // @match *://www.nicovideo.jp/user/*
  31. // @match *://www.nicovideo.jp/series/*
  32. // @match *://www.nicovideo.jp/my/*
  33. // @match *://www.nicovideo.jp/ranking*
  34. // @match *://www.nicovideo.jp/watch/*
  35. // @match *://*.5ch.net/*
  36. // @match *://www.ebay.com/sch/*
  37. // @match *://www.ebay.com/itm/*
  38. // @match *://jmty.jp/*
  39. // @match *://gf.qytechs.cn/*/scripts*
  40. // @match *://*.aliexpress.com/af/*
  41. // @match *://*.aliexpress.com/item/*
  42. // @match *://*.aliexpress.com/wholesale*
  43. // @match *://www.cmoa.jp/freecontents*
  44. // @match *://piccoma.com/*
  45. // @match *://www.mangaz.com/*
  46. // @match *://www.sukima.me/*
  47. // @match *://*.userbenchmark.com/*
  48. // @match *://www.hellowork.mhlw.go.jp/kensaku/*
  49. // @match *://kakaku.com/*
  50. // @match *://seiga.nicovideo.jp/*
  51. // @match *://tsugimanga.jp/*
  52. // @match *://www.yodobashi.com/*
  53. // @match *://www.youtube.com/*
  54. // @match *://*.iherb.com/*
  55. // @match *://www.suruga-ya.jp/*
  56. // @match *://twitter.com/*
  57. // @match *://www.nicovideo.me/*
  58. // @match *://www.nicochart.jp/*
  59. // @match *://pubmed.ncbi.nlm.nih.gov/?term=*
  60. // @match *://pubmed.ncbi.nlm.nih.gov/?linkname=*
  61. // @match *://pubmed.ncbi.nlm.nih.gov/*
  62. // @match *://a-timesale.com/*
  63. // @match *://rrws.info/*
  64. // @match *://commons.nicovideo.jp/*
  65. // @match *://scholar.google.tld/*
  66. // @match *://hibiki-radio.jp/*
  67. // @match *://www.onsen.ag/
  68. // @match *://www.freem.ne.jp/*
  69. // @match *://shopping.yahoo.co.jp/search*
  70. // @match *://360life.shinyusha.co.jp/*
  71. // @match *://omocoro.jp/*
  72. // @match *://minsoku.net/*
  73. // @match https://refind2ch.org/search*
  74. // @match *://chiebukuro.yahoo.co.jp/*
  75. // @match *://www.msdmanuals.com/*
  76. // @match *://ff5ch.syoboi.jp/?q=*
  77. // @match *://todo-ran.com/*
  78. // @match *://booth.pm/*
  79. // @match *://sakura-checker.jp/category/*
  80. // @match https://chrome.google.com/webstore/search/*
  81. // @match https://chrome.google.com/webstore/detail/*
  82. // @match *://twicomi.com/*
  83. // @match *://twiman.net/*
  84. // @match *://free.arinco.org/*
  85. // @match *://workman.jp/shop/*
  86. // @match *://www.uniqlo.com/*
  87. // @match *://*.shitaraba.net/bbs/read.cgi/*
  88. // @match *://*.shitaraba.net/bbs/read_archive.cgi/*
  89. // @match *://*.ftbucket.info/*
  90. // @match *://kuzure.but.jp/*
  91. // @match *://*.2chan.net/*
  92. // @match *://anige.horigiri.net/*
  93. // @match *://futapo.futakuro.com/*
  94. // @match *://kako.futakuro.com/futa/*
  95. // @match https://kakaku.com/pc/note-pc/itemlist.aspx
  96. // @match https://kakaku.com/pc/desktop-pc/itemlist.aspx
  97. // @match *://btopc-minikan.com/*
  98. // @match *://pcfreebook.com/*
  99. // @match *://search.bilibili.com/*
  100. // @match *://www.mcdonalds.co.jp/menu/*
  101. // @match *://*.2chan.net/b/futaba.php*
  102. // @match *://nitter.cz/*
  103. // @match *://nitter.net/*
  104. // @match *://www.uexpress.com/*
  105. // @match https://find.5ch.net/search
  106. // @match https://tsumanne.net/*/data/*
  107. // @match *://zzzsearch.com/*
  108. // @match *://review.kakaku.com/review/*
  109. // @match *://www.netoff.co.jp/*
  110. // @match *://jp.daisonet.com/*
  111. // @noframes
  112. // @grant GM_setValue
  113. // @grant GM_getValue
  114. // @grant GM_deleteValue
  115. // @grant GM_addStyle
  116. // @grant GM.addStyle
  117. // @grant GM.setClipboard
  118. // @grant GM.openInTab
  119. // @run-at document-idle
  120. // @namespace https://gf.qytechs.cn/users/181558
  121. // @require https://code.jquery.com/jquery-3.7.1.min.js
  122. // @require https://code.jquery.com/ui/1.13.2/jquery-ui.min.js
  123. // ==/UserScript==
  124.  
  125. (function() {
  126. const FUTAPO_CRAM_TITLE = 1; // 1:futapoでboxの横幅が狭いときでもタイトルを詰め込む
  127. const FUTAPO_89_NOTIFY = "notify"; // futapoで8/9登録がヒットした時にどう通知するか "notify"でnotification API(推奨)、"sound"で効果音。"notify sound"で両方、""で通知しない
  128. const FUTABA_SET_56MEMO_TO_ANCHORED = 3; // 1:ふたばで監視ワードヒットレスと自分のレスに自動的に5メモを付ける 2:1に加え5メモへのレスに6メモを付ける 3:1+2に加え遠くても5メモに連鎖するレスには6メモをつける(推奨) 4:1+2+3に加え遠くても6メモに連鎖するレスにも6メモをつける
  129. const FUTABA_NOTIFY_NEWRES_SOUND_MEMO_QUOTED = "5 6 m"; // ふたばで新着レスのNotification通知でメモのついたレスが引用された時に音で知らせるか "5"で○メモに鳴らす、"6"で×メモに鳴らす、"m"で監視ワードに鳴らす、""で鳴らさない、"5 6 m"などで複数設定可能
  130. const FUTABA_Z_TO_COPY_TO_CLIPBOARD_AS_TEXT_TOO = "${num1} ${name1} ${name2} ${time} ${num2} ${soudane}\n${text}\n"; // ふたばでzキーかレス右上の□のクリック時についでに内容をテキストとしてクリップボードにコピーする、その書式 "":コピーしない
  131. const FUTABA_FLOAT_RELOAD_BUTTON = 1; // 1:ふたばでリロードボタンを浮遊させる
  132. const FUTABA_HOVER_POPUP_REPLACE = 1; // 1:ふたばで>引用ポップアップを置き換える
  133. const FUTABA_HOVER_POPUP_DELAY = 1; // ふたばで>引用の上に静止してn/60秒間後にポップアップを表示する -1:瞬間&低負荷(mousemove) 1:瞬間(interval) 2~:n/60秒(interval) 0:無効
  134. const FUTABA_REPLACE_RES0 = 1; // 1:ふたばでスレ本文をレス番号0のように置き換える 引用ポップアップ等が働くために必要
  135. const FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY = 1; // 1:ふたばで>no.○○や>○○.jpgや>fu○○.jpgといった引用にも本文のバルーン引用を追加する(要「5chサムネイル表示他」併用)
  136. const FUTABA_EXPERIMENTAL_DISPLAY_CHAINED = 1; // 1:ふたばでレス右上の□に引用連鎖数を書き入れていく ※現状重い処理
  137. const FUTABA_AUTO_RELOAD_INTERVAL = 1; // 1-10:ふたばでnキーオン時の自動リロードする最短間隔(分) ※新着がなく無操作だと自動的に10分まで伸びる
  138. const FUTABA_ALTZ_FILENAME_SUFFIX = "●"; // ふたばでAlt+Z時にファイル名の末尾に付ける文字
  139. const FUTABA_PLAY_GIF_INLINE = 0; // 1:ふたばのgifをインラインで動かす
  140. const FUTABA_POPUP_PADDING_RATE = 169; // ふたばの引用ポップアップの額縁の太さ(大きいほど細い)
  141. const FUTABA_REMOVE_REDIRECT_PAGE = 1; // 1:ふたばでリンクからクッションページを省略
  142.  
  143. const IN5CH_REMOVE_AKABAN = 1; // 1:5chで垢版ボタンをとりあえず隠す 0:そのまま
  144. const dniCancel = 1; // DNIがobserve(ms)以上連続して発火しても途切れるのを待ち続ける
  145. const FUTABA_DEBUG = 0; // 1-2:ふたばで開発用情報を表示 1:最下行ログ 2:1+タブタイトル
  146. const DEBUG_CATCH = 0; // 1:catchしたエラーをalert
  147. const KEYCHANGE_DEBUG = "disable"; // 押す度にdebugを0~3に切り替えるキー "Shift+D","disable"等
  148. const ENABLE_HELP = 1; // 1:操作ガイドを表示 0:無効
  149. const ENABLE_AUTOMEMO = 7; // 0:自動メモを無効 1でオン 2~7:大きくするほど一時的に表示が崩れる代わりに確実
  150. const REPLACE_LINK_IN_YOUTUBE = 1; // 1:YouTubeで投稿者のチャンネルのホームタブへのリンクをチャンネルの動画タブへのリンクに置き換える
  151. const ENABLE_EXCEPT_YAJ = 1; // 1:ヤフオク以外でも有効 0:ヤフオクでのみ動作
  152. var debug = 0; // 1~だとデバッグモード V&&dc(text) 1:非対応ページでその旨表示など/コンソールにverbose表示 2:verboseをポップアップ(速度測定して表示 debug&&sw("項目"))&非表示にした原因に枠追加 3:Q/1/2等の対象要素を目立たせる
  153. const ENABLE_MEASURE_TIME_SPENT = 0; // 1で速度測定して表示 debug&&sw("項目")
  154.  
  155. const fasttest = 1; // 1:高速モードを試用
  156. const FUTABA_BGC = 0 ? "#f0e0d6" : "#ffffee"
  157.  
  158. const ISCHROME = window.navigator.userAgent.toLowerCase().indexOf('chrome') != -1
  159. var futabapopupscale;
  160. const futabapicksizeDefault = 84
  161. var futabapicksizeL = futabapicksizeDefault;
  162. var futabapicksize = 100;
  163. var hovertimer = 0;
  164. var swb = new Date();
  165. var prefCache = []
  166.  
  167. GM_addStyle("span.yhmMyMemo{all:initial; word-wrap:break-word;cursor:pointer; font-size:14px; font-weight:bold; margin:0px 1px; text-align:center; padding:0px 6px 0px 6px; border-radius:12px; color:white;font-family:sans-serif;}")
  168. debug && sw("reset")
  169.  
  170. String.prototype.match0 = function(re) { let tmp = this.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可
  171. String.prototype.match1 = function(re) { return this?.match(re)?.slice(1)?.find(v => v) } // this./a(bc)|d(ef)/ 等の()でキャプチャした最初の1つを返す gフラグ不可
  172. //String.prototype.nfd = function() { return SITE.nfd ? this?.normalize("NFD") : String(this) } // 文字列をNFDエンコードにまとめる
  173. String.prototype.sanit = function() { return this.replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;') }
  174.  
  175. function adja(place = document.body, pos, html) {
  176. return place ? (place.insertAdjacentHTML(pos, html), place) : null;
  177. }
  178. let addstyle = {
  179. added: new Set(),
  180. add: function(str) {
  181. if (this.added.has(str)) return;
  182. end(document.head, `<style>${str}</style>`);
  183. this.added.add(str);
  184. },
  185. }
  186.  
  187. var SITE = {}
  188. let inYOUTUBE = location.hostname.match0(/^www\.youtube\.com|^youtu\.be/);
  189.  
  190. $.fn.animate2 = function(properties, duration, ease) {
  191. ease = ease || 'ease';
  192. var $this = this;
  193. var cssOrig = { transition: $this.css('transition') };
  194. return $this.queue(next => {
  195. properties['transition'] = 'all ' + duration + 'ms ' + ease;
  196. $this.css(properties);
  197. setTimeout(function() {
  198. $this.css(cssOrig);
  199. next();
  200. }, duration);
  201. });
  202. };
  203.  
  204. if (window != parent) return;
  205. const WAIT = performance.now(); // ページ開始後のウエイト用 delayAutoWeightingをかける
  206. /* const COLOR1 = "#6080ff",
  207. COLOR2 = "#c03020",
  208. COLOR3 = "#808080",
  209. COLOR5 = "#6080ff",
  210. COLOR6 = "#c03020",
  211. COLORVIDEOTIME = "#204020",
  212. COLORCPUSCORE = "#a08000",
  213. */
  214. const OLD_COLOR1 = "#6080ff",
  215. OLD_COLOR2 = "#c03020",
  216. OLD_COLOR3 = "#808080",
  217. OLD_COLOR5 = "#6080ff",
  218. OLD_COLOR6 = "#c03020",
  219. OLD_COLORVIDEOTIME = "#204020",
  220. OLD_COLORCPUSCORE = "#a08000",
  221. COLOR1 = "#57f", //"#6080ff",
  222. COLOR2 = "#c32", //"#c03020",
  223. COLOR3 = "#888", //"#808080",
  224. COLOR5 = "#57f", //"#6080ff",
  225. COLOR6 = "#c32", //"#c03020",
  226. COLORVIDEOTIME = "#242", //"#204020",
  227. COLORCPUSCORE = "#970", //"#a08000",
  228. COLOR_ALERT_WORD = "#882", //"#a08000",
  229. KEYHIDE = "q",
  230. KEYUNDO = "w",
  231. KEYBW = "b",
  232. KEYEDIT = "Shift+Q",
  233. // KEYEDIT2 = "Shift+B",
  234. KEYMAXP = ".",
  235. KEYMEMO1 = "1",
  236. KEYMEMO2 = "2",
  237. KEYMEMO1S = "3",
  238. KEYMEMO2S = "4",
  239. KEYMEMO5 = "5",
  240. KEYMEMO6 = "6",
  241. KEYMEMO5EDIT = "Shift+%",
  242. KEYMEMO6EDIT = "Shift+&",
  243. KEYTOGGLEtranslucent = "t",
  244. KEYRESETMEMO = "Shift+!",
  245. KEYRESETMEMOAUTO = "Shift+\"";
  246. var MEMO5WORD = "", // 5キーの定型文初期値 ""なら現在年月日
  247. MEMO6WORD = ""; // 6キーの定型文初期値 ""なら現在年月日
  248.  
  249. var pauseAll = 0;
  250. let kaisuuU = 0;
  251. var GF = {}
  252. GF.yhmSortType = 0
  253. GF.isNico = location.host == "www.nicovideo.jp"
  254. var memofast = false;
  255.  
  256. // 上が優先
  257. const SITEINFO = [{
  258. id: "DAISONET",
  259. urlRE: '//jp.daisonet.com/',
  260. title: 'h1.product-meta__title.heading.h1.text--strong , a.product-item__title',
  261. box: 'div.product-block-list , div.product-item--vertical',
  262. forceTranslucentFunc: e => lh('daisonet.com/products/'),
  263. redoWhenRefocused: 1,
  264. }, {
  265. id: `NETOFF`,
  266. urlRE: '//www.netoff.co.jp/',
  267. box: 'li.clearfix',
  268. title: 'p > a.fw',
  269. wholeHelp: [() => 1, " A:ソート"],
  270. keyFunc: [{
  271. key: 'a', // a::
  272. func: () => {
  273. var sorttype = GF.yhmSortType || 0
  274. let menu = [
  275. { t: "安い→新しい", f: () => { sortdom(elegeta('li.clearfix'), v => +eleget0('.price', v)?.textContent?.replace(/,/g, "")?.match0(/\d+/) * 1000000000 + (1000000 - +(eleget0('.subinfo', v)?.textContent?.replace(/(\d+).(\d+).*/, "$1$2")))) } },
  276. ]
  277. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  278. menu[sorttype].f()
  279. GF.yhmSortType = (++sorttype) % menu.length
  280. }
  281. }]
  282. }, {
  283. id: 'KAKAKU',
  284. urlRE: 'https://review.kakaku.com/review/',
  285. title: 'h2[itemprop="name"]',
  286. box: 'div#main',
  287. forceTranslucentFunc: e => 1,
  288. memoFunc: e => e?.parentNode?.parentNode,
  289. }, {
  290. id: 'zzzsearch.com',
  291. urlRE: '//zzzsearch.com/',
  292. title: '//div[@class="gs-title"]/a[@dir="ltr"]',
  293. box: 'div.gsc-webResult.gsc-result',
  294. observe: 333,
  295. keyFunc: [{
  296. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  297. // func: () => { searchWithHistory("find5ch", "find5ch", ['https://find.5ch.net/search?q=***',`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`], " OR ") },
  298. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  299. // func: () => { searchWithHistory("REFIND2CH", "re.Find2ch", 'https://refind2ch.org/search?q=***&sort=rate', " OR ") },
  300. }],
  301. }, {
  302. id: 'uexpress',
  303. urlRE: /\/\/www\.uexpress\.com\//,
  304. keyFunc: [{
  305. key: 'Shift+F', // Shift+F::キーワード検索
  306. func: () => { searchWithHistory("uexpress", "UExpress", 'https://www.google.co.jp/search?q=***%20site:www.uexpress.com/life/miss-manners', "|") },
  307. }],
  308. }, {
  309. id: 'nitter',
  310. urlRE: /\/\/nitter\.cz\/|\/\/nitter.\.net\//,
  311. title: '.username',
  312. box: '.timeline-item',
  313. observe: 500,
  314. }, {
  315. id: 'futaba_catalog',
  316. urlRE: /https?:\/\/[^\.]+\.2chan\.net\/[^/]+\/futaba\.php\?mode=cat/,
  317. title: '.tdDiv small',
  318. box: '#cattable tbody tr td',
  319. isHidePartialMatch: 1,
  320. titleSubstr: true,
  321. hideSelectedWord: 1,
  322. disableKeyB: 0,
  323. listTitleXPIgnoreNotExist: 1,
  324. funcOnlyFirst: () => {
  325.  
  326. $('#cattable td').wrapInner('<div class="tdDiv"></div>')
  327.  
  328. // レス数とvボタンを下の帯に固定
  329. elegeta('.pdmc').forEach(e => e.closest('td')?.appendChild(e))
  330. addstyle.add(`.pdmc { margin-top:auto; margin-bottom:auto; right: 0em; bottom:0.2em; position:absolute; z-index:99; opacity:1; padding:0.15em; background-color:#ffffee; }`)
  331. GF.imgw = Math.max(eleget0('#cattable img')?.offsetWidth, eleget0('#cattable img')?.offsetHeight) || 40
  332. GF.boxw = eleget0('#cattable td')?.offsetWidth || 40
  333.  
  334. setSlider(eleget0('//body/span[1]'), 0, 320, 0, "画像サイズ:***px", "futaba_catalog_imagesize", (val) => {
  335. eleget0('#imagesizecss')?.remove()
  336. $("#boxs").remove();
  337. GF.imgw = val
  338. if (val) end(document.head, `<style id="imagesizecss" data-val="${val}">#cattable img{max-width:${val}px; width:auto; height:auto; max-height:${val}px; }</style>`)
  339. if (val) { end(document.head, `<style id="boxs">${GF.boxw<2*GF.imgw?"#cattable img{display:block; height:auto !important; max-width:100% !important; margin-bottom:5px; margin-right:auto; margin-left:auto;}":"#cattable img{float:left; margin-bottom:5px; margin-right:5px;}"}</style>`) }
  340.  
  341. }, 0, '')
  342. setSlider(eleget0('#setSliderfutaba_catalog_imagesize'), 0, 300, 0, "box高さ:***px", "futaba_catalog_boxheight", (val) => {
  343. eleget0('#futaba_catalog_imagesize')?.remove()
  344. if (val) end(document.head, `<style id="boxheightcss">#cattable td{height:calc(${val - 2}px - 0.5em); } #cattable tbody{display:grid !important;} #cattable tr,#cattable td{ display:inline-block; overflow:hidden; min-height:${val - 2}px !important; max-height:${val - 2}px !important; height:${val - 2}px !important;}</style>`) // レス数とvボタンを下の帯に固定
  345. if (val) addstyle.add(`#cattable img{border:black solid 1px;}`); //$("#cattable img").wrap('<div class="imgDiv"></div>') eleget0('#futaba_catalog_imagesize')?.remove()
  346.  
  347. }, 0, '')
  348. setSlider(eleget0('#setSliderfutaba_catalog_imagesize'), 0, 300, 0, "box横幅:***px", "futaba_catalog_boxwidth", (val) => {
  349. eleget0('#boxwidthcss')?.remove()
  350. $("#boxs").remove();
  351. $('#cattable td a+br').remove()
  352. GF.boxw = val - 5
  353. if (val) end(document.head, `<style id="boxwidthcss">.tdDiv{margin:5px;} #cattable small{line-break: anywhere; } #cattable td{vertical-align:top; word-break:break-all; width:${1+val}px !important;}</style>`)
  354. if (val) { end(document.head, `<style id="boxs">${GF.boxw<2*GF.imgw?"#cattable img{display:block; height:auto !important; max-width:100% !important; margin-bottom:5px; margin-right:auto; margin-left:auto;}":"#cattable img{float:left; margin-bottom:5px; margin-right:5px;}"}</style>`) }
  355.  
  356. }, 0, '')
  357. setSlider(eleget0('#setSliderfutaba_catalog_imagesize'), 0, 24 * 3, 0, "文字サイズ:***/3px", "futaba_catalog_fontsize", (val) => {
  358. eleget0('#textsizecss')?.remove()
  359. if (val) end(document.head, `<style id="textsizecss">#cattable small{font-size:${val/3}px; }</style>`)
  360. }, 0, '')
  361. },
  362. }, {
  363. id: 'search.bilibili.com',
  364. urlRE: '//search.bilibili.com/',
  365. listTitleXP: '//h3[@class="bili-video-card__info--tit"]',
  366. listTitleSearchXP: '//h3[@class="bili-video-card__info--tit"][**title**]/ancestor::div[contains(@class,"video-list-item")]',
  367. listTitleMemoSearchXP: '//h3[@class="bili-video-card__info--tit"][**title**]',
  368. listGen: 7,
  369. observe: 999,
  370. useText: 1,
  371. }, {
  372. id: 'mcdonaldsmenu',
  373. urlRE: '//www.mcdonalds.co.jp/menu/',
  374. keyFunc: [{
  375. key: 'a', // a::
  376. func: () => {
  377. var sorttype = GF.yhmSortType || 0
  378. let menu = [
  379. { t: "安い順", f: () => { sortdom(elegeta('//span[@class="product-list-card-price-number text-2xl font-extrabold"]/../../..'), v => eleget0('//span[@class="product-list-card-price-number text-2xl font-extrabold"]', v)?.textContent) } },
  380. { t: "高い順", f: () => { sortdom(elegeta('//span[@class="product-list-card-price-number text-2xl font-extrabold"]/../../..'), v => eleget0('//span[@class="product-list-card-price-number text-2xl font-extrabold"]', v)?.textContent, 1) } },
  381. { t: "タイトル", f: () => { sortdom(elegeta('//span[@class="product-list-card-price-number text-2xl font-extrabold"]/../../..'), v => eleget0('.product-list-card-name', v)?.textContent) } },
  382. ]
  383. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  384. menu[sorttype].f()
  385. GF.yhmSortType = (++sorttype) % menu.length
  386. return
  387. }
  388. }],
  389. func: () => popup3("A:ソート", 5),
  390. }, {
  391. id: 'pcfreebook.com',
  392. urlRE: '//pcfreebook.com/',
  393. listTitleXP: '//td[1]/a[@target="_blank" and @rel="noopener nofollow noreferrer"]',
  394. listTitleSearchXP: '//td[1]/a[@target="_blank" and @rel="noopener nofollow noreferrer"][+++]/ancestor::tr',
  395. listTitleMemoSearchXP: '//td[1]/a[@target="_blank" and @rel="noopener nofollow noreferrer"][+++]',
  396. listGen: 3,
  397. listTitleMemoSearchXPSameGen: 1,
  398. listTitleXPIgnoreNotExist: 1,
  399. observe: 2500,
  400. }, {
  401. id: 'btopc-minikan.com',
  402. urlRE: '//btopc-minikan.com/',
  403. titleProcessFunc: (title) => { return title.replace(/\n|\s/gmi, " ").trim() },
  404. listTitleXP: '//span[@class="itemname"]',
  405. listTitleSearchXP: '//span[@class="itemname"][++title++]/ancestor::tr',
  406. listTitleMemoSearchXP: '//span[@class="itemname"][++title++]',
  407. listTitleMemoSearchXPSameGen: 1,
  408. useTitle: 1,
  409. listGen: 4,
  410. func: () => {
  411. elegeta('//td[1]/div[@class="notranslate"]|.//td[@class="CPUgrease-GraphCell-Maker"]').forEach(e => e.insertAdjacentHTML("beforeend", `<span class="itemname" title="${e.textContent.replace(/\n|\s/gmi," ").trim()}"> </span>`))
  412. },
  413. listTitleXPIgnoreNotExist: 1,
  414. observe: 2500,
  415. }, {
  416. urlRE: /^https:\/\/kakaku.com\/pc\/note-pc\/itemlist\.aspx|https:\/\/kakaku\.com\/pc\/desktop-pc\/itemlist.aspx|\/\/kakaku.com\/pc\/gaming-pc\/itemlist.aspx|\/\/kakaku.com\/pc\/gaming-note\/itemlist.aspx|\/\/kakaku.com\/pc\/stick-pc\/itemlist.aspx/,
  417. WhateverFirstAndEveryAPFunc: () => {
  418. if (!elegeta('//th[@class="sub thHeader" and contains(text(),"CPUスコア(PassMark) ")]')[0]) return;
  419. popup3("A:CPUスコア単価で絞り込み", 4)
  420. //$(".cps").remove()
  421. // let arr = lh("gaming") ? elegeta('//table/tbody/tr[@class="tr-border"]/td[11]') : elegeta('//table/tbody/tr[@class="tr-border"]/td[10]')
  422. let arr = lh("gaming") ? elegeta('table tbody tr.tr-border td:nth-child(11):not([data-scorecost])') : elegeta('table tbody tr.tr-border td:nth-child(10):not([data-scorecost])')
  423. arr.forEach(e => {
  424. e.dataset.scorecost = 1
  425. // let p = elegeta('//td[2]/ul/li[@class="pryen"]/a', e?.closest("tr"))[0]
  426. let p = elegeta('td:nth-child(2) ul li.pryen a', e?.closest("tr"))[0]
  427. let b = e.parentNode
  428. let cpu = parseInt(e.innerText.replace(/\D/g, ""))
  429. let price = parseInt(p.innerText.replace(/\D/g, ""))
  430. if (e.textContent.match(/\d/)) {
  431. e.insertAdjacentHTML("beforeend", `<div title="Aキーでこの上限で絞り込み" class="cps" style="color:#F00;" >価格/スコア<br><span class="cputanka">${((price/cpu).toFixed(2))}</span></div>`)
  432. } else {
  433. end(e, '<span class="cputanka"></span>')
  434. }
  435. })
  436. },
  437. keyFunc: [{
  438. key: 'a', // a::
  439. func: () => {
  440. if (!elegeta('//th[@class="sub thHeader" and contains(text(),"CPUスコア(PassMark) ")]')[0]) return;
  441. GF.base = proInput("CPUスコア単価上限を入力してください", $('#CPS').data("cps") || 10) || 0;
  442. autoPagerizedD("cpsAP", () => {
  443. $('#CPS').remove();
  444. $(document.body).append(`<span id="CPS" data-cps="${GF.base}" style="background-color:#"></span>`)
  445. $(elegeta('table tbody tr.tr-border')).show()
  446. if (GF.base <= 0) return
  447. elegeta('.cputanka').forEach(e => {
  448. let cps = Number(e?.innerText || 0)
  449. let b = e.closest("tr.tr-border")
  450. if (!cps || cps > GF.base) {
  451. $([b, b.previousSibling, b.previousSibling.previousSibling]).hide()
  452. }
  453. })
  454. })
  455. }
  456. }, ],
  457. }, {
  458. urlRE: /\/\/www.ftbucket.info\/scrapshot\/ftb\/index\.php|\/\/www.ftbucket.info\/scrapshot\/ftb\/?$|\/\/www.ftbucket.info\/scrapshot\/ftb\/\?favo=/,
  459. id: 'FUTACHAN_CATALOG',
  460. listTitleXP: '//div[@class="tdDiv"]/span/div',
  461. listTitleSearchXP: '//div[@class="tdDiv"]/span/div[***]/../..',
  462. listTitleMemoSearchXP: '//td/div[@class="tdDiv"]/span/div[***]',
  463. listGen: 5,
  464. listTitleXPIgnoreNotExist: 1,
  465. listGen: 4,
  466. WhateverFirstAndEveryAPFunc: () => {
  467. popup3("Shift+F:FTBucket検索", 8, 5000)
  468. },
  469. // WhateverFirstAndEveryAPFunc: () => { SITEINFO[SITEINFO.findIndex(c => c.id == "FUTACHAN")].WhateverFirstAndEveryAPFunc() },
  470. keyFunc: [{
  471. key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
  472. func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
  473. // func: () => { SITEINFO[SITEINFO.findIndex(c => c.id == "FUTACHAN")].keyFunc[0].func() },
  474. }],
  475. // memoStyle:'display:inline-block;',
  476. //listTitleMemoSearchXPSameGen: 1,
  477. delay: 333,
  478. funcOnlyFirst: () => {
  479. //if (!lh("mode=c")) return;
  480.  
  481. eleget0('//html/body/table[2]')?.setAttribute("id", "cattable")
  482. $('#cattable td').wrapInner('<div class="tdDiv"></div>')
  483. begin(document.body, `<div id="slidersP" style="position:fixed;z-index:999; top:1em; right:1em;"><div id="sliders1"></div><br><div id="sliders2"></div><br><div id="sliders3"></div><br><div id="sliders4"></div><br></div>`)
  484. $('#cattable td>a>img').css({ "border": "black solid 1px" }).wrap('<div class="imgDiv"></div>')
  485. // $('#cattable td').wrapInner('<div class="tdDiv"></div>')
  486.  
  487. setSlider(eleget0('#sliders4'), 0, 300, 0, "box高さ:***px", "futabucket_catalog_boxheight", (val) => {
  488. eleget0('#boxheightcss')?.remove()
  489. if (val) end(document.head, `<style id="boxheightcss">#cattable tbody tr td{height:calc(${val - 2}px - 0.5em); } tbody{display:grid !important;} #cattable tbody tr { display:inline-block; overflow:hidden; margin:0 auto; min-height:${val - 2}px !important; max-height:${val - 2}px !important; height:${val - 2}px !important;}</style>`)
  490. }, 0, '')
  491.  
  492. setSlider(eleget0('#sliders3'), 0, 500, 0, "box横幅:***px", "futabucket_catalog_boxwidth", (val) => {
  493. eleget0('#boxwidthcss')?.remove()
  494. $('#cattable td a+br').remove()
  495. if (val) end(document.head, `<style id="boxwidthcss">.tdDiv{margin:5px;} #cattable tbody tr td{line-break: anywhere; } #cattable tbody tr td img{float:left; margin-bottom:5px; margin-right:5px;} #cattable tbody tr td{vertical-align:top; word-break:break-all; width:${1+val}px !important; max-width:${1+val}px !important;}</style>`)
  496. if (val) elegeta('td div span[title] div').forEach(e => e.textContent = e.parentNode.title)
  497. }, 0, '')
  498.  
  499. //setSlider(eleget0('#sliders'), 1, 24 * 3, 12 * 3, "文字サイズ:***/3px", "futabucket_catalog_fontsize", (val) => {
  500. // eleget0('#textsizecss')?.remove()
  501. // end(document.head, `<style id="textsizecss">#cattable div{font-size:${val/3}px !important; }</style>`)
  502. //}, 0, '')
  503.  
  504. setSlider(eleget0('#sliders2'), 0, 320, 0, "画像サイズ:***px", "futabucket_catalog_imagesize", (val) => {
  505. eleget0('#imagesizecss')?.remove()
  506. if (val) end(document.head, `<style id="imagesizecss">#cattable img{ object-fit: cover !important; max-width:${val}px !important; width:auto !important; height:auto !important; max-height:${val}px !important; }</style>`)
  507. }, 0, '')
  508.  
  509. setSlider(eleget0('#sliders1'), 0, 20, 0, "タイトル行数:***行", "futabucket_catalog_titlerow", (val) => {
  510. eleget0('#catalogrowscss')?.remove()
  511. if (val) end(document.head, `<style id="catalogrowscss">#cattable .tdDiv span div{ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: ${val} !important;; overflow: hidden; }</style>`)
  512. if (val) elegeta('td div span[title] div').forEach(e => e.textContent = e.parentNode.title)
  513. }, 0, '')
  514.  
  515. /*elegeta('//div/input[@type="search" and @id="searchword"]').forEach(e => e.style.width = "calc(100% - 4em)") // 検索フォームを大きく
  516. if (location.href.match0("//www.ftbucket.info/scrapshot/ftb/")) {
  517. setSlider(eleget0('//html/body/div[2]/a/img/..'), 4, 255, 16, "タイトル表示:***文字", "FTBTitleLength", (val) => elegeta('//td/span[@title]/div').forEach(e => e.textContent = e.parentNode.title.substr(0, val)))
  518. setSlider(eleget0('//html/body/div[2]/a/img/..'), 4, 30, 8, "セル幅:***em", "FTBcallWidth", (val) => elegeta('//td/span[@title]/div/../..').forEach(e => e.style.width = `${val}em`))
  519. }*/
  520. },
  521. }, {
  522. urlRE: "\/\/futapo.futakuro.com", // futapo::
  523. id: 'FUTACHAN_CATALOG',
  524. listTitleXP: '//div[@class="thread-text"]',
  525. listTitleSearchXP: '//div[@class="thread-text"][***]/../..|.//span[@class="emph"][***]/../../..',
  526. listTitleMemoSearchXP: '//div[@class="thread-text"][***]|.//span[@class="emph"][***]/..',
  527. listGen: 5,
  528. Bsyntax2: 1,
  529. memoStyle: 'word-break:break-all; font-size:10px !important; line-height:130%; padding:0px 4px 0px 4px; line-break:anywhere;',
  530. preventMemo: m => ["★", "◎", "○"].includes(m),
  531. QRule: "\n\n非表示化に関しては正規表現は使えませんが\nこのサイトではここで登録した内容で8/9メモの追加動作の抑制ができ、\nその抑制に関してだけは正規表現が使え、全角/半角、大文字/小文字も区別しません\n",
  532. listTitleXPIgnoreNotExist: 1,
  533. observe: 666,
  534. observeClass: ["box", "box ", "yhmMyMemo"], //2022年07月12日
  535. WhateverFirstAndEveryAPFunc: () => {
  536. popup3("Shift+F:FTBucket検索\n7:左上優先配置タイトルを設定\n8:左上優先配置(+通知)タイトルを設定\n9:左上優先配置(+開く)タイトルを設定\nShift+789:独自構文使用版789\n0:789メモ一括削除画面\nE:更新 D:下まで読み込む\nG:画像でNG H:画像でピックアップ", 8, 5000) // ↻
  537. },
  538. listTitleMemoSearchXPSameGen: 1,
  539. funcOnlyFirst: () => {
  540. GF.latestReload = Date.now() - 3000
  541. GF.FUTAPO_AUTO_RELOAD_DEFAULT = pref("FUTAPO_AUTO_RELOAD_DEFAULT") || 0;
  542. GM_addStyle('.graybutton{ cursor:pointer; position: fixed; z-index:100; opacity:1; font-size:12px; margin:0px 1px; padding:1px 6px 1px 6px; word-break: break-all !important; border-radius:12px; border:solid 1px #888; background-color:#fff; color:#888;}')
  543. GM_addStyle('.popuptext,.popuptext-back{z-index:1000000000000;}')
  544. GM_addStyle(".boxpri1{animation: pulse1 5s 1; } @keyframes pulse1 { 0% { outline:5px solid #0000ffff; } 40% { outline:5px solid #0000ffff; } 100% { outline:5px solid #0000ff00; } }")
  545. document.querySelector(`head`).insertAdjacentHTML('beforeend', `<style>.waiting{ display: inline-block; vertical-align: middle; color: #666; line-height: 1; width: 1em; height: 1em; border: 0.12em solid currentColor; border-top-color: rgba(102, 102, 102, 0.3); border-radius: 50%; box-sizing: border-box; -webkit-animation: rotate 1s linear infinite; animation: rotate 1s linear infinite; } @-webkit-keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } @keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } }</style>`)
  546.  
  547. if (FUTAPO_CRAM_TITLE) GM_addStyle("div.thread-contents { padding-left: 0px !important;} div.thumbnailContainer { min-width:3em; position:inherit !important; margin-left: 0px !important;}") // boxの横幅が狭いときでもタイトルを詰め込む
  548.  
  549. // フィルタフォームでEscで削除して抜ける
  550. document.addEventListener("keydown", e => {
  551. if (document.activeElement.matches("input#cat_text_search") && e.key == "Escape" && !e.isComposing) {
  552. $("input#cat_text_search").val("").blur()
  553. }
  554. }, true)
  555.  
  556. var lastope = Date.now()
  557. var cdID
  558. //if (eleget0('#reload') && !cdID) {
  559. function waitAndDo(checkFunc, func) { // checkFuncがtrueになったらfuncを実行
  560. if (!checkFunc()) setTimeout(waitAndDo, 500, checkFunc, func);
  561. else func();
  562. }
  563. waitAndDo(() => eleget0('#reload'), () => {
  564. document.body.insertAdjacentHTML("beforeend", `<tt id="cdsw" class="graybutton" style="cursor:pointer;left:1em; bottom:2em; position:fixed;" title="左クリックで無操作時60秒毎に自動更新開始\nもう一度左クリックで停止">&#9211;無操作<br>自動更新</tt>`)
  565.  
  566. $(document).on("mousedown", `#cdsw`, (e) => {
  567. if (e?.button != 0) return;
  568. cdon()
  569. })
  570.  
  571. function cdon() {
  572. pref("FUTAPO_AUTO_RELOAD_DEFAULT", 1)
  573. $('#cdsw').fadeOut(222);
  574. var lastope = Date.now()
  575. $(document).on("mousemove mousedown keydown", () => { lastope = Date.now() })
  576.  
  577. clearInterval(GF?.cdID);
  578. GF.cdID = setInterval(() => {
  579. $('#cd,#cdsw').remove();
  580. document.body.insertAdjacentHTML("beforeend", `<tt id="cd" class="graybutton" style="left:1em; bottom:2em; opacity:0.9; ">${Math.max(0,~~(60.9-(Date.now()-lastope)/1000))}</tt>`) //&#9213;
  581. if (Date.now() - lastope > 60 * 1000 && !eleget0('.blinkingOL')) { // 開き待ちのが1つでもあれば押さない
  582. lastope = Date.now();
  583. eleget0('//li[1]/a[@id="reload"]')?.click()
  584. }
  585. }, 333)
  586. }
  587.  
  588. $(document).on("mousedown", `#cd`, (e) => {
  589. if (e?.button != 0) return;
  590. cdoff()
  591. })
  592.  
  593. function cdoff() {
  594. pref("FUTAPO_AUTO_RELOAD_DEFAULT", "")
  595. clearInterval(GF?.cdID);
  596. $('#cd,#cdsw').remove() //text("停止")//.hide(999);
  597. document.body.insertAdjacentHTML("beforeend", `<tt id="cdsw" class="graybutton" style="cursor:pointer;left:1em; bottom:2em; position:fixed;" title="左クリックで無操作時60秒毎に自動更新開始\nもう一度左クリックで停止\n\n9:${GF?.opened2?.size||0}\n8:${GF?.opened1?.size||0}\n7:${GF?.opened?.size||0}\n">&#9211;無操作<br>自動更新</tt>`)
  598. }
  599.  
  600. if (GF.FUTAPO_AUTO_RELOAD_DEFAULT >= 1) cdon() //$("#cdsw").click()
  601. if (GF.FUTAPO_AUTO_RELOAD_DEFAULT >= 2) scr(0)
  602. })
  603. setTimeout(() => {
  604.  
  605. function scr(i) {
  606. let last = eleget0('#kako-search')
  607. window.scroll({ left: 0, top: last ? 0 : 99999, behavior: i % 2 == 1 ? "instant" : "smooth" })
  608. if (!last && i < 99) setTimeout(() => { scr(++i) }, 100)
  609. }
  610. // setTimeout(() => {
  611. elegeta("#reload,#logo,#cdsw").forEach(e => e.title = e?.title + "\nE:更新\nD/右クリック:更新+下まで読み込み") // ↻
  612. $(document).on("contextmenu", '#reload,#logo,#cdsw,#cd', () => { // d::
  613. let r = eleget0('//a[@id="reload"]');
  614. if (r) {
  615. if (!GF.latestReload || new Date().getTime() - GF.latestReload > 5000) {
  616. r.click();
  617. scr(0)
  618. GF.latestReload = new Date().getTime();
  619. } // 要5秒インターバル
  620. }
  621. return false
  622. })
  623.  
  624. $('a#server.pulldown').attr("title", ($("a#server.pulldown").attr("title") || "") + "\n右クリック:may←→img") // ↻
  625. $('a#server.pulldown').on("contextmenu", () => {
  626. let url = location.href == 'https://futapo.futakuro.com/?server=img_b' ? 'https://futapo.futakuro.com/?server=may_b' : 'https://futapo.futakuro.com/?server=img_b'
  627. location.href = url;
  628. return false
  629. })
  630. $('a#mode.pulldown').on("contextmenu", () => {
  631. let url = lh(/\&mode=6_0/) ? location.href.replace("&mode=6_0", "&mode=4_0") : lh(/\&mode=4_0/) ? location.href.replace("&mode=4_0", "&mode=6_0") : `https://futapo.futakuro.com/?server=may_b&mode=4_0&search=&searchMode=0&kako=0`
  632. location.href = url;
  633. return false
  634. })
  635. /* if (FUTAPO_AUTO_RELOAD_DEFAULT >= 1) $("#cdsw").click()
  636. if (FUTAPO_AUTO_RELOAD_DEFAULT >= 2) scr(0)
  637. */
  638. }, 500)
  639.  
  640. GM_addStyle("div.thread-text{display:inline;line-break: anywhere;} .thread-text{word-break:break-all;}") // html{line-height:1.2;}
  641. setTimeout(() => {
  642. setSlider(eleget0('//div[@id="boxArea"]'), 54, 300, 54, "box高さ:***", "boxheight", (val) => {
  643. eleget0('#boxheightcss')?.remove()
  644. end(document.head, `<style id="boxheightcss">div.thread-contents{height:${val - 2}px !important;} a.box{height:${15 + val}px !important;}</style>`)
  645. }, 0, 'style="width:7em;height:0.5em;"')
  646. setSlider(eleget0('//div[@id="boxArea"]'), 0, 10, 5, "タイトル行間:***", "lineheight", (val) => {
  647. eleget0('#boxlineheightcss')?.remove()
  648. end(document.head, `<style id="boxlineheightcss">html{line-height:${1+val/10} !important;}</style>`)
  649. }, 0, 'style="width:7em;height:0.5em;"')
  650. }, 999)
  651. },
  652. funcMemo: () => { SITE.funcFinally() },
  653. funcFinally: (disableHide, numberOfHidden) => {
  654. setTimeout(() => {
  655. let found = 0;
  656.  
  657. // 7::8::9:: メモが付いたものを左上に優先整列
  658. // ここの7/8/9動作は正規表現対応や大文字小文字全角半角非区別のために標準のメモが付く動作(正規表現非対応)や非表示動作(正規表現非対応)とは一致しない点に注意
  659. try {
  660. // メモをクリックで消す&ESC/パネル外をクリックでパネルを消す動作を登録
  661. if (!GF.yhmMemoDeleteButton) {
  662. GF.yhmMemoDeleteButton = 1
  663. $(document).on("keydown", e => {
  664. if (e.key === "Escape") $('#yhmMemoDeletePanel').hide(200).queue(function() {
  665. $(this).remove();
  666. run("observed");
  667. })
  668. })
  669. $(document).on("mousedown", e => {
  670. if (!e?.target?.closest("#yhmMemoDeletePanel") || e?.target?.matches("#yhmMemoDeletePanelClose")) $('#yhmMemoDeletePanel').hide(200).queue(function() {
  671. $(this).remove();
  672. run("observed");
  673. })
  674. })
  675. $(document).on("click", ".yhmMemoDeleteButton,.yhmNoSelect", e => { // クリックで削除
  676. let ele = e.target?.closest(".yhmMemoDeleteButton")
  677. if (!ele) return;
  678. // 非表示
  679. if (ele?.dataset?.qword) {
  680. var str = pref(SITE.id + ' : SearchHideTitle') || [];
  681. let qword = str.find(v => escape(v) === ele?.dataset?.qword)
  682. if (qword) {
  683. $(ele).hide(200).queue(function() { $(this).remove() }); // これは削除パネル用の動作
  684. //elegeta('.yhmMyMemo').filter(e => e === escape(qword)).forEach(e => { $(e).hide(200).queue(function() { $(this).remove() }) })
  685. //adja(document.body, "afterbegin", "<yhmmymemoremoved></yhmmymemoremoved>");
  686. //eleget0('yhmmymemoremoved')?.remove(); // 学園祭用に消去を告知
  687. GM.setClipboard(qword)
  688. showByTitle(qword)
  689. pref(SITE.id + ' : SearchHideTitle', (pref(SITE.id + ' : SearchHideTitle') || []).filter(n => n != qword))
  690. }
  691. e.preventDefault()
  692. return false
  693. } else {
  694. // メモ
  695. var str = pref(SITE.id + ' : SearchMyMemo') || [];
  696. let memo = str.find(v => escape(v.t + v.m + v.c) === ele.id)
  697. if (memo) {
  698. $(ele).hide(200).queue(function() { $(this).remove() }); // これは削除パネル用の動作
  699. elegeta('.yhmMyMemo').filter(e => e.id === escape(memo.t + memo.m + memo.c)).forEach(e => { $(e).hide(200).queue(function() { $(this).remove() }) })
  700. //adja(document.body, "afterbegin", "<yhmmymemoremoved></yhmmymemoremoved>");
  701. //eleget0('yhmmymemoremoved')?.remove(); // 学園祭用に消去を告知
  702. document.body.dispatchEvent(new Event('yhmMyMemoRemoved'))
  703. GM.setClipboard(memo.t)
  704. pref(SITE.id + ' : SearchMyMemo', (pref(SITE.id + ' : SearchMyMemo') || []).filter(n => JS(n) !== JS(memo)))
  705. }
  706. e.preventDefault()
  707. return false
  708. }
  709. })
  710. document.addEventListener("scroll", e => {
  711. let my = eleget0('#yhmMemoDeletePanel')?.getBoundingClientRect()?.bottom + window.scrollY - clientHeight() + 15
  712. if (window.scrollY > my) window.scrollTo({ left: 0, behavior: "smooth", top: my })
  713. })
  714. }
  715.  
  716. let memoa = pref(SITE.id + ' : SearchMyMemo') || [];
  717. memoa = memoa.filter(v => SITE?.preventMemo(v.m)).map(v => {
  718. v.than = han(v.t);
  719. if (isValidRE(v.t)) v.re = new RegExp(v.t, "mi");
  720. return v
  721. }) // 重いので計算を最内周でせず1回で済ます
  722. let hide = disableHide ? [] : pref(SITE.id + ' : SearchHideTitle') || []
  723. hide = hide.map(v => { return { word: v, re: isValidRE(v) ? new RegExp(v, "mi") : null } }) // 重いので計算を最内周でせず1回で済ます
  724.  
  725. var hit = new Set()
  726. for (let e of elegeta('.box:not([relocatedByMemo])')) {
  727. let tt = eleget0('.thread-text', e)?.textContent
  728. for (let v of memoa) {
  729. if (v.re && v.re.test(han(tt)) ||
  730. tt?.indexOf(v.t) !== -1) { // u/U/jメモ登録ワードが正規表現として有効なら正規表現としてチェック、また単純文字列としてヒットしてもヒットとする
  731. hit.add(e)
  732. e.dataset.vip = Math.max("○◎★".indexOf(v.m), e.dataset?.vip || 0) // 9>8>7の順で強い結果を残す
  733. e.title = `${e.title?e.title+" ":""}${v.m}${v.t}`
  734. e.dataset.hitwords = `${e.dataset.hitwords?e.dataset.hitwords+" ":""}${v.m}${v.t}`;
  735. if (v?.t?.length > 3) { if (!eleget0(`*[id="${escape(v.t+v.m+v.c)}"]`, e)) after(eleget0('.thread-text', e), `<span class="ignoreMe yhmMyMemo yhmMemoDeleteButton" id="${escape(v.t+v.m+v.c)}" title="『${sani(v.t)}』についたメモ\nクリックで削除&クリップボードにコピー" style="${MEMOSTYLE} cursor:pointer; background-color:${v.c}; border-radius:1em; color:#fff;">${sani(v.m)}${sani(v.t)?.substr(0,25)+(v?.t?.length>25?"…":"")}</span>`) } else {
  736. if (!eleget0(`*[id="${escape(v.t+v.m+v.c)}"]`, e)) after(eleget0('.thread-text', e), `<ruby class="ignoreMe yhmMyMemo yhmMemoDeleteButton" id="${escape(v.t+v.m+v.c)}" title="『${sani(v.t)}』についたメモ\nクリックで削除&クリップボードにコピー"><span class="ignoreMe yhmMyMemo" style="${MEMOSTYLE} cursor:pointer; background-color:${v.c}; border-radius:1em; color:#fff;">${sani(v.m)}${sani(v.t)?.substr(0,25)+(v?.t?.length>25?"…":"")}</span></ruby>`)
  737. }
  738. }
  739. }
  740. eleget0('.thumbnail', e)?.setAttribute("title", `${tt}\n${e.title}`)
  741. }
  742. GF.opened = GF.opened || new Set()
  743. GF.opened1 = GF.opened1 || new Set()
  744. GF.opened2 = GF.opened2 || new Set()
  745.  
  746. while (1) {
  747. var b = elegeta('.box:not([relocatedByMemo])')
  748. var e = b.find(v => hit.has(v))
  749. if (!e) break;
  750.  
  751. //GF.opened.push(e.href)
  752.  
  753. let vip = Number(e.dataset.vip)
  754. e.setAttribute("relocatedByMemo", "")
  755. let memoEle = e
  756. let firstBox = elegeta('.box:not(.boxpri,.boxpri2)').filter(e => e.style.backgroundColor !== "rgb(255, 255, 0)")[0]
  757. if (vip == 1) {
  758. firstBox = elegeta('.box:not(.boxpri2,.boxpri3)').filter(e => e.style.backgroundColor !== "rgb(255, 255, 0)")[0]
  759. eleget0('.thread-text', memoEle).style.color = "#12e";
  760. memoEle.style.boxShadow = "4px 4px 4px 0px #0006";
  761. memoEle.style.zIndex = 2;
  762. memoEle.style.fontWeight = "bold"
  763. memoEle.classList.add("boxpri2")
  764. } else if (vip == 2) {
  765. firstBox = elegeta('.box:not(.boxpri3)').filter(e => e.style.backgroundColor !== "rgb(255, 255, 0)")[0]
  766. eleget0('.thread-text', memoEle).style.color = "#12e";
  767. memoEle.style.boxShadow = "4px 4px 4px 0px #0006";
  768. memoEle.style.zIndex = 3;
  769. memoEle.style.fontWeight = "bold"
  770. memoEle.classList.add("boxpri3")
  771. } else {
  772. memoEle.style.boxShadow = "4px 4px 4px #0006";
  773. memoEle.style.zIndex = 1;
  774. }
  775. memoEle.classList.add("boxpri")
  776.  
  777. firstBox.parentNode.insertBefore(memoEle, firstBox)
  778.  
  779. // Qの非表示にヒットしたものは除外、正規表現対応・全角半角非区別・大文字小文字非区別
  780. let tt = eleget0('.thread-text', e)?.textContent;
  781. let hitPreventWord = hide.find(q => {
  782. return q.re && q.re.test(han(tt)) || tt?.indexOf(q.word) !== -1
  783. }) // Q非表示登録ワードが正規表現として有効なら正規表現としてもチェック、また単純文字列としてヒットしてもヒットとする
  784. if (!(disableHide || !hitPreventWord)) {
  785. e.title += `\n\nブロックワード『${hitPreventWord?.word}』で抑制`
  786. } else {
  787. if (vip == 0 && e.offsetHeight && !GF.opened.has(e.href)) {
  788. GF.opened.add(e.href);
  789. //GF.opened = GF.opened.slice(0, 1000)
  790. }
  791.  
  792. if (vip == 1 && e.offsetHeight && !GF.opened1.has(e.href)) {
  793. GF.opened1.add(e.href);
  794. // GF.opened1 = GF.opened1.slice(0, 1000)
  795. found = memoEle.cloneNode(true);
  796. if (FUTAPO_89_NOTIFY.split(" ").includes("notify")) notifyMe(eleget0(".thread-text", found)?.innerText, e.dataset.hitwords, e => {
  797. e.preventDefault(); //`${"\n\n"+eleget0('//a[@id="server"]')?.innerText||""}`
  798. window.open(memoEle.href, "", "noreferrer");
  799. }, eleget0('img', found)?.src)
  800. }
  801. if (vip == 2 && e.offsetHeight && !GF.opened2.has(e.href)) {
  802. GF.opened2.add(e.href);
  803. //GF.opened2 = GF.opened2.slice(0, 1000)
  804. // GF.open = GF.open || []
  805. found = memoEle.cloneNode(true);
  806. if (FUTAPO_89_NOTIFY.split(" ").includes("notify")) notifyMe(eleget0(".thread-text", found)?.innerText, e.dataset.hitwords, e => {
  807. e.preventDefault();
  808. window.open(memoEle.href, "", "noreferrer");
  809. }, eleget0('img', found)?.src)
  810. memoEle.classList.add('blinkingOL')
  811. addstyle.add('@keyframes outline { 0% { outline: 2px solid #f0f; } 100% { outline: 2px solid #c8f; } } .blinkingOL{ animation: outline 1s ease infinite alternate; }')
  812.  
  813. function opentab(href) {
  814. if (Date.now() - (GF.latest || 0) > (ISCHROME ? 7000 : 5000)) {
  815. GF.latest = Date.now()
  816. GM.openInTab(href, true)
  817. memoEle.classList.remove('blinkingOL')
  818. } else {
  819. setTimeout(() => { opentab(href) }, 333)
  820. }
  821. }
  822. opentab(memoEle.href)
  823. //}
  824. }
  825. }
  826. }
  827. if (found) {
  828. //if (FUTAPO_SOUND_NOTIFY) sound("sine", 0.1);
  829. if (FUTAPO_89_NOTIFY.split(" ").includes("sound")) sound("sine", 0.1);
  830. }
  831. } catch (e) { if (DEBUG_CATCH) alert(e) }
  832. }, 200)
  833. if (numberOfHidden) window.dispatchEvent(new CustomEvent('scroll')) // 非表示をしてスレアイテム数が画面に入り切るようになるとスクロールができなくて続きがあっても読み込めなくなるのでスクロールイベントだけ起こす
  834. },
  835. keyFunc: [{
  836. key: /^g$|^h$/, // g::画像でNG h::画像でピックアップ
  837. func: (k) => {
  838. e = eleget0('img.thumbnail:hover')
  839. if (e) {
  840. eleget0('div.cat-menu', e?.closest(".box"))?.click()
  841. eleget0(k == "h" ? 'a#th_img_pickup' : 'a#th_img_ng')?.click()
  842. /* waitdo(() => eleget0('select[name="img_match"]'), e => e.value = "100")
  843. waitdo(() => eleget0('input#all_board'), e => e?.click())
  844. waitdo(() => eleget0('input#save.submit.option-button'), e => e?.focus())
  845. */
  846. waitdo(() => eleget0('select[name="img_match"]'), e => e.value = pref("FUTAPO_IMAGE_NG_PERCENT") || "100")
  847. waitdo(() => eleget0('input#all_board'), e => e?.click())
  848. waitdo(() => eleget0('input#save.submit.option-button'), e => e?.focus())
  849. waitdo(() => eleget0('select[name="img_match"]'), () => {
  850. eleget0('select[name="img_match"]')?.addEventListener("change", e => {
  851. pref("FUTAPO_IMAGE_NG_PERCENT", e.target.value)
  852. })
  853. })
  854. }
  855. }
  856. }, {
  857. key: 'd', // d::
  858. func: (e) => {
  859. let r = eleget0('//a[@id="reload"]');
  860. if (r) {
  861. let scr = (i) => {
  862. let last = eleget0('#kako-search')
  863. window.scroll({ left: 0, top: last ? 0 : 99999, behavior: i % 2 == 1 ? "instant" : "smooth" })
  864. if (!last && i < 100) setTimeout(() => { scr(++i) }, 100) // 10秒まで
  865. //if (!last && i < 150) setTimeout(() => { scr(++i) }, 100) // 15秒まで
  866. }
  867. scr(0)
  868. //} // 要5秒インターバル
  869. }
  870. },
  871. }, {
  872. key: 'e', // e::リロード
  873. func: () => {
  874. let r = eleget0('//a[@id="reload"]');
  875. if (r) {
  876. if (!GF.latestReload || new Date().getTime() - GF.latestReload > 4000) {
  877. r.click();
  878. GF.latestReload = new Date().getTime();
  879. } // 要4秒インターバル
  880. }
  881. },
  882. }, {
  883. key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
  884. func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
  885. }, {
  886. key: /^7$|^8$|^9$|^Shift\+\'$|^Shift\+\($|^Shift\+\)$/, // 7::8::9::Shift+789
  887. func: (e) => {
  888. let shift = e.match0("Shift+");
  889. var str = pref(SITE.id + ' : SearchMyMemo') || [];
  890. let memostr = (e == "9" || e == "Shift+)") ? "★" : (e == "7" || e == "Shift+'") ? "○" : "◎"
  891. var newstr = str.filter(e => e.m === memostr).map(e => e.t)
  892. GF.sorttype = ((GF.sorttype || 0) % 3 + 1)
  893. var [order, finstrfunc] = [
  894. ["登録順", a => a.join(" ")],
  895. ["abc順", a => a.sort(new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare).join(" ")],
  896. ["長さ→abc順", a => a.sort((a, b) => a.length === b.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a, b) : a.length > b.length ? 1 : -1).join(" ")]
  897. ][GF.sorttype - 1]
  898. let tips = shift ? "独自構文Tips:\n「ABCやDEFを含まず、GHIかJKLを含み、かつMNOとPQRも含む」\n!ABC|DEF GHI|JKL MNO PQR" : "複数の単語をスペースで区切って入力するとまとめて登録できます";
  899. var target = (window.getSelection() && window.getSelection().toString().trim()) || (prompt(`${memostr}メモを付けるキーワードを入力してください\n\nこのサイトではここで設定した項目、メモが付く項目を左上に優先配置します\n(部分一致、正規表現使用可)\n\n${"7:○メモではヒットした項目を左上に優先配置します\n8:◎メモではさらに音声とNotificationで通知します\n9:★メモでは更に自動的に新しいタブで開きます"}\n\nすでに登録されている文字列を入力するとそれを削除します\n\n${tips}\n\n現在登録済み(${newstr.length}): ${order})\n${finstrfunc(newstr)}\n\n`) || "").trim();
  900. if (!target) return;
  901. let targets = shift ? [target.replace(/^S$/, "??").replace(/^S([\s \||])/, "??$1").replace(/([\s \||!!])S([\s \||])/, "$1??$2").replace(/([\s \||!!])S$/, "$1??").replace(/|/gm, "|").replace(/^[\!|!](\S*)/, "^(?!.*($1)).*").replace(/(\S*)[  ](\S*)/gm, "^(?=.*($1))(?=.*\($2\))").replace(/\s| /gm, ".*")] // 独自構文を正規表現に変換
  902. :
  903. target.split(/\s| /)
  904.  
  905. var dele = 0;
  906. targets.forEach(targetc => {
  907. targetc = targetc.trim()
  908. var str = pref(SITE.id + ' : SearchMyMemo') || [];
  909. var str2 = str.filter(e => { return e.t != targetc })
  910. if (str.length != str2.length) {
  911. if (confirm(`『${targetc}』(${str.find(e=>e.t==targetc)?.m})は既に存在します\n削除しますか?`)) {
  912. if (debug) V && dc(`『${targetc}』をメモから削除しました`)
  913. pref(SITE.id + ' : SearchMyMemo', JSON.stringify(str2));
  914. dele = 1;
  915. elegeta('[relocatedByMemo]').forEach(v => v.removeAttribute("relocatedByMemo"))
  916. $(".yhmMyMemo").remove()
  917. run("returned")
  918. }
  919. } else {
  920. storeMemo(targetc.trim(), memostr, COLOR1)
  921. elegeta('[relocatedByMemo]').forEach(v => v.removeAttribute("relocatedByMemo"))
  922. run("returned")
  923. }
  924. })
  925. if (dele) run(document.body, "returned")
  926. },
  927. }, {
  928. key: /^0$/, // 0::メモ一覧一括削除画面
  929. func: (e) => {
  930. var str = pref(SITE.id + ' : SearchMyMemo') || [];
  931. var newstr = str
  932. GF.sorttype = eleget0("#yhmMemoDeletePanel") ? ((GF.sorttype) + 1) : 1
  933. var [order, finstrfunc] = [
  934. ["登録順", a => a.reverse()],
  935. ["abc順→種別", a => a.sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1).sort((a, b) => (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t))],
  936. ["長さ→abc順→種別", a => a.sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1).sort((a, b) => a.t.length === b.t.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t) : a.t.length > b.t.length ? 1 : -1)],
  937. ["種別→登録順", a => a.reverse().sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1)],
  938. ["種別→abc順", a => a.sort((a, b) => (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t)).sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1)],
  939. ["種別→長さ→abc順", a => a.sort((a, b) => a.t.length === b.t.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a.t, b.t) : a.t.length > b.t.length ? 1 : -1).sort((a, b) => a.m == b.m ? 0 : a.m < b.m ? 1 : -1)]
  940. ][(GF.sorttype - 1) % 6]
  941. var words = finstrfunc(newstr)
  942. $("#yhmMemoDeletePanel").remove()
  943. end(document.body, `<div id="yhmMemoDeletePanel" style="width:85%; font-size:95%; position:absolute; top:1em; left: 50%; transform: translate(-50%, 0%); box-shadow:0px 0px 2em #0008; word-break:keep-all; z-index:${Number.MAX_SAFE_INTEGER}; padding:2em; margin:auto; background-color:#fff; line-height:1.8em;"><span id="yhmMemoDeletePanelClose" style="cursor:pointer;float:right;">×(Esc)</span>0:メモ&非表示一括削除<br>メモ(${words.length})(${order})をクリックすると削除してクリップボードにコピーします<br><div>`)
  944. let dup = [] // 重複しているものは暗い色にする
  945. let list = ""
  946. words.forEach(w => {
  947. // list += `<span class="yhmMemoDeleteButton" id="${escape(w.t+w.m+w.c)}" data-m="${escape(w.m)}" data-t="${escape(w.t)}" data-c="${escape(w.c)}" style="cursor:pointer; background-color:${w.c}; ${dup.includes(w.t)?"filter:saturate(0.66);":""} padding:1px 0.4em 1px 0.3em; margin:0; border-radius:1em; color:#fff;"><font class="yhmNoSelect" style="user-select:none;" ${dup.includes(w.t)?'data-gakusai="1"':''}>${sani(w.m)}</font>${sani(w.t)}</span> `
  948. list += `<span class="yhmMemoDeleteButton" id="${escape(w.t+w.m+w.c)}" style="cursor:pointer; background-color:${w.c}; ${dup.includes(w.t)?"filter:saturate(0.66);":""} padding:1px 0.4em 1px 0.3em; margin:0; border-radius:1em; color:#fff;"><font class="yhmNoSelect" style="user-select:none;" ${dup.includes(w.t)?'data-gakusai="1"':''}>${sani(w.m)}</font>${sani(w.t)}</span> `
  949. dup.push(w.t)
  950. })
  951.  
  952. var [order, finstrfunc] = [
  953. ["登録順", a => a.reverse()],
  954. ["abc順", a => a.sort((a, b) => (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a, b))],
  955. ["長さ→abc順", a => a.sort((a, b) => a.length === b.length ? (new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare)(a, b) : a.length > b.length ? 1 : -1)],
  956. ][(GF.sorttype - 1) % 3]
  957. var words = pref(SITE.id + ' : SearchHideTitle') || [];
  958. words = finstrfunc(words)
  959. list += `<br><br>非表示登録(${words.length})(${order})をクリックすると削除してクリップボードにコピーします<br>`;
  960. words.forEach(w => {
  961. list += `<span class="yhmMemoDeleteButton" id="${escape(w)}" data-qword="${escape(w)}" style="cursor:pointer; background-color:#444;font-weight:500; ${dup.includes(w)?"filter:saturate(0.66);":""} padding:1px 0.5em 1px 0.5em; margin:0; border-radius:1em; color:#fff;">${sani(w)}</span> `;
  962. })
  963.  
  964. end(eleget0("#yhmMemoDeletePanel"), list)
  965. },
  966. }, {
  967. key: 'a', // a::ソート
  968. func: () => {
  969. var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
  970. $('.yhmSortType').remove(), $(document.body).append(`<span class="yhmSortType" id="${++sorttype%4}"></span>`)
  971. popup2("A:ソート\n" + (["レス数", "勢い", "タイトル", "元"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
  972. sorttype == 1 && sortdom(elegeta('.box:not(#kako-search)'), v => Number(eleget0('.rescnt', v)?.textContent), 1)
  973. sorttype == 2 && sortdom(elegeta('.box:not(#kako-search)'), v => Number(0 + eleget0('.ikioi-icon', v)?.textContent) + Number((eleget0('span.red', v)?.textContent + 0 || 0)) * 10, 1)
  974. sorttype == 3 && sortdom(elegeta('.box:not(#kako-search)'), v => (eleget0('.thread-text', v)?.textContent))
  975. sorttype == 4 && sortdom(elegeta('.box:not(#kako-search)'), v => v?.dataset?.idx)
  976. }
  977. }, ],
  978. wholeHelp: [() => 1, " A:ソート"],
  979. hideSelectedWord: 1,
  980. selectedHelp: { help: [KEYHIDE + ":NGワードに追加", "7/8/9:左上に優先配置(8:+通知/9:+開く)"] }, //, multi: "複数行に渡る文字列は NG に入れられません" },
  981. },
  982. {
  983. id: 'FUTACHAN_CATALOG',
  984. urlRE: /\/\/anige\.horigiri\.net\/?$|\/\/anige\.horigiri\.net\/\?cat=|\/\/anige\.horigiri\.net\/\?paged=/,
  985. listTitleXP: '//div/h3[@class="entry-title"]/a',
  986. listTitleSearchXP: '//div/h3[@class="entry-title"]/a[+++]/../../../..',
  987. hideSelectedWord: 1,
  988. listTitleMemoSearchXP: '//div/h3[@class="entry-title"]/a[+++]',
  989. listGen: 5,
  990. delat: 500,
  991. listTitleMemoSearchXPSameGen: 1,
  992. WhateverFirstAndEveryAPFunc: () => { SITEINFO[SITEINFO.findIndex(c => c.id == "FUTACHAN_CATALOG")].WhateverFirstAndEveryAPFunc() },
  993. keyFunc: [{
  994. key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
  995. func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
  996. }],
  997. },
  998. {
  999. id: 'FUTACHAN',
  1000. urlRE: '//kuzure.but.jp/f/$',
  1001. WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+FFTBucket検索`, 8, 5000) },
  1002. keyFunc: [{
  1003. key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
  1004. func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
  1005. }],
  1006. },
  1007. {
  1008. id: 'FUTACHAN', // futaba::
  1009. urlRE: '//.*.ftbucket.info/|//kuzure.but.jp/f/b/|//[^.]+.2chan.net\/|//anige.horigiri.net|//kako.futakuro.com/futa/|https:\/\/tsumanne\.net\/.*\/data\/',
  1010. title: '.thre table .cno',
  1011. box: '.thre table',
  1012. disableKeyB: 0,
  1013. redoWhenRefocused: 1,
  1014. funcMemo: () => GF.resChained = [],
  1015. // isMemoPartialMatch:1,
  1016. isHidePartialMatch: 1,
  1017. memoFunc: titleEle => eleget0('.memo', titleEle.closest('tr')),
  1018. memoPosition: "afterbegin",
  1019. listHelpJQS: '.thre table',
  1020. delay: 111,
  1021. memoStyle: 'display:table !important; margin-bottom:2px;',
  1022. //memoStyle: 'display:block !important; width:fit-content; margin-bottom:2px;',
  1023. detailURLRE: /$^/,
  1024. detailTitleXP: '',
  1025. hideSelectedWord: 1,
  1026. selectedHelp: { help: [KEYHIDE + ":NGワードに追加", "y:YouTubeで検索"], multi: "y:YouTubeで検索" },
  1027. detailTitleSearchXP: '',
  1028. listTitleSearchFunc: (title) => { // q::レス中キーワードNG // todo:リロードで追加されたレスにも非表示を適用
  1029. let resHit = [];
  1030. if (typeof title === "string" && !/^No\.\d+$/gmi.test(title)) { // textContentでサーチする
  1031. for (let res of elegeta('.thre table:not(.ftbpu table,#respopup_area table)')) { // レス全体(ID:~も対象)
  1032. if (res.textContent.indexOf(title) !== -1) resHit.push(res?.closest('table'));
  1033. }
  1034. }
  1035. return resHit;
  1036. },
  1037.  
  1038. // WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+F:FTBucket検索\nA:画像順/そうだね順/引用順でソート${location.href.match0(/^https?:\/\/[^.]+\.2chan\.net\//)?"\nE:新着チェック\nD:新着チェック+新着に移動":""}`, 7, 5000) },
  1039. //WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+F:FTBucket検索\na:画像順/そうだね順/引用順でソート${location.href.match0(/^https?:\/\/[^.]+\.2chan\.net\//)?"\ne:新着チェック\nd:新着チェック+新着に移動\nc:ホバー中レスにそうだね\nn:自動更新&通知":""}`, 7, 5000) },
  1040. WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+FFTBucket検索\na:画像順/そうだね順/引用順でソート${location.href.match0(/^https?:\/\/[^.]+\.2chan\.net\//)?"\ne:新着チェック\nd:新着チェック+新着に移動\nc:ホバー下にそうだね\nn:自動リロード&新着通知\nm:監視ワード設定":""}`, 7, 5000) },
  1041. //WhateverFirstAndEveryAPFunc: () => { popup3(`Shift+F:FTBucket検索\nA:画像順/そうだね順/引用順でソート${location.href.match0(/^https?:\/\/[^.]+\.2chan\.net\//)?"\nE:新着チェック\nD:新着チェック+新着に移動\nC:ホバー下にそうだね\nN:自動リロード&新着通知\nM:監視ワード設定":""}`, 7, 5000) },
  1042. funcD: () => { // d::
  1043. // let r = eleget0("#contres>a,#fvw_loading");
  1044. let r = eleget0("#contres>a,#fvw_loading,a#akahuku_reload_button");
  1045. if (r) {
  1046. if (!GF.latestReload || new Date().getTime() - GF.latestReload > 4000) {
  1047. r.click();
  1048. GF.latestReload = new Date().getTime();
  1049. } // 要4秒インターバル
  1050. setTimeout(() => { eleget0('.reloadline')?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }) }, 200);
  1051. }
  1052. },
  1053. keyFunc: [{
  1054. key: "y", // y::
  1055. func: e => {
  1056. let str = window.getSelection()?.toString()?.trim()
  1057. if (!str) return;
  1058. let strs = str.split("\n").map(v => v.trim())?.slice(0, 6)
  1059. let urls = strs.map(str => `https://www.youtube.com/results?search_query=${(str)}`)
  1060. let urls2 = strs.map(str => `https://www.youtube.com/results?search_query=${encodeURI(str)}`)
  1061. if (confirm(`${strs.join("\n")}\nYouTube検索します(安全のため一度に最大6行にしています)\n\nまたついでに下記をクリップボードにコピーします\nよろしいですか?\n\n${urls.join("\n")}\n`)) {
  1062. GM.setClipboard(strs.map((v, i) => `${v} - YouTube\n${urls2[i]}\n`).join(""))
  1063. urls2.forEach((v, i) => {
  1064. setTimeout(() => {
  1065. GM.openInTab(v, true)
  1066. }, i * 5000)
  1067. })
  1068. }
  1069. }
  1070. }, {
  1071. key: /^(?:Shift\+)?(?:Alt\+)?(?:z|Z)$/, // z::ポップアップを画像として「名前を付けて保存」 Shift+で高画質、Alt+でメモを反映 Alt+だとクリップボードには○メモが付いたものだけコピーする
  1072. id: "z",
  1073. func: (e) => {
  1074. elegeta('.relpost').forEach(e => e.classList.remove("relpost"))
  1075. if (document.elementFromPoint(mousex, mousey)?.matches("video,img")) return;
  1076. let isZ = e.indexOf("Shift+") != -1;
  1077. let target = eleget0('.ftbpu') ? ".ftbpu" : eleget0('#pickbox') ? "#presentPick" : ""
  1078. let orgtarget = eleget0('.ftbpu') ? ".ftbpu" : eleget0('#pickbox') ? "#pickbox" : ""
  1079. if (!target || !orgtarget) return;
  1080. if (target == "#presentPick") {
  1081. let p = end(document.body, `<div id="presentPick" class="ignoreMe" style="padding:5px; width:max-content; max-width:100%; background-color:#ffffeecc; "></div>`)
  1082. if (GF.presentPick) GF.presentPick.forEach(v => p.append(v.cloneNode(true)))
  1083. sortdom(elegeta('#presentPick table[data-rsc]'), v => v.getAttribute("data-rsc"))
  1084. } else {
  1085. let p = eleget0(target).cloneNode(true);
  1086. p.id = "presentPick";
  1087. p.className = "ignoreMe"
  1088. target = "#presentPick"
  1089. document.body.appendChild(p)
  1090. // end(document.body, `<div id="presentPick" class="ignoreMe" style="padding:5px; width:max-content; max-width:100%; background-color:#ffffeecc; "></div>`)
  1091. }
  1092. if (elegeta(`${target} img:not(.quoteSpeechBalloonImg)`).length) { // 画像が1つでもあったら
  1093. if (1 || !eleget0("#contdisp font:text*=スレッドがありません")) {
  1094. let imgs = ld('kuzure.but.jp') ? elegeta(`${target} a>img[src*="s."]:not([data-rep-lar])`).filter(e => e.src.match(/s\./)) :
  1095. elegeta(`${target} a>img[src*="thumb/"]:not([data-rep-lar])`).filter(e => e.src.match(/thumb\/\d+s\./))
  1096. imgs.forEach(img => {
  1097. let orgHref = img?.parentNode?.href
  1098. if (orgHref?.match(/\.(jpe?g|png|bmp|gif|webp)/)) {
  1099. cldt("head");
  1100. img.dataset.repLar = 2;
  1101. $.ajax({
  1102. url: orgHref,
  1103. type: 'HEAD',
  1104. error: (function(img) {
  1105. return function() {
  1106. img.dataset.repLar = 0;
  1107. cldt(`404`);
  1108. }
  1109. })(img),
  1110. success: (function(img) {
  1111. return function() {
  1112. img.src = orgHref;
  1113. img.dataset.repLar = 1
  1114. cldt(`replace`);
  1115. }
  1116. })(img),
  1117. });
  1118. }
  1119. })
  1120. }
  1121. let zwait = () => {
  1122. cldt("compele?");
  1123. if (!eleget0(`${target} table a>img[data-rep-lar="2"]`) && elegeta(`${target} table a>img[data-rep-lar="1"]`).every(e => e.complete)) { z(e, isZ ? 3 : 2, isZ ? 3 : 2) } else { setTimeout(zwait, 50) }
  1124. }
  1125. setTimeout(zwait, 100 + elegeta(`${target} img:not(.quoteSpeechBalloonImg)`)?.length * 10)
  1126. } else { z(e, isZ ? 2 : 1.5, isZ ? 2 : 1.5) }
  1127.  
  1128. if (FUTABA_Z_TO_COPY_TO_CLIPBOARD_AS_TEXT_TOO) { // 文字としてもクリップボードにコピー
  1129. let txt = elegeta('table[data-rsc]', eleget0(orgtarget)).filter(v => e.indexOf("Alt+") == -1 || eleget0('.yhmMyMemoO', v)).map(t => FUTABA_Z_TO_COPY_TO_CLIPBOARD_AS_TEXT_TOO.replace("${num1}", eleget0('.rsc', t)?.innerText || "").replace("${name1}", eleget0('.csb', t)?.innerText || "").replace("${name2}", eleget0('.cnm', t)?.innerText || "").replace("${time}", eleget0('.cnw', t)?.innerText || "").replace("${num2}", eleget0('.cno', t)?.innerText || "").replace("${soudane}", eleget0('.sod', t)?.innerText || "").replace("${text}", eleget0('blockquote', t)?.innerText || ""))
  1130. //let txt = elegeta('table[data-rsc]', eleget0(orgtarget)).map(t => FUTABA_Z_TO_COPY_TO_CLIPBOARD_AS_TEXT_TOO.replace("${num1}", eleget0('.rsc', t)?.innerText || "").replace("${name1}", eleget0('.csb', t)?.innerText || "").replace("${name2}", eleget0('.cnm', t)?.innerText || "").replace("${time}", eleget0('.cnw', t)?.innerText || "").replace("${num2}", eleget0('.cno', t)?.innerText || "").replace("${soudane}", eleget0('.sod', t)?.innerText || "").replace("${text}", eleget0('blockquote', t)?.innerText || ""))
  1131. GM.setClipboard(txt.join("\n"))
  1132. popup3(elegeta('table[data-rsc]', eleget0(orgtarget)).map(t => `${eleget0('.rsc',t)?.innerText}`).join(","), 0, 5000, "top")
  1133. }
  1134. return;
  1135.  
  1136. function z(key, SCALE_MIN = 1, SCALE_MAX = 2) {
  1137. //var SCALE_MIN = 1 // 保存最低倍率
  1138. //var SCALE_MAX = scaleLimit || 2 // 保存最大倍率
  1139. //var D_FILENAME_MAXLENGTH = 87 // ファイル名の最大長
  1140. var D_FILENAME_MAXLENGTH = 83 // ファイル名の最大長
  1141. if (!eleget0(target)) return;
  1142. let filenameSuffix = (key.indexOf("Alt+") != -1) ? FUTABA_ALTZ_FILENAME_SUFFIX : ""
  1143.  
  1144. GF?.zFunc && GF?.zFunc()
  1145.  
  1146. let honbun = elegeta(`${target} blockquote`).map(e => e.innerText)?.join(" ")?.replace(/\s+|\n+/gm, " ")?.trim()
  1147. honbun = honbun?.replace(/\s*\>+[^\s]+/gm, "")?.trim() || res
  1148. honbun = honbun?.slice(0, 100); // ?.replace(/キタ━+\(゚\∀゚\)━+\!+/gm,"");
  1149.  
  1150. if (key.indexOf("Alt+") == -1) {
  1151. $(`${target} .yhmMyMemo,${target} .relallArea,${target} .adddel`).remove()
  1152. $(`${target} .sod`).css({ "font-size": "100%" }).removeClass("sodmypush") //,"float":"right" })
  1153. }
  1154. $(`${target} .relallArea`).remove()
  1155.  
  1156. $(`${target}`).css({ "box-shadow": "none", "transform": "scale(1)" })
  1157.  
  1158. if (orgtarget == "#pickbox") {
  1159. $(`${target} table`).css({ "margin-right": "auto", "margin-left": "0" })
  1160. $(`${target} a img`).css({ "max-height": "" }) // pickの画像縦圧縮を解放する
  1161. }
  1162. $(`${target} .revQuote`).after("<br>"); //css({ "display": "inline-block" })
  1163.  
  1164. addstyle.add(`.yendotsaveElement .GM_FRRS_Counter,.yendotsaveElement .GM_FRRS_own_res{display:none}`)
  1165. elegeta(`${target} .rsc`).forEach(e => e.style = "")
  1166.  
  1167. var hrefName = ""
  1168. // var fn = `${signzen(document.title?.replace(/\s+|\n+/gm," ")?.trim()+" "+location.href).substr(0, D_FILENAME_MAXLENGTH-hrefName.length-1)} ${hrefName}`?.trim()
  1169. var fn = `${signzen(document.title?.replace(/\s+|\n+/gm," ")?.trim()+" "+location.href).substr(0, D_FILENAME_MAXLENGTH-hrefName.length)}`?.trim()
  1170. var res = honbun
  1171. res = res?.replace(/^\s*\>.*\s*$/gm, "")?.replace(/キタ━+\(゚\∀゚\)━+\!+/gm, "")?.trim() || res;
  1172. // if (res) fn = `${signzen(document.title+" "+location.href).substr(0, D_FILENAME_MAXLENGTH/2-hrefName.length-1)} ${signzen(res).substr(0, D_FILENAME_MAXLENGTH/2-1)} ${hrefName}`.trim()
  1173. if (res) fn = `${signzen(document.title+" "+location.href).substr(0, D_FILENAME_MAXLENGTH/2-hrefName.length)} ${signzen(res).substr(0, D_FILENAME_MAXLENGTH/2)}`.trim()
  1174. //if(filenameSuffix&&fn.length>D_FILENAME_MAXLENGTH)fn=fn.slice(-1,1)
  1175. fn += filenameSuffix
  1176.  
  1177. function signzen(str) { return str.replace(/^\s+/, "").replace(/\\|\/|\:|\;|\,|\+|\&|\=|\*|\?|\"|\'|\>|\<|\./g, c => { return String.fromCharCode(c.charCodeAt(0) + 0xFEE0) }) }
  1178.  
  1179. let puele = eleget0(`${target}`)
  1180. puele.classList.add('yendotsaveElement')
  1181.  
  1182. let scale = Math.max(1, Math.min(SCALE_MAX, SCALE_MIN + (elegeta('img:not(.quoteSpeechBalloonImg)', puele).length * 0.5)))
  1183. popup3(`z:ポップアップ(ピックアップ)を保存\nShift+で高画質、Alt+でメモを維持)\nScale = ${scale}`, 12)
  1184. // document.dispatchEvent(new CustomEvent('saveDOMAsImage', { detail: { element: puele, filename: fn, scale: scale, hd: (key.indexOf("Shift+") != -1) ? 1 : 0, eleToFlash: target == ".ftbpu" ? eleget0(".ftbpu") : eleget0("#pickbox") } }))
  1185. document.dispatchEvent(new CustomEvent('saveDOMAsImage', { detail: { element: puele, filename: fn, scale: scale, hd: (key.indexOf("Shift+") != -1) ? 1 : 0, eleToFlash: orgtarget == ".ftbpu" ? eleget0(".ftbpu") : eleget0("#pickbox") } }))
  1186. $('#presentPick').remove()
  1187. //if (orgtarget == "#pickbox") setTimeout(() => window.dispatchEvent(new Event('resize')), 1000)
  1188. }
  1189. },
  1190. }, {
  1191. key: 'e', // e::リロード
  1192. func: () => {
  1193. let r = eleget0("#contres>a,#fvw_loading,a#akahuku_reload_button");
  1194. if (r) {
  1195. if (!GF.latestReload || new Date().getTime() - GF.latestReload > 4000) {
  1196. r.click();
  1197. GF.latestReload = new Date().getTime();
  1198. } // 要4秒インターバル
  1199. }
  1200. }
  1201. }, {
  1202. key: 'd', // d::
  1203. func: (e) => {
  1204. if (eleget0("a:hover,video:hover,img:hover")) return
  1205. SITE.funcD()
  1206. },
  1207. }, {
  1208. key: 'Shift+F', // Shift+F::FTBucketでキーワード検索
  1209. func: () => { searchWithHistory("FUTACHAN", "FTBucket", 'https://www.ftbucket.info/scrapshot/ftb/index.php?mode=c&favo=0&ord=1&s=***', "|") },
  1210. }, {
  1211. key: 'n', // n::Notificationで新着レスを通知on/off
  1212. func: (key, opt = null, changeto = null) => {
  1213. if (changeto === null) {
  1214. GF.reloadAndNotifyNewArrival = ((GF.reloadAndNotifyNewArrival || 0) + 1) % 5;
  1215. pref("FUTABA_RELOAD_AND_NOTIFY_NEWRES_DEFAULT", GF.reloadAndNotifyNewArrival)
  1216. } else {
  1217. GF.reloadAndNotifyNewArrival = Number(changeto);
  1218. }
  1219. $('#notiApiOn').remove();
  1220. let mess = `N:自動リロードと新着通知…${GF.reloadAndNotifyNewArrival}\n${["オフ","自動リロード","自動リロード+新着レスをNotificationで通知(メモ付きのみ)","自動リロード+新着レスをNotificationで通知(画像かメモ付きのみ)","自動リロード+新着レスをNotificationで通知(全て)"][GF.reloadAndNotifyNewArrival]}`
  1221. //if (opt != "automation") popup2(`${mess}`, 8);
  1222. if (opt != "automation") popup2(`N:自動リロードと新着通知\n${["オフ","自動リロード","自動リロード+新着レスをNotificationで通知(メモ付きのみ)","自動リロード+新着レスをNotificationで通知(画像かメモ付きのみ)","自動リロード+新着レスをNotificationで通知(全て)"].map((c, i) => " " + c + (i == GF.reloadAndNotifyNewArrival ? " ←\n" : "\n")).join("")}`, 9, "min-width:31em;")
  1223.  
  1224. if (GF.reloadAndNotifyNewArrival && ld("2chan.net")) {
  1225. $(`<span id="notiApiOn" class="ignoreMe" title="${mess}" style="all:initial; cursor:pointer; position: fixed; right:60em; bottom:0.5em; z-index:100; opacity:0.55; font-size:15px; margin:0px 1px; text-decoration:none !important; padding:1px 6px 1px 6px; word-break: break-all !important; border-radius:12px; border:solid 1px #888; background-color:${["#fff","#dfe","#dfe","#dfe"][GF.reloadAndNotifyNewArrival-1]}; color:#888; ">${["オフ","更新","メモ","画像","全て"][GF.reloadAndNotifyNewArrival]}</span>`).click(e => keyFuncDispatch("n")).appendTo('body');
  1226. }
  1227. },
  1228. }, {
  1229. key: 'a', // a::
  1230. func: () => {
  1231. GF.stopmoq = 1
  1232. let isftchan = /^https?:\/\/kuzure\.but\.jp\/f\/b\//.test(location.href);
  1233. let isanigeaki = /\/\/anige\.horigiri\.net\/\?p/.test(location.href);
  1234. if (isanigeaki || isftchan) $(elegeta('.thre .rtd').filter(e => !e.closest("#pickbox,.ftbpu"))[0]).closest("table").before($('<div id="thre0"></div>'))
  1235. $('.reloadline').remove();
  1236. GF.sort = (GF?.sort || 0) % 4 + 1 //var sorttype = GF.sort||0//Number($('.yhmSortType')?.attr("id") || 0);
  1237. let sorttype = GF.sort
  1238. popup2("A:ソート\n" + (["画像", "そうだね", "引用", "古い順"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
  1239. sorttype == 1 && sortdom(elegeta('table:not([data-reszero]) .rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('table:not([data-reszero]) .sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1) + (v.querySelectorAll("table:not([data-reszero]) .revQuote").length * 1) + (((v.textContent.match(/\.(gif|webm|mp4).*\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(gif|webm|mp4)/gmi) ? 1 : 0) * 1000000000) || ((v.textContent.match(/\d\d\d\sB\)|(?<!>)fu?\d+\.(jpg|jpeg|png|bmp|webp)/gmi) ? 1 : 0) * 1000000) || ((v.textContent.match(/ttps?\:\/\//gmi) ? 1 : 0) * 1000)) }, 1) // リンクも加点
  1240. //sorttype == 1 && sortdom(elegeta('table:not([data-reszero]) .rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('table:not([data-reszero]) .sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1) + (v.querySelectorAll("table:not([data-reszero]) .revQuote").length * 1) + (((v.textContent.match(/\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/gmi) ? 1 : 0) * 1000000) || ((v.textContent.match(/ttps?\:\/\//gmi) ? 1 : 0) * 1000)) }, 1) // リンクも加点
  1241. sorttype == 2 && sortdom(elegeta('table:not([data-reszero]) .rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('table:not([data-reszero]) .sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1000000000) + (v.querySelectorAll("table:not([data-reszero]) .revQuote").length * 1000000) + (((v.textContent.match(/\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/gmi) || []).length * 1000) || ((v.textContent.match(/ttps?\:\/\//gmi) || []).length * 1)) }, 1) // リンクも加点
  1242. sorttype == 3 && sortdom(elegeta('table:not([data-reszero]) .rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), (v) => { return (((v.querySelector('table:not([data-reszero]) .sod') || v).innerText?.match0(/そうだねx(\d+)/) || 0) * 1000000) + (v.querySelectorAll("table:not([data-reszero]) .revQuote").length * 1000000000) + (((v.textContent.match(/\d\d\d\sB\)|youtube\.|youtu\.be|nicovideo|(?<!>)fu?\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/gmi) || []).length * 1000) || ((v.textContent.match(/ttps?\:\/\//gmi) || []).length * 1)) }, 1) // リンクも加点
  1243. sorttype == 4 && sortdom(elegeta('table:not([data-reszero]) .rtd:not(#pickbox .rtd,.ftbpu .rtd)').map(v => v?.closest('table')), v => v.getAttribute("rsc")) //,
  1244. setTimeout(() => { GF.stopmoq = 0 }, 500)
  1245. },
  1246. }],
  1247. funcOnlyFirst: () => {
  1248. hoverHelp(e => e.closest('table[border="0"]') ? "Q:非表示 W:アンドゥ 1,5:○メモ 2,6:×メモ" : "")
  1249. GF.latestReload = Date.now() - 3000
  1250. GF.newarticle = 1000
  1251. GF.latestInterval = FUTABA_AUTO_RELOAD_INTERVAL * 60 * 1000
  1252.  
  1253. //GF.alertWord = pref("alertWord")?.replace(/^<string>([\s\S]*)<\/string>$/, "$1") || ""; // m::
  1254. document.addEventListener("focus", () => GF.alertWord = pref("alertWord")?.replace(/^<string>([\s\S]*)<\/string>$/, "$1") || "")
  1255. keyFuncAdd([{
  1256. key: 'm',
  1257. func: () => {
  1258. const tips = "Tips:\n「ABCやDEFを含まず、GHIかJKLを含み、かつMNOとPQRも含む」\n!ABC|DEF GHI|JKL MNO PQR\n";
  1259. let a = prompt(`m:\n監視ワードを正規表現+独自構文で設定できます\nこれにヒットしたレスはNotificationで通知されます\n\n${tips}\n\n現在の設定値:\n${GF?.alertWord||"なし"}`, GF?.alertWord || "")
  1260. if (a === null) return;
  1261. try {
  1262. GF.alertWordRE = new RegExp(a.replace(/^S$/, "??").replace(/^S([\s \||])/, "??$1").replace(/([\s \||!!])S([\s \||])/, "$1??$2").replace(/([\s \||!!])S$/, "$1??").replace(/|/gm, "|").replace(/^[\!|!](\S*)/, "^(?!.*($1)).*").replace(/(\S*)[  ](\S*)/gm, "^(?=.*($1))(?=.*\($2\))").replace(/\s| /gm, ".*"), "mi"); //alert(searRE); // 独自構文を正規表現に変換
  1263. } catch (e) {
  1264. alert(`${a}\n\nは正規表現としてエラーが出てしまうため取り消します\n\n参考:\nhttps://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_expressions\n`);
  1265. a = "";
  1266. }
  1267. GF.alertWord = a;
  1268. pref("alertWord", a ? `<string>${a}</string>` || "" : "")
  1269. }
  1270. }])
  1271.  
  1272. let is2chan = /^https?:\/\/[^.]+\.2chan\.net\//.test(location.href);
  1273. let isftb = /^https?:\/\/[^\.]+\.ftbucket\.info\//.test(location.href); // let isftb = /^https?:\/\/www\.ftbucket\.info\//.test(location.href);
  1274. let istsumanne = ld("tsumanne.net");
  1275. if (is2chan && !location.href.match0(/\.2chan\..+\/res\//)) return;
  1276. let iskurokako = /\/\/kako\.futakuro\.com\/futa\//.test(location.href);
  1277. let isftchan = /^https?:\/\/kuzure\.but\.jp\/f\/b\//.test(location.href);
  1278. let isanigeaki = /\/\/anige\.horigiri\.net\/\?p/.test(location.href);
  1279. let isfvw = eleget0('#fvw_menu') // futakuro
  1280. if (isanigeaki) GM_addStyle('table, th, td{border:0;}');
  1281. if (isftchan || isanigeaki) { document.body.innerHTML = "<div class='thre'>" + document.body.innerHTML + "</div>" }
  1282. if (isftchan) { GM_addStyle("body{min-width:95%} .thre table{margin-right:0} #v0z{display:none;}") }
  1283. if (is2chan || isftchan) GM_addStyle(".rtd{vertical-align:top} #pdm{z-index:2000000021}")
  1284. //GM_addStyle("#pickbox .yhmMyMemo{white-space: nowrap;} .quo{vertical-align:top} a:visited{color:#800080;}")
  1285. GM_addStyle("#pickbox .yhmMyMemo{font-size:85%; white-space: nowrap;} .quo{vertical-align:top} a:visited{color:#800080;} .ftbpu .quo{max-width:25vw;}")
  1286. //let fivechthumbnailetc = (!lh(/\.2chan\.net\//) || eleget0('#fivechthumbnailetc')) && 1
  1287. GM_addStyle(".quoteSpeechBalloon{padding:0 0.68em; margin-left:0.68em; font-size:14px; position:relative; bottom:1px; color:#484; background-color:#ffffee;border-radius:1em; user-select:none; cursor:pointer;}") // qsb::
  1288. //GM_addStyle(".quoteSpeechBalloon{font-size:14px; position:relative; bottom:1px; color:#484; background-color:#ffffee;border-radius:1em; user-select:none; cursor:pointer;}") // qsb::
  1289. GM_addStyle(".quoteSpeechBalloonImg{float:right; clear:right; max-height:2.8em !important; padding:4px; user-select:none; background-color:#ffffee; border-radius:6px; cursor:pointer;")
  1290. GM_addStyle(".revQuote{cursor:pointer;color:#789922; margin:0.19em; }")
  1291. addstyle.add('.waiting{ display: inline-block; vertical-align: middle; font-size:85%; color: #666; line-height: 1; width: 1em; height: 1em; border: 0.12em solid currentColor; border-top-color: rgba(102, 102, 102, 0.3); border-radius: 50%; box-sizing: border-box; -webkit-animation: rotate 1s linear infinite; animation: rotate 1s linear infinite; } @-webkit-keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } @keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } }</style>')
  1292. //addstyle.add('.relallArea{user-select:none; text-align:center; display:inline-block; line-height:1.5em; color:#789922c0; min-width:1.5em; height:1.5em; margin:1px 0 1px 3px; margin-top:0.3em; } .memo:empty+.backlink:empty+.relallArea{margin-top:3px; } .backlink:empty+.relallArea{margin-top:7px; } ') //background-color:#eed;
  1293. addstyle.add('.relallArea{user-select:none; text-align:center; display:inline-block; line-height:1.5em; color:#789922c0; min-width:1.5em; height:1.5em; margin:1px 0 1px 3px; margin-top:0.3em; } .memo:empty+.backlink:empty+.relallArea{margin-top:3px; } .backlink:empty+.relallArea{margin-top:7px; } .backlink{word-break:break-word;}') //background-color:#eed;
  1294. addstyle.add('.relallAreaon{outline:2px dotted #789922f0; cursor:pointer;}') //background-color:#eed;
  1295. addstyle.add('.sodmypush{color:#f00;}')
  1296. if (location.href.match0("anige.horigiri")) GM_addStyle(`blockquote{color:#800000;line-height:1.2em;font-style:normal;`)
  1297. addstyle.add('.GM_FRRS_Counter{display:none !important;}')
  1298. //addstyle.add(`#pickbox .sod{ margin: 0 0px 0 8px;} `)
  1299. addstyle.add('#pickbox blockquote { word-wrap: anywhere; }')
  1300. addstyle.add(`#pickbox .rts {cursor:pointer;}`)
  1301.  
  1302. GF.originalDocTitle = eleget0('//div[@class="thre"]/blockquote')?.textContent || document.title;
  1303. GF.originalDocTitle0 = document.title;
  1304. GF.anchor = new Array(1000).fill("")
  1305.  
  1306. //let favi=eleget0('.thre>a>img')?.src; if(favi)end(document.head,`<link rel="icon" href="${favi}">`) // ファビコンを最初の画像にする
  1307.  
  1308. // フォーカスが戻った時に0を表示
  1309. //$(document).on("click","div.thre",e=>{e.preventDefault();if(e?.target?.matches("div.thre"))leadFocus();})
  1310. let Rimg = eleget0('//div[@class="thre"]/a/img')?.cloneNode(true)
  1311. let Rdesc = elegeta('//div[@class="thre"]/span[1]|//div[@class="thre"]/span[2]|//div[@class="thre"]/span[3]|//div[@class="thre"]/span[4]|//div[@class="thre"]/span[5]|//div[@class="thre"]/a[@class="sod"]')?.map(e => e.cloneNode(true))
  1312. let Rhonbun = eleget0('//div[@class="thre"]/blockquote')?.cloneNode(true)
  1313. // if (!img || !honbun) return;
  1314. if (Rimg && Rhonbun) {
  1315. document.addEventListener("focus", e => { if (!elegeta('.thre img:not(img.quoteSpeechBalloonImg):inscreen:visible').length) leadFocus() })
  1316. document.addEventListener("blur", e => { $(".leadFocus").remove() })
  1317. Rhonbun.style.minWidth = "800px"
  1318.  
  1319. function leadFocus(e) {
  1320. if (!lh("/res/") || eleget0('//div[@class="thre"]/a/img|//div[@class="thre"]/a[2]/img:inscreen:visible') || eleget0('//div[@class="thre"]/blockquote:inscreen:visible') || eleget0('#pickbox,.leadFocus,.yhmMyMemo')) return;
  1321. let Rlead = end(document.body, `<div class="ignoreMe leadFocus" style="background-color:#ffffeef8; box-shadow:#00000070 0 0 1em ; border:solid 2px #800000b0; border-radius:1em; padding:1.2em; opacity:1; z-index:2000000020; position:fixed; top:0; right:0; transform:translate(0,-150%);"><table border="0"><tbody><tr><td class="rts">…</td><td class="rtd"></td></tr></tbody></table></div>`)
  1322. Rdesc.forEach(e => eleget0(".rtd", Rlead)?.appendChild(e))
  1323. eleget0(".rtd", Rlead)?.appendChild(Rimg)
  1324. eleget0(".rtd", Rlead)?.appendChild(Rhonbun)
  1325.  
  1326. $(Rlead).animate2({ "transform": "translate(0,0)" }, 333) //, (function(e) { return function() { setTimeout(() => { $(e).animate({"transform":"translate(0,-100%)"},333, () => $(e).remove()) }, 999) } })(lead))
  1327. setTimeout(Rlead => {
  1328. $(document).one("click wheel mousemove keydown", "body", (function(Rlead) {
  1329. return function() {
  1330. $(Rlead).animate2({ "transform": "translate(0,-150%)" }, 333);
  1331. setTimeout(Rlead => Rlead.remove(), 333, Rlead);
  1332. }
  1333. }(Rlead)))
  1334. }, 1333, Rlead)
  1335. }
  1336. }
  1337.  
  1338. // res0:: レス本文をレス0かのように加工
  1339. if (FUTABA_REPLACE_RES0 && ld(/\.2chan\./) && !isfvw) {
  1340. let img = eleget0('div.thre a img')?.cloneNode(true)
  1341. let imgfn = eleget0('div.thre a')?.cloneNode(true)
  1342. let imgfn2 = eleget0('div.thre a')?.cloneNode(true)
  1343. let desc = elegeta('div.thre>span.rsc,div.thre>span.csb,div.thre>span.cnm,div.thre>span.cnw,div.thre>span.cno')?.slice(0, 6)?.map(e => e.cloneNode(true))
  1344. let honbun = eleget0('div.thre blockquote')?.cloneNode(true)
  1345. if (imgfn && imgfn2 && img && honbun) {
  1346. addstyle.add(`.thre table[data-reszero] blockquote:not(.ftbpu table blockquote,#pickbox table blockquote){min-width:800px;}`)
  1347. let lead = before(eleget0(`table[border="0"]`), `<table border="0" data-reszero><tbody><tr><td class="rts">…</td><td class="rtd"><span class="rsc">0</span></td></tr></tbody></table>`)
  1348. lead = !lead ? after(eleget0(`.maxres`), `<table border="0" data-reszero><tbody><tr><td class="rts">…</td><td class="rtd"><span class="rsc">0</span></td></tr></tbody></table>`) : lead
  1349. //let lead = before(eleget0(`table[border="0"]`), `<table border="0" data-reszero><tbody><tr><td class="rts">…</td><td class="rtd"><span class="rsc">0</span></td></tr></tbody></table>`)
  1350. desc.forEach(e => eleget0(".rtd", lead).appendChild(e))
  1351. end(eleget0(".rtd", lead), `<br>  `)
  1352. eleget0(".rtd", lead).appendChild(imgfn)
  1353. //end(imgfn, `B)<br>`)
  1354. after(imgfn, `<br>`)
  1355. imgfn2.innerText = ""
  1356. eleget0(".rtd", lead).appendChild(imgfn2)
  1357. imgfn2.appendChild(img)
  1358. eleget0(".rtd", lead).appendChild(honbun)
  1359. elegeta('div.thre>a>img,div.thre>blockquote').forEach(e => {
  1360. e.dataset.hiddenzero = 1;
  1361. e.style.display = "none"
  1362. })
  1363. elegeta('div.thre>span.rsc,div.thre>span.csb,div.thre>span.cnm,div.thre>span.cnw,div.thre>span.cno').forEach(e => {
  1364. e.dataset.hiddenzero = 1;
  1365. e.style.display = "none"
  1366. })
  1367. /*elegeta('div.thre>a>img,div.thre>blockquote').forEach(e => e.style.display = "none")
  1368. elegeta('div.thre>span.rsc,div.thre>span.csb,div.thre>span.cnm,div.thre>span.cnw,div.thre>span.cno').forEach(e => e.style.display = "none")*/
  1369. }
  1370. $(document).on("keydown", e => { e.key == "c" && !e.shiftKey && !e.altKey && !e.ctrlKey && eleget0('div.thre>table[data-rsc="0"]:hover') && $(eleget0('div.thre>a.sod:not(.sodmypush)')).click().effect("highlight") })
  1371. }
  1372.  
  1373. // let isfvw = eleget0('#fvw_menu')
  1374. let replaceMainPopup = (FUTABA_HOVER_POPUP_REPLACE) || !is2chan
  1375. if (is2chan && replaceMainPopup) { GM_addStyle("#slp{z-index:1001} .qtd{display:none !important;} .fvw_respop,#respopup_area{display:none;opacity:0}"); }
  1376. $("#contres>a,#fvw_loading").attr("title", ($("#contres>a,#fvw_loading").attr("title") || "新着レスを読み込みます") + "\nE:リロード\nD/右クリック:リロード+新着にスクロール").on("contextmenu", (e) => {
  1377. SITE.funcD();
  1378. return false;
  1379. })
  1380. if (FUTABA_FLOAT_RELOAD_BUTTON) {
  1381. $('#contres').attr("floated", "");
  1382. GM_addStyle(`#contres{z-index:999; position:fixed; right:18em; left:auto; bottom:3px; height:auto; padding:0.1em 0.2em; border:2px solid #dddddd; background-color:#ffffff;}`)
  1383. }
  1384. pick2title(1)
  1385.  
  1386. GF.myRes = [];
  1387. eleget0('input[value="返信する"]')?.addEventListener("click", e => {
  1388. let ysend = window.scrollY; // スクロールを戻す
  1389. GF.myRes.push(eleget0("#ftxa")?.value?.trim())
  1390.  
  1391. function revscr(i) {
  1392. if (window.scrollY != ysend) window.scrollTo(0, ysend);
  1393. else if (i--) setTimeout(revscr, 17, i);
  1394. }
  1395. revscr(1000)
  1396. }, true)
  1397.  
  1398. $(document).on("click", ".relallAreaon", e => SITE?.keyFunc?.find(v => v.id === "z")?.func(e.ctrlKey ? "Shift+Z" : "z"))
  1399.  
  1400. // 自動リロード::
  1401. if (1 || FUTABA_AUTO_RELOAD_INTERVAL >= 1) {
  1402. var musousa = {
  1403. last: Date.now(),
  1404. elapsed: () => { return Date.now() - this.last },
  1405. init: () => {
  1406. this.last = Date.now();
  1407. $('body').on('keydown mousedown mousemove', () => this.last = Date.now());
  1408. },
  1409. }
  1410. musousa.init()
  1411. setInterval(() => {
  1412. if (document.body.textContent.match("スレッドがありません|上限\d+レスに達しました") && !GF?.stopThre) {
  1413. GF.stopThre = 1
  1414. if (document.visibilityState == "hidden") document.title = `🐾${document.title}`
  1415. }
  1416. if (!GF?.reloadAndNotifyNewArrival) return;
  1417. if ((musousa.elapsed() < 30000 && document.activeElement.tagName.match(/textarea|input/i)) || eleget0('//span[@id="thread_down"]') || GF?.stopThre) return;
  1418. let r = eleget0('#contres>a,#fvw_loading')
  1419. if (!r) return
  1420. let inter = Math.max(60 * 1000, Math.min(Math.max(600000, (FUTABA_AUTO_RELOAD_INTERVAL * 60 * 1000)), (FUTABA_AUTO_RELOAD_INTERVAL * 60 * 1000) + (musousa.elapsed() >= 59000 && GF?.newarticle == 0 && GF.latestInterval / 1))) // 1分以上無操作の時リロードして新着がないと更新間隔を広げていく、最低1分最大10分
  1421. if (!GF.latestReload || Date.now() - GF.latestReload >= inter) {
  1422. if (FUTABA_DEBUG >= 1) end(document.body, `<div>update : ${gettime()} / 現在更新間隔:${~~(inter/1000)} / 新着:${GF?.newarticle} / リロード後経過秒:${~~((Date.now()-GF.latestReload)/1000)} / 無操作秒:${~~(musousa.elapsed()/1000)} / 前回:${GF.latestInterval/1000}</div>`)
  1423. GF.latestReload = Date.now()
  1424. GF.latestInterval = inter
  1425. r?.click()
  1426. }
  1427. if (FUTABA_DEBUG >= 2) document.title = `${~~(inter/1000)}/${GF?.newarticle}/${~~((Date.now()-GF.latestReload)/1000)}/${~~(musousa.elapsed()/1000)} 現在更新間隔:${~~(inter/1000)} / 新着:${GF?.newarticle} / リロード後経過秒:${~~((Date.now()-GF.latestReload)/1000)} / 無操作秒:${~~(musousa.elapsed()/1000)} / 前回:${GF.latestInterval/1000}`
  1428. }, 1000)
  1429. }
  1430.  
  1431. // 画面最下段で下ホイールでリロード
  1432. window.addEventListener('wheel', (e) => {
  1433. if (e.deltaY > 0 && document.body.clientHeight - window.innerHeight <= window.pageYOffset && Date.now() - GF.latestReload >= 5000) {
  1434. $('#contres>a').click().effect("highlight");
  1435. GF.latestReload = Date.now();
  1436. }
  1437. })
  1438.  
  1439. // c::ホバー下にそうだね
  1440. var xTarget = []
  1441. var cnoPushed = []
  1442. var sodTarget = []
  1443. var lastc = 0
  1444. document.addEventListener('keypress', e => {
  1445. if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;
  1446. var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
  1447. var ele = document.elementFromPoint(mousex, mousey);
  1448. var cno = eleget0('table:not([data-reszero]) .cno', ele?.closest('table'))?.textContent?.replace(/\D/g, "")
  1449. if (cno && key == "c") $(ele?.closest('td')).effect("highlight")
  1450. if (cno && key == "c" && cno && !cnoPushed.includes(cno)) {
  1451. cnoPushed.push(cno)
  1452. xTarget.push({ key: key, cno: cno });
  1453. xTarget = (Array.from(new Set(xTarget.map(v => JSON.stringify(v))))).map(v => JSON.parse(v)) // uniq:オブジェクトの配列→JSON文字列配列→uniq→オブジェクトの配列
  1454. dosou()
  1455. //end(eleget0('.sod', ele?.closest('td')), `<span class="waiting">?</span>`) // くるくるを表示
  1456. //elegeta(`table .cno:text*=${cno}`).forEach(e => end(eleget0(".sod", e?.closest('table')), `<span class="waiting">?</span>`)) // くるくるを表示
  1457. }
  1458. })
  1459.  
  1460. function dosou() {
  1461. if (Date.now() - lastc < 3500) return
  1462. var a = xTarget.shift()
  1463. if (!a) return
  1464. let [key, cno] = [a.key, a.cno]
  1465. let t = eleget0(`table .cno:text*=${cno}`)?.closest('table')
  1466. if (!t) return;
  1467. if (key == "c" && !t?.dataset?.soddone) {
  1468. //$('.waiting', t).remove()
  1469. //elegeta(`table .cno:text*=${cno}`).forEach(e => eleget0(".waiting", e?.closest('table'))?.remove())
  1470. $('.sod', t).click().effect("highlight") // eleget0('//div[@class="thre"]/a[@class="sod"]')
  1471. lastc = Date.now()
  1472. t.dataset.soddone = 1;
  1473. }
  1474. }
  1475. setInterval(dosou, 500)
  1476.  
  1477. // そうだねを改行しないようにする
  1478. //document.body.addEventListener('copy', (event) => { $("#pickbox .sod:contains('x')").css({ "font-size": "125%", "float": "none" }); setTimeout(() => { $("#pickbox .sod:contains('x')").css({ "font-size": "125%", "float": "right" }) }, 1) });
  1479.  
  1480. var sdset = () => { if (is2chan) elegeta('#pickbox .sod:not([onclick]),.ftbpu .sod:not([onclick])').forEach(e => { e.setAttribute("onclick", `sd(${e?.id.replace(/\D/g,"")});return(false);`) }) }
  1481. // $(document).on("click", "a.sod", (e) => { e.target.style.color = "#f00" }) //$(document).on("click","a.sod",(e)=>{e.target.style.textDecoration="underline"})
  1482. $(document).on("click", "a.sod", (e) => { e.target.classList.add("sodmypush") }) //$(document).on("click","a.sod",(e)=>{e.target.style.textDecoration="underline"})
  1483.  
  1484. $("#contres>a,#fvw_loading").on("click", (e => {
  1485. GF.newarticle = 0
  1486. let latestEle = eleget0('//*[@class="thre"]/table[last()]');
  1487. //setTimeout(() => { document.body.dispatchEvent(new Event('2chanReloaded')) }, 1500)
  1488. document.body.dispatchEvent(new Event('2chanReloadedNodelay'))
  1489. })); // リロード再実行
  1490.  
  1491. //moq(eleget0('.thre:not(#pickbox .thre'), ".thre>table,.thre>div:not(#pickbox .thre>div,#pickbox,.qtd,.slp)", v => { // 新しいレスが追加されたら
  1492. // moq(eleget0('.thre:not(#pickbox .thre'), "table", v => {
  1493. moq(eleget0('.thre:not(#pickbox .thre'), "table,div:not(#pickbox,.qtd)", v => { // ,divはfutakuro共存用
  1494. //moq(eleget0('.thre:not(#pickbox .thre'), "table,div", v => { // ,divはfutakuro共存用
  1495. if (!GF.stopmoq) {
  1496. //let newarticle = elegeta('.thre table .rtd .rsc:not([data-basec]),.thre table .res_no:not([data-basec])')
  1497. let newarticle = elegeta('.thre table .rsc:not([data-basec]),.thre table .res_no:not([data-basec])')
  1498. GF.newarticle = newarticle.length || 0
  1499. setTimeout(() => { document.body.dispatchEvent(new Event('2chanReloaded')) }, 1)
  1500. }
  1501. })
  1502. // document.addEventListener("focus", () => { // firefox
  1503. window.addEventListener("focus", () => { // firefox/chrome
  1504. document.title = document.title.replace(/^🐾/g, "");
  1505. if (GF?.arrival) {
  1506. document.title = document.title.replace(/^[🐾🔴🔵⚠️■]+/g, "");
  1507. //document.title = document.title.replace(/^[🐾🔴🔵■]+/g, "");
  1508. GF.arrival = 0
  1509. }
  1510. })
  1511.  
  1512. function moq(observeNode, targetCSSSelector, cb) {
  1513. new MutationObserver((m) => {
  1514. let eles = [...m.filter(v => v.addedNodes).map(v => [...v.addedNodes]).filter(v => v.length)].flat().find(v => v.nodeType === 1 && v?.matches(targetCSSSelector));
  1515. if (eles) cb(eles)
  1516. })?.observe(observeNode || document.body, { attributes: false, childList: true, subtree: false });
  1517. }
  1518.  
  1519. document.body.addEventListener('2chanReloadedNodelay', function() {
  1520. $(`<hr class="reloadline" style="color:#aaa;">`).fadeIn("slow", function() { $(this).hide(0).fadeIn("slow") }).insertAfter($(elegeta('.thre table:not(#pickbox table,.ftbpu table,#respopup_area table,[floated] table)').pop()))
  1521. }, false);
  1522. $(document).on("scroll", () => {
  1523. if (elegeta('.reloadline:not([found])').filter(e => isinscreen(e)).length) {
  1524. $(elegeta('.reloadline')).attr("found", 1).delay(2000).hide("slow").delay(3000, function() { $(this).remove(); })
  1525. }
  1526. })
  1527.  
  1528. /* $(elegeta('//table[@class="deleted"]|//tr/td[@class="rtd"]/blockquote[contains(text(),"del")]/../../../..')).attr("title", "クリックで復帰").attr("floated", "1").animate2({ "opacity": "0.3", "transform": "scale(0.8)", "transform-origin": "right", "float": "right" }, 500).one("click", function() {
  1529. $(elegeta('//table[@class="deleted"]|//tr/td[@class="rtd"]/blockquote[contains(text(),"del")]/../../../..')).attr("title", "").animate2({ "opacity": "0.7", "transform": "scale(1)", "transform-origin": "right", "float": "none" }, 500);
  1530. */
  1531. $(elegeta('//table[@class="deleted"]')).attr("title", "クリックで復帰").attr("floated", "1").animate2({ "opacity": "0.3", "transform": "scale(0.8)", "transform-origin": "right", "float": "right" }, 500).one("click", function() {
  1532. $(elegeta('//table[@class="deleted"]')).attr("title", "").animate2({ "opacity": "0.7", "transform": "scale(1)", "transform-origin": "right", "float": "none" }, 500);
  1533. $(this)[0].scrollIntoView({ block: "nearest", behavior: "smooth" })
  1534. }) // 隔離を薄くして右に
  1535.  
  1536. $(document.body).append(`<script type="text/javascript">function scrRsc(n){let e=[...document.querySelectorAll('.rsc')].find(c=>c.textContent==n);if(e){e.closest(".rtd").style.outline="4px solid #0f0";setTimeout(()=>e.closest(".rtd").style.outline=null,1000)}e?.closest("table")?.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center'})}</script>`)
  1537.  
  1538. addstyle.add(`.embedyt{margin-bottom:0; max-width:43vw; margin-top:-0.5em; min-width: unset !important; width:fit-content; display: grid; grid-template-columns: repeat(auto-fit, minmax(321px, 1fr)); gap: 0px;}`)
  1539. // ニコ動埋め込み(PrivacyBadger等は要Disable)
  1540. var embednv = () => {
  1541. var elea = elegeta('a[href*="nicovideo"]:not([nde]),a[href*="//nico.ms/sm"]:not([nde])').filter(e => !e.closest('font[color="#789922"]'))
  1542. for (let ele of elea.filter(e => eleget0('.yhmMyMemo', e.closest("table"))).concat(elea.filter(e => isinscreen(e)))) { // リロード回避のためpickされるものは先に読み込む
  1543. let url = ele.href; //innerText.replace(/^ttp/i, "http");
  1544. ele.setAttribute("nde", "nde");
  1545. var nico = url.match(/h?ttps?:\/\/(?:www\.|sp\.)?nicovideo.jp\/watch(?:_tmp)?\/(.*)/i);
  1546. //var nico = url.match(/h?ttps?:\/\/(?:www\.|sp\.)?nicovideo.jp\/watch\/(.*)/i);
  1547. if (!nico) var nico = url.match(/h?https:\/\/nico\.ms\/(.*)/i);
  1548. if (!nico) continue;
  1549.  
  1550. let bq = ele?.closest("td,div.thre>blockquote:not([yte])")
  1551. let vbq = eleget0('.embedyt', ele?.closest("td,div.thre>blockquote:not([yte])"))
  1552. if (!vbq) $(bq).append('<blockquote class="embedyt"></blockquote>');
  1553. $(eleget0('.embedyt', bq)).append(`<p class="ignoreMe" style="display:inline-block; margin:0 1em 1em 0;"><iframe sandbox="allow-scripts allow-same-origin" class="ignoreMe" referrerpolicy="no-referrer" rel="nofollow external noopener noreferrer" allowfullscreen="allowfullscreen" allow="autoplay" src="https://embed.nicovideo.jp/watch/${nico[1]}${nico[1].match0(/\?/)?"&":"?"}persistence=1&amp;oldScript=1&amp;allowProgrammaticFullScreen=1" style="max-width: 100%;" height="181" frameborder="0"></iframe></p>`);
  1554. //$(ele?.closest("td,div.thre>blockquote:not([nde])")).append(`<blockquote><p class="ignoreMe" style="margin:0 0 0px;"></p></blockquote>`) // 埋め込み外部プレイヤー版
  1555. break; // 一度に1つずつしかやらない
  1556. }
  1557. if (elea.length) setTimeout(() => embednv(), 2000 + elea.length * 10);
  1558. }
  1559. autoPagerized(() => { embednv() })
  1560.  
  1561. // youtube埋め込み
  1562. var embedyt = () => {
  1563. var elea = elegeta('a[href*="youtube.com"]:not(#pickbox a,[yte]),a[href*="youtu.be"]:not(#pickbox a,[yte])').filter(e => !e.closest('font[color="#789922"]'))
  1564. for (let ele of elea.filter(e => eleget0('.yhmMyMemo', e.closest("table"))).concat(elea.filter(e => isinscreen(e)))) { // リロード回避のためpickされるものは先に読み込む
  1565. let url = ele.href //innerText;
  1566. ele.setAttribute("yte", "yte");
  1567. var sm = (url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11}).*[\?\&]t=(\d*).*$/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/(?:live\/|watch\?v=)([a-zA-Z0-9_\-]{11}).*&t=(\d*).*$/i)) || url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/shorts\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/(?:live\/|watch\?v=)([a-zA-Z0-9_\-]{11})/i);
  1568. var videoList = url.match0(/https:\/\/www\.youtube\.com\/watch_videos\?video_ids=([a-zA-Z0-9_\-\,]+)/)?.split(",")?.filter(v => v.match(/^[a-zA-Z0-9_\-]{11}$/));
  1569. if (!sm && !videoList) continue;
  1570. var pl = (url.match0(/[\&\?]list=([a-zA-Z0-9_\-]+)/));
  1571. if (1) { // 2列詰め込む
  1572. let bq = ele?.closest("td,div.thre>blockquote:not([yte])")
  1573. let vbq = eleget0('.embedyt', ele?.closest("td,div.thre>blockquote:not([yte])"))
  1574. if (!vbq) $(bq).append('<blockquote class="embedyt"></blockquote>');
  1575. let src = sm ? 'https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") :
  1576. videoList ? `https://www.youtube.com/embed/${videoList[0]}?playlist=${videoList?.join(',')}` :
  1577. ""
  1578. if (src) $(eleget0('.embedyt', bq)).append(`<p class="ignoreMe" style="display:inline-block; margin:0 1em 1em 0;"><iframe sandbox="allow-scripts allow-same-origin" class="ignoreMe" referrerpolicy="no-referrer" src="${src}" id="ytplayer" type="text/html" height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></iframe></p>`);
  1579. /*if (!sm) continue
  1580. var pl = (url.match0(/[\&\?]list=([a-zA-Z0-9_\-]+)/));
  1581.  
  1582. if (1) { // 2列詰め込む
  1583. let bq = ele?.closest("td,div.thre>blockquote:not([yte])")
  1584. let vbq = eleget0('.embedyt', ele?.closest("td,div.thre>blockquote:not([yte])"))
  1585. if (!vbq) $(bq).append('<blockquote class="embedyt"></blockquote>');
  1586. $(eleget0('.embedyt', bq)).append('<p class="ignoreMe" style="display:inline-block; margin:0 1em 1em 0;"><iframe sandbox="allow-scripts allow-same-origin" class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") + `" id="ytplayer" type="text/html" height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p>`);
  1587. */
  1588. } else { // 1列モード
  1589. if (sm) $(ele?.closest("td,div.thre>blockquote:not([yte])")).append('<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe sandbox="allow-scripts allow-same-origin" class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") + `" id="ytplayer" type="text/html" height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p></blockquote>`); //width=${pl?401:321}
  1590. }
  1591. break; // 一度に1つずつしかやらない
  1592. };
  1593. if (elea.length) setTimeout(() => embedyt(), 2000 + elea.length * 10);
  1594. }
  1595. autoPagerized(() => { embedyt() })
  1596. /* // ニコ動埋め込み(PrivacyBadger等は要Disable)
  1597. var embednv = () => {
  1598. var elea = elegeta('a[href*="nicovideo"]:not([nde]),a[href*="//nico.ms/sm"]:not([nde])').filter(e => !e.closest('font[color="#789922"]'))
  1599. for (let ele of elea.filter(e => eleget0('.yhmMyMemo', e.closest("table"))).concat(elea.filter(e => isinscreen(e)))) { // リロード回避のためpickされるものは先に読み込む
  1600. let url = ele.href; //innerText.replace(/^ttp/i, "http");
  1601. ele.setAttribute("nde", "nde");
  1602. var nico = url.match(/h?ttps?:\/\/(?:www\.|sp\.)?nicovideo.jp\/watch\/(.*)/i);
  1603. //var nico = url.match(/h?ttps?:\/\/(?:www\.)?nicovideo.jp\/watch\/(.*)/i);
  1604. //var nico = url.match(/h?ttps?:\/\/www.nicovideo.jp\/watch\/(.*)/i);
  1605. if (!nico) var nico = url.match(/h?https:\/\/nico\.ms\/(.*)/i);
  1606. if (!nico) continue
  1607. $(ele?.closest("td,div.thre>blockquote:not([nde])")).append(`<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe class="ignoreMe" referrerpolicy="no-referrer" rel="nofollow external noopener noreferrer" allowfullscreen="allowfullscreen" allow="autoplay" src="https://embed.nicovideo.jp/watch/${nico[1]}${nico[1].match0(/\?/)?"&":"?"}persistence=1&amp;oldScript=1&amp;allowProgrammaticFullScreen=1" style="max-width: 100%;" width="312" height="176" frameborder="0"></iframe></p></blockquote>`) // 埋め込み外部プレイヤー版
  1608. break; // 一度に1つずつしかやらない
  1609. }
  1610. if (elea.length) setTimeout(() => embednv(), 2000 + elea.length * 10);
  1611. }
  1612. autoPagerized(() => { embednv() })
  1613.  
  1614. // youtube埋め込み
  1615. var embedyt = () => {
  1616. var elea = elegeta('a[href*="youtube.com"]:not(#pickbox a,[yte]),a[href*="youtu.be"]:not(#pickbox a,[yte])').filter(e => !e.closest('font[color="#789922"]'))
  1617. for (let ele of elea.filter(e => eleget0('.yhmMyMemo', e.closest("table"))).concat(elea.filter(e => isinscreen(e)))) { // リロード回避のためpickされるものは先に読み込む
  1618. let url = ele.href //innerText;
  1619. ele.setAttribute("yte", "yte");
  1620. // var sm = (url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11}).*[\?\&]t=(\d*).*$/i) || url.match(/h?ttps?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11}).*&t=(\d*).*$/i)) || url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.)?youtube\.com\/shorts\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11})/i);
  1621. // var sm = (url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11}).*[\?\&]t=(\d*).*$/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11}).*&t=(\d*).*$/i)) || url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/shorts\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11})/i);
  1622. var sm = (url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11}).*[\?\&]t=(\d*).*$/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/(?:live\/|watch\?v=)([a-zA-Z0-9_\-]{11}).*&t=(\d*).*$/i)) || url.match(/h?ttps?:\/\/youtu\.be\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/shorts\/([a-zA-Z0-9_\-]{11})/i) || url.match(/h?ttps?:\/\/(?:www\.|m\.)?youtube\.com\/(?:live\/|watch\?v=)([a-zA-Z0-9_\-]{11})/i);
  1623. if (!sm) continue
  1624. var pl = (url.match0(/[\&\?]list=([a-zA-Z0-9_\-]+)/));
  1625. // $(ele?.closest("td,div.thre>blockquote:not([yte])")).append('<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") + '" id="ytplayer" type="text/html" width=321 height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p></blockquote>');
  1626.  
  1627. if (1) { // 2列詰め込む
  1628. let bq = ele?.closest("td,div.thre>blockquote:not([yte])")
  1629. let vbq = eleget0('.embedyt', ele?.closest("td,div.thre>blockquote:not([yte])"))
  1630. if (!vbq) $(bq).append('<blockquote class="embedyt" style="margin-bottom:0; max-width:40vw;"></blockquote>');
  1631. let index = +(eleget0('.embedyt', bq)?.dataset?.videos || 0) % 2
  1632. $(eleget0('.embedyt', bq)).append('<p class="ignoreMe" style="display:inline-block; margin:0 1em 1em 0;"><iframe class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") + `" id="ytplayer" type="text/html" height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p>`);
  1633. eleget0('.embedyt', bq).dataset.videos = index + 1;
  1634. //if (index == 1) $(eleget0('.embedyt', bq)).append('<br>')
  1635. } else { // 1列モード
  1636. $(ele?.closest("td,div.thre>blockquote:not([yte])")).append('<blockquote><p class="ignoreMe" style="margin:0 0 0px;"><iframe class="ignoreMe" referrerpolicy="no-referrer" src="https://www.youtube.com/embed/' + sm[1] + (pl ? `?list=${pl}` : "") + (sm[2] ? `${pl?"&":"?"}start=` + sm[2] : "") + `" id="ytplayer" type="text/html" height=181 frameborder=0 allowfullscreen allow="picture-in-picture"></p></blockquote>`); //width=${pl?401:321}
  1637. }
  1638. break; // 一度に1つずつしかやらない
  1639. };
  1640. if (elea.length) setTimeout(() => embedyt(), 2000 + elea.length * 10);
  1641. }
  1642. autoPagerized(() => { embedyt() })
  1643. */
  1644.  
  1645. // fu画像埋め込み
  1646. var embedimg = () => {
  1647. if (ld("tsumanne")) {
  1648. elegeta('table blockquote a:not([ime])').filter(v => v?.href?.match(/fu?\d+\.(jpg|jpeg|png|gif|bmp|webp)/gmi)).forEach(e => {
  1649. e.setAttribute("ime", "ime");
  1650. $(e?.closest("td,div.thre>blockquote")).append(`<blockquote style="margin-top:0;"><p class="ignoreMe" style="margin:0 0 0px;"><img class="ignoreMe" referrerpolicy="no-referrer" style="max-height:250px;" src="${e.href}"></p></blockquote>`)
  1651. })
  1652. elegeta('table blockquote a:not([ime])').filter(v => v?.href?.match(/fu?\d+\.(mp4|webm|mp3|aac|flac|m4a)/gmi)).forEach(e => {
  1653. e.setAttribute("ime", "ime");
  1654. $(e?.closest("td,div.thre>blockquote")).append(`<blockquote style="margin-top:0;"><p class="ignoreMe" style="margin:0 0 0px;"><video controls="" name="media" src="${e.href}" style="max-height:250px;" class="ignoreMe"></video></p></blockquote>`)
  1655. })
  1656. } else {
  1657. var elea = elegeta('.rtd blockquote:not([ime]),div.thre>blockquote:not([ime])')
  1658. for (let ele of elea) { // 画面内にあるものだけが基本だけどリロード回避のためpickされるものは優先的に読み込む
  1659. let txt = ele.innerText;
  1660. ele.setAttribute("ime", "ime");
  1661. var sm = txt.match(/^fu?\d+\.(jpg|jpeg|png|gif|bmp|webp)/gmi);
  1662. if (sm?.length) {
  1663. sm.forEach(v => $(ele?.closest("td,div.thre>blockquote")).append(`<blockquote style="margin-top:0;"><p class="ignoreMe" style="margin:0 0 0px;"><img class="ignoreMe" referrerpolicy="no-referrer" style="max-height:250px;" src="https://${/^fu\d+\./.test(v)?"dec.2chan.net/up2/src/":"dec.2chan.net/up/src/"}${v}"></p></blockquote>`))
  1664. }
  1665. var sm = txt.match(/^fu?\d+\.(mp4|webm|mp3|aac|flac|m4a)/gmi);
  1666. if (sm?.length) {
  1667. sm.forEach(v => $(ele?.closest("td,div.thre>blockquote")).append(`<blockquote style="margin-top:0;"><p class="ignoreMe" style="margin:0 0 0px;"><video controls="" name="media" src="https://${/^fu\d+\./.test(v)?"dec.2chan.net/up2/src/":"dec.2chan.net/up/src/"}${v}"" style="max-height:250px;" class="ignoreMe"></video></p></blockquote>`)) // preload="none"
  1668. }
  1669. //break; // 一度に1つずつしかやらない
  1670. };
  1671. //if (elea.length) setTimeout(() => embedimg(), 2000 + elea.length * 10);
  1672. }
  1673. }
  1674. autoPagerized(() => { embedimg() })
  1675.  
  1676. FUTABA_PLAY_GIF_INLINE && autoPagerized(() => embedGif())
  1677.  
  1678. function embedGif() {
  1679. elegeta('.thre>a>img[href*=".gif"]:not([data-gifloaded]),td.rtd>a[href*=".gif"]>img:not([data-gifloaded])').forEach(e => {
  1680. let a = e.closest("a")
  1681. if (a) {
  1682. e.dataset.gifloaded = 1
  1683. e.src = a.href;
  1684. }
  1685. })
  1686. }
  1687.  
  1688. var popped = []
  1689. //$(eleget0('//td/input[@value="返信する"]')).on("click", () => { setTimeout(() => shikomi(), 999) })
  1690. // 引用ポップアップ仕込み
  1691. var cited = [];
  1692. var resEnum = [];
  1693.  
  1694. if (eleget0('//b[contains(text(),"このスレの書き込みはIPアドレスが表示されます。")]')) addstyle.add('#ftxa{background-color:#fee !important;}') // IPスレ警告
  1695. addstyle.add('.idw{color:#f00; font-weight:800;}')
  1696.  
  1697. function shikomi() {
  1698. if (FUTABA_REMOVE_REDIRECT_PAGE) elegeta('td.rtd blockquote a[href*="/bin/jump.php?"] , div.thre blockquote a[href*="/bin/jump.php?"]').forEach(e => {
  1699. e.rel = "noopener nofollow noreferrer"
  1700. e.href = e.href.replace(/^.*\/bin\/\jump\.php\?/, "")
  1701. }); // リダイレクトページを省略
  1702.  
  1703. GF.alertWord = pref("alertWord")?.replace(/^<string>([\s\S]*)<\/string>$/, "$1") || ""; // m::
  1704. let idw = elegeta('.cnw:not(.idw)')
  1705. if (idw.every(v => /ID\:/.test(v.innerText))) {
  1706. GF.idw = 1;
  1707. addstyle.add('#ftxa{background-color:#fee;}') // addstyle.add('#ftxa{background-color:#ffd;}')
  1708. } else if (GF?.idw) addstyle.add('#ftxa{background-color:#fff;}')
  1709. idw.filter(v => /ID\:|IP\:/.test(v.innerText)).forEach(e => e.classList.add("idw")) // IDスレ警告
  1710.  
  1711. elegeta('.thre table tr:not([data-quospan])').forEach(e => {
  1712. e.dataset.quospan = "1";
  1713. e.insertAdjacentHTML("beforeend", `<td class="ignoreMe quo" style="position:relative;"><div class="ignoreMe memo"></div><div class="ignoreMe backlink"></div><div class="ignoreMe relallArea"> </div></td>`)
  1714. })
  1715.  
  1716. let notifyDelay = 0;
  1717. let awNotify = 0;
  1718.  
  1719. elegeta('.thre table .rtd .rsc:not([data-basec]),.thre table .res_no:not([data-basec])').forEach(e => {
  1720. e.dataset.basec = "1"
  1721. e.style.cursor = "pointer"
  1722. e.setAttribute("onclick", `scrRsc(${Number(e.textContent)})`); //クリックで中心にスクロール
  1723. let resno = e?.textContent
  1724. e.closest('table').setAttribute("rsc", resno)
  1725. e.closest('.rtd').dataset.rsc = resno
  1726. e.closest('table').dataset.rsc = resno
  1727. // })
  1728.  
  1729. // elegeta('.thre table .rtd .rsc:not([data-basec]),.thre table .res_no:not([data-basec])').forEach(e => {
  1730. e.dataset.basec = "1"
  1731.  
  1732. var text = eleget0('blockquote', e.closest('table'))?.innerText?.trim()
  1733. let isMyres = (text && GF?.myRes?.includes(text))
  1734.  
  1735. if (FUTABA_SET_56MEMO_TO_ANCHORED >= 1 && isMyres) { // 送信したレスに5メモを付ける
  1736. // let text = eleget0('blockquote', e.closest('table'))?.innerText?.trim()
  1737. // if (text && GF?.myRes?.includes(text)) {
  1738. memoElement(e, document.body, COLOR5, getDefault56memo());
  1739. GF.myRes = GF.myRes.filter(v => !GF?.myRes?.includes(text))
  1740.  
  1741. /*if (isMyres) {
  1742. setTimeout((function(e) {
  1743. return function() {
  1744. //var dateStr = getDefault56memo();
  1745. memoElement(e, document.body, COLOR5, getDefault56memo());
  1746. }
  1747. })(e), 1)
  1748. GF.myRes = GF.myRes.filter(v => !GF?.myRes?.includes(text))
  1749. }*/
  1750. }
  1751.  
  1752. setTimeout(() => { // 非表示等を反映させるため遅らせる
  1753.  
  1754. var tomemo = GF?.anchor[e?.closest("table")?.dataset?.rsc] || ""
  1755. let hasAnyMemo = eleget0('.yhmMyMemo', e?.closest("table")) ? 1 : 0
  1756.  
  1757. if (GF?.fromSecond) {
  1758. // if (FUTABA_SET_56MEMO_TO_ANCHORED >= 3 && !isMyres) { // 遠くても5メモと連鎖していれば通知する
  1759. if (FUTABA_SET_56MEMO_TO_ANCHORED >= 3 && !isMyres && !hasAnyMemo) { // 遠くても5メモと連鎖していれば通知する
  1760. //var relatedMemoO = getRelatedRsca(e?.closest("table")?.dataset?.rsc)?.find(rsc => (eleget0('.yhmMyMemoO', eleget0(`table[data-rsc="${rsc}"]`))))
  1761. var [relatedMemoO, ] = getRelatedRsca(e?.closest("table")?.dataset?.rsc)
  1762. relatedMemoO = relatedMemoO?.find(rsc => (eleget0(`.yhmMyMemoO[data-yhmc="${COLOR1}"]`, eleget0(`table[data-rsc="${rsc}"]`))))
  1763. if (relatedMemoO && !tomemo.match("🔵")) {
  1764. let res = eleget0(`blockquote`, eleget0(`table[data-rsc="${relatedMemoO}"]`))?.innerText
  1765. res = res?.replace(/^\s*\>.*\s*$/gm, "")?.replace(/キタ━+\(゚\∀゚\)━+\!+/gm, "")?.trim() || res;
  1766. tomemo = tomemo || text?.match0(/^\>[^\n]*/m) || "";
  1767. tomemo += (tomemo ? "\n" : "");
  1768. tomemo = (`>🔵distant:${res.split("\n")?.[0]}\n`) + tomemo;
  1769. }
  1770. }
  1771.  
  1772. if (FUTABA_SET_56MEMO_TO_ANCHORED >= 4 && !isMyres) { // 遠くても6メモと連鎖していれば通知する
  1773. var [relatedMemoO, ] = getRelatedRsca(e?.closest("table")?.dataset?.rsc)
  1774. relatedMemoO = relatedMemoO?.find(rsc => (eleget0('.yhmMyMemoX', eleget0(`table[data-rsc="${rsc}"]`))))
  1775. if (relatedMemoO && !tomemo.match("🔴")) {
  1776. let res = eleget0(`blockquote`, eleget0(`table[data-rsc="${relatedMemoO}"]`))?.innerText
  1777. res = res?.replace(/^\s*\>.*\s*$/gm, "")?.replace(/キタ━+\(゚\∀゚\)━+\!+/gm, "")?.trim() || res;
  1778. tomemo = tomemo || text?.match0(/^\>[^\n]*/m) || "";
  1779. tomemo += (tomemo ? "\n" : "");
  1780. tomemo = (`>🔴distant:${res.split("\n")?.[0]}\n`) + tomemo;
  1781. }
  1782. }
  1783. }
  1784.  
  1785. let table = e.closest('table');
  1786. var text = table?.textContent;
  1787.  
  1788. let awMatch = GF?.alertWord > "" && text?.match0(GF?.alertWord) || text?.match0(new RegExp(GF?.alertWord.replace(/^S$/, "??").replace(/^S([\s \||])/, "??$1").replace(/([\s \||!!])S([\s \||])/, "$1??$2").replace(/([\s \||!!])S$/, "$1??").replace(/|/gm, "|").replace(/^[\!|!](\S*)/, "^(?!.*($1)).*").replace(/(\S*)[  ](\S*)/gm, "^(?=.*($1))(?=.*\($2\))").replace(/\s| /gm, ".*"), "i")); //alert(searRE); // 独自構文を正規表現に変換
  1789. if (!isMyres && GF?.alertWord > "" && (e.offsetHeight && awMatch) && !eleget0('.yhmMyMemo', table)) {
  1790. var path = eleget0('img', table)?.src
  1791. if (FUTABA_SET_56MEMO_TO_ANCHORED) memoElement(e, document.body, COLOR_ALERT_WORD, getDefault56memo());
  1792. if (awNotify++ < 3) notifyMe(eleget0("blockquote", table)?.textContent + "\n", `⚠️${awMatch}⚠️ ${GF?.originalDocTitle||document.title}`, () => setTimeout(() => scrRsc(e?.closest('table')?.dataset?.rsc), 150), path || null, true)
  1793. if (FUTABA_NOTIFY_NEWRES_SOUND_MEMO_QUOTED.split(" ").includes("m")) sound("sawtooth", 0.025, 440)
  1794. document.title = "⚠️" + document.title.replace(/^[■🔴🔵⚠️]+/g, "");
  1795. } //else
  1796.  
  1797. if (GF?.fromSecond) {
  1798. // nキーのモードと条件にマッチすれば通知する
  1799. if (!isMyres && (((GF?.reloadAndNotifyNewArrival >= 2 && tomemo) || (GF?.reloadAndNotifyNewArrival >= 3 && (tomemo || (e.offsetHeight && eleget0("img:not(.quoteSpeechBalloonImg),blockquote a,blockquote video", e.closest('table'))))) || (GF?.reloadAndNotifyNewArrival >= 4 && e.offsetHeight)) && (document.visibilityState !== "visible" || tomemo))) {
  1800. var path = eleget0('img', e.closest('table'))?.src
  1801. notifyMe(tomemo + eleget0('blockquote', e.closest('table'))?.innerText?.replace(/^>.*$/gm, "")?.trim(), tomemo.replace(/[^🔴🔵]/gm, "") + GF.originalDocTitle, () => setTimeout(() => scrRsc(e?.closest('table')?.dataset?.rsc), 150), path || null)
  1802. if (tomemo.match("🔵")) {
  1803. if (FUTABA_NOTIFY_NEWRES_SOUND_MEMO_QUOTED.split(" ").includes("5")) sound("square", 0.025, 880); // type:sine, square, sawtooth, triangleがある
  1804. if (!document.hasFocus()) {
  1805. GF.arrival = 1;
  1806. document.title = "🔵" + document.title.replace(/^[■🔴🔵]+/g, "");
  1807. }
  1808. }
  1809. if (tomemo.match("🔴")) {
  1810. if (FUTABA_NOTIFY_NEWRES_SOUND_MEMO_QUOTED.split(" ").includes("6")) sound("square", 0.025, 220); // type:sine, square, sawtooth, triangleがある
  1811. if (!document.title.match(/^[■🔴]*🔵/) && !document.hasFocus()) {
  1812. GF.arrival = 1;
  1813. document.title = "🔴" + document.title.replace(/^[■🔴]+/g, "");
  1814. }
  1815. }
  1816. }
  1817.  
  1818. if ((!GF?.arrival && document.visibilityState !== "visible") && (!GF?.reloadAndNotifyNewArrival || (GF?.reloadAndNotifyNewArrival && e.offsetHeight))) {
  1819. GF.arrival = 1;
  1820. document.title = `■${document.title}` //document.title = `■${GF.originalDocTitle}`
  1821. }
  1822. }
  1823. /* if (FUTABA_SET_56MEMO_TO_ANCHORED >= 3 && !isMyres&&tomemo.match("🔵")) memoElement(e, document.body, COLOR6, getDefault56memo()); // 5メモへアンカーしたレスに6メモを付ける
  1824. if (FUTABA_SET_56MEMO_TO_ANCHORED >= 4 && !isMyres&&tomemo.match("🔴")) memoElement(e, document.body, COLOR6, getDefault56memo()); // 6メモへアンカーしたレスに6メモを付ける
  1825. */
  1826. if (GF?.fromSecond) {
  1827. if (FUTABA_SET_56MEMO_TO_ANCHORED >= 3 && !isMyres) { // 5メモへアンカーしたレスに6メモを付ける
  1828. if (tomemo.match("🔵")) {
  1829. memoElement(e, document.body, COLOR6, getDefault56memo());
  1830. }
  1831. }
  1832. if (FUTABA_SET_56MEMO_TO_ANCHORED >= 4 && !isMyres) { // 6メモへアンカーしたレスに6メモを付ける
  1833. if (tomemo.match("🔴")) {
  1834. memoElement(e, document.body, COLOR6, getDefault56memo());
  1835. }
  1836. }
  1837. }
  1838.  
  1839. // }, 1 + (notifyDelay++) * 17, e)
  1840. // setTimeout(()=>document.body.dispatchEvent(new CustomEvent('plzGKSI')),555)
  1841. }, 1, e)
  1842. })
  1843. // GF.fromSecond = 1; // 初回は新着ではないのでやらない
  1844.  
  1845. /* elegeta('.thre table tr:not([data-quospan])').forEach(e => {
  1846. e.dataset.quospan = "1";
  1847. e.insertAdjacentHTML("beforeend", `<td class="ignoreMe quo" style="position:relative;"><div class="ignoreMe memo"></div><div class="ignoreMe backlink"></div><div class="ignoreMe relallArea"> </div></td>`)
  1848. })
  1849. */
  1850. // 逆引用を追加
  1851. var issorted = eleget0('#sortType2') || eleget0('#sortType1')
  1852. resEnum = [];
  1853. cited = [];
  1854. GF.anchor = new Array(1000).fill("")
  1855.  
  1856. var resa = elegeta('.thre table .rtd:not(#pickbox .rtd,.ftbpu .rtd,#respopup_area .rtd)').sort((a, b) => { return (Number(a.dataset.rsc) - Number(b.dataset.rsc)) })
  1857. elegeta(".revQuote:not(#pickbox .revQuote,.ftbpu .revQuote)").forEach(e => e?.remove())
  1858.  
  1859. //test: 5578ms - タイマー終了 test: 5327ms - タイマー終了
  1860. //elegeta('.thre table .rtd blockquote font:not(#pickbox font,.ftbpu font,#respopup_area font),.thre table .rtd blockquote p font:not(#pickbox font,.ftbpu font,#respopup_area font)').forEach((h, i) => { //緑文字の引用行文字列
  1861. resa.map(v => elegeta('blockquote :is(font,p font)', v)).flat().forEach((h, i) => { //緑文字の引用行文字列
  1862. var eWord = h.textContent.match(/^\>+(.+)$/)?.[1]; // >***の***部分 // oこれだと>>No.*への逆引用がつくのは「>No.*」と「No.*」の両方に逆引用がつく x本当にレスしている対象より前の初出のレスだけに逆引用がついてしまう
  1863. //var eWord = h.textContent.match(/^\>(.+)$/)?.[1]; // >***の***部分 // xこれだと>>No.*への逆引用がつくのは「>No.*」だけになり「No.*」にはつかない o本当にレスしている対象より前のものだけに逆引用がついてしまう
  1864. if (eWord) {
  1865. //h.style.cursor="pointer" //これをやるとちょっとうるさい
  1866. var greenResNo = h.closest('table').dataset.rsc; //緑文字列があるレスのレス番
  1867. resa.filter(e => e.textContent.indexOf(eWord) !== -1).forEach((c, i) => { // c=***が含まれるレス
  1868. let n = c.dataset.rsc; // ***が含まれるレスのレス番
  1869. if (i === 0 && !(!resEnum[n] && n === greenResNo)) { // i==0つまりスレの初出のそれにしかヒットしない
  1870. let r = eleget0(".relallArea", h.closest('table'))?.classList.add("relallAreaon") // >>100があったらrelallOn
  1871. eleget0(".relallArea", c.closest('table'))?.classList.add("relallAreaon") // >あいう の対象レスが本当に存在したらrelallOn
  1872. if (!resEnum[n]) resEnum[n] = []
  1873. if (!resEnum[n].includes(greenResNo)) {
  1874. resEnum[n].push(greenResNo)
  1875. // end(c.parentNode.querySelector(".backlink"), `<font class="revQuote" data-resenum="${resEnum[n]}" data-rsc="${n}" onclick="scrRsc(${greenResNo})">&gt;&gt;${greenResNo}</font>`) //クリックで中心にスクロール
  1876. end(c.parentNode.querySelector(".backlink"), `<font class="revQuote" data-resenum="${resEnum[n]}" data-rsc="${n}" onclick="scrRsc(${greenResNo})">&gt;&gt;${greenResNo}</font>`) //クリックで中心にスクロール
  1877. // let memo = (eleget0('.yhmMyMemoO', c.closest('table'))) ? `>🔵${eWord}\n` : (eleget0('.yhmMyMemoX', c.closest('table'))) ? `>🔴${eWord}\n` : null;
  1878. let memo = (eleget0(`.yhmMyMemoO[data-yhmc="${COLOR1}"]`, c.closest('table'))) ? `>🔵${eWord}\n` : (eleget0('.yhmMyMemoX', c.closest('table'))) ? `>🔴${eWord}\n` : null;
  1879. if (memo) GF.anchor[h?.closest("table")?.dataset?.rsc] += memo
  1880. }
  1881. }
  1882. })
  1883. }
  1884. })
  1885.  
  1886. let fivechthumbnailetc = (!lh(/\.2chan\.net\//) || eleget0('#fivechthumbnailetc')) && 1
  1887. // >No.○に本文の引用を追加 qsb::
  1888. // if (FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY && fivechthumbnailetc) { //} || lh("ftbucket|kuzure")) {
  1889. if (FUTABA_QUOTE_LEAD_FOR_NUMBER_ONLY) { //} || lh("ftbucket|kuzure")) {
  1890. var quos = elegeta('.thre table .rtd blockquote font:not([data-quoted],#pickbox font,.ftbpu font,#respopup_area font),.thre table .rtd blockquote p font:not([data-quoted],#pickbox font,.ftbpu font,#respopup_area font)').filter(v => v.innerText.match(/>+No\.|>+\d|>+fu/))
  1891. quos.filter(e => /^\>+No\.\d+$/m.test(e?.textContent)).forEach((e, i) => { //緑文字の引用行文字列
  1892. e.dataset.quoted = 1
  1893. let ecno = e?.textContent?.replace(/\D/g, "")
  1894. var srcTable = elegeta("table .cno").find(v => v?.textContent?.replace(/\D/g, "") == ecno)?.closest("table[rsc]")
  1895. if (srcTable && srcTable != e?.closest("table[rsc]")) {
  1896. var origno = e?.textContent
  1897. var lead = eleget0('blockquote', srcTable)?.innerText?.replace(/^\s*>+.*$/gm, "")?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
  1898. if (!lead) lead = eleget0('blockquote', srcTable)?.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
  1899. if (lead?.slice(33)?.length) lead = lead?.slice(0, 33)?.trim() + "…"
  1900. lead = lead?.replace(/\n/gm, " ")
  1901. if (lead) {
  1902. // adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
  1903. fivechthumbnailetc && adja(e, "afterend", `<span class="quoteSpeechBalloon" data-quoteno="${origno}">&gt;${lead}</span>`)
  1904. }
  1905. var srcImg = eleget0("img", srcTable)?.cloneNode()
  1906. if (srcImg) {
  1907. srcImg.removeAttribute("width")
  1908. srcImg.removeAttribute("height")
  1909. srcImg.dataset.quoteno = origno
  1910. srcImg.className = "quoteSpeechBalloonImg"
  1911. srcImg.removeAttribute("hspace")
  1912. srcImg.removeAttribute("align")
  1913. srcImg.dataset.zoomonhover = "disable"
  1914. srcTable && e.appendChild(srcImg)
  1915. }
  1916. }
  1917. })
  1918. // >>○.jpgに本文の引用を追加 qsb::
  1919. quos.filter(e => /^\>+\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)$/m.test(e?.textContent)).forEach((e, i) => { //緑文字の引用行文字列
  1920. e.dataset.quoted = 1
  1921. let ertd = e?.textContent?.replace(/\>+/, "")
  1922. var srcTable = elegeta("table .rtd").find(v => { return v?.textContent?.match(/\d+\.(jpg|jpeg|png|gif|bmp|webp|webm|mp4)/)?.[0] == ertd })?.closest("table[rsc]")
  1923. if (srcTable && srcTable != e?.closest("table[rsc]")) {
  1924. var origno = e?.textContent
  1925. var lead = eleget0('blockquote', srcTable)?.innerText?.replace(/^\s*>+.*$/gm, "")?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
  1926. if (!lead) lead = eleget0('blockquote', srcTable)?.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
  1927. if (lead?.slice(33)?.length) lead = lead?.slice(0, 33)?.trim() + "…"
  1928. lead = lead?.replace(/\n/gm, " ")
  1929. var srcImg = eleget0("img", srcTable)?.cloneNode()
  1930. if (lead) {
  1931. // adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
  1932. fivechthumbnailetc && adja(e, "afterend", `<span class="quoteSpeechBalloon" data-quoteno="${origno}">&gt;${lead}</span>`)
  1933. }
  1934. if (srcImg) {
  1935. srcImg.removeAttribute("width")
  1936. srcImg.removeAttribute("height")
  1937. srcImg.dataset.quoteno = origno
  1938. srcImg.className = "quoteSpeechBalloonImg"
  1939. srcImg.removeAttribute("hspace")
  1940. srcImg.removeAttribute("align")
  1941. srcImg.dataset.zoomonhover = "disable"
  1942. srcTable && e.appendChild(srcImg)
  1943. }
  1944. }
  1945. })
  1946. // >fu○.jpgに本文の引用を追加 qsb::
  1947. quos.filter(e => /^\>+fu\d+\.(jpg|jpeg|png|gif|bmp|webp)$/m.test(e?.textContent)).forEach((e, i) => { //緑文字の引用行文字列 fu*
  1948. e.dataset.quoted = 1
  1949. let ertd = e?.textContent?.replace(/\>+/, "")
  1950. var srcTable = elegeta("table .rtd").find(v => elegeta('img', v).find(w => w?.src?.indexOf(ertd) !== -1))?.closest("table[rsc]")
  1951. if (srcTable && srcTable != e?.closest("table[rsc]")) {
  1952. var origno = e?.textContent
  1953. var lead = eleget0('blockquote', srcTable)?.innerText?.replace(/^\s*>*fu\S+\s*/gm, "")?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
  1954. //if (!lead) lead = eleget0('blockquote', srcTable)?.innerText?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.trim()
  1955. if (lead?.slice(33)?.length) lead = lead?.slice(0, 33)?.trim() + "…"
  1956. lead = lead?.replace(/\n/gm, " ")
  1957. var srcImg = elegeta('img', srcTable).find(w => w?.src?.indexOf(e?.textContent?.replace(/\>+/, "")) !== -1)?.cloneNode()
  1958. if (lead) {
  1959. // adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}"> &gt;${lead} </span>`)
  1960. fivechthumbnailetc && adja(e, "afterend", ` <span class="quoteSpeechBalloon" data-quoteno="${origno}">&gt;${lead}</span>`)
  1961. }
  1962. if (srcImg) {
  1963. srcImg.dataset.quoteno = origno
  1964. srcImg.className = "quoteSpeechBalloonImg"
  1965. srcImg.dataset.zoomonhover = "disable"
  1966. srcTable && e.appendChild(srcImg)
  1967. }
  1968. }
  1969. })
  1970. }
  1971.  
  1972. elegeta('.cnw a:not([data-popped]),.cnm a:not([data-popped])').forEach(e => {
  1973. e.dataset.popped = 1;
  1974. after(e, ` <span class="mailtoPopped">${sani(decodeURI(e?.href))}</span>`)
  1975. }) // メール欄の中身を外に出す
  1976. }
  1977. autoPagerized(() => shikomi())
  1978.  
  1979. // .relAllAreaon枠に連鎖レス数を書き入れていく
  1980. if (FUTABA_EXPERIMENTAL_DISPLAY_CHAINED) {
  1981. GF.resChained = []
  1982. if (!GF.hasmemo) GF.hasmemo = new Set();
  1983. clearTimeout(GF?.resChainTO);
  1984. GF.resChainTO = setTimeout(() => reschain(), 4000)
  1985. if (lh(".2chan.")) {
  1986. // GF.resChainTO = document.body.addEventListener('2chanReloaded', () => setTimeout(reschain, 2000), false)
  1987. document.body.addEventListener('2chanReloaded', () => {
  1988. clearTimeout(GF?.resChainTO)
  1989. GF.resChainTO = setTimeout(reschain, 2000)
  1990. }, false)
  1991. }
  1992.  
  1993. function reschain(dash = null) {
  1994. let stime = Date.now()
  1995. let org
  1996. if (!GF.resChained || !GF.resChained?.length) {
  1997. GF.resChained = [...elegeta('.thre table:has(.yhmMyMemo) .relallAreaon:not([data-filled])').map(e => { GF.hasmemo.add(e); return e }), ...elegeta('.thre .relallAreaon:not([data-filled],.ftbpu .relallAreaon,#pickbox .relallAreaon)')]; // 最初はピックアップにあるものだけ最速でやる
  1998. GF.resTotal = elegeta('.thre .rtd').length
  1999. }
  2000. do {
  2001. stime = Date.now();
  2002. do {
  2003. org = GF.resChained.shift()
  2004. } while (org && org?.dataset?.filled)
  2005. if (org) {
  2006. let rsc = org.closest('[data-rsc]')?.dataset?.rsc
  2007. let [lists, overflow] = getRelatedRsca(rsc)
  2008. lists?.forEach(v => {
  2009. elegeta('table[data-rsc="' + v + '"] .relallAreaon').forEach(w => {
  2010. w.innerText = `${lists?.length}${overflow?"+":""}`;
  2011. w.dataset.filled = "1"
  2012. if (debug) $(w).effect("highlight"); //org.areaonEle.scrollIntoView()
  2013. })
  2014. })
  2015. }
  2016. } while (org && GF.hasmemo.has(org))
  2017. clearTimeout(GF?.resChainTO)
  2018. //GF.resChainTO = setTimeout(reschain, (org || dash) ? ((GF?.resTotal || 9) * 1 + 100) : 60000)
  2019. //document.title=`${Date.now()-st}`
  2020. let next = (org || dash) ? 50 + (Date.now() - stime) * 3 : 60000;
  2021. //console.log(next)
  2022. GF.resChainTO = setTimeout(reschain, next)
  2023. }
  2024. }
  2025.  
  2026. autoPagerized(() => {
  2027. GF.stoppick = 1;
  2028. memofast = 1;
  2029. run(document.body, "observed");
  2030. GF.stoppick = 0;
  2031. memofast = false;
  2032. plzGKSI()
  2033. }, "not1st")
  2034. // autoPagerized(() => shikomi())
  2035. //GF.fromSecond = 1; // 初回は新着ではないのでやらない
  2036.  
  2037. function plzGKSI() {
  2038. clearTimeout(GF?.gksiAfterMemo);
  2039. GF.gksiAfterMemo = setTimeout(() => document.dispatchEvent(new CustomEvent('plzGKSI')), 444)
  2040. }
  2041.  
  2042. GF.FUTABA_RELOAD_AND_NOTIFY_NEWRES_DEFAULT = pref("FUTABA_RELOAD_AND_NOTIFY_NEWRES_DEFAULT") || 0;
  2043. // setTimeout(() => { for (let i = 0; i < GF.FUTABA_RELOAD_AND_NOTIFY_NEWRES_DEFAULT; i++) { keyFuncDispatch("n", "automation") } }, 444);
  2044. SITE.keyFunc.find(v => v.key == "n")?.func("n", "automation", GF.FUTABA_RELOAD_AND_NOTIFY_NEWRES_DEFAULT)
  2045. // setTimeout(() => { GF.FUTABA_RELOAD_AND_NOTIFY_NEWRES_DEFAULT; i++) { keyFuncDispatch("n", "automation") } }, 444);
  2046.  
  2047. // autoPagerized((node) => {run()},"not1sttime")
  2048.  
  2049. // onclick,html埋め込み,レス番,不安
  2050. autoPagerized((node) => {
  2051. // elegeta('blockquote font,.quoteSpeechBalloon,.quoteSpeechBalloonImg', node).filter(v => !v.onclick && (v?.dataset?.quoteno || /^>+/gm.test(v.textContent))).forEach(e => {//test: 1017ms - タイマー終了
  2052. elegeta('blockquote font:not([onclick]),.quoteSpeechBalloon:not([onclick]),.quoteSpeechBalloonImg:not([onclick])', node).filter(v => /^>./gm.test(v.textContent?.trim())).forEach(e => { //test: 832ms - タイマー終了
  2053. let etext = e?.dataset?.quoteno?.match(/^>(.+)$/)?.[1].trim() || e.textContent.replace(/^>/gm, "").trim()
  2054. let r = [...document.querySelectorAll(".thre table")].find(v => v.textContent.indexOf(etext) !== -1) || null
  2055. e.setAttribute("onclick", `scrRsc(${eleget0('.rsc', r)?.textContent})`) //クリックで中心にスクロール
  2056. })
  2057. })
  2058.  
  2059. // レス番rscに引用・非引用が連鎖するレスのレス番rscを全て配列で返す rsc => [rsc,rsc,rsc,...]
  2060. function getRelatedRsca(rsc) {
  2061. let stime = Date.now()
  2062. let tableRsc = elegeta('table[data-rsc]').sort((a, b) => a.dataset.rsc === b.dataset.rsc ? 0 : Number(a.dataset.rsc) > Number(b.dataset.rsc) ? 1 : -1) // レステーブル[登場順]
  2063. let tableRscOrder = [] // レステーブル[rsc]
  2064. tableRsc.forEach(v => tableRscOrder[v.dataset.rsc] = v) // 速度のためにキャッシュする
  2065. let ress = getRelCno([rsc], tableRsc, tableRscOrder)
  2066. let abort = 0;
  2067. for (let i = 200; i--;) { //while (1) {
  2068. let r = getRelCno(ress, tableRsc, tableRscOrder)
  2069. // if (r.length >= 100 || r.length <= ress.length) { ress = r; break }
  2070. if (r.length >= 100 || r.length <= ress.length) { ress = r; break; }
  2071. if ((document.visibilityState == "visible" && Date.now() - stime > 2000)) {
  2072. ress = r;
  2073. abort = 1;
  2074. }
  2075. ress = r
  2076. }
  2077. if (ress?.length < 2) return [null, null];
  2078. return [ress, abort];
  2079. }
  2080.  
  2081. function getRelCno(resa, tableRsc, tableRscOrder) {
  2082. let a = resa || []
  2083. resa.forEach(res => {
  2084. a = a.concat(elegeta(`.quo .revQuote`, tableRscOrder[res]).map(v => v.innerText.replace(/^>>/, ""))) // test: 6137ms - タイマー終了
  2085. let rscText = elegeta(`blockquote font[color="#789922"]`, tableRscOrder[res]).map(e => e?.innerText?.replace(/^>/, "")?.trim())
  2086. rscText.forEach(v => a.push(tableRsc.find(w => w.innerText.indexOf(v) !== -1)?.dataset.rsc)) // 最初の1つめの>abcだけにヒット
  2087. })
  2088. return [...new Set(a?.flat())].filter(v => v !== undefined && v !== null).sort()
  2089. }
  2090.  
  2091. // 引用ホバー hover::
  2092. GM_addStyle(".rtdAttract{background-color:#fed;}")
  2093. if (location.href.match0(/ftbucket/) && !eleget0(`.csb`)) GM_addStyle(".rsc,.cnw,.cno{padding:0 0.5em 0 0;}")
  2094. var latestHover;
  2095. var latestlevel = 0
  2096. var latestPU
  2097.  
  2098. if (FUTABA_HOVER_POPUP_DELAY == -1) { document.addEventListener("mousemove", function(e) { hover() }, false); } else { hover_enter() }
  2099.  
  2100. function hover_enter() {
  2101. hover();
  2102. setTimeout(hover_enter, 1 * 17);
  2103. }
  2104.  
  2105. function hover() {
  2106.  
  2107. if (!replaceMainPopup) return;
  2108. let ele = document.elementFromPoint(mousex, mousey);
  2109. hovertimer++;
  2110. if (ele !== latestHover) latestPU = 0
  2111. if (ele && (FUTABA_HOVER_POPUP_DELAY || (ele && latestHover != ele))) {
  2112. var quoteDesEle = ele.matches('table FONT,table .quoteSpeechBalloon,table .quoteSpeechBalloonImg,.relallArea') ? ele : null; //ホバーしている黄土色文字の要素群
  2113. var hoverEle = quoteDesEle; //ele.tagName === "FONT" && ele.closest("table") ? [ele] : []; //ホバーしている黄土色文字の要素群
  2114.  
  2115. let level = Number(ele.closest(".ftbpu")?.dataset.level || 0);
  2116. var lists = []
  2117. //if (debug) V&&dc("quoteDesEle:" + quoteDesEle?.tagName)
  2118. if ((quoteDesEle && latestPU !== ele) && ((FUTABA_HOVER_POPUP_DELAY == 0 && latestHover != quoteDesEle) || (FUTABA_HOVER_POPUP_DELAY && hovertimer >= (Math.max(hoverEle?.closest('#pickbox,.ftbpu') && FUTABA_HOVER_POPUP_DELAY != -1 ? 6 : 0, FUTABA_HOVER_POPUP_DELAY))))) { // ピックアップの中では遅延を少なくとも6にする
  2119. var eWord = quoteDesEle?.dataset?.quoteno?.match0(/^\>+(.+)$/)?.trim() || quoteDesEle?.textContent?.match0(/^\>+(.+)$/)?.trim(); // 引用文 // >の入れ子数を無視してすべて遡る
  2120. //var eWord = quoteDesEle?.dataset?.quoteno?.match0(/^\>(.+)$/)?.trim() || quoteDesEle?.textContent?.match0(/^\>(.+)$/)?.trim(); // 引用文 // >の入れ子数を忠実に遡る
  2121. var resa = elegeta('.rtd').filter(e => !e.closest("#pickbox,.ftbpu,#respopup_area"))
  2122. var hit0no = (replaceMainPopup && resa.find(a => a.textContent && a.textContent.indexOf(eWord) != -1))?.dataset?.rsc; //ヒットした最初のレス番号
  2123. if (hit0no < 0) return;
  2124. var motoNumber = hoverEle.closest('table').getAttribute("rsc"); // ホバーしているレスのレス番号
  2125.  
  2126. var hitResNo = hoverEle.dataset.rsc; // rscがある=レスの右側に追加した>>100型逆引用である、そのレス番号
  2127. var relAll = ele.matches(".relallArea:not(.ftbpu .relallArea)") && ele?.closest("table")?.dataset?.rsc // …:全関連レス
  2128.  
  2129. if (relAll) { // relall::…:全関連レスモード
  2130. $(".ftbpu").remove();
  2131. [lists, ] = getRelatedRsca(relAll)
  2132. } else
  2133.  
  2134. if (hitResNo) { // >>100:逆引用モード
  2135. var lists = []
  2136. resa?.forEach(c => { if (c.dataset.rsc == hitResNo) lists.push(c.closest("table").dataset.rsc) })
  2137. resEnum[hitResNo]?.forEach(e => resa.forEach(c => { if (c.dataset.rsc == e) lists.push(c.closest("table").dataset.rsc) })); // rscがある=レスの右側に追加した逆引用である、そのレス番号
  2138. } else {
  2139. // レス本文内の引用
  2140. if (motoNumber) {
  2141. var quoteStr = eWord; //quoteDesEle?.textContent?.match0(/^\>+(.+)$/)?.trim(); // 文字列
  2142. if (quoteStr) {
  2143. var hitEles = resa.filter(e => e.textContent.indexOf(quoteStr) !== -1)
  2144. if (hitEles.length) {
  2145. var hoverResNo = (replaceMainPopup && hoverEle.getAttribute("rsc")) //ホバーしているレス番号
  2146. //hits[0].classList.add("rtdAttract")
  2147. var lists = hitEles.map(e => e.closest("table").dataset.rsc)
  2148. }
  2149. }
  2150. }
  2151. }
  2152.  
  2153. // 表示
  2154. if (hitResNo || lists) {
  2155. latestPU = ele
  2156. lists = lists.sort((a, b) => a - b)
  2157. var hit0no = lists[0] //tables[0][0].getAttribute("rsc") //ヒットした最初のレス番号
  2158. var restable = elegeta('.rtd:not(#pickbox .rtd,.ftbpu .rtd,#respopup_area .rtd)').map(e => e.closest("table"))
  2159. var tables = lists.map(c => ($(restable.find(e => e.dataset.rsc == c)).clone(true, true))?.[0])
  2160. var lists2 = (hit0no == motoNumber) ? lists.slice(1) : lists
  2161. debug && dc(`list : ${lists}\nlist2 : ${lists2}`, 0)
  2162. debug && dc("既存:" + elegeta('.ftbpu').find(e => lists == e.dataset.list || lists2 == e.dataset.list2 || lists == e.dataset.list2)?.dataset.list)
  2163. if (
  2164. !(elegeta('.ftbpu').find(e => lists == e.dataset.list || lists2 == e.dataset.list2 || lists == e.dataset.list2))
  2165. ) { // まだ重複するポップアップがなければ
  2166. debug && dc(`list-sorted : ${lists}`, 0)
  2167. let pupad = (Math.min(window.screen.availWidth, window.screen.availHeight) || 1080) / FUTABA_POPUP_PADDING_RATE;
  2168. var pu = $(`<span data-anchor="${hit0no}" class="ftbpu ${relAll?"relAll ":""}ignoreFilter entry-content" data-list="${lists}" data-list2="${lists2}" data-level="${1+Number(level)}" style="z-index:2000000020; padding:${pupad}px; box-shadow:2px 2px 15px #000a; border-radius:2px; background-color:${FUTABA_BGC}; margin:0 0em 0px 0px; outline:1px solid #999; position:absolute; top:${quoteDesEle.getBoundingClientRect().top + window.scrollY + quoteDesEle.getBoundingClientRect().height-1}px; left:0;" ondblclick="this.remove();"><table style="table-layout:auto;"></table></span>`); //ヒットした全部をポップアップする版
  2169.  
  2170.  
  2171. if (!relAll && hit0no == motoNumber) { tables.shift() } // 1個目の引用が自分自身なら削除
  2172. if (tables.length) {
  2173. let frag = new DocumentFragment();
  2174. tables.forEach(e => { frag.append(e) });
  2175. [...frag.querySelectorAll('span[data-mbt]')].forEach(e => {
  2176. $(e).css({ "display": "inline-block", "width": "fit-content" })
  2177. $(e).after("<br>")
  2178. })
  2179. $(pu).append(frag)
  2180.  
  2181. $(".thre:first()").append(pu)
  2182. if (!relAll) $(pu).find(".quoteSpeechBalloon").remove()
  2183. $(elegeta('.ftbpu table').filter(e => !gmDataList_includesPartial(e, "gmHideByyhm"))).fadeIn(300)
  2184.  
  2185. domsort(pu[0], elegeta('table', pu[0]), v => -v.getAttribute("rsc"))
  2186. sdset()
  2187.  
  2188. $(".ftbpu .relallArea").remove()
  2189. let xr = ((mousex - 18) >= (clientWidth() - $(pu).outerWidth() - 1))
  2190. //$(pu).css({ "left": minmax(mousex - 18, 0, clientWidth() - $(pu).width() - 11) + "px" })
  2191. $(pu).css({ "left": minmax(mousex - 18, 0, clientWidth() - $(pu).outerWidth() - 1) + "px" })
  2192.  
  2193. // 少し縮小するか?
  2194. let eleBottomY = $(quoteDesEle).offset().top - $(window).scrollTop() + $(quoteDesEle).outerHeight() + 1;
  2195. let eleTopY = quoteDesEle.getBoundingClientRect().top // +window.scrollY;//gbcr $(quoteDesEle).offset().top - $(window).scrollTop() // + $(quoteDesEle).outerHeight() + 1;
  2196. let puHeight = pu[0].getBoundingClientRect().height // offsetHeight //$(pu).outerHeight() // + 15;
  2197. let bottomMargin = Math.min(window.innerHeight, document.documentElement.clientHeight) - eleBottomY
  2198. let upMargin = (quoteDesEle.getBoundingClientRect().top)
  2199. let originx = window.innerWidth - mousex
  2200. // 画面の下のほうより上のほうが大きくあいていれば上に表示
  2201. if (puHeight > bottomMargin && upMargin > puHeight) {
  2202. $(pu).css({ "top": `${window.scrollY + eleTopY - puHeight}px` })
  2203. } else {
  2204. // 少し縮小する
  2205. if (bottomMargin / puHeight < 1) $(pu).css({ "transform-origin": xr ? `${$(pu).outerWidth()-(window.innerWidth-mousex)+30}px -1px` : `0px -1px` }).delay(100).animate2({ "transform": `scale(${Math.max(futabapopupscale/100,bottomMargin/(puHeight))})`, "opacity": "1" }, 100) // 右が足りなければ縮小しない transform-originがtopleft=JQのdraggableが不具合起こさない
  2206. }
  2207.  
  2208. elegeta('.relpost').forEach(e => e.classList.remove("relpost"))
  2209. elegeta(`table[data-rsc="${motoNumber}"] .rts`).forEach(e => e.classList.add("relpost"))
  2210. clearTimeout(GF?.relpostID);
  2211. GF.relpostID = setTimeout(() => elegeta('.relpost').forEach(e => e.classList.remove("relpost")), 2000)
  2212. addstyle.add(`.relpost{ background-color:#dfc !important;}`)
  2213. //addstyle.add(".relpost{animation: pulse1 1s infinite; } @keyframes pulse1 { 0% { background-color:#ffff0060; } 50% { background-color:#ffff0000; } 100% { background-color:#ffff0060; } }")
  2214.  
  2215. // z使用モード
  2216. GF?.zFunc && GF?.zFunc()
  2217. dragElement(pu[0], "*", ".rtd,.yhmMyMemo,.revQuote")
  2218. }
  2219. }
  2220. }
  2221. } else {
  2222. // if (!hoverEle && eleget0('.ftbpu') && !(ele.closest(".ftbpu") || ele.closest("#slp") || ele.closest(".fvw_respop") || eleget0("#pdm"))) {
  2223. if (!hoverEle && eleget0('.ftbpu') && !(ele.closest(".ftbpu") || ele.closest("#slp") || ele.closest(".fvw_respop") || eleget0("#pdm") || ele.closest("#hzPv,.hzP"))) {
  2224. $(".ftbpu").remove();
  2225. $(".rtdAttract").removeClass("rtdAttract")
  2226. elegeta('.relpost').forEach(e => e.classList.remove("relpost"))
  2227. }
  2228. if (latestHover != ele && ele.closest(".ftbpu,#slp,.fvw_respop")) { // levelが低い要素に降りたら上のは消す
  2229. elegeta(".ftbpu").forEach(e => { if (e?.dataset?.level > level) { e.remove() } })
  2230. }
  2231. }
  2232. }
  2233. latestlevel = ele?.closest(".ftbpu")?.dataset?.level || 0
  2234. latestHover = ele; //V&&dc("latest:"+latestHover?.tagName)
  2235. }
  2236.  
  2237. // pick::メモの付いたレスを右上に列挙
  2238. var pick_overflow;
  2239. GF.pickOFMaxH = 250;
  2240. if (is2chan || isftb || isftchan || iskurokako || istsumanne) {
  2241. var pick = (force = 0) => {
  2242. if (GF.stoppick) return;
  2243.  
  2244. if (eleget0('.thre table:has( :is(a[href*="youtube.com"],a[href*="youtu.be"],a[href*="nicovideo"],a[href*="//nico.ms/sm"]):not(#pickbox a,[yte],[nde],font[color="#789922"] a)):has( .yhmMyMemo)')) { // まだyt埋め込みしてないytリンクがあるならpickしない
  2245. clearTimeout(GF.pickID);
  2246. GF.pickID = setTimeout(() => pick(force), 999);
  2247. return;
  2248. }
  2249. if (window.getSelection() == "" && $("#pickbox:hover").length == 0 && $('#pickbox:hidden').length == 0) {
  2250. var res = [...new Set($.makeArray($('.thre table:has(span.yhmMyMemo):not([data-hidden="1"])')))].filter(e => !e.closest("#pickbox,.ftbpu")); // 埋め込み動画はロードが発生するので無視
  2251. if (res.some(v => { let e = eleget0('.relallAreaon', v); return e && !e?.dataset?.filled })) {
  2252. clearTimeout(GF.pickID);
  2253. GF.pickID = setTimeout(() => pick(force), 999);
  2254. return;
  2255. } // まだ関連レス数が書き込まれていない.relallAreaonがあるなら待つ
  2256. GF.presentPick = res
  2257. let update = (GF.res !== JSON.stringify(res.map(e => e.innerText).sort()))
  2258. if (update || force) {
  2259. GF.res = JSON.stringify(res.map(e => e.innerText).sort())
  2260. if (debug) popup2("更新:" + GF.res.slice(0, 200))
  2261. if (!pick_overflow) {
  2262. var p = eleget0('#pickbox:not(:hover)');
  2263. if (p && p?.scrollHeight > p?.offsetHeight) {
  2264. pick_overflow = 1;
  2265. // GF.pickOFMaxH--;
  2266. }
  2267. }
  2268. $("#pickbox").remove();
  2269. $('#5chVerticalThreadTitle').remove()
  2270. let threR = $('#rightadfloat:visible')[0] ? document.documentElement.clientWidth - ($(".thre").offset().left + $('.thre').outerWidth()) : 3
  2271. if (res.length) {
  2272. // let threR = $('#rightadfloat:visible')[0] ? document.documentElement.clientWidth - ($(".thre").offset().left + $('.thre').outerWidth()) : 3
  2273. if (1 || document.documentElement.clientWidth - threR > 1300) {
  2274. $.makeArray($(".thre")).filter(e => !e.closest("#pickbox,.ftbpu"))[0].insertAdjacentHTML("beforeend", `<div id='pickbox' class='ignoreFilter' floated="" style='z-index:1; max-height:calc(${(100)*(100/futabapicksize)}vh - ${8*(100/futabapicksize)}em) ; scrollbar-gutter: stable; scrollbar-width: thin; overflow-y:auto; max-width:${55}%; opacity:0.9; outline:2px #8888 solid; position:fixed; top:6px; right:${threR+2}px; background-color:#ffffeecc; transform:scale(${futabapicksize/100}); transform-origin:top right;'></div>`)
  2275. let pickbox = eleget0("#pickbox")
  2276.  
  2277. let frag = new DocumentFragment();
  2278. res.forEach(e => { frag.append($(e).clone(true, true).css({ "display": "revert", "margin-left": "auto", "margin-right": "0" })[0]) })
  2279. pickbox.append(frag)
  2280.  
  2281. //res.forEach(e => { pickbox.appendChild($(e).clone(true, true).css({ "display": "revert", "margin-left": "auto", "margin-right": "0" })[0]) })
  2282. //elegeta('.quoteSpeechBalloon', pickbox).forEach(e => { if (e?.textContent?.length > 18) { e.textContent = e.textContent.slice(0, 18) + "…" } })
  2283. elegeta('.quoteSpeechBalloon', pickbox).forEach(e => { if (e?.textContent?.length > 16) { e.textContent = e.textContent.slice(0, 16) + "…" } })
  2284. //$("#pickbox .sod:contains('x')").css({ "font-size": "125%", "float": "right" })
  2285. $("#pickbox .sod:contains('x')").css({ "float": "right" })
  2286. if (pick_overflow) {
  2287. $("#pickbox img").css({ "width": "auto", "max-height": Math.max(50, GF.pickOFMaxH) + "px" });
  2288. $("#pickbox blockquote").css({ "margin": "5px 40px" })
  2289. }
  2290. //$("#pickbox .relallAreaon").css({ "right": "1px", "position": "absolute", "bottom": "0" }) //,"z-index":"-1"})
  2291. //$("#pickbox .relallAreaon").css({ "right": "1px", "position": "absolute" }) //,"z-index":"-1"})
  2292. elegeta("#pickbox .relallAreaon").forEach(e => e.previousElementSibling.insertAdjacentElement('beforebegin', e))
  2293. $("#pickbox .relallAreaon").css({ "float": "right", "margin": "4px 4px 0 0" }) //,"z-index":"-1"})
  2294. elegeta("#pickbox .rts").forEach(e => { let no = e?.closest("table")?.dataset?.rsc; if (no) e.setAttribute("onclick", `scrRsc(${no})`); })
  2295.  
  2296. $("#pickbox .revQuote").after("<br>"); //css({ "display": "inline-block" })
  2297. $("#pickbox .yhmMyMemo,.revQuote").css({ "user-select": "none" })
  2298. if (update) { $("#pickbox").css({ "outline": "#f00 5px solid" }).delay(100).queue(() => { $("#pickbox").css({ "outline": "2px #8888 solid" }) }) }
  2299. domsort(pickbox, elegeta('table', pickbox).filter(e => e.closest("#pickbox")), v => -v.getAttribute("rsc"))
  2300. sdset()
  2301. GF?.zFunc && GF?.zFunc()
  2302. dragElement(pickbox, "*", ".rts,.rtd,.yhmMyMemo,.relallArea,.revQuote")
  2303. checkOF(1)
  2304. }
  2305. } else {
  2306.  
  2307. //let threR = $('#rightadfloat:visible')[0] ? document.documentElement.clientWidth - ($(".thre").offset().left + $('.thre').outerWidth()) : 3
  2308. $(document.body).append(`<div id="5chVerticalThreadTitle" style="writing-mode: vertical-rl; top:2em; bottom:3em; right:${threR+16}px; position:fixed;z-index:-111; font-size:2.5em; opacity:0.5; color:#800;">${GF.originalDocTitle?.substr(0,63)}</div>`);
  2309. // $(eleget0('//ul/li[@class="menubottomnav"]/a[@class="menuitem" and text()="全部"]/../../..')).before(`<span id="bottomDocTitle" style=" margin:0 0 0 0.2em;font-size:1.5em; opacity:0.9; color:${serverColor};">${document.title}</span>`);
  2310. }
  2311. pick2title(20)
  2312. }
  2313. }
  2314. setTimeout(() => pick(), 2000)
  2315. }
  2316. setTimeout(pick, 2000)
  2317.  
  2318. function checkOF(force = 0) {
  2319. if (Date.now() - GF?.resized < 100) return; // リサイズ直後はしない(resizeイベントが複数回起こってガクガクするため)
  2320. if (futabapicksize == futabapicksizeL && GF.pickOFMaxH <= 50 && !force) return;
  2321. var p = eleget0('#pickbox:not(:hover)')
  2322. if (p) {
  2323. var lr = elegeta('.rtd')?.filter(e => isinscreen(e, 1) && !e?.closest("#pickbox,.ftbpu,#respopup_area,[floated]"))?.map(e => { let r = e.getBoundingClientRect().right; return e?.closest('table')?.querySelector('.revQuote,.relallArea')?.getBoundingClientRect()?.right + 4 || r + 2 }).reduce((a, b) => a > b ? a : b, 0) || 0 //test 175 / 1sec
  2324. var big = p.getBoundingClientRect().left - lr
  2325. var bigabs = Math.abs(big)
  2326. if (p.scrollHeight > p.offsetHeight) {
  2327. $("#pickbox blockquote").css({ "margin": "5px 40px" })
  2328. GF.pickOFMaxH = GF.pickOFMaxH - ~~(p.scrollHeight - p.offsetHeight) / 8;
  2329. $("#pickbox img").css({ "width": "auto", "max-height": Math.max(50, GF.pickOFMaxH) + "px" });
  2330. futabapicksize = Math.max(futabapicksizeL, futabapicksize - (p.scrollHeight - p.offsetHeight) / 62);
  2331. if (pick_overflow != 1) {
  2332. pick_overflow = 1
  2333. pick(1);
  2334. } else {
  2335. pick_overflow = 1;
  2336. p.style.transform = `scale(${futabapicksize/100})`
  2337. p.style.maxHeight = `calc(${(100)*(100/futabapicksize)}vh - ${8*(100/futabapicksize)}em)`;
  2338. debug && dc("picksize:" + futabapicksize, 1)
  2339. }
  2340. } else if (big < 0) {
  2341. futabapicksize = Math.max(futabapicksizeL, futabapicksize - bigabs / 62);
  2342. p.style.transform = `scale(${futabapicksize/100})`
  2343. debug && dc("picksize:" + futabapicksize, 1)
  2344. }
  2345. }
  2346. }
  2347. setInterval(checkOF, 52)
  2348. //}, 60)
  2349.  
  2350. window.addEventListener('resize', () => {
  2351. GF.resized = Date.now()
  2352. futabapicksize = 100;
  2353. if (!eleget0('#pickbox iframe')) {
  2354. GF.pickOFMaxH = 250;
  2355. pick_overflow = 0;
  2356. $("#pickbox").remove();
  2357. pick(1);
  2358. //checkOF();
  2359. return;
  2360. }
  2361. var p = eleget0('#pickbox:not(:hover)')
  2362. if (p) {
  2363. p.style.transform = `scale(${futabapicksize/100})`
  2364. p.style.maxHeight = `calc(${(100)*(100/futabapicksize)}vh - ${8*(100/futabapicksize)}em)`;
  2365. GF.pickOFMaxH = 250;
  2366. $("#pickbox img").css({ "width": "auto", "max-height": Math.max(50, GF.pickOFMaxH) + "px" });
  2367. //checkOF();
  2368. }
  2369. // pick(1)
  2370. })
  2371.  
  2372. //window.addEventListener('focus', () => { futabapicksize = 100; pick(1) }) // ややうるさい
  2373.  
  2374. setTimeout(() => {
  2375. let slider = eleget0('#pickbox') ? [eleget0('/HTML/BODY/HR[2]'), "style=' position:fixed; right:8em; bottom:0.5em; font-size:11px; transform:scale(0.9); display:block;'", "style=' position:fixed; right:20em; bottom:0.5em; font-size:11px; transform:scale(0.9); display:block;'"] : [eleget0(`//span[@id="hml"]/..`), "style='float:left; font-size:13px; transform:scale(0.9);'", "style='float:left; font-size:13px; transform:scale(0.9);'"]
  2376.  
  2377. setSlider(slider[0], 30, 100, futabapicksizeDefault, "ピックアップの最小スケール:***%", "FUTABA_pickupSize", (val) => {
  2378. futabapicksizeL = val;
  2379. futabapicksize = Math.min(100, ++futabapicksize);
  2380. pick(1);
  2381. }, 0, slider[1])
  2382.  
  2383. setSlider(slider[0], 50, 100, 95, "ポップアップの最小スケール:***%", "FUTABA_popupScale", (val) => { futabapopupscale = val; }, 1, slider[2]);
  2384. }, 2100)
  2385. }
  2386.  
  2387. function pick2title(len) {
  2388. var suff = document.title.match0(/(\s-\s.*)/) || ""
  2389. let intro = [...new Set(elegeta('.thre>blockquote,table[data-reszero] blockquote,#pickbox blockquote')?.slice(0, len)?.map(e => e?.innerText))]?.map(e => e?.replaceAll("キタ━━━(゚∀゚)━━━!!", "")?.replace(/\n/gm, " "))
  2390. intro = intro?.join(" ")?.replace(/[ \s\u200B-\u200D\uFEFF\u2028\u2029\u200eㅤ]{1,99}/g, " ")
  2391. // if ((isftb || isftchan || is2chan) && intro && suff) { // 0とpickのレス100文字までページタイトルにする
  2392. if ((isftb || isftchan || is2chan) && intro) { // 0とpickのレス100文字までページタイトルにする
  2393. let threno = location?.href?.match0(/(\d{3,})/) || ""
  2394. if (intro && !GF?.arrival) {
  2395. document.title = `${(GF.originalDocTitle0+" "+threno+" - "+intro)?.slice(0, 94)}`
  2396. }
  2397. }
  2398. }
  2399. },
  2400. },
  2401. {
  2402. id: 'www.uniqlo.com',
  2403. urlRE: '//www.uniqlo.com/',
  2404. listTitleXP: '//a/div[2]/h3',
  2405. listTitleSearchXP: '//a/div[2]/h3[+++]/../../..',
  2406. listTitleMemoSearchXP: '//a/div[2]/h3[+++]|//h1[@data-test="product-name"][+++]',
  2407. listGen: 6,
  2408. redoWhenReturned: 1,
  2409. delay: 500,
  2410. observe: 500,
  2411. detailURLRE: /\/www.uniqlo.com\/jp\/ja\/products\//,
  2412. detailTitleXP: '//h1[@data-test="product-name"]',
  2413. detailTitleSearchXP: '//h1[@data-test="product-name"][+++]/../../..',
  2414. urlHasChangedCommonFunc: () => {
  2415. setTimeout(() => {
  2416. isDetail = (SITE.detailURLRE && location.href.match(SITE.detailURLRE)) ? 1 : 0;
  2417. run(document.body)
  2418. }, 2000);
  2419. },
  2420. },
  2421. {
  2422. id: 'workman',
  2423. urlRE: '//workman.jp/shop/',
  2424. listTitleXP: '//div[@class="block-thumbnail-t--goods-name"]/a|.//div[@class="_wrap"]/div[@class="_title"]/a',
  2425. listTitleSearchXP: '//div[@class="block-thumbnail-t--goods-name"]/a[+++]/../../..|.//div[@class="_wrap"]/div[@class="_title"]/a[+++]/../../..',
  2426. listTitleMemoSearchXP: '//div[@class="block-thumbnail-t--goods-name"]/a[+++]|//h1[@class="h1 block-goods-name--text js-enhanced-ecommerce-goods-name"][+++]|.//div[@class="_wrap"]/div[@class="_title"]/a[+++]',
  2427. listGen: 4,
  2428. observe: 500,
  2429. detailURLRE: /shop\/g\//,
  2430. detailTitleXP: '//h1[@class="h1 block-goods-name--text js-enhanced-ecommerce-goods-name"]',
  2431. detailTitleSearchXP: '//h1[@class="h1 block-goods-name--text js-enhanced-ecommerce-goods-name"][+++]/../../../..',
  2432. },
  2433. {
  2434. id: 'free.arinco.org',
  2435. urlRE: 'http://free.arinco.org/mail/index1.html',
  2436. listTitleXP: '//a',
  2437. redoWhenRefocused: 1,
  2438. useURL: 1,
  2439. listTitleMemoSearchXPSameGen: 1,
  2440. listGen: 4,
  2441. listTitleSearchXP: '//a[++url++]/..',
  2442. listTitleMemoSearchXP: '//a[++url++]',
  2443. },
  2444. {
  2445. id: 'free.arinco.org',
  2446. urlRE: '//free.arinco.org/',
  2447. useURL: 1,
  2448. redoWhenRefocused: 1,
  2449. listTitleMemoSearchXPSameGen: 1,
  2450. listGen: 4,
  2451. listTitleXP: '//a|//h1/span[@itemprop="name"]',
  2452. listTitleSearchXP: '//a[**url**]/..|//h1/span[@itemprop="name"][**url**]',
  2453. listTitleMemoSearchXP: '//a[**url**]|//h1/span[@itemprop="name"][**url**]',
  2454. detailURLRE: /\/mail\//,
  2455. detailTitleXP: '//h1/span[@itemprop="name"]',
  2456. detailTitleSearchXP: '//h1/span[@itemprop="name"][**url**]',
  2457. funcOnlyFirst: function() {
  2458. GM_addStyle('.itemlist li{height:auto; margin:0.5em;}');
  2459. var e = location.href.replace(/^https?:\/\/free.arinco.org\/mail\/([^/]+\/)$/, "$1");
  2460. var t = eleget0('//h1/span[@itemprop="name"]')
  2461. if (document.body.innerText.match(/ホーム » Free Mail » /) && e && t) t.setAttribute("href", e)
  2462. },
  2463. automemoURLRE: /^https?:\/\/free.arinco.org\/mail\/[^/]+\/$/, // メールサービス名にホバーしないと作られない
  2464. automemoSearchFunc: function() { return eletext(['//article[@role="main"]/section[@id="detail"]', '//div[@id="main"]/article/section[1]']); },
  2465. automemoFunc: function() {
  2466. // [/(imap)/im, /(pop3)/mi, /(Tor)/m, /(e2ee)/m, /(openpgp)|(gnupgp)|(pgp)/mi].forEach(m => autoMemo(m));
  2467. [/(imap)/im, /(pop3)/mi, /(Tor)/m, /(e2ee)/m, /(openpgp)|(gnupgp)|(gpg)|(pgp)/mi].forEach(m => autoMemo(m));
  2468. },
  2469. automemoForceFunc: function() { return 1; },
  2470. /* autoTranslucentURLRE: /^https?:\/\/free.arinco.org\/mail\/[^/]+\/$/, // urlだけでは詳細概要画面を特定できない
  2471. detailURLRE: /^https?:\/\/free.arinco.org\/mail\/.+/,
  2472. detailTitleXP: '//h1/span[@itemprop="name"]',
  2473. detailTitleSearchXP: '//h1/span[@itemprop="name"][**url**]/../../../..',
  2474. automemoURLRE: /^https?:\/\/free.arinco.org\/mail\/[^/]+\/$/,
  2475. automemoSearchFunc: () => { return eletext(['//article[@role="main"]/section[@id="detail"]']); },
  2476. automemoFunc: () => {
  2477. [/(imap)/im,/(pop3)/mi,/(openpgp)|(gnupgp)|(pgp)/mi].forEach(m => autoMemo(m));
  2478. },
  2479. */
  2480. },
  2481. {
  2482. id: 'twiman.net',
  2483. urlRE: '//twiman.net/',
  2484. listTitleXP: '//div[@class="v-list-item__content"]/div[2]',
  2485. listTitleSearchXP: '//div[@class="v-list-item__content"]/div[2][***]/../../../..',
  2486. listTitleMemoSearchXP: '//div[@class="v-list-item__content"]/div[2][***]/../..',
  2487. listGen: 7,
  2488. observe: 500,
  2489. trim: 1,
  2490. },
  2491. {
  2492. id: 'twicomi.com',
  2493. urlRE: '//twicomi.com',
  2494. trim: 1,
  2495. title: 'div.screen-name,div.fixed-tweet>div:nth-child(3),span.screen-name,div.tweet-text',
  2496. box: 'div.author-profile,.fixed-area,div.manga-item',
  2497. forceTranslucentFunc: e => e.closest('div.author-profile,.fixed-area'),
  2498. autoTranslucentURLRE: /\/\/twicomi\.com\/manga\//,
  2499. XP2name: 'ユーザー名 ',
  2500. listTitleXP2: 'div.screen-name,span.screen-name',
  2501. listGen: 8,
  2502. observe: 500,
  2503. redoWhenReturned: 1,
  2504. func: () => { $('.list').css({ "min-height": "0px" }) }, // AP継ぎ足し時の空白を詰める
  2505. funcOnlyFirst: () => {
  2506. var observeUrlHasChangedhref = location.href;
  2507. var observeUrlHasChanged = new MutationObserver(mutations => {
  2508. if (observeUrlHasChangedhref !== location.href) {
  2509. pauseAll = 1;
  2510. prefCacheClear()
  2511. observeUrlHasChangedhref = location.href;
  2512. elegeta('//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
  2513. setTimeout(() => {
  2514. pauseAll = 0;
  2515. $(".phov2").remove();
  2516. $('span.phov').remove();
  2517. // elegeta('//div[@class="fixed-area"]/div[@class="fixed-tweet"]/div[@class="text"]/..').forEach(e => e.style.opacity = "1")
  2518. elegeta('div.author-profile,.fixed-area', ).forEach(e => e.style.opacity = "1")
  2519. disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
  2520. run(document.body, "returned")
  2521. }, 100);
  2522. }
  2523. });
  2524. observeUrlHasChanged.observe(document, { childList: true, subtree: true });
  2525. },
  2526. },
  2527. {
  2528. id: 'chrome.google.com/webstore/search/',
  2529. urlRE: '//chrome.google.com/webstore/search/|//chrome.google.com/webstore/detail/',
  2530. listTitleXP: '//div[@class="a-na-d-w" and @role="heading"]',
  2531. listTitleSearchXP: '//div[@class="a-na-d-w" and @role="heading"][+++]/../../../../../..',
  2532. listTitleMemoSearchXP: '//div[@class="a-na-d-w" and @role="heading"][+++]|.//div[@class="e-f-n-Va"]/div[@class="e-f-w-Va"]/h1[@class="e-f-w"][+++]',
  2533. listGen: 7,
  2534. delay: 2500,
  2535. observe: 500,
  2536. redoWhenReturned: 1,
  2537. detailURLRE: /https:\/\/chrome.google.com\/webstore\/detail\//,
  2538. detailTitleXP: '//div[@class="e-f-n-Va"]/div[@class="e-f-w-Va"]/h1[@class="e-f-w"]',
  2539. detailTitleSearchXP: '//div[@class="e-f-n-Va"]/div[@class="e-f-w-Va"]/h1[@class="e-f-w"][+++]/../../../..',
  2540. listTitleMemoSearchXPSameGen: 1,
  2541. },
  2542. {
  2543. id: 'sakura-checker.jp',
  2544. urlRE: '//sakura-checker.jp/category/',
  2545. listTitleXP: '//div[1]/figure/a',
  2546. listTitleSearchXP: '//div[1]/figure/a[++url++]/../../..',
  2547. listTitleMemoSearchXP: '//div[1]/figure/a[++url++]',
  2548. listGen: 5,
  2549. listHelpXP: '//div[1]/figure/a/../../..',
  2550. useURL: 1,
  2551. },
  2552. {
  2553. id: 'BOOTH.PM', // 作者名でQ/1/2 出品者名でQ
  2554. urlRE: 'https:\/\/booth\.pm\/ja\/browse/|https:\/\/booth\.pm\/ja\/items|https:\/\/booth.pm\/ja$|https:\/\/booth\.pm\/ja\/events\/|https:\/\/booth\.pm\/ja\/search\/',
  2555. listHelpXP: '//a[@class="item-card__title-anchor nav"]/../../../..|.//a[@class="item-card__title-anchor--multiline nav"]/../../../..',
  2556. listTitleXP: '//a[@class="item-card__title-anchor nav"]|.//a[@class="item-card__title-anchor--multiline nav"]',
  2557. listTitleXP2: '//div[@class="item-card__shop-name"]|//div[@class="u-text-ellipsis"]|//a[@class="nav u-tpg-title2"]',
  2558. XP2memo: 1,
  2559. XP2name: '出品者名 ',
  2560. listTitleSearchXP: '//a[@class="item-card__title-anchor nav"][+++]/../../../..|//div[@class="item-card__shop-name"][+++]/../../../../../..|.//a[@class="item-card__title-anchor--multiline nav"][+++]/../../../..',
  2561. listTitleMemoSearchXP: '//a[@class="item-card__title-anchor nav"][+++]|//header/h2[@class="u-text-wrap u-tpg-title1 u-mt-0 u-mb-400"][+++]|.//a[@class="item-card__title-anchor--multiline nav"][+++]|.//div[@class="item-card__shop-name"][+++]|.//div[@class="u-text-ellipsis"][+++]|//a[@class="nav u-tpg-title2"][+++]',
  2562. listGen: 7,
  2563. detailURLRE: /https:\/\/booth\.pm\/ja\/items\//,
  2564. detailTitleXP: '//header/h2[@class="u-text-wrap u-tpg-title1 u-mt-0 u-mb-400"]',
  2565. detailTitleSearchXP: '//header/h2[@class="u-text-wrap u-tpg-title1 u-mt-0 u-mb-400"][+++]/../../../../../../../..|//div[@class="u-text-ellipsis"][+++]/../../../../../../../..',
  2566. redoWhenReturned: 1,
  2567. hideListEvenDetail: 1,
  2568. },
  2569. {
  2570. id: 'TOODORAN',
  2571. urlRE: '//todo-ran.com/t/soukan/',
  2572. listTitleXP: '//td/a[1]',
  2573. listTitleSearchXP: '//td/a[1][+++]/../..',
  2574. listTitleMemoSearchXP: '//td/a[1][+++]',
  2575. listGen: 3,
  2576. listTitleMemoSearchXPSameGen: 1,
  2577. },
  2578. {
  2579. id: '2CHTHREADLIST',
  2580. urlRE: /\/\/ff5ch\.syoboi\.jp\/\?q=/,
  2581. title: 'a.thread,a.col-brd',
  2582. titleSubstr: true,
  2583. box: 'li.bdr-b',
  2584. listTitleXP2: 'a.col-brd',
  2585. XP2name: `板名 `,
  2586. keyFunc: [{
  2587. key: 'a', // a::
  2588. func: () => {
  2589. var sorttype = GF.yhmSortType || 0
  2590. let menu = [
  2591. { t: "タイトル", f: () => { sortdom(elegeta('li.bdr-b'), v => eleget0('a.thread', v)?.textContent) } },
  2592. { t: "板名", f: () => { sortdom(elegeta('li.bdr-b'), v => eleget0('a.col-brd', v)?.textContent + eleget0('.board_title span', v)?.textContent) } },
  2593. { t: "レス数", f: () => { sortdom(elegeta('li.bdr-b'), v => eleget0('span.fnt-small.col-sec', v)?.textContent, 1) } },
  2594. { t: "新しい", f: () => { sortdom(elegeta('li.bdr-b'), v => eleget0('//div[@class="fnt-small col-sec m-tb-4"]/span', v)?.textContent, 1) } },
  2595. ]
  2596. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  2597. menu[sorttype].f()
  2598. GF.yhmSortType = (++sorttype) % menu.length
  2599. return
  2600. }
  2601. }, {
  2602. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  2603. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  2604. }],
  2605. },
  2606. {
  2607. id: 'MSDMANUAL', // 検索結果と詳細ページでは項目名に表記ゆれがあるので合致しない
  2608. urlRE: '//www.msdmanuals.com/',
  2609. listTitleXP: '//div/a[@class="search__result--title"]',
  2610. listTitleSearchXP: '//div/a[@class="search__result--title"][+++]/../../..',
  2611. listTitleMemoSearchXP: '//div/a[@class="search__result--title"][+++]|//h1[@class="topic__header__headermodify--title topic__header__headermodify--title--animate"][+++]',
  2612. listGen: 3,
  2613. delay: 2000,
  2614. observe: 500,
  2615. detailURLRE: /^(?!.*(SearchResults)).*/,
  2616. detailTitleXP: '//h1[@class="topic__header__headermodify--title topic__header__headermodify--title--animate"]',
  2617. detailTitleSearchXP: '//h1[@class="topic__header__headermodify--title topic__header__headermodify--title--animate"][+++]/../../../../../..',
  2618. },
  2619. {
  2620. id: 'CHIEBUKURO',
  2621. urlRE: '//chiebukuro.yahoo.co.jp/',
  2622. // urlRE: /\/\/chiebukuro.yahoo.co.jp\/|\/\/detail.chiebukuro.yahoo.co.jp\//,
  2623. listTitleXP: '//div/a/div/div/div/div/h2/../../../../..',
  2624. listTitleSearchXP: '//article/div/a/div/div/div/div/h2/../../../../..[++url++]/../..',
  2625. listTitleMemoSearchXP: '//article/div/a[++url++]/div/div/div/div/h2',
  2626. listGen: 9,
  2627. useURL: 1,
  2628. redoWhenReturned: 1,
  2629. },
  2630. {
  2631. urlRE: 'https://refind2ch.org/search',
  2632. id: '2CHTHREADLIST',
  2633. title: 'p.list-group-item-heading.thread_title,p.board_title span',
  2634. box: '#search_results a.thread_url.list-group-item.entry.board_border',
  2635. /* listTitleXP: '//p[contains(@class,"thread_title")]',
  2636. listTitleXP2: '//p/span[@class="board_clr_font_shitaraba"]|.//p/span[@class="board_clr_font_2chnet"]', // おーぷん板名は重複'|//p/span[@class="board_clr_font_open2chnet"]',
  2637. XP2name: '板 ',
  2638. listTitleSearchXP: '//p[contains(@class,"thread_title")][***]/../..|.//p/span[@class="board_clr_font_shitaraba"][***]/../../..|.//p/span[@class="board_clr_font_2chnet"][***]/../../..', //'|//p/span[@class="board_clr_font_open2chnet"][+++]/../../..',
  2639. listTitleMemoSearchXP: '//p[contains(@class,"thread_title")][***]',
  2640. listGen: 4,
  2641. */
  2642. observe: 500,
  2643. redoWhenReturned: 1,
  2644. XP2name: '板名 ',
  2645. listHelpXP2: '.board_title span',
  2646. trim: 1,
  2647. //titleProcessFunc: (title) => { return title.replace(/\s\(したらば\)/gmi, "") },
  2648. WhateverFirstAndEveryAPFunc: () => {
  2649. $(".side_box").css({ "height": "100vh" });
  2650. popup3("Shift+F:re.Find2ch検索", 8, 5000)
  2651. },
  2652. wholeHelp: [() => 1, " A:ソート"],
  2653. keyFunc: [{
  2654. key: 'a', // a::
  2655. func: () => {
  2656. var sorttype = GF.yhmSortType || 0
  2657. let menu = [
  2658. { t: "タイトル", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('p.list-group-item-heading.thread_title', v)?.textContent) } },
  2659. { t: "板名", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('p:last-child span small', v)?.textContent + eleget0('.board_title span', v)?.textContent) } },
  2660. { t: "新しい", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('.date_raw,.date', v)?.textContent, 1) } },
  2661. { t: "勢い", f: () => { sortdom(elegeta('#search_results a.thread_url.list-group-item.entry.board_border'), v => eleget0('.rate_cnt', v)?.textContent, 1) } },
  2662. ]
  2663. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  2664. menu[sorttype].f()
  2665. GF.yhmSortType = (++sorttype) % menu.length
  2666. return
  2667. }
  2668. }, {
  2669. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  2670. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  2671. }],
  2672. func: (node = document) => { // 高密度化&https化
  2673. elegeta('//div/div[@class="container-fluid"]').forEach(e => {
  2674. e.style.width = "95%";
  2675. e.style.maxWidth = "100%";
  2676. })
  2677. elegeta('//div[@id="content_main"]').forEach(e => {
  2678. e.style.width = "calc(95vw - 400px)";
  2679. e.style.maxWidth = "100%";
  2680. })
  2681. elegeta('//div[@class="progress rate pull-right"]').forEach((e) => { e.style.width = "5%" });
  2682. for (let element of elegeta('//div[@class="clearfix"]|//a[contains(@class,"thread_url list-group-item entry clearfix board_border board_clr_border_2chnet") and @target="_blank" and @rel="nofollow noreferrer"]/p')) {
  2683. element.parentNode.href = element.parentNode.href.replace(/http:\/\//, "https://");
  2684. element.style = "display:inline;float:left; margin:0px 0.0em; padding:0px 0.5em 0px 0.5em;";
  2685. }
  2686. for (let element of elegeta('//a[@rel="nofollow noreferrer"]')) { element.style = "padding:0px;"; }
  2687. elegeta('//div[@id="content_main"]/div[@id="search_results"]/a', node).forEach(e => { e.setAttribute("onclick", "") })
  2688. elegeta('div>small.pull-right', node).forEach(e => {
  2689. e.style = "float:none !important";
  2690. e.parentNode.parentNode.appendChild(e);
  2691. });
  2692. },
  2693. },
  2694. {
  2695. id: 'KAKAKUBB',
  2696. urlRE: '//kakaku.com/bb/',
  2697. listTitleXP: '//a[@class="planName"]',
  2698. listTitleSearchXP: '//a[@class="planName"][+++]/../../../../..',
  2699. listTitleMemoSearchXP: '//a[@class="planName"][+++]',
  2700. listGen: 3,
  2701. },
  2702. {
  2703. id: 'MINSOKU',
  2704. urlRE: '//minsoku.net/',
  2705. listTitleXP: '//div/div[@class="text-bold mt-xxs"]/a|.//div/div[@class="mt-10 text-bold"]/a|.//div[@class="mt-10 mb--xxxs text-bold"]/a',
  2706. listTitleSearchXP: '//div/div[@class="text-bold mt-xxs"]/a[+++]/../../..|.//div/div[@class="mt-10 text-bold"]/a[+++]/../../..|.//div[@class="mt-10 mb--xxxs text-bold"]/a[+++]/../../..',
  2707. listTitleMemoSearchXP: '//div/div[@class="text-bold mt-xxs"]/a[+++]|.//div/div[@class="mt-10 text-bold"]/a[+++]|.//div[@class="mt-10 mb--xxxs text-bold"]/a[+++]',
  2708. listGen: 4,
  2709. },
  2710. {
  2711. id: 'OMOCORO',
  2712. urlRE: '//omocoro.jp/',
  2713. listTitleXP: '//div[@class="details"]/div[@class="title"]/a',
  2714. listTitleSearchXP: '//div[@class="details"]/div[@class="title"]/a[+++]/../../..',
  2715. listTitleMemoSearchXP: '//div[@class="details"]/div[@class="title"]/a[+++]',
  2716. listGen: 4,
  2717. },
  2718. {
  2719. id: '360life.shinyusha.co.jp',
  2720. urlRE: '//360life.shinyusha.co.jp/',
  2721. listTitleXP: '//article/div[@class="m-article-item__info"]/h3[@class="m-article-item__title"]',
  2722. listTitleSearchXP: '//article/div[@class="m-article-item__info"]/h3[@class="m-article-item__title"][***]/../../../..',
  2723. listTitleMemoSearchXP: '//article/div[@class="m-article-item__info"]/h3[@class="m-article-item__title"][***]|//div[@class="article-header"]/h1[@class="article-header__title"][***]',
  2724. listGen: 4,
  2725. detailURLRE: /\/\/360life\.shinyusha\.co\.jp\/articles\//,
  2726. detailTitleXP: '//div[@class="article-header"]/h1[@class="article-header__title"]',
  2727. detailTitleSearchXP: '//div[@class="article-header"]/h1[@class="article-header__title"][***]/../../../../..',
  2728. redoWhenReturned: 1,
  2729. trim: 1,
  2730. },
  2731. {
  2732. id: 'SHOPPING_YAHOO',
  2733. urlRE: '//shopping.yahoo.co.jp/search',
  2734. listTitleXP: '//div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span',
  2735. listTitleSearchXP: '//div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span[+++]/../../../../..',
  2736. listTitleMemoSearchXP: '//li[@class="LoopList__item"]/div/div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span[+++]',
  2737. listGen: 6,
  2738. func: () => { // 商品名を省略しなくする
  2739. elegeta('//div[2]/p/a[@target="_blank" and @data-rapid_p="1"]/span/..').forEach(e => {
  2740. e.style.display = "block";
  2741. e.style.maxHeight = "none";
  2742. });
  2743. },
  2744. observe: 1000,
  2745. },
  2746. {
  2747. id: 'FREEM',
  2748. urlRE: '//www.freem.ne.jp/',
  2749. listTitleXP: '//a/h3[@class="pc"]',
  2750. listTitleSearchXP: '//ul[contains(@class,"game-list game-list-wrap row")]/li/a/h3[@class="pc"][+++]/../..',
  2751. listTitleMemoSearchXP: '//ul[contains(@class,"game-list game-list-wrap row")]/li/a/h3[@class="pc"][+++]',
  2752. listGen: 3,
  2753. },
  2754. {
  2755. id: 'ONSEN',
  2756. urlRE: '//www.onsen.ag/',
  2757. listTitleXP: '//h4[@class="title"]',
  2758. listTitleSearchXP: '//h4[@class="title"][+++]/../..',
  2759. listTitleMemoSearchXP: '//h4[@class="title"][+++]',
  2760. listGen: 4,
  2761. observe: 500,
  2762. },
  2763. {
  2764. id: 'HIBIKI',
  2765. urlRE: '//hibiki-radio.jp',
  2766. listTitleXP: '//div[@class="title program-title-animate ng-binding"]',
  2767. listTitleSearchXP: '//div[@class="title program-title-animate ng-binding"][+++]/../../..',
  2768. listTitleMemoSearchXP: '//div[@class="title program-title-animate ng-binding"][+++]',
  2769. listGen: 3,
  2770. observe: 500,
  2771. },
  2772. {
  2773. id: 'GOOGLE_SCHOLAR',
  2774. urlRE: '//scholar\.google\..*/',
  2775. listTitleXP: '//h3[@class="gs_rt"]/a',
  2776. listTitleSearchXP: '//h3[@class="gs_rt"]/a[++url++]/../../..',
  2777. listTitleMemoSearchXP: '//h3[@class="gs_rt"]/a[++url++]',
  2778. listGen: 3,
  2779. useURL: 1,
  2780. disableKeyB: 1,
  2781. },
  2782. {
  2783. id: 'NICODOUGA',
  2784. urlRE: '//commons.nicovideo.jp/',
  2785. listTitleXP: '//a[@class="title_link"]',
  2786. listTitleSearchXP: '//a[@class="title_link"][+++]/..',
  2787. listTitleMemoSearchXP: '//a[@class="title_link"][+++]', // ちゃんと動かない
  2788. listGen: 2,
  2789. observe: 500,
  2790. },
  2791. {
  2792. id: 'RRWS',
  2793. urlRE: '//rrws.info/',
  2794. listTitleXP: '//h2[@class="entry-card-title card-title e-card-title"]',
  2795. listTitleSearchXP: '//h2[@class="entry-card-title card-title e-card-title"][***]/../../..',
  2796. listTitleMemoSearchXP: '//h2[@class="entry-card-title card-title e-card-title"][***]|//h1[@class="entry-title"][***]',
  2797. listGen: 3,
  2798. detailURLRE: /rrws.info\/archives\//,
  2799. detailTitleXP: '//h1[@class="entry-title"]',
  2800. detailTitleSearchXP: '//h1[@class="entry-title"][***]/../..',
  2801. trim: 1,
  2802. },
  2803. {
  2804. id: 'A-TIMESALE',
  2805. urlRE: '//a-timesale.com/',
  2806. listTitleXP: '//div[3]/div[@class="border-b pb-3 mb-4"]/a[@target="_blank"]',
  2807. listTitleSearchXP: '//div[3]/div[@class="border-b pb-3 mb-4"]/a[@target="_blank"][+++]/../../../../..',
  2808. listTitleMemoSearchXP: '//div[3]/div[@class="border-b pb-3 mb-4"]/a[@target="_blank"][+++]',
  2809. listGen: 6,
  2810. observe: 500,
  2811. },
  2812. {
  2813. id: 'PUBMED',
  2814. // urlRE: '//pubmed.ncbi.nlm.nih.gov/.term=',
  2815. urlRE: '//pubmed.ncbi.nlm.nih.gov/.term=|//pubmed.ncbi.nlm.nih.gov/.linkname=|//pubmed.ncbi.nlm.nih.gov/',
  2816. listTitleXP: '//span[@class="docsum-pmid" and text()]|.//span[@class="docsum-pmid"]/font[1]/font[1]',
  2817. listHelpXP: '//span[@class="docsum-pmid" and text()]/../../../../..|.//span[@class="docsum-pmid"]/font/font/../../../../../../..',
  2818. listTitleSearchXP: '//span[@class="docsum-pmid"][+++]/../../../../..|.//span[@class="docsum-pmid"]/font/font[+++]/../../../../../../..',
  2819. listTitleMemoSearchXP: '//span[@class="docsum-pmid"][+++]|.//span[@class="docsum-pmid"]/font/font[+++]|//header[@id="heading"]/div[1]/ul/li/span/strong[@class="current-id"][+++]|//strong[@class="current-id"]/font/font[+++]/../..',
  2820. observe: 500,
  2821. listGen: 7,
  2822. trim: 1,
  2823. detailURLRE: /\/\/pubmed.ncbi.nlm.nih.gov\/\d*\//,
  2824. detailTitleXP: '//header[@id="heading"]/div[1]/ul/li/span/strong[@class="current-id"][1]|//strong[@class="current-id"][1]/font[1]/font[1]',
  2825. detailTitleSearchXP: '//header[@id="heading"]/div[1]/ul/li/span/strong[@class="current-id"][+++]/../../../../../..|//strong[@class="current-id"][1]/font[1]/font[1][+++]/../../../../../../../..',
  2826. useText: 1,
  2827. },
  2828. {
  2829. id: 'NICOCHART',
  2830. urlRE: '//www.nicochart.jp/',
  2831. listTitleXP: '//li[@class="title"]/a',
  2832. listTitleSearchXP: '//li[@class="title"]/a[+++]/../../../../..',
  2833. listTitleMemoSearchXP: '//li[@class="title"]/a[+++]',
  2834. listGen: 5,
  2835. redoWhenReturned: 1,
  2836. },
  2837. {
  2838. id: 'NICOCHART',
  2839. urlRE: '//www.nicovideo.me/',
  2840. listTitleXP: '//h3[@class="fxs mtxs"]/a',
  2841. listTitleSearchXP: '//h3[@class="fxs mtxs"]/a[+++]/../../..',
  2842. listTitleMemoSearchXP: '//h3[@class="fxs mtxs"]/a[+++]',
  2843. listGen: 3,
  2844. redoWhenReturned: 1,
  2845. },
  2846. {
  2847. id: 'TWITTER',
  2848. urlRE: '//twitter.com/',
  2849. title: 'a div[dir="ltr"] span',
  2850. //listTitleXP: '//a/div[@dir="ltr"]/span',
  2851. //listTitleSearchXP: '//a/div[@dir="ltr"]/span[+++]/../../../../../../../../../../../../../../..',
  2852. box: 'div[data-testid="cellInnerDiv"]',
  2853. //listTitleSearchXP: '//a/div[@dir="ltr"]/span[+++]/ancestor::div[@data-testid="cellInnerDiv"]',
  2854. //listTitleMemoSearchXP: '//a/div[@dir="ltr"]/span[+++]',
  2855. //listGen: 14,
  2856. observe: 500,
  2857. disableHelpForce: 1,
  2858. },
  2859. {
  2860. id: 'SURUGAYA',
  2861. urlRE: '//www.suruga-ya.jp/',
  2862. listTitleXP: '//p[@class="title"]/a[1]',
  2863. listTitleSearchXP: '//p[@class="title"]/a[1][+++]/../../..',
  2864. listTitleMemoSearchXP: '//p[@class="title"]/a[1][+++]',
  2865. listGen: 5,
  2866. // titleProcessFunc: (title) => { return title.replace(/ランクB\)/gmi, "").replace(/(.*$|\(.*$/g, "").replace(/全??\d+巻セット.*$|全?\d+?~?\d+巻セット.*$/gmi, "").replace(/\s\/.*$/gmi, "").trim() },
  2867. redoWhenReturned: 1,
  2868. funcOnlyFirst: function() {
  2869. if (location.href == "https://www.suruga-ya.jp/pcmypage/action_nyuka_search/list") {
  2870. setupbutton("zaiko", "品切れの項目を非表示", () => {
  2871. setInterval(() => { elegeta('//div[last()]/input[@value="再入荷通知する"]/../../../..').forEach(e => e.style.display = "none") }, 500);
  2872. }, "もとに戻すにはリロード", "removeWhenClicked")
  2873. }
  2874. /* $(document).keypress(k=>{
  2875. if(k.key=="1"){ setInterval(()=>{elegeta('//div[last()]/input[@value="再入荷通知する"]/../../../..').forEach(e=>e.style.display="none") },999);}
  2876. if(k.key=="2"){ elegeta('//div[last()]/input[@value="再入荷通知する"]/../../../..').forEach(e=>e.style.display="block")}
  2877. });
  2878. */
  2879. },
  2880. wholeHelp: [() => 1, " A:ソート"],
  2881. keyFunc: [{
  2882. key: 'a', // a::
  2883. func: () => {
  2884. if (1 || lh(/\/\/www\.youtube\.com\/playlist\?list=/)) {
  2885. addstyle.add('div.item_box{display: flex; flex-wrap: wrap;}')
  2886. let menu = [
  2887. { t: "安い", f: () => { sortdom(elegeta('div.item'), v => Number((eleget0('//div[contains(@class,"item_price")]/p[3]/span[1]/strong', v) || eleget0('//p[@class="price_teika"]/span[1]/strong', v) || eleget0('//div[@class="item_price"]/p/span[1]/strong', v))?.textContent?.replace(/[^0-9]/gmi, "") || 9999), 0) } },
  2888. ]
  2889. var sorttype = GF.yhmSortType % menu.length || 0
  2890. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  2891. menu[sorttype].f()
  2892. GF.yhmSortType = (++sorttype) % menu.length
  2893. return
  2894. }
  2895. },
  2896. }],
  2897. },
  2898. {
  2899. id: 'YOUTUBE', // youtube::
  2900. // helpOnDNI: 1,
  2901. //listTitleMemoSearchXPSameGen: 1,
  2902. //delayAutoWeighting: lh("www.youtube.com/playlist") ? 1 : 0,
  2903. urlRE: /\/\/www\.youtube\.com\/(?:\?bp=.*)?$|\/\/www\.youtube\.com\/results|\/\/www\.youtube\.com\/channel\/|\/\/www\.youtube\.com\/playlist|\/\/www\.youtube\.com\/c\/|\/\/www\.youtube\.com\/user\/|\/\/www\.youtube\.com\/watch\?|\/\/www\.youtube\.com\/@/,
  2904. disableUrlRE: /\/\/www\.youtube\.com\/watch\?/,
  2905. redoWhenRefocused: 1,
  2906. redoWhenReturned: 1,
  2907. callGKSIafterMemo: 1,
  2908. // redoWhenReturned: 1,
  2909. listTitleXPIgnoreNotExist: 1,
  2910. //nfd: 1,
  2911. trim: 1,
  2912. title: 'ytd-channel-name.ytd-c4-tabbed-header-renderer>.ytd-channel-name>div>yt-formatted-string,div.ytd-channel-name>yt-formatted-string#text>a,h1.title.ytd-video-primary-info-renderer>yt-formatted-string,h3.title-and-badge.ytd-video-renderer>a#video-title>yt-formatted-string.ytd-video-renderer,#items #dismissible a#video-title.yt-simple-endpoint,h4.ytd-playlist-panel-video-renderer span#video-title,h3.ytd-playlist-video-renderer a#video-title,#video-title.ytd-rich-grid-media,h1 yt-formatted-string.style-scope.ytd-watch-metadata,yt-formatted-string.style-scope.ytd-channel-name.complex-string a,span#video-title,.ytd-watch-next-secondary-results-renderer yt-formatted-string.ytd-channel-name,#byline', //,h1.ytd-watch-metadata yt-formatted-string.ytd-watch-metadata
  2913. box: 'ytd-grid-video-renderer, ytd-video-renderer, div.ytd-playlist-video-list-renderer ytd-playlist-video-renderer, ytd-rich-item-renderer, div#title.style-scope.ytd-watch-metadata, div#channel-header .ytd-channel-name yt-formatted-string, ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string, ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,ytd-compact-video-renderer,ytd-reel-item-renderer',
  2914. forceTranslucentFunc: e => e.closest('#channel-container div ytd-channel-name div div yt-formatted-string.style-scope.ytd-channel-name,ytd-watch-metadata div#title.style-scope.ytd-watch-metadata,ytd-watch-metadata .ytd-channel-name a,div#channel-header .ytd-channel-name yt-formatted-string,ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string,ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,#byline'),
  2915. dniCancel: 1, // DNIがobserve(ms)以上連続して発火しても途切れるのを待ち続ける
  2916. /*
  2917. #channel-container div ytd-channel-name div div yt-formatted-string.style-scope.ytd-channel-name
  2918. ↑チャンネルホームの投稿者名
  2919. ytd-watch-metadata h1 yt-formatted-string.ytd-watch-metadata
  2920. ↑新視聴画面タイトル
  2921. ytd-watch-metadata .ytd-channel-name a
  2922. ↑新視聴画面投稿者名
  2923. div#channel-header .ytd-channel-name yt-formatted-string
  2924. ↑旧チャンネルホーム投稿者名
  2925. ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string
  2926. ↑旧視聴タイトル
  2927. ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a
  2928. ↑旧視聴投稿者名
  2929. */
  2930. listHelpXP: '//div[@id="dismissible"]|//div[@class="style-scope ytd-playlist-video-renderer"]/h3[@class="style-scope ytd-playlist-video-renderer"]/a/../../../../..',
  2931. listTitleXP: '//a/yt-formatted-string[@class="style-scope ytd-video-renderer"]/..|.//a[@id="video-title"]|.//h3/span[@id="video-title"]|.//a[@id="video-title-link"]/yt-formatted-string[@id="video-title"]|.//yt-formatted-string[@id="video-title" and @class="style-scope ytd-rich-grid-media"]|//div[2]/ytd-video-primary-info-renderer[@has-date-text=""]/div/h1/yt-formatted-string[@force-default-style="" and contains(@class,"style-scope ytd-video-primary-info-renderer")]|//ytd-watch-metadata[@class="style-scope ytd-watch-flexy"]/div/div[@class="style-scope ytd-watch-metadata"]/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string',
  2932. listTitleSearchXP: '//ytd-grid-video-renderer[.//a[@id="video-title" and +++]]|//ytd-channel-name[@wrap-text=""]/div/div/yt-formatted-string[+++]/following::a|.//ytd-video-renderer[.//a[@id="video-title" and ++title++]]|.//ytd-video-renderer[.//a[contains(@class,"yt-simple-endpoint") and +++]]|.//ytd-rich-item-renderer[.//yt-formatted-string[@id="video-title" and +++]]|.//ytd-rich-item-renderer[.//a[contains(@class,"yt-simple-endpoint") and +++]]|.//ytd-playlist-video-renderer[.//a[@id="video-title" and ++title++]]',
  2933. XP2name: '投稿者名 ',
  2934. //XP2memo:1, // 投稿者にメモ可は重そう
  2935. listTitleXP2: '//ytd-item-section-renderer[@class="style-scope ytd-section-list-renderer" and @use-height-hack=""]/div[3]/ytd-video-renderer[@class="style-scope ytd-item-section-renderer" and @use-prominent-thumbs=""]/div[@id="dismissible" and @class="style-scope ytd-video-renderer"]/div/div/ytd-channel-name[@id="channel-name" and @class="long-byline style-scope ytd-video-renderer" and @wrap-text="true"]/div[@id="container"]/div[@id="text-container" and @class="style-scope ytd-channel-name"]/yt-formatted-string[@id="text" and @class="style-scope ytd-channel-name"]/a|.//div[@class="byline style-scope ytd-rich-grid-media"]/ytd-video-meta-block[@rich-meta="" and @mini-mode=""]/div[@class="style-scope ytd-video-meta-block"]/div[@class="style-scope ytd-video-meta-block"]/ytd-channel-name/div[@class="style-scope ytd-channel-name"]/div[@class="style-scope ytd-channel-name"]/yt-formatted-string[@id="text" and @class="style-scope ytd-channel-name complex-string"]/a[@class="yt-simple-endpoint style-scope yt-formatted-string" and @spellcheck="false" and @dir="auto"]|//div[@id="meta" and @class="style-scope ytd-c4-tabbed-header-renderer"]/ytd-channel-name/div[@class="style-scope ytd-channel-name"]/div[@id="text-container" and @class="style-scope ytd-channel-name"]/yt-formatted-string[@id="text" and @class="style-scope ytd-channel-name"]|.//ytd-channel-name[@id="channel-name" and @class="style-scope ytd-video-meta-block"]/div[@id="container"]/div[@class="style-scope ytd-channel-name"]/yt-formatted-string[@class="style-scope ytd-channel-name complex-string" and @ellipsis-truncate=""]/a[@class="yt-simple-endpoint style-scope yt-formatted-string" and @dir="auto"]|.//ytd-channel-name[@id=\"channel-name\" and @wrap-text=\"true\"]/div[@class=\"style-scope ytd-channel-name\"]/div/yt-formatted-string/a|//div[@id="container"]/div[@class="style-scope ytd-channel-name"]/yt-formatted-string/a[@class="yt-simple-endpoint style-scope yt-formatted-string"]',
  2936. listGen: 7,
  2937. observe: 500,
  2938. // ignoreDNI: e => e.nodeType !== 1 || !["YTD-PLAYLIST-VIDEO-RENDERER", "YTD-VIDEO-RENDERER", "YTD-RICH-ITEM-RENDERER", "YTD-PLAYLIST-PANEL-VIDEO-RENDERER"].includes(e.tagName), //ytd-playlist-panel-video-renderer
  2939. ignoreDNI: e => e.nodeType !== 1 || !e?.matches(SITE.box), //!["YTD-PLAYLIST-VIDEO-RENDERER", "YTD-VIDEO-RENDERER", "YTD-RICH-ITEM-RENDERER", "YTD-PLAYLIST-PANEL-VIDEO-RENDERER"].includes(e.tagName), //ytd-playlist-panel-video-renderer
  2940. //observeId: "dismissible",
  2941. disableKeyB: 1,
  2942. preventHelpFunc: () => 1,
  2943. funcOnlyFirst: () => {
  2944. hoverHelp(e => {
  2945. if (e.closest('span#video-title , a#video-title , div#title.style-scope > h1.style-scope , yt-formatted-string#video-title.style-scope')) return "Q:非表示 W:アンドゥ 1,5:○メモ 2,6:×メモ<br>D:この投稿者の新しい/古い順の再生リストで再生<br>S:この動画を含む再生リストを検索"
  2946. if (e.closest('ytd-channel-name > div#container.ytd-channel-name')) return "投稿者 Q:非表示 W:アンドゥ 1,5:○メモ 2,6:×メモ"
  2947. if (e.closest('ytd-video-renderer , ytd-reel-item-renderer , ytd-rich-item-renderer')) return "Q:非表示 W:アンドゥ 1,5:○メモ 2,6:×メモ"
  2948. if (e.closest('div.style-scope.ytd-channel-name > yt-formatted-string.complex-string > a , yt-formatted-string.ytd-channel-name > a')) return "投稿者 Q:非表示 W:アンドゥ 1,5:○メモ 2,6:×メモ<br>S:この投稿者の動画を入力ワードで検索"
  2949. })
  2950.  
  2951. addstyle.add('#channel-name.ytd-video-meta-block {--ytd-channel-name-text-complex-display: initial !important;}') // プレイリストの投稿者名のメモをなんとか見えるようにする
  2952. addstyle.add('div#container.style-scope.ytd-playlist-panel-renderer {resize: both !important;}') // プレイリストをサイズ可変に
  2953. document.body.addEventListener('mousedown', e => {
  2954. var one = document.elementFromPoint(mousex, mousey) || e?.target
  2955. //動画視聴ページで再生リストタイトルを右クリックでプレイリスト詳細を開く
  2956. if (e.button == 2 && lh(/\&list=([0-9a-zA-Z-_]+)/) && one == eleget0('//yt-formatted-string[@class="title style-scope ytd-playlist-panel-renderer" and @ellipsis-truncate="" and @title="Untitled List" and text()="Untitled List"]|//div[@id="container"]/div/div[@id="header-contents" and @class="style-scope ytd-playlist-panel-renderer"]/div[1]/div[1]/h3[1]/yt-formatted-string/a')) {
  2957. let u = location.href.match0(/\&list=([0-9a-zA-Z-_]+)/)
  2958. if (u) window.open(`https://www.youtube.com/playlist?list=${u}`, "", "noreferrer")
  2959. }
  2960. //動画視聴ページで再生中タイトルを右クリックでその動画を含む再生リストを検索する
  2961. if (e.button == 2 && lh(/\/watch/) && one?.matches('div#title>h1>yt-formatted-string')) {
  2962. let u = encodeURIComponent(one?.innerText?.trim())
  2963. if (u) {
  2964. if (confirm(`https://www.youtube.com/results?search_query="${one?.innerText?.trim()}"&sp=EgIQAw%253D%253D\n\nを開きます。よろしいですか?`)) {
  2965. elegeta('video').forEach(v => v.pause());
  2966. window.open(`https://www.youtube.com/results?search_query=%22${u}%22&sp=EgIQAw%253D%253D`, "", "noreferrer")
  2967. }
  2968. }
  2969. }
  2970. }, false);
  2971.  
  2972. var observeUrlHasChangedhref = location.href;
  2973. var observeUrlHasChanged = new MutationObserver(mutations => {
  2974. if (observeUrlHasChangedhref !== location.href) {
  2975. pauseAll = 1;
  2976. prefCacheClear();
  2977. observeUrlHasChangedhref = location.href;
  2978. // elegeta('//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
  2979. elegeta('.yhmMyMemo').forEach(e => e?.parentNode?.remove());
  2980. elegeta(SITE.box).forEach(e => e.style.opacity = "1");
  2981. setTimeout(() => {
  2982. pauseAll = 0;
  2983. /*let watchTitle=eleget0('//div[@id="above-the-fold" and @class="style-scope ytd-watch-metadata"]/div/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string'); if(watchTitle)watchTitle.innerText=watchTitle?.textContent?.normalize("NFC")*/
  2984. run(document.body, "returned")
  2985. }, 3500);
  2986. }
  2987. });
  2988. observeUrlHasChanged.observe(document, { childList: true, subtree: true });
  2989. GM_addStyle("#meta.ytd-playlist-panel-video-renderer{display:block}") // プレイリストがdisplay:flexで1行に詰め込めないので外す試用
  2990. GM_addStyle('ytd-watch-flexy[rounded-player-large][default-layout] #ytd-player.ytd-watch-flexy{border-radius: 0 !important;} ytd-thumbnail[size="medium"] a.ytd-thumbnail, ytd-thumbnail[size="medium"]::before,ytd-thumbnail[size="large"] a.ytd-thumbnail, ytd-thumbnail[size="large"]::before { border-radius: 0 !important;}') // 動画の角丸を解除
  2991. },
  2992. func: function(node = document.body) {
  2993. /*var watchtitle = eleget0('h1>yt-formatted-string.style-scope.ytd-video-primary-info-renderer');
  2994. if (watchtitle) watchtitle.innerText = watchtitle.innerText.normalize("NFC"); //動画視聴画面のタイトルだけNFDでマッチしないので変換*/ //これやると動画遷移時タイトルが書き換わらなくなる
  2995. // if (location.href.indexOf("https://www.youtube.com/playlist?list=") !== -1) { elegeta('a#video-title,span#video-title').forEach(e => { e.title = e.textContent.trim(); e.innerText = e.textContent.trim(); }); } // 再生リストだけテキストにゴミスペースがある
  2996. //if (lh(/^https:\/\/www\.youtube\.com\/playlist\?list=|^https:\/\/www\.youtube\.com\/watch/)) { elegeta('a#video-title,span#video-title').forEach(e => { e.title = e.textContent.trim(); e.innerText = e.textContent.trim(); }); } // 再生リストだけテキストにゴミスペースがある
  2997. if (REPLACE_LINK_IN_YOUTUBE) {
  2998. // elegeta('//a', node).forEach(e => { if (/\/(channel|user|c)\/[^\/]+$/.test(e.href)) e.href = e.href + "/videos"; });
  2999. elegeta('a', node).forEach(e => { if (/\/(channel|user|c)\/[^\/]+$|youtube\.com\/@[^\/]+$/.test(e?.href) && !/\/video/.test(e?.href)) { e.href = e.href + "/videos"; } })
  3000. // elegeta('a', node).forEach(e => { if (/\/(channel|user|c)\/[^\/]+$|youtube\.com\/@[^\/]+$/.test(e.href)) e.href = e.href + "/videos"; });
  3001. //elegeta('a[href*="&pp="]', node).forEach(e => e.href=e?.href?.replace(/&pp=[^&]+/,"") );
  3002. }
  3003. },
  3004. // helpOnDNI:1,
  3005. keyFunc: [{
  3006. key: "d", // d::
  3007. func: (e, evt) => {
  3008. let targets = (elegeta(['//div[@id="title"]/h1/yt-formatted-string/span[1]', // watchのタグついてるタイトル
  3009. '//h3[@class="title-and-badge style-scope ytd-video-renderer"]/a[@id="video-title" and @class="yt-simple-endpoint style-scope ytd-video-renderer"]/yt-formatted-string',
  3010. '//div[@class="style-scope ytd-playlist-video-renderer"]/h3/a[@id="video-title"]',
  3011. '//div[@id="title" and contains(@class,"style-scope ytd-watch-metadata")]/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string',
  3012. '//span[@id="video-title" and @class=" style-scope ytd-compact-video-renderer style-scope ytd-compact-video-renderer"]',
  3013. '//a[@id="video-title-link"]/yt-formatted-string[@id="video-title" and @class="style-scope ytd-rich-grid-media"]',
  3014. '//div[@class="style-scope ytd-playlist-panel-video-renderer"]/div[3]/h4/span[@id="video-title"]',
  3015. '//ytd-rich-grid-slim-media[@lockup="true"]/div[@class="style-scope ytd-rich-grid-slim-media"]/div[@id="details"]/h3/a/span[@id="video-title"]',
  3016. '//span[@class="style-scope ytd-reel-item-renderer"]', 'div#meta.style-scope.ytd-grid-video-renderer > h3.style-scope > a#video-title'
  3017. ])) //
  3018. targets.forEach(e => debugEle(e, "test autoRemove"))
  3019. var one = document.elementFromPoint(mousex, mousey)
  3020. if (targets.some(e => e.contains(one))) {
  3021.  
  3022. let vid = (one?.closest('a[href*="watch?v="],a[href*="/shorts/"]')?.href || location.href).match(/watch\?v=([a-zA-Z0-9\-_]{11})|shorts\/([a-zA-Z0-9\-_]{11})/)?.slice(1)?.find(v => v)
  3023.  
  3024. //チャンネル/videosページか視聴ページのみ 動画タイトル上でdキーでこの投稿者の「新しい順プレイリスト」でこの動画を再生するURL
  3025. let chid = one.closest('[channel_id]')?.getAttribute("channel_id"); // 検索結果画面等のchID.youtubeフィルタを入れていると使える
  3026. let plid = chid ? `${chid?.match0(/UC([a-zA-Z0-9\-_]+)/m)}` :
  3027. !one.closest('div#items.style-scope.ytd-watch-next-secondary-results-renderer') ? (
  3028. eleget0('#infocard-videos-button a[href*="/channel/UC"]')?.href?.match0(/\/channel\/UC([a-zA-Z0-9\-_]+)/m) ||
  3029. elegeta('script').map(v => v?.innerHTML)?.join()?.match1(/"channelId":"UC([a-zA-Z0-9\-_]+)"|"externalId":"UC([a-zA-Z0-9\-_]+)"/m)
  3030. ) : null
  3031. if (plid && !one?.closest('ytd-playlist-panel-renderer#playlist.style-scope.ytd-watch-flexy')) {
  3032. /*
  3033. let vid = (one?.closest('a[href*="watch?v="],a[href*="/shorts/"]')?.href || location.href).match(/watch\?v=([a-zA-Z0-9\-_]{11})|shorts\/([a-zA-Z0-9\-_]{11})/)?.slice(1)?.find(v => v)
  3034. //チャンネル/videosページか視聴ページのみ 動画タイトル上でdキーでこの投稿者の「新しい順プレイリスト」でこの動画を再生するURL
  3035. let chid = one.closest('[channel_id]')?.getAttribute("channel_id"); // 検索結果画面等のchID.youtubeフィルタを入れていると使える
  3036. let plid = chid ? `${chid?.match0(/UC([a-zA-Z0-9\-_]+)/m)}` :
  3037. eleget0('#infocard-videos-button a[href*="/channel/UC"]')?.href?.match0(/\/channel\/UC([a-zA-Z0-9\-_]+)/m) || elegeta('script').map(v => v?.innerHTML)?.join()?.match1(/"channelId":"UC([a-zA-Z0-9\-_]+)"|"externalId":"UC([a-zA-Z0-9\-_]+)"/m)
  3038. if (plid && !one?.closest('ytd-playlist-panel-renderer#playlist.style-scope.ytd-watch-flexy')) {
  3039. */
  3040. evt.preventDefault();
  3041. evt.stopPropagation(); // 有効なdキーだったら本来の機能(10秒進む)をキャンセル
  3042. if (plid && vid) {
  3043. var url = `https://www.youtube.com/watch?v=${vid}&list=UU${plid}`
  3044. if (confirm(`d:この投稿者の『新しい順のプレイリスト』でこの動画を再生するURL\n\n${url}\n\nを開きますか?`)) {
  3045. //elegeta('video').forEach(v => v.pause()); // 停止する
  3046. GM.openInTab(url, true)
  3047. return false;
  3048. }
  3049. }
  3050. }
  3051.  
  3052. // /videosページ、視聴ページ、検索結果、どこでも この投稿者の『古い順プレイリスト』でこの動画を再生するURL
  3053. var url = `https://www.youtube.com/watch?v=${vid}&list=${Math.random()>0.5?"ULcxqQ59vzyTk":"UL01234567890"}`;
  3054. if (vid && confirm(`d:この投稿者の『古い順プレイリスト』でこの動画を再生するURL\n\n${url}\n\nを開きますか?`)) {
  3055. //elegeta('video').forEach(v => v.pause()); // 停止する
  3056. GM.openInTab(url, true)
  3057. return false;
  3058. }
  3059. return false;
  3060. }
  3061. }
  3062. }, {
  3063. key: "s", // s::
  3064. func: (e, evt) => {
  3065. let targets = (elegeta('//h3[@class="title-and-badge style-scope ytd-video-renderer"]/a[@id="video-title" and @class="yt-simple-endpoint style-scope ytd-video-renderer"]/yt-formatted-string|//div[@class="style-scope ytd-playlist-video-renderer"]/h3/a[@id="video-title"]|//div[@id="title" and contains(@class,"style-scope ytd-watch-metadata")]/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string|//span[@id="video-title" and @class=" style-scope ytd-compact-video-renderer style-scope ytd-compact-video-renderer"]|//a[@id="video-title-link"]/yt-formatted-string[@id="video-title" and @class="style-scope ytd-rich-grid-media"]|//div[@class="style-scope ytd-playlist-panel-video-renderer"]/div[3]/h4/span[@id="video-title"]'))
  3066. var one = document.elementFromPoint(mousex, mousey)
  3067. //let hover=(eleget0('yt-formatted-string:hover,a:hover'))
  3068. one = targets.find(e => e.contains(one))
  3069. if (targets.includes(one)) {
  3070. //動画タイトル上でsキーでその動画を含む再生リストを検索する
  3071. let title = one?.innerText?.trim()
  3072. let u = encodeURIComponent(title)
  3073. if (u) {
  3074. evt.preventDefault();
  3075. evt.stopPropagation(); // 有効なlキーだったら本来の機能(10秒進む)をキャンセル
  3076. if (confirm(`s:指したタイトルを含む再生リストを検索する\n\nhttps://www.youtube.com/results?search_query="${one?.innerText?.trim()}"&sp=EgIQAw%253D%253D\n\nを開きます。よろしいですか?`)) {
  3077. //elegeta('video').forEach(v => v.pause()); // 停止する
  3078. GM.openInTab(`https://www.youtube.com/results?search_query=%22${u}%22&sp=EgIQAw%253D%253D`, "true")
  3079. }
  3080. }
  3081. return false;
  3082. }
  3083. //投稿者名上でsキーでそのチャンネルの動画を入力したキーワードで検索する
  3084. var one = document.elementFromPoint(mousex, mousey)
  3085. if (lh(/\/watch|search_query|^https:\/\/www\.youtube\.com\/$/) && one?.matches('yt-formatted-string#text.style-scope.ytd-channel-name > a.yt-simple-endpoint[herf*="https://www.youtube.com/channel/"],div.ytd-channel-name yt-formatted-string a,yt-formatted-string#text.ytd-channel-name>a[href*="https://www.youtube.com/@"],ytd-channel-name div.ytd-channel-name div#text-container yt-formatted-string a[href*="https://www.youtube.com/@"]')) { //div#channel-header ytd-channel-name div div yt-formatted-string
  3086. let u = one?.href?.match0(/(https:\/\/www\.youtube\.com\/@[^\/]+)\/videos/) || one?.href?.match0(/(https:\/\/www\.youtube\.com\/channel\/[^\/]+)/)
  3087. if (u) {
  3088. evt.preventDefault();
  3089. evt.stopPropagation(); // 有効なlキーだったら本来の機能(10秒進む)をキャンセル
  3090. u += '/search?query='
  3091. let qu = prompt(`s:指した投稿者の動画をキーワードで検索する\n\n${one?.textContent}\nの動画を入力した検索キーワード(***)で検索します\n\n${u}***\n\n`)?.trim()
  3092. if (qu) {
  3093. GM.openInTab(u + encodeURIComponent(qu), "true")
  3094. }
  3095. }
  3096. }
  3097. return false;
  3098. },
  3099. }, {
  3100. key: 'Shift+F', // Shift+F::YouTubeでキーワード検索
  3101. func: () => { searchWithHistory("YouTube", "YouTube", 'https://www.youtube.com/results?search_query=***', "+OR+") },
  3102. }, {
  3103. key: 'u', // u::チャプターメモ
  3104. func: (e) => {
  3105. if (lh(/https:\/\/www\.youtube\.com\/results\?search_query\=/)) { // u::uniq
  3106. let undup = []
  3107. let dup = []
  3108. elegeta('h3.title-and-badge.style-scope.ytd-video-renderer>a>yt-formatted-string:visible').forEach(e => {
  3109. if (undup.includes(e.textContent)) {
  3110. e.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
  3111. $(e.closest("ytd-grid-video-renderer, ytd-video-renderer, div.ytd-playlist-video-list-renderer ytd-playlist-video-renderer, ytd-rich-item-renderer, h1 yt-formatted-string.ytd-watch-metadata, div#channel-header .ytd-channel-name yt-formatted-string, ytd-watch-flexy h1.ytd-video-primary-info-renderer yt-formatted-string, ytd-video-owner-renderer #channel-name .ytd-channel-name div yt-formatted-string a,ytd-playlist-panel-video-renderer,ytd-compact-video-renderer,ytd-reel-item-renderer")).hide(999, function() { $(this).remove() }); //e?.closest(".entry")?.remove()
  3112. dup.push(e.textContent)
  3113. } else { undup.push(e.textContent) }
  3114. })
  3115. popup2(`u:重複タイトルを隠す\n${dup.join("\n")}`, 6)
  3116. return
  3117. }
  3118.  
  3119. chapterMemo(/watch/, () => eleget0('//div[2]/ytd-video-primary-info-renderer[@has-date-text=""]/div/h1/yt-formatted-string[@force-default-style="" and contains(@class,"style-scope ytd-video-primary-info-renderer")]|//ytd-watch-metadata[@class="style-scope ytd-watch-flexy"]/div/div[@class="style-scope ytd-watch-metadata"]/h1[@class="style-scope ytd-watch-metadata"]/yt-formatted-string')?.textContent, `https://www.youtube.com/watch?v=${location.href.match0(/v\=([^?&]*)/)}&t=**time**`)
  3120. },
  3121. }, {
  3122. key: 'Shift+U', // Shift+U::チャプターメモをクリップボードにコピー
  3123. func: (e) => {
  3124. // watch視聴画面
  3125. elegeta('a[href*="&pp="]').forEach(e => e.href = e?.href?.replace(/&pp=[^&]+/, ""))
  3126. if (lh(/watch/) && kaisuuU % 4 < 2) chapterMemo(/watch/, () => eleget0('meta[name="title"]:visible')?.getAttribute("content") || eleget0('//div[@id="title" and @class="style-scope ytd-watch-metadata"]/h1/yt-formatted-string:visible')?.textContent?.trim(), `${(kaisuuU%3%2==1?"https://www.youtube.com/watch?v=**id**&t=**time**":"https://youtu.be/**id**?t=**time**").replace("**id**",location.href.match0(/v\=([a-zA-Z0-9_\-]{11})/))}`, 1) // 1-2回目:今見てる動画のついているチャプターメモを列挙
  3127. if (lh(/watch/) && kaisuuU % 4 == 2) { // 3回目:プレイリスト中の○メモかチャプターメモがついた動画(Qで消されていたら除外)を列挙
  3128. let chaMemoTU = [...new Set((elegeta('div#items ytd-playlist-panel-video-renderer#playlist-items').reduce((ac, v) => {
  3129. if (eleget0('.yhmMyMemo:not(.yhmMyMemoX)', v) && v?.style?.opacity != 0.5) {
  3130. //ac.push(`${eleget0('#video-title', v)?.innerText?.normalize("NFC")?.trim()}\n${eleget0('a', v)?.href?.replace(/\&list=.*/, "")}\n`)
  3131. ac.push(`${eleget0('#video-title', v)?.innerText?.normalize("NFC")?.trim()} - YouTube\n${eleget0('a', v)?.href?.replace(/\&.*/, "")}\n`)
  3132. }
  3133. return ac
  3134. }, [])))]
  3135. GM.setClipboard(chaMemoTU.join(""))
  3136. popup2(chaMemoTU.join(""), -1, "", "top")
  3137. }
  3138. if (lh(/watch/) && (kaisuuU % 5 == 3 || kaisuuU % 5 == 4)) { // 4/5回目:プレイリスト中の○メモかチャプターメモがついた動画(Qで消されていたら除外)を列挙、メモを掲載
  3139. let chaMemoTU = [...new Set((elegeta('div#items ytd-playlist-panel-video-renderer#playlist-items').reduce((ac, v) => {
  3140. let uploader = eleget0('span#byline.style-scope.ytd-playlist-panel-video-renderer', v)?.textContent?.trim();
  3141. let videolen = eleget0('div.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.trim();
  3142. let memoot = elegeta('.yhmMyMemo:not(.yhmMyMemoX)', v).filter(v => v?.style?.opacity != 0.5).map(v => v.textContent).join(" ")
  3143. let memoxt = elegeta('.yhmMyMemoX', v).filter(v => v?.style?.opacity != 0.5).map(v => v.textContent).join(" ")
  3144. let chapterurl = elegeta('.yhmMyMemo:not(.yhmMyMemoX)', v).find(v => v?.style?.opacity != 0.5 && v?.dataset?.url)?.dataset.url.match0(/&t=\d*/)
  3145. if (kaisuuU % 5 == 4 || memoot) {
  3146. // ac.push(`${eleget0('#video-title', v)?.innerText?.normalize("NFC")?.trim()} - YouTube${uploader?` - ${uploader}`:""}${(memoot||memoxt)?" - ":""}${memoot}${memoxt?" "+memoxt:""}\n${chapterurl?eleget0('a', v)?.href?.replace(/\&.*/, "")+chapterurl: eleget0('a',v)?.href?.replace(/\&.*/, "")}\n`)
  3147. ac.push(`${eleget0('#video-title', v)?.innerText?.normalize("NFC")?.trim()} - YouTube${uploader?` - ${uploader}`:""}${videolen?` - [${videolen}]`:""}${(memoot||memoxt)?" - ":""}${memoot}${memoxt?" "+memoxt:""}\n${chapterurl?eleget0('a', v)?.href?.replace(/\&.*/, "")+chapterurl: eleget0('a',v)?.href?.replace(/\&.*/, "")}\n`)
  3148. }
  3149. return ac
  3150. }, [])))]
  3151. GM.setClipboard(chaMemoTU.join(""))
  3152. popup2(`${kaisuuU % 5 ==3?"メモとチャプター反映/メモあり":"メモとチャプター反映/全て"}(${chaMemoTU?.length})\n` + chaMemoTU.join(""), -1, "background-color:#447;", "top")
  3153. //popup2(`${chaMemoTU?.length})\n` + chaMemoTU.join(""), -1, "", "top")
  3154. }
  3155.  
  3156. // 検索、プレイリスト画面等
  3157. if (!lh(/\/watch/) && lh(/\/results\?search_query=|\/videos|\/playlist|\/shorts|\/search/)) {
  3158.  
  3159. let list
  3160. if (kaisuuU % 4 == 3) { // 4回目:○メモかチャプターメモがついた動画(Qで消されていたら除外)を列挙、メモを掲載
  3161. list = [...new Set((elegeta('ytd-grid-video-renderer,ytd-video-renderer,ytd-playlist-video-renderer,ytd-rich-item-renderer,ytd-reel-item-renderer.style-scope.yt-horizontal-list-renderer').reduce((ac, v) => {
  3162. let memoot = elegeta('.yhmMyMemo:not(.yhmMyMemoX)', v).filter(v => v?.style?.opacity != 0.5).map(v => v.textContent).join(" ")
  3163. let memoxt = elegeta('.yhmMyMemoX', v).filter(v => v?.style?.opacity != 0.5).map(v => v.textContent).join(" ")
  3164. let chapterurl = elegeta('.yhmMyMemo:not(.yhmMyMemoX)', v).find(v => v?.style?.opacity != 0.5 && v?.dataset?.url)?.dataset.url.match0(/&t=\d*/)
  3165. if (memoot) {
  3166. ac.push(`${eleget0('#video-title', v)?.innerText?.normalize("NFC")?.trim()} - YouTube ${memoot}${memoxt?" "+memoxt:""}\n${chapterurl?eleget0('a', v)?.href?.replace(/\&.*/, "")+chapterurl: eleget0('a',v)?.href?.replace(/\&.*/, "")}\n`)
  3167. }
  3168. return ac;
  3169. }, [])))];
  3170. list = [...new Set(list)];
  3171. } else {
  3172.  
  3173. // 1-3回め:
  3174. list = elegeta('.yhmMyMemo:not(.yhmMyMemoX):visible')
  3175. .filter(e => e?.closest("ytd-grid-video-renderer,ytd-video-renderer,ytd-playlist-video-renderer,ytd-rich-item-renderer,ytd-reel-item-renderer.style-scope.yt-horizontal-list-renderer") && ((GF?.chaptermemotype || 0) % 3 != 1 || e?.dataset?.cm))
  3176. .map(memoEle => {
  3177. let vEle = eleget0("a[href*='/watch?v='],a[href*='/shorts/']", memoEle?.closest(SITE.box));
  3178. // let vID = vEle?.href?.match0(/https:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11})/);
  3179. let vID = vEle?.href?.match0(/(?:\/watch\?v=|\/shorts\/)([a-zA-Z0-9_\-]{11})/);
  3180. let url = `https://www.youtube.com/watch?v=${ vID}`;
  3181. let title = eleget0(SITE.title, memoEle?.closest(SITE.box))?.textContent?.trim();
  3182. let stime = hms2sec(memoEle.textContent.match0(/^([\d:]+)\s/) || "");
  3183. let memo = !stime ? memoEle.textContent?.replace(/^\d\d\d\d\.\d\d\.\d\d(?:\s\(.\))?$/, "") : "";
  3184. let line = (GF?.chaptermemotype || 0) % 4 < 2 && stime ? `${title} - YouTube ${memoEle?.textContent?.trim()}\n${url}?t=${stime}\n` : `${title} - YouTube${memo?" "+memo:""}\n${url}\n`;
  3185. return line;
  3186. });
  3187. list = [...new Set(list)];
  3188. }
  3189.  
  3190. GF.chaptermemotype = (GF?.chaptermemotype || 0) + 1; // 偶数回目に押した時はチャプターメモに絞る
  3191. GM.setClipboard(list?.join("") || "")
  3192. popup2((list?.join("") || ""), -1, "", "top") //popup2(`(${list?.length})\n` + (list?.join("") || ""), -1, "", "top")
  3193. }
  3194. kaisuuU++
  3195. },
  3196. }, {
  3197. key: 'h', // a:: h::キューかプレイリストありでの視聴画面 (「YouTube検索結果「全てキューに入れて再生」ボタンを追加」用)
  3198. func: () => {
  3199. if (/\/\/www\.youtube\.com\/watch/.test(location.href)) {
  3200. let menu = [
  3201. { t: "時間長", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => Number(v?.querySelector('span.style-scope.ytd-thumbnail-overlay-time-status-renderer')?.innerText?.replace(/[^0-9]/gmi, "") || Number.MAX_SAFE_INTEGER), 1) } },
  3202. { t: "時間短", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => Number(v?.querySelector('span.style-scope.ytd-thumbnail-overlay-time-status-renderer')?.innerText?.replace(/[^0-9]/gmi, "") || Number.MAX_SAFE_INTEGER)) } },
  3203. //{ t: "メモ多", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => Number(elegeta('.yhmMyMemo', v).length), 1) } },
  3204. { t: "メモ多", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => (elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  3205. { t: "タイトル", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => v?.querySelector('span#video-title')?.textContent?.trim()) } },
  3206. { t: "投稿者名", f: () => { sortdom(elegeta('ytd-playlist-panel-video-renderer:visible'), v => v?.querySelector('span#byline')?.textContent?.trim()) } },
  3207. ]
  3208. var sorttype = GF.yhmSortType % menu.length || 0
  3209. popup2("h:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3210. menu[sorttype].f()
  3211. GF.yhmSortType = (++sorttype) % menu.length
  3212. }
  3213. }
  3214. }, {
  3215. key: 'a', // a::
  3216. func: () => {
  3217. if (lh(/\/\/www\.youtube\.com\/playlist\?list=/)) {
  3218. let menu = [
  3219. { t: "時間長", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")), 1) } },
  3220. { t: "時間短", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, ""))) } },
  3221. //{ t: "メモ多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => elegeta('.yhmMyMemo', v).length, 1) } },
  3222. { t: "メモ多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => (elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  3223. { t: "タイトル", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('#video-title', v)?.textContent?.trim()) } },
  3224. { t: "投稿者", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('div.style-scope.ytd-channel-name yt-formatted-string a', v)?.textContent?.trim() || "") } },
  3225. { t: "再生多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) } },
  3226. { t: "再生少", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 0) } },
  3227. { t: "古い", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
  3228. { t: "新しい", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 0) } },
  3229. { t: "逆順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 1) } },
  3230. { t: "元順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 0) } },
  3231. ]
  3232. var sorttype = GF.yhmSortType % menu.length || 0
  3233. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3234. menu[sorttype].f()
  3235. GF.yhmSortType = (++sorttype) % menu.length
  3236. return
  3237. }
  3238. if (lh(/\/\/www.youtube.com\/(?:channel\/|c\/|user\/|@)[^\/]+\/(?:search)/)) { // a::
  3239. let menu = [
  3240. { t: "メモ多", f: () => { sortdom(elegeta('ytd-item-section-renderer.style-scope.ytd-section-list-renderer'), v => (elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+、×メモは-評価
  3241. { t: "時間短", f: () => { sortdom(elegeta('ytd-item-section-renderer.style-scope.ytd-section-list-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, ""))) } },
  3242. { t: "タイトル", f: () => { sortdom(elegeta('ytd-item-section-renderer.style-scope.ytd-section-list-renderer:visible'), v => v?.querySelector('a#video-title.style-scope > yt-formatted-string')?.textContent?.trim()) } },
  3243. { t: "古い", f: () => { sortdom(elegeta('ytd-item-section-renderer.style-scope.ytd-section-list-renderer'), (v) => { let n = v?.querySelector('div.ytd-video-meta-block span:nth-child(4).inline-metadata-item.style-scope.ytd-video-meta-block')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
  3244. { t: "新しい", f: () => { sortdom(elegeta('ytd-item-section-renderer.style-scope.ytd-section-list-renderer'), (v) => { let n = v?.querySelector('div.ytd-video-meta-block span:nth-child(4).inline-metadata-item.style-scope.ytd-video-meta-block')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }) } },
  3245. ]
  3246. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == GF.yhmSortType % menu.length ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3247. menu[GF.yhmSortType % menu.length]?.f()
  3248. GF.yhmSortType = (GF?.yhmSortType + 1) % menu.length
  3249. }
  3250. if (lh(/\/\/www.youtube.com\/(?:channel\/|c\/|user\/|@)[^\/]+\/(?:videos|shorts|streams)/)) { // a::
  3251. $('ytd-rich-grid-row .style-scope.ytd-rich-grid-row').unwrap(); // 表示が乱れるのでよくわからない4列化行要素を消す
  3252. var sorttype = GF.yhmSortType || 0
  3253. let menu = [
  3254. { t: "現状を反転", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v, i) => { return -i }) } },
  3255. { t: "時間長", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1) } },
  3256. { t: "時間短", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }) } },
  3257. { t: "メモ多", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return (elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0) }, 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  3258. { t: "タイトル", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => v?.querySelector('#video-title')?.textContent?.trim()) } },
  3259. { t: "再生多", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(3)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) } },
  3260. { t: "再生少", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(3)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }) } },
  3261. { t: "古い", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(4)')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
  3262. { t: "新しい", f: () => { sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(4)')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }) } },
  3263. // { t: "", f: () => { } },
  3264. ]
  3265. menu = menu.slice(0, lh(/\/\/www\.youtube\.com\/playlist\?list=/) ? 5 : 9)
  3266. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+4),0)}em;`);
  3267. //popup2("A:ソート\n\n※YouTubeの仕様変更により現在「時間短」しかまともに動作しないようです\n\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+4),0)}em;`);
  3268. menu[sorttype].f()
  3269. GF.yhmSortType = (++sorttype) % menu.length
  3270. return;
  3271.  
  3272. /*var menumax = lh(/\/\/www\.youtube\.com\/playlist\?list=/) ? 5 : 9
  3273. var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
  3274. $('.yhmSortType').remove();
  3275. $(document.body).append(`<span class="yhmSortType" id="${++sorttype}"></span>`)
  3276. popup2("A:ソート\n" + (["現状を反転", "時間長", "時間短", "メモ多", "タイトル", "再生多", "再生少", "古い", "新しい"].slice(0, menumax).map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:8em;")
  3277. //popup2("A:ソート\n" + (["時間長", "時間短", "タイトル", "再生多", "再生少"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
  3278. let newUI = eleget0('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer') || eleget0('//div[@class="style-scope ytd-rich-grid-row"]')
  3279. if (newUI) $('ytd-rich-grid-row .style-scope.ytd-rich-grid-row').unwrap(); // 表示が乱れるのでよくわからない4列化行要素を消す
  3280. [() => {
  3281. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v, i) => { return -i }) // 20221029UI
  3282. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v, i) => { return -i }, 1);
  3283. }, () => {
  3284. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1) // 20221029UI
  3285. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { return -Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1);
  3286. }, () => {
  3287. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }) // 20221029UI
  3288. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { return Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")) }, 1);
  3289. }, () => {
  3290. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => (elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) // ○メモとチャプターメモは+1、×メモは-1評価
  3291. }, () => {
  3292. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => v?.querySelector('#video-title')?.textContent?.trim()) // 20221029UI
  3293. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => v?.querySelector('a#video-title')?.title?.trim(), 3);
  3294. }, () => {
  3295. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(3)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) // 20221029UI
  3296. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(1)')?.textContent; return -parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1);
  3297. }, () => {
  3298. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(3)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }) // 20221029UI
  3299. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(1)')?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1);
  3300. }, () => {
  3301. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(4)')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) // 20221029UI
  3302. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = eleget0('//div[1]/div[@id="metadata-line"]/span[2]', v)?.textContent; return -parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1)
  3303. }, () => {
  3304. if (newUI) sortdom(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-grid-row,ytd-grid-playlist-renderer.style-scope.ytd-grid-renderer,ytd-grid-video-renderer.style-scope.ytd-grid-renderer'), (v) => { let n = v?.querySelector('#metadata-line>span:nth-child(4)')?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }) // 20221029UI
  3305. if (!newUI) domsort(elegeta('//div[@id="index-container"]/../..|//ytd-item-section-renderer/div[3]/ytd-grid-renderer[@class="style-scope ytd-item-section-renderer"]/div[@id="items"]:visible'), elegeta('//div[@id="index-container"]/..|//ytd-grid-video-renderer[@class="style-scope ytd-grid-renderer"]'), (v) => { let n = eleget0('//div[1]/div[@id="metadata-line"]/span[2]', v)?.textContent; return -parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 3)
  3306. }][sorttype - 1]()
  3307. if (sorttype == menumax) $('.yhmSortType').remove();
  3308. return
  3309. */
  3310. }
  3311. if (/\/\/www.youtube.com\/results\?search_query=/.test(location.href)) { // 検索結果 // a::
  3312. let menu = [
  3313. //{ t: "メモ多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => elegeta('.yhmMyMemo', v).length, 1) } },
  3314. // { t: "メモ多", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => Number(elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  3315. { t: "メモ多", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => Number(elegeta('.yhmMyMemoO:visible', v)?.length || 0) - (elegeta('.yhmMyMemoX:visible', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価 // 投稿者名には見えない要素が1つあるのでメモが2倍ついているのでvisible指定するが本当はしたくない
  3316. { t: "時間長", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => Number(eleget0('span#text.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "")), 1); } },
  3317. { t: "時間短", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => Number(eleget0('span#text.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.replace(/[^0-9]/gmi, ""))); } },
  3318. { t: "タイトル", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => eleget0('//yt-formatted-string[@class="style-scope ytd-video-renderer"]', v)?.textContent?.trim()); } }, // shortsを含めない
  3319. //{ t: "タイトル", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => eleget0('//yt-formatted-string[@class="style-scope ytd-video-renderer"]', v)?.textContent?.replace(/[\s "”\[\]「」[]「」『』【】()\(\)\::・\-\//]/gmi,"")?.trim()); } }, // shortsを含めない // 空白と記号を無視する版
  3320. { t: "投稿者", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => eleget0('//a[@class="yt-simple-endpoint style-scope yt-formatted-string"]', v)?.textContent); } },
  3321. { t: "再生多", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@id="metadata-line"]/span[1]', v)?.textContent || "0"; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) } },
  3322. { t: "再生少", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@id="metadata-line"]/span[1]', v)?.textContent || "0"; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }) } },
  3323. { t: "古い", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@class="style-scope ytd-video-meta-block"]/div/span[2]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
  3324. { t: "新しい", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer:visible'), v => { let n = eleget0('//div[@class="style-scope ytd-video-meta-block"]/div/span[2]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }) } },
  3325. { t: "動画多", f: () => { sortdom(elegeta('ytd-video-renderer.style-scope.ytd-item-section-renderer,ytd-playlist-renderer:visible'), v => Number(eleget0('yt-formatted-string.style-scope.ytd-thumbnail-overlay-bottom-panel-renderer,.style-scope.ytd-thumbnail-overlay-side-panel-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "") || 0) * 10000000 || Number(eleget0('span#text.style-scope.ytd-thumbnail-overlay-time-status-renderer', v)?.textContent?.replace(/[^0-9]/gmi, "")), 1) } },
  3326. ]
  3327. var sorttype = (GF.yhmSortType || 0) % menu.length
  3328. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3329. menu[sorttype].f()
  3330. GF.yhmSortType = (++sorttype) % menu.length
  3331. return
  3332. }
  3333. },
  3334. }],
  3335. //WhateverFirstAndEveryAPFunc: () => {if((/\/\/www.youtube.com\/results\?search_query=/.test(location.href)) || (/\/\/www.youtube.com\/channel\/[^\/]+\/videos/.test(location.href) || /\/\/www.youtube.com\/user\/[^\/]+\/videos/.test(location.href))) popup3(`A:ソート`,8,5000)},
  3336. // wholeHelp: [() => (/\/\/www.youtube.com\/results\?search_query=/.test(location.href)) || (/\/\/www.youtube.com\/channel\/[^\/]+\/videos/.test(location.href) || /\/\/www.youtube.com\/user\/[^\/]+\/videos/.test(location.href)), " A:ソート"],
  3337. wholeHelp: [() => (lh(/\/\/www\.youtube\.com\/playlist\?list=/) || /\/\/www.youtube.com\/results\?search_query=/.test(location.href) || lh(/\/\/www.youtube.com\/(?:channel\/|c\/|user\/|@)[^\/]+\/(?:videos|shorts|streams)/)), " A:ソート"],
  3338. },
  3339. {
  3340. id: 'IHERB',
  3341. urlRE: '//.*.iherb.com/',
  3342. title: 'div.product-title,div div#name',
  3343. box: 'div.product-cell-container,article.ga-product.product-grouping-refresh',
  3344. redoWhenRefocused: 1,
  3345. //listTitleXP: '//div[@class="absolute-link-wrapper"]/a',
  3346. //listTitleSearchXP: '//div[@class="absolute-link-wrapper"]/a[++title++]/../../..',
  3347. //listTitleMemoSearchXP: '//div[@class="absolute-link-wrapper"]/a[++title++]|.//div[@itemprop="name" and @id="name" and ***]|.//div/div[@id="name" and ***]|//section[3]/div[@id="product-summary-header"]/div[3][***]',
  3348. //listGen: 3,
  3349. observe: 1000,
  3350. //runWhenUrlHasChanged:1,
  3351. /*detailURLRE: /iherb.com\/pr\//,
  3352. detailTitleXP: '//div[@itemprop="name" and @id="name"]',
  3353. detailTitleSearchXP: '//div[@itemprop="name" and @id="name"][***]/../../../../..',*/
  3354. forceTranslucentFunc: () => lh(/iherb.com\/pr\//),
  3355. trim: 1,
  3356. titleProcessFunc: (title) => { return title.replace(/<br>/gmi, "")?.trim() },
  3357. func: () => {
  3358. lh(/\/c\/|\/search\?/) && elegeta('div.rating > a.stars:not([data-starpop])').forEach(e => {
  3359. before(e, `<span style="color:#444" data-estars="${parseFloat(e?.title.match0(/^([0-9\.]+)/)) }">${e?.title.match0(/^([0-9\.]+)/||"0")+" "||""}</span>`);
  3360. e.dataset.starpop = 1;
  3361. })
  3362. elegeta('//div[@itemprop="name" and @id="name"]').forEach(e => e.textContent = e.textContent.replace(/\&/gmi, "&").replace(/\"/gmi, "”").trim()) // &はxpath/textで見逃す
  3363. elegeta('//div[@class="absolute-link-wrapper"]/a').forEach(e => e.title = e.title.replace(/\&/gmi, "&").replace(/\"/gmi, "”").trim())
  3364. GM_addStyle('.product-column .product { height: auto; min-height:395px; }');
  3365. lh('https://jp.iherb.com/pr/') && [/(メチルコバラミン[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(Methylcobalamin[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(アデノシルコバラミン[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(Adenosylcobalamin[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(ヒドロキソコバラミン[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(Hydroxocobalamin[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(シアノコバラミン[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(Cyanocobalamin[^\n]*\d+\s*(?:mg|mcg|μg))/mi, /(Cyanocobalamin[^\n]*\d+\s*mg)/mi, /(ubiquinol|ubiquinon|ユビキノン|ユビキノール)/mi, /(iron[^\n]*\d+\s*mg)/im, /(鉄[^\n]*\d+\s*mg)/im].forEach(m => autoMemo2(eletext('section.content-wrapper'), m));
  3366. //lh('https://jp.iherb.com/pr/') && [/(アデノシルコバラミン|Adenosylcobalamin|メチルコバラミン|cyanocobalamin|ヒドロキソコバラミン|Hydroxocobalamin|methylcobalamin|シアノコバラミン)/mi,/(ubiquinol|ubiquinon|ユビキノン|ユビキノール)/mi,/(iron[^\n]*\d+\s*mg)/im, /(鉄[^\n]*\d+\s*mg)/im].forEach(m => autoMemo2(eletext('section.content-wrapper'), m));
  3367. }, // 商品ブロックの縦幅固定をやめる
  3368. }, {
  3369. id: 'YODOBASHI',
  3370. urlRE: '//www.yodobashi.com/',
  3371. //title:!lh(`/product`)?'div:last-of-type > ul > li:last-of-type > a , a > div.pName.fs14 > p:last-of-type , span.mr10':' h1[class*="pName js_variHeight"] > span , td#js_makerTD.maker',
  3372. title: 'div.srcResultItem.spt_hznList.tileTypeList.js_productList.changeTile :is(div:last-of-type > ul > li:last-of-type > a , a > div.pName.fs14 > p:last-of-type , span.mr10) , div.pdTopContainer :is( h1[class*="pName js_variHeight"] > span , td#js_makerTD.maker )',
  3373. box: `div.srcResultItem_block.pListBlock.hznBox.js_productBox.js_smpClickable.js_latestSalesOrderProduct.productListTile , div.pdTopContainer`,
  3374. listHelpXP2: 'div.srcResultItem.spt_hznList.tileTypeList.js_productList.changeTile :is(div:last-of-type > ul > li:last-of-type > a , a > div.pName.fs14 > p:last-of-type , span.mr10) , div.pdTopContainer :is( h1[class*="pName js_variHeight"] > span , td#js_makerTD.maker )',
  3375. forceTranslucentFunc: e => lh("https://www.yodobashi.com/product/1"),
  3376. /* listTitleXP: '//div[@class="pName fs14"]/p[2]|.//div[@class="product js_productName"]',
  3377. listTitleSearchXP: '//div[@class="pName fs14"]/p[2][+++]/../../..|.//div[@class="product js_productName" and +++]/../../..|.//div[@class="product js_productName" and +++]/../../../../..',
  3378. listTitleMemoSearchXP: '//div[@class="pName fs14"]/p[2][+++]|.//div[3]/h1[@id="products_maintitle"]/span[1][+++]|.//div[@class="product js_productName" and +++]|.//div[@class="product js_productName"][+++]',
  3379. listGen: 4,
  3380. listHelpXP: '//div[@class="pName fs14"]/p[2]/../../..',
  3381. detailURLRE: /\/www.yodobashi.com\/product\//,
  3382. detailTitleXP: '//div[3]/h1[@id="products_maintitle"]/span[1]',
  3383. detailTitleSearchXP: '//div[3]/h1[@id="products_maintitle"]/span[1][+++]/../../../../..',*/
  3384. hideListEvenDetail: 1,
  3385. observe: 500,
  3386. automemoURLRE: /^https:\/\/www.yodobashi.com\/product\//,
  3387. automemoSearchFunc: () => { return eletext(['//div[@id="pinfo_productSummury"]', '//div[@id="productSet1Box"]', '//div[@class="specBox"]', '//h1[@class="pName js_variHeight"]/span[1]']); },
  3388. automemoFunc: () => {
  3389. var cat = elegeta('//div[@class="txtnav clearfix"]');
  3390. if ((cat.some(e => /ヘルス&ビューティー/.test(e.innerText)))) {
  3391. [/(イソプロピルメチルフェノール)/m, /(IPMP)/m, /(塩化セチルピリジニウム|塩化セシルピリジニウム|セチルピリジニウム塩化物)/m, /(CPC)/m, /(塩化ベンザルコニウム)/m, /(BKC)/m, /(ラウロイルサルコシンナトリウム|ラウロイルサルコシンNa|ラウロイルサルコシンNa)/m, /(LSS)/m, /(塩化ベンゼトニウム)/m, /(BTC)/m, /(クロルヘキシジン)/m, /(CHG)/m, /(グリチルリチン酸アンモニウム)/m, /(イプシロン.アミノカプロン酸)/m, /(ε.ACA)/m, /(トラネキサム酸)/m, /(TXA)/m, /(グリチルリチン酸ジカリウム|グリチルリチン酸二カリウム|グリチルリチン酸2K|グリチルリチン酸2K|GK2)/mi, /(1\,?450\s?ppm)/m, /(高?濃?度?フッ化ナトリウム|高?濃?度?フッ素)/m, /(ハイドロオ?キシアパタイト)/m, /(リン酸化オリゴ糖カルシウム)/m, /(POs-Ca|POs-Ca)/mi, /(カゼインホスホペプチド.非結晶性リン酸カルシウム|リカルデント)/m, /(CPP-ACP)/m, /(チモール)/m, /(サリチル酸メ?チ?ル?)/m, /(1\,8-シネオール)/m, /(トリクロサン)/m, /(トリクロカルバン)/m, /(オクトピロックス|オクトロピックス|ピロクトン.?オラミン)/m, /(Znピリチオン|ジンクピリチオン)/m, /(硫黄|イオウ)/m, /(アラントイン)/m, /(グリチルリチン酸アンモニウム)/m, /(ミコナゾール硝?酸?塩?)/m, /(クロラムフェニコール)/m, /(フラジオマイシン硫?酸?塩?)/m, /(ナイスタチン)/m, /(塩化亜鉛)/m, /(ポビドン.?ヨード)/m, /(ラウリルジアミノエチルグリシンナトリウム)/m, /(カキタンニン)/m, /(チャエキス)/m, /(ローズマリー)/m, /(カンゾウ)/m, /(クマザサ)/m, /(セージ)/m, /(シソエキス)/m, /(β?-?グリチルレチン酸?)/m, /(メントール)/m, /(ポリリン酸ナトリウム|ポリリン酸Na)/m, /(ヒノキチオール)/m, /(ティーツリー油オ?イ?ル?)/m, /(ティートゥリー油オ?イ?ル?)/m].forEach(m => autoMemo(m));
  3392. }
  3393. if ((cat.some(e => /浄水器/.test(e.innerText)))) {
  3394. // [/([0-90-9++].*?物質)/m, /(除?去?物質.{0,19}[0-90-9++]+)/m, /([0-90-9++]+?項目)/gm,/(交換.{1,19}[0-9.]+ヶ月)|(交換.{1,19}[0-9.]+年)|(取替.{1,19}[0-9.]+ヶ月)|(取替.{1,19}[0-9.]+年)/m].forEach(m => autoMemo(m)); //,/(除去物質数[\s\S]*\d+)/gm
  3395. [/([0-90-9++].*?物質)/m, /([0-90-9++]+?項目)/gm, /(交換.{1,19}[0-9.]+ヶ月)|(交換.{1,19}[0-9.]+年)|(取替.{1,19}[0-9.]+ヶ月)|(取替.{1,19}[0-9.]+年)/m].forEach(m => autoMemo(m)); //,/(除去物質数[\s\S]*\d+)/gm
  3396. }
  3397. if ((cat.some(e => /電池/.test(e.innerText)))) {
  3398. [/([\d\s\,]+mAh)/m, /([\d\s\,]+mAh)/m, /([\d\s\,]{2,9}回)/m].forEach(m => autoMemo(m));
  3399. }
  3400. if ((cat.some(e => /食器・グラス・カトラリー/.test(e.innerText)))) {
  3401. [/(?:寸法|サイズ).*[::](.+)$/m, /容量[::](.+$)/m, /生産国[::](.+$)/m, /(深さ.*[::].+$)/m, /(\dつ穴)/m].forEach(m => autoMemo(m));
  3402. }
  3403. if ((cat.some(e => /シュレッダー/.test(e.innerText)))) {
  3404. [/(細断サイズ[\s\S]{0,9}[0-9.]+×?[0-9.]*m?m?)/m, /ダストボックス(容量[\s\S]{0,9}[0-9.]+L)/m].forEach(m => autoMemo(m));
  3405. }
  3406. if ((cat.some(e => /食品/.test(e.innerText)))) {
  3407. [/(食物繊維\D{0,9}[0-9.]+[gg])/m].forEach(m => autoMemo(m));
  3408. }
  3409. if ((cat.some(e => /圧力鍋/.test(e.innerText)))) {
  3410. [/(低圧\D?\d+kpa)/mi, /(高圧\D?\d+kpa)/mi, /(圧力[\::]\d+kPa)/mi].forEach(m => autoMemo(m));
  3411. }
  3412. if ((cat.some(e => /ヘッドセット/.test(e.innerText)))) {
  3413. [/(感度.{1,20}dB)/mi, /(\-\s*[0-90-9]+\s*dB)/mi].forEach(m => autoMemo(m));
  3414. }
  3415. if ((cat.some(e => /プランター/.test(e.innerText)))) {
  3416. [/(容量[\s\S]{0,8}[0-9\.\,]+(?:L|L|リットル))/mi, /(容量\((?:L|L|リットル)\):[0-9\.\,]+)/mi].forEach(m => autoMemo(m));
  3417. }
  3418. if ((cat.some(e => /家電/.test(e.innerText)))) {
  3419. [/(本体丸洗い[\s\S]{0,8}(?:可|不可))/mi, /(電源方式[\s\S]{0,8}充電・交流両式|充電式)/mi].forEach(m => autoMemo(m));
  3420. }
  3421. if ((cat.some(e => /入浴剤/.test(e.innerText))))[/\D(\d\dg)/m].forEach(m => autoMemo(m));
  3422. if ((cat.some(e => /洗剤/.test(e.innerText))))[/(界面活性剤\s*[\((]+\s*\d+[\%%]+[^\))]*[\))]+)/m].forEach(m => autoMemo(m));
  3423. },
  3424. redoWhenReturned: 1,
  3425. },
  3426. {
  3427. id: 'TSUGIMANGA',
  3428. urlRE: '//tsugimanga.jp/',
  3429. listTitleXP: '//div/div[@class="work__title"]',
  3430. listTitleSearchXP: '//div/div[@class="work__title"][+++]/../..',
  3431. listTitleMemoSearchXP: '//div/div[@class="work__title" and +++]',
  3432. listGen: 5,
  3433. },
  3434. {
  3435. id: 'NICOSEIGA_COMIC',
  3436. urlRE: /\/\/seiga.nicovideo.jp\/(?:watch|comic|manga)\//,
  3437. title: 'div.main_title>h1,div.description>div.title>a,div.inner_content>div>h1>span.episode_title,div.description_block>div>div>div.title>a,strong.mg_title>a',
  3438. box: 'div.main_title,li.episode_item,li.mg_item.item,#mg_recent_inner li,div.inner.cfix div div.title h1', //'',
  3439. forceTranslucentFunc: e => e.closest('div.main_title,div.inner.cfix div div.title h1'),
  3440. trim: 1,
  3441. listHelpJQS: 'div.main_title,li.episode_item,article#detail.vertical,li.mg_item.item,#mg_recent_inner li',
  3442. redoWhenReturned: 1,
  3443. disableHelpUrlRE: /\/watch\//,
  3444. func: () => { if (lh('https://seiga.nicovideo.jp/comic/')) GM.addStyle(`.episode_item {float:none !important; display:inline-flex !important;}`) },
  3445. wholeHelp: [() => 1, " A:ソート"],
  3446. keyFunc: [{
  3447. key: 'a', // a::
  3448. func: () => {
  3449. elegeta('li.episode_item:not([data-orgorder])').forEach((v, i) => v.dataset.orgorder = i)
  3450. $(".yfokgk").remove()
  3451. let menu = [
  3452. //{ t: "メモ総長順", f: () => { sortdom(elegeta('.NC-MediaObject.NC-VideoMediaObject.VideoContainer-item'), v => (elegeta('.yhmMyMemoO', v)?.reduce((a, b) => b?.textContent?.length + a, 0) || 0) - (elegeta('.yhmMyMemoX', v).reduce((a, b) => b?.textContent?.length + a, 0) || 0), 1) } }, // ○メモとチャプターメモは+文字数、×メモは-文字数評価
  3453. { t: "再生+コメント多", f: () => { sortdom(elegeta('li.episode_item'), v => Number(eleget0('div.counter', v)?.textContent?.match0(/再生\:(\d+)/) || 0) + Number(eleget0('div.counter', v)?.textContent?.match0(/コメント\:(\d+)/) || 0) * 100, 1) } },
  3454. {
  3455. t: "再生+コメント多2",
  3456. f: () => {
  3457. sortdom(elegeta('li.episode_item'), (v, i) => {
  3458. v.dataset.giantkilling = Number(v.dataset.orgorder) - i;
  3459. end(v, `<span class="yfokgk" style="color:#499">${v.dataset.giantkilling>0?"+":""}${v.dataset.giantkilling}</span>`);
  3460. return Number(v.dataset.orgorder) - i
  3461. }, 1)
  3462. }
  3463. }, // 再生数とコメント数は古い話ほど多いのが普通なのでその順からズレた順位=相対人気順で並べる
  3464. { t: "メモ総長順", f: () => { sortdom(elegeta('li.episode_item'), v => (elegeta('.yhmMyMemoO', v)?.reduce((a, b) => b?.textContent?.length + a, 0) || 0) - (elegeta('.yhmMyMemoX', v).reduce((a, b) => b?.textContent?.length + a, 0) || 0), 1) } }, // ○メモとチャプターメモは+文字数、×メモは-文字数評価
  3465. { t: "再生多", f: () => { sortdom(elegeta('li.episode_item'), v => Number(eleget0('div.counter', v)?.textContent?.match0(/再生\:(\d+)/) || 0), 1) } },
  3466. { t: "再生少", f: () => { sortdom(elegeta('li.episode_item'), v => Number(eleget0('div.counter', v)?.textContent?.match0(/再生\:(\d+)/) || 0), 0) } },
  3467. { t: "コメント多", f: () => { sortdom(elegeta('li.episode_item'), v => Number(eleget0('div.counter', v)?.textContent?.match0(/コメント\:(\d+)/) || 0), 1) } },
  3468. { t: "コメント少", f: () => { sortdom(elegeta('li.episode_item'), v => Number(eleget0('div.counter', v)?.textContent?.match0(/コメント\:(\d+)/) || 0), 0) } },
  3469. { t: "タイトル順", f: () => { sortdom(elegeta('li.episode_item'), v => (eleget0('.title', v)?.textContent), 0) } },
  3470. { t: "url降順", f: () => { sortdom(elegeta('li.episode_item'), v => (eleget0('a', v)?.href), 1) } },
  3471. { t: "url昇順", f: () => { sortdom(elegeta('li.episode_item'), v => (eleget0('a', v)?.href), 0) } },
  3472. ]
  3473. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == GF.yhmSortType ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3474. menu[GF.yhmSortType].f()
  3475. GF.yhmSortType = ((GF?.yhmSortType + 1) % menu.length)
  3476. },
  3477. }],
  3478. },
  3479. {
  3480. id: 'NICOSEIGA',
  3481. urlRE: '//seiga.nicovideo.jp/illust/ranking/point/',
  3482. listGen: 5,
  3483. // 項目名:投稿者名
  3484. listTitleXP: '//span[@class="rank_txt_user"]/a',
  3485. listTitleSearchXP: '//span[@class="rank_txt_user"]/a[+++]/../../../../../..',
  3486. listTitleMemoSearchXP: '//span[@class="rank_txt_user"]/a[+++]',
  3487. listHelpXP: '//tr/td[contains(@class,"rank_block_right rank_no_")]',
  3488. },
  3489. {
  3490. id: 'NICOSEIGA',
  3491. urlRE: '//seiga.nicovideo.jp/tag/|//seiga.nicovideo.jp/seiga/|//seiga.nicovideo.jp/user/illust/|//seiga.nicovideo.jp/illust/|//seiga.nicovideo.jp|//seiga.nicovideo.jp/my/personalize',
  3492. listGen: 5,
  3493. detailURLRE: /\/\/seiga.nicovideo.jp\/seiga\/|\/\/seiga.nicovideo.jp\/user\/illust\//,
  3494. // 項目名:投稿者名
  3495. listTitleXP: '//li[@class="user"]|.//span[@class="rank_txt_user"]/a|.//span[@class="popular_illust_block__item__info--nickname"]|.//p[@class="info_source"]/a[@class="user_name"]',
  3496. listTitleSearchXP: '//li[@class="user" and +++]/../../..|.//span[@class="rank_txt_user"]/a[+++]/../../../..|.//span[@class="popular_illust_block__item__info--nickname" and +++]/../../..|.//p[@class="info_source"]/a[@class="user_name" and +++]/../../..',
  3497. hideListEvenDetail: 1,
  3498. listTitleMemoSearchXP: '//li[@class="user" and +++]/..|//ul/li[@class="user_name"]/strong[+++]/..|.//span[@class="nickname" and +++]/..|.//span[@class="rank_txt_user"]/a[+++]|.//span[@class="popular_illust_block__item__info--nickname" and +++]|.//p[@class="info_source"]/a[@class="user_name" and +++]',
  3499. listHelpXP: '//li[contains(@class,"list_item list_no_trim2")]/a|.//tbody/tr/td[contains(@class,"rank_list_block rank_no_")]|.//div[@class="popular_illust_block__item"]|.//ul[@class="item_list"]/li[@class="list_item middle"]/a|.//div/ul[@class="item_list"]/li[@class="list_item middle"]/a|.//p[@class="info_source"]/a[@class="user_name"]/../../..',
  3500. detailTitleXP: '//ul/li[@class="user_name"]/strong|//span[@class="nickname"]',
  3501. detailTitleSearchXP: '//ul/li[@class="user_name"]/strong[+++]/../../../../../../../../../../../..|//span[@class="nickname" and +++]/../../../../../../..',
  3502. },
  3503. {
  3504. id: 'KAKAKU',
  3505. urlRE: '//kakaku.com/search_results/',
  3506. listTitleXP: '//p[@class="p-item_name s-biggerlinkHover_underline"]',
  3507. listTitleSearchXP: '//p[@class="p-item_name s-biggerlinkHover_underline"][+++]/../../../../..',
  3508. listTitleMemoSearchXP: '//p[@class="p-item_name s-biggerlinkHover_underline"][+++]',
  3509. listGen: 5,
  3510. },
  3511. {
  3512. id: 'KAKAKU',
  3513. urlRE: '//kakaku.com/specsearch|//kakaku.com/item/',
  3514. listTitleXP: '//td[@class="textL"]/strong/a[1]',
  3515. listTitleSearchXP: '//td[@class="textL"]/strong/a[1 and +++]/../../..',
  3516. listTitleMemoSearchXP: '//td[@class="textL"]/strong/a[1 and +++]|//div[@class="boxL"]/h2[@itemprop="name" and +++]/..',
  3517. listGen: 4,
  3518. detailURLRE: /\/\/kakaku.com\/item\//,
  3519. detailTitleXP: '//div[@class="boxL"]/h2[@itemprop="name"]',
  3520. detailTitleSearchXP: '//div[@class="boxL"]/h2[@itemprop="name" and +++]/../../../..',
  3521. },
  3522. {
  3523. id: 'HELLOWORK',
  3524. urlRE: '//www.hellowork.mhlw.go.jp/kensaku/',
  3525. listTitleXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div',
  3526. listTitleSearchXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div[+++]/../../../../../../../../..|//div[@id="ID_kjNo"]',
  3527. listTitleMemoSearchXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div[+++]/../../../..|//div[@id="ID_kjNo" and +++]/../../..',
  3528. listHelpXP: '//td[@class="fb in_width_9em" and text()="求人番号"]/following-sibling::td/div/../../../../../../../../..',
  3529. listGen: 8,
  3530. detailURLRE: /Detail/i,
  3531. detailTitleXP: '//div[@id="ID_kjNo"]',
  3532. detailTitleSearchXP: '//div[@id="ID_kjNo" and +++]/../../../../..',
  3533. func: () => { if (location.href.match(/detail/i)) { GM_addStyle('table.normal tr th, table.normal tr td { padding: 0.2em 1em;}') } else { GM_addStyle('table.kyujin th, table.kyujin td { padding: 0.5em 0.5em; } table.normal tr th, table.normal tr td { border-top: 1px solid #125939; padding: 0.5em 10px; text-align: left; } .mb03 { margin-bottom: 0em; }'); } },
  3534. },
  3535. {
  3536. id: 'USERBENCHMARK',
  3537. urlRE: '.*?.userbenchmark.com',
  3538. listTitleXP: '//span/a[@class="nodec"]',
  3539. listTitleSearchXP: '//span/a[@class="nodec" and +++]/../../../../..',
  3540. listTitleMemoSearchXP: '//span/a[@class="nodec" and +++]|//h1[@class="pg-head-title"]/a[+++]',
  3541. listGen: 5,
  3542. observe: 1000,
  3543. detailURLRE: /\/\/.*?.userbenchmark.com\/SpeedTest\/|\/\/.*?.userbenchmark.com\/.*?\/Rating\//i,
  3544. detailTitleXP: '//h1[@class="pg-head-title"]/a',
  3545. detailTitleSearchXP: '//h1[@class="pg-head-title"]/a[+++]/../../..',
  3546. automemoURLRE: /\/\/.*?.userbenchmark.com\/SpeedTest\/|\/\/.*?.userbenchmark.com\/.*?\/Rating\//i,
  3547. automemoSearchFunc: () => { return eletext('//h3[@class="pg-head-toption"]/span[@class="pg-head-toption-post"]') + "\n"; },
  3548. automemoFunc: () => { autoMemo(/(.*)/); },
  3549. },
  3550. {
  3551. urlRE: '//www.sukima.me/(?!bv|login)',
  3552. id: 'SUKIMA',
  3553. listTitleXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div',
  3554. listTitleSearchXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div[***]/../../../..',
  3555. listTitleMemoSearchXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div[***]',
  3556. listHelpXP: '//div[@class="row ma-0 flex-nowrap align-center title-name-content"]/div/../../../..',
  3557. listGen: 5,
  3558. titleProcessFunc: title => { return title.replace(/\n\s*?\n\s*?|(?分冊版)?.*|【期間限定 無料お試し版】.*|[0-90-9]*?巻.*/g, "").trim() },
  3559. observe: 1500,
  3560. func: () => {
  3561. document.title = document.title.replace(/(^\[.*\])(.*)/, "$2$1");
  3562. } // ページタイトルの「[全話無料]」等の接頭辞を末尾に移動
  3563. },
  3564. {
  3565. urlRE: '//www.mangaz.com/',
  3566. // id: 'MANGAZ', // SUKIMAと登録内容を共通にしない
  3567. id: 'SUKIMA', // SUKIMAと登録内容を共通にする
  3568. title: 'div.listBoxDetail>h4>a,p.author,div.header h2,ul.seriesAuthor li a,span.sort-word' + `,ul.detailAuthor li span a`,
  3569. box: '.itemList>li,div.seriesMain div.header,div.sort-inner' + `,ul.detailAuthor`,
  3570. forceTranslucentFunc: e => e.closest('div.seriesMain div.header,div.sort-inner' + `,ul.detailAuthor`),
  3571. observeFunc: e => e?.nodetype === 1 && e?.matches('.itemList>li,div.seriesMain div.header,div.sort-inner'),
  3572. listHelpJPS: '.itemList>li,div.seriesMain div.header,div.sort-inner',
  3573. listHelpXP2: 'p.author,ul.seriesAuthor li a',
  3574. XP2name: '作者名 ',
  3575. wholeHelp: [() => 1, " Shift+F:作品検索 A:ソート"],
  3576. keyFunc: [{
  3577. key: 'Shift+F', // Shift+F::キーワード検索
  3578. func: () => { searchWithHistory("MANGAZ", "マンガ図書館Z", 'https://www.mangaz.com/title/index?category=&query=***&sort=&search=input', "") },
  3579. }, {
  3580. key: 'a', // a::ソート
  3581. func: () => {
  3582. var sorttype = GF.yhmSortType || 0;
  3583. // $('.yhmSortType').remove(), $(document.body).append(`<span class="yhmSortType" id="${++sorttype%2}"></span>`)
  3584. GF.yhmSortType = ++sorttype % 2
  3585. popup2("A:ソート\n" + (["タイトル", "著者名"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
  3586. sorttype == 1 && sortdom(elegeta('.itemList>li'), v => eleget0('div.listBoxDetail>h4>a', v)?.textContent)
  3587. sorttype == 2 && sortdom(elegeta('.itemList>li'), v => eleget0('.listBoxDetail>p', v)?.textContent)
  3588. }
  3589. }],
  3590. titleProcessFunc: (title) => { return title.replace(/\s[0-90-9]+巻?$|【.*?】|全.*?巻|第\d*話/gmi, "").trim() },
  3591. observe: 500,
  3592. redoWhenRefocused: 1,
  3593. func: () => {
  3594. document.title = document.title.replace(/(^【.*】)(.*)/, "$2$1"); // ページタイトルの「[全話無料]」等の接頭辞を末尾に移動
  3595. // 作品一覧の著者名をクリックで検索できるようにする
  3596. elegeta('p.author:not([data-linked])').forEach((e, i, a) => {
  3597. let author = e.textContent.trim().replace(/,/gm, " ").replace(/\s+/gm, " ")
  3598. let url = 'https://www.mangaz.com/title/index?category=&query=***&sort=&search=input'.replace("***", encodeURI(author))
  3599. e.dataset.linked = url
  3600. e.style.cursor = "pointer"
  3601. e.title = `クリックで「${author}」で作品検索をします\n${url}`
  3602. e.addEventListener("click", v => window.open(v.target.dataset.linked, "", "noreferrer"))
  3603. })
  3604. }
  3605. },
  3606. {
  3607. id: 'PICCOMA',
  3608. urlRE: '//piccoma.com/',
  3609. listTitleXP: '//div[@class="PCM-productCoverImage_title"]/span|.//div[@class="PCM-rankingProduct_title"]/p|.//p[@class="PCM-productCoverImage_title"]/span',
  3610. listTitleSearchXP: '//div[@class="PCM-productCoverImage_title"]/span[+++]/ancestor::li[contains(@class,"PCM-slotProducts_list")]|.//div[@class="PCM-rankingProduct_tdata"]/div/p[+++]/ancestor::li[contains(@class,"PCM-slotProducts_list")]|.//p[@class="PCM-productCoverImage_title"]/span[+++]/ancestor::li[contains(@class,"PCM-slotProducts_list")]',
  3611. listTitleMemoSearchXP: '//div[@class="PCM-productCoverImage_title"]/span[+++]', // 実質表示されない
  3612. listGen: 7,
  3613. observe: 3000,
  3614. },
  3615. {
  3616. id: 'TAMESHIYOMI',
  3617. urlRE: '//www.cmoa.jp/freecontents/',
  3618. listTitleXP: '//p[@class="titile_name"]/a',
  3619. listTitleSearchXP: '//p[@class="titile_name"]/a[+++]/../../../..',
  3620. listTitleMemoSearchXP: '//p[@class="titile_name"]/a[+++]',
  3621. listGen: 4,
  3622. redoWhenReturned: 1,
  3623. },
  3624. {
  3625. id: 'ja.aliexpress.com',
  3626. urlRE: '//ja.aliexpress.com/',
  3627. listTitleXP: '//h1[@class="_3eC3x"]/../../..',
  3628. listTitleXP2: '//a[@class="ox0KZ"]',
  3629. listHelpXP: '//h1[@class="_3eC3x"]/../../..',
  3630. XP2name: 'セラー名 ',
  3631. XP2memo: 1,
  3632. listTitleSearchXP: '//a[**url**]/*/*/h1[@class="_3eC3x"]/../../..|//a[@class="ox0KZ"][+++]/../../..',
  3633. listTitleMemoSearchXP: '//a[**url**]/*/*/h1[@class="_3eC3x"]|//a[@class="ox0KZ"][+++]',
  3634. listGen: 3,
  3635. useURL: 1,
  3636. func: () => { // 商品名を全行表示する
  3637. elegeta('//div[@class="product-container"]/div[2]/a/div[2]/div[1]/h1').forEach(e => {
  3638. e.style.whiteSpace = "";
  3639. e.style.height = "auto";
  3640. e.style.whiteSpace = "normal";
  3641. e.parentNode.style.display = "block"
  3642. });
  3643. },
  3644. },
  3645. {
  3646. id: 'GREASYFORK',
  3647. urlRE: '//gf.qytechs.cn/.*?/scripts',
  3648. listTitleXP: `//a[@class="script-link"]|.//a[@class="script-link"]/font/font`, //'//article/h2/a',
  3649. listTitleSearchXP: `//a[@class="script-link"][+++]/ancestor::li|.//a[@class="script-link"]/font/font[+++]/ancestor::li`, //'//article/h2/a[+++]/../../..|//article/h2/a/font/font[+++]/../../../../..',
  3650. listTitleMemoSearchXP: `//a[@class="script-link"][+++]|.//a[@class="script-link"]/font/font[+++]/../..`, //'//article/h2/a[+++]|//article/h2/a/font/font[+++]/../..',
  3651. listGen: 7,
  3652. // func:(n)=>{elegeta('//h2/a[@class="script-link"]',n).forEach(e=>{$(e.parentNode.parentNode.parentNode).append(' <a style="float:right;margin:0 0 0 1em;" href="'+e.href+'/stats?period=all">統計</a>').append(' <a style="float:right;margin:0 0 0 1em;" href="'+e.href+'/feedback">フィードバック</a>')}) },
  3653. },
  3654. {
  3655. id: 'JMTY',
  3656. urlRE: '//jmty.jp/',
  3657. listTitleXP: '//div[@class="p-item-title"]/a',
  3658. listTitleSearchXP: '//div[@class="p-item-title"]/a[++url++]/../../..',
  3659. listTitleMemoSearchXP: '//div[@class="p-item-title"]/a[++url++]',
  3660. listGen: 5,
  3661. useURL: 1,
  3662. },
  3663. {
  3664. id: 'EBAY',
  3665. urlRE: 'ebay.com/',
  3666. listTitleXPIgnoreNotExist: 1,
  3667. listTitleXP: '//div[@class="s-item__title"]/span[@role="heading"]/../..',
  3668. listTitleSearchXP: '//div[@class="s-item__title"]/span[@role="heading"]/../..[**url**]/../../..',
  3669. listTitleMemoSearchXP: '//div[@class="s-item__title"]/span[@role="heading"]/../..[**url**]|//h1[@class="x-item-title__mainTitle"]/span[1][**url**]/..',
  3670. listGen: 5,
  3671. detailTitleXP: '//h1[@class="x-item-title__mainTitle"]/span[1]',
  3672. detailTitleSearchXP: '//h1[@class="x-item-title__mainTitle"]/span[1][**url**]/../../../../..',
  3673. XP2memo: 1,
  3674. XP2name: 'セラー名 ',
  3675. listGen: 6,
  3676. useURL: 1,
  3677. funcOnlyFirst: () => {
  3678. var e = eleget0('//link[@rel="canonical"]');
  3679. var t = eleget0('//h1[@class="x-item-title__mainTitle"]/span[1]|//h1[@itemprop="name" and @id="itemTitle"]')
  3680. if (e && t) t.setAttribute("href", e.href)
  3681. },
  3682. detailURLRE: /www.ebay.com\/itm\//,
  3683. listHelpJQS: 'li.s-item',
  3684. helpInBlock: 1,
  3685. maxpriceXP: '//div/input[@aria-label="Maximum Value"]',
  3686. }, {
  3687. id: '2CHTHREADLIST',
  3688. urlRE: /\/\/.*\.5ch\.net\/[^\/]*\/(\?v=pc)?$/,
  3689. listTitleXP: '//td/a',
  3690. listTitleSearchXP: '//table[@id="thread-list"]/tbody/tr/td/a[+++]/../..',
  3691. listTitleMemoSearchXP: '//tr/td/a[+++]',
  3692. listTitleMemoSearchXPSameGen: 1,
  3693. listGen: 6,
  3694. delay: 1000,
  3695. observe: 500, // 並べ替え時に必要
  3696. redoWhenReturned: 1,
  3697. keyFunc: [{
  3698. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  3699. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  3700. // func: () => { searchWithHistory("REFIND2CH", "re.Find2ch", 'https://refind2ch.org/search?q=***&sort=rate', " OR ") },
  3701. }],
  3702. }, {
  3703. urlRE: 'https://find.5ch.net/search',
  3704. id: '2CHTHREADLIST',
  3705. title: 'div.list_line_link_title,div.list_line_info_container.list_line_info_container-board>a',
  3706. box: 'div.list_line',
  3707. titleProcessFunc: v => v.replace(/\(\d+\)$/, "").trim(),
  3708. titleSubstr: 1,
  3709. redoWhenReturned: 1,
  3710. XP2name: '板名 ',
  3711. listHelpXP2: '//div[@class="list_line_info_container list_line_info_container-board"]/a',
  3712. trim: 1,
  3713. keyFunc: [{
  3714. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  3715. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  3716. }, {
  3717. key: 'a', // a::
  3718. func: () => {
  3719. let menu = [
  3720. { t: "勢い強", f: () => sortdom(elegeta('div.list_line'), v => { return (eleget0('//div/div[3]', v)?.textContent) }, 1) },
  3721. { t: "メモ多", f: () => { sortdom(elegeta('div.list_line'), v => Number(elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  3722. { t: "タイトル", f: () => sortdom(elegeta('div.list_line'), v => { return (eleget0('//a/div[@class="list_line_link_title"]', v)?.textContent) }, 0) },
  3723. { t: "板名", f: () => sortdom(elegeta('div.list_line'), v => { return (eleget0('div.list_line_info_container-board>a', v)?.textContent?.trim()) }, 0) },
  3724. { t: "新しい", f: () => sortdom(elegeta('div.list_line'), v => { return (eleget0('//div[@class="list_line_info_container"]', v)?.textContent) }, 1) },
  3725. ]
  3726. popup2("a:ソート\n" + (menu.map((c, i) => " " + c.t + (i == (GF?.yhmSortType % menu.length) ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3727. menu[GF?.yhmSortType % menu.length].f()
  3728. GF.yhmSortType = (GF?.yhmSortType || 0) + 1
  3729. }
  3730. }],
  3731. wholeHelp: [() => 1, " A:ソート"], // Shift+F:スレッド検索
  3732. }, { // 5chスレッド内 5ch::
  3733. id: 'new5ch',
  3734. urlRE: () => lh('.5ch.net/test/read.cgi/') && !lh("/c/"),
  3735. title: 'details.post-header,.uid',
  3736. listTitleXP2: '.uid',
  3737. funcQ: e => e?.textContent?.match(/https:\/\/i\.imgur\.com\/[\w\.]+/gi)?.forEach(v => addNG(v)),
  3738. XP2name: `ID `,
  3739. box: 'article.post',
  3740. memoStyle: "float:right;",
  3741. memoOnRead: v => v?.concat((pref('5CH : SearchMyMemo') || [])?.map(v => { v.t = v.t.replace(/(\d\d\d\d\/\d\d\/\d\d\(.\))\s*(\d\d\:\d\d\:\d\d)/, "$1 $2").replace(/\>\>\d+/gm, ""); return v; })), // 旧5chで付けたメモも一方通行的に取り込む それらは旧5chでしか削除できない
  3742. // delay: 5000+(Math.min(elegeta('article.post')?.length,1000)**2)/200,
  3743. funcOnlyFirst: () => {
  3744. if (eleget0('//span[@class="postid" and starts-with(text(),"0")]')) elegeta('.postid').forEach(e => e.textContent = Number(e.textContent))
  3745. //if (IN5CH_REMOVE_AKABAN) elegeta('.post-header>summary>span:has( form)').filter(e => e?.textContent.indexOf("垢版") != -1).forEach(e => e?.remove())
  3746. if (IN5CH_REMOVE_AKABAN) elegeta('.post-header>summary>span>form').filter(e => e?.textContent.indexOf("垢版") != -1).forEach(e => e?.remove())
  3747. //if (IN5CH_REMOVE_AKABAN) elegeta('.post-header>summary>span').filter(e => e?.textContent == "垢版").forEach(e => e?.remove())
  3748. }, // 0001みたいなゼロサプレスを削除
  3749. redoWhenReturned: 1,
  3750. redoWhenRefocused: 1,
  3751. memoFunc: e => e?.parentNode?.querySelector(".post-content")?.previousElementSibling || e,
  3752. hideSelectedWord: 1,
  3753. delay: 333,
  3754. selectedHelp: { help: [KEYHIDE + ":NGワードに追加"] }, //, multi: "複数行に渡る文字列は NG に入れられません" },
  3755. listTitleSearchFunc: (title) => { // レス中キーワードNG
  3756. let resHit = [];
  3757. if (typeof title === "string" && /\D/m.test(title)) { // textContentでサーチする
  3758. for (let res of elegeta('article.post')) { // レス本文
  3759. if (res.textContent.indexOf(title) !== -1) resHit.push(res.closest("article.post"));
  3760. }
  3761. /* for (let res of elegeta('.uid')) { // ID
  3762. if (res.textContent.indexOf(title) !== -1) resHit.push(res.closest("article.post"));
  3763. }*/
  3764. }
  3765. return resHit;
  3766. },
  3767. keyFunc: [{
  3768. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  3769. // func: () => { searchWithHistory("find5ch", "find5ch", ['https://find.5ch.net/search?q=***',`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`], " OR ") },
  3770. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  3771. // func: () => { searchWithHistory("REFIND2CH", "re.Find2ch", 'https://refind2ch.org/search?q=***&sort=rate', " OR ") },
  3772. }, {
  3773. key: 'a', // a::
  3774. func: () => {
  3775. let menu = [
  3776. { t: "引用", f: () => sortdom(elegeta('article'), v => { return -(v.querySelectorAll('.allpopup').length) }) },
  3777. { t: "リンク", f: () => sortdom(elegeta('.post'), v => { return Number(v?.textContent?.match(/ttps?:\/\//gmi)?.length) * 10000 - (v.id) || 0 }, 1) },
  3778. { t: "元", f: () => sortdom(elegeta('.post'), v => { return (v.id) }) },
  3779. ]
  3780. popup2("a:ソート\n" + (menu.map((c, i) => " " + c.t + (i == (GF?.yhmSortType % menu.length) ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3781. menu[GF?.yhmSortType % menu.length].f()
  3782. GF.yhmSortType = (GF?.yhmSortType || 0) + 1
  3783. }
  3784. }],
  3785. wholeHelp: [() => 1, " A:ソート"], // Shift+F:スレッド検索
  3786. }, {
  3787. id: `${/shitaraba\.net/.test(location.href)?"SHITARABA":"5CH"}`, //'5CH',
  3788. urlRE: '.5ch.net/test/read.cgi/|.shitaraba.net/bbs/read.cgi/|.shitaraba.net/bbs/read_archive.cgi/',
  3789. // memoOnRead: v => v?.concat((pref('new5ch : SearchMyMemo') || [])?.map(v => { v.t = v.t.replace(/(\d\d\d\d\/\d\d\/\d\d\(.\))\s*(\d\d\:\d\d\:\d\d)/, "$1$2"); return v; })), // 新5chで付けたメモも一方通行的に取り込む それらは新5chでしか削除できない
  3790. memoOnRead: v => v?.concat((pref('new5ch : SearchMyMemo') || [])?.map(v => { v.t = v.t.replace(/\s/g, ""); return v; })), // 新5chで付けたメモも一方通行的に取り込む それらは新5chでしか削除できない
  3791. listTitleXP2: '//span[@class="uid"]',
  3792. listTitleXPIgnoreNotExist: 1,
  3793. memoStyle: 'float:right;', //' margin-bottom:1px;',
  3794. forceRunIffunc: () => { return /\.shitaraba\.net\/bbs\/read\.cgi\//.test(location.href) || eleget0('.thread > dd:nth-child(2)') },
  3795. hideSelectedWord: 1,
  3796. selectedHelp: { help: [KEYHIDE + ":NGワードに追加"] }, //, multi: "複数行に渡る文字列は NG に入れられません" },
  3797. titleProcessFunc: (title) => { return /^\d{1,4}.+\d\d\d\d\/\d\d\/\d\d\(.\)\s..\:/.test(title.replace(/\n/gm, "").trim()) ? title?.replace(/⋮/g, "").replace(/\>\>.*$|\[\d*\]$/, "").replace(/\n| |\s|:/g, "").trim() : title?.replace(/⋮/g, "").replace(/\n/gm, "").replace(/\>\>.*$|\[\d*\]$/, "").trim() },
  3798. XP2name: 'ID ',
  3799. listTitleXP: '//div[@class="meta"]', // 項目名はレス番~IDまでの一連のdiv.meta
  3800. listTitleSearchXP: '//div[@class="meta"][**alt**]/..|//span[@class="escaped"][***]/../..',
  3801. listTitleMemoSearchXP: '//div[@class="meta"][**alt**]/span[@class="date"]',
  3802. listHelpXP: '//div[@class="post"]',
  3803. listGen: 6,
  3804. searchAllowLength: 1,
  3805. delay: 100, //delayAutoWeighting: 0.6, // 5chサムネイル表示他のhNukiURLHokan()より後でないとメモを消せなくなる
  3806. keyFunc: [{
  3807. key: 'Shift+F', // Shift+F::refind2chでキーワード検索
  3808. func: () => { searchWithHistory("find5ch,掲示板横断検索,re.find2ch,ff5ch", "find5ch,掲示板横断検索,re.find2ch,ff5ch", [`https://zzzsearch.com/bbs/#gsc.q=%22***%22&gsc.sort=date`, `https://refind2ch.org/search?q=***&sort=rate`, 'https://find.5ch.net/search?q=***', `https://ff5ch.syoboi.jp/?q=***`], " OR ") },
  3809. }, {
  3810. key: 'a', // a::
  3811. func: () => {
  3812. var sorttype = Number($('.yhmSortType')?.attr("id") || 0);
  3813. $('.yhmSortType').remove();
  3814. $(document.body).append(`<span class="yhmSortType" id="${++sorttype}"></span>`)
  3815. popup2("A:ソート\n" + (["引用", "リンク", "古い順"].map((c, i) => " " + c + (i + 1 == sorttype ? " ←\n" : "\n")).join("")), 6, "min-width:6em;")
  3816. $(".thread>br,#thread-body>br").remove()
  3817. switch (sorttype) {
  3818. case 1:
  3819. domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return -(v.querySelectorAll('.allpopup').length) }, 1)
  3820. break;
  3821. case 2:
  3822. domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return Number((v?.textContent?.match(/ttps?:\/\//gmi)?.length)) && -1 - Number((v.querySelectorAll('.allpopup').length)) || 0 }, 1)
  3823. break;
  3824. case 3:
  3825. domsort(eleget0('.thread,#thread-body'), elegeta('.post'), v => { return (v.id) }, 1)
  3826. $('.yhmSortType').remove();
  3827. break;
  3828. }
  3829. $('.post').after("<br>")
  3830. }
  3831. }],
  3832. wholeHelp: [() => 1, " A:ソート"],
  3833. listTitleSearchFunc: (title) => { // レス中キーワードNG
  3834. let resHit = [];
  3835. if (typeof title === "string" && /\D/m.test(title)) { // textContentでサーチする
  3836. for (let res of elegeta('.message')) { // レス本文
  3837. if (res.textContent.indexOf(title) !== -1) resHit.push(res.parentNode);
  3838. }
  3839. for (let res of elegeta('.uid')) { // ID
  3840. if (res.textContent.indexOf(title) !== -1) resHit.push(res.parentNode.parentNode);
  3841. }
  3842. }
  3843. return resHit;
  3844. },
  3845. funcQ: function() {
  3846. setTimeout(() => {
  3847. $('div.post:hidden').next("br").css("display", "none");
  3848. $('div.post:visible').next("br:hidden").css("display", "block");
  3849. }, 200);
  3850. }, //余計な改行を詰める
  3851. funcB: () => SITE.funcQ(),
  3852. funcOnlyFirst: () => {
  3853. GM_addStyle('.uid:hover{background:#ddeeffc0; border: 0px solid #ddeeffc0; color: #000000; text-shadow: 0 0 4px #ddeeffc0; box-shadow: inset 0 0 6px #ddeeffc0, 0 0 6px #ddeeffc0; }')
  3854. // 旧表示なら対応するために加工
  3855. if (/\.shitaraba\.net\/bbs\/read\.cgi\/|\.shitaraba\.net\/bbs\/read_archive.cgi\//.test(location.href)) $('dl.rep-comment:hidden').remove(); // したらばでは本家の>>1等のアンカーの中に見えないHTMLのコピーがありQ等がそれに反応してしまうので消す
  3856. if (/\.5ch\.net\/test\/read\.cgi\/|\.shitaraba\.net\/bbs\/read\.cgi\/|\.shitaraba\.net\/bbs\/read_archive.cgi\//.test(location.href) && eleget0("//div/dl/dt|//body/dl/dt")) {
  3857. if (/\.shitaraba\.net\/bbs\/read/.test(location.href) && eleget0("//div/dl/dt|//body/dl/dt")) { $('dl>br').remove() }
  3858. elegeta('.thread dd').forEach(e => elegeta('br', e)?.pop()?.remove()) // 本文末尾の空改行をtrim
  3859. var res1 = elegeta("//div/dl/dt|//body/dl/dt").slice(0, 1001)
  3860. var res2 = elegeta("//div/dl/dd|//body/dl/dd").slice(0, 1001)
  3861. if (res1.length && res1.length == res2.length) {
  3862. GM_addStyle('div.post{border-width: 1px; display: inline-block; border-style: none solid solid none; border-color: #ddd; background-color: #efefef; margin-bottom: 8px; padding: 8px;}div.meta { margin: 0 0 0.33em; } .message { font-size: 17px; color: #333; padding: 2px 0 10px; overflow-wrap: break-word; }')
  3863. GM_addStyle('div.post2{background-color:#efefef; display:inline-block; padding:1em; margin:0; box-shadow: 1px 1px 2px #cccccc;} div.meta{margin:0 0 0.33em;} ') // line-height:1.2em;
  3864. var e = eleget0('//div/dl[@class="thread"]/../../../..|//div[@id="thread-body-wrapper"]/..');
  3865. if (e) e.style.backgroundColor = "#f2f3f7";
  3866. var e = eleget0('//body/div/span[@style="float:left;"]');
  3867. if (e) e.style.float = "none";
  3868. res1.forEach((e, i) => {
  3869. var res1t = e.textContent; // innerTextは遅い
  3870. var res2o = res2[i].outerHTML; //alert(res2o)
  3871. while (/<br>[\s]{0,22}\<\/dd\>/.test(res2o)) res2o = res2o.replace(/<br>[\s]{0,22}\<\/dd\>/, "</dd>"); // 後ろの空改行をtrim
  3872. e.outerHTML = `<div class="post"><div class="meta" alt="${res1t.replace(/ |\s|:/g,"").trim()}"><span class="date">${res1[i].innerHTML}</span></div><div class="message"><span class="escaped">${res2o.replace(/^<dd>/,"").replace(/<\/dd>/,"")}</span></div></div><br>`;
  3873. res2[i].remove();
  3874. });
  3875. }
  3876. elegeta('//div[@class="post"]/div[1]/span[@class="date"]').slice(0, 1001).forEach(e => { e.closest(".post").id = e.textContent.trim().match0(/^\d+/) || null; })
  3877. adja(document.body, "beforeend", "<span id='ch5styleoldnewmodend'><span>"); //加工終了を告げる
  3878. }
  3879. //ct(() => { if (ld(".5ch.net")) elegeta('.number').forEach(e => e.innerText = Number(e.innerText)) }) //test 25 / 1sec
  3880. if (ld(".5ch.net") && lh('/test/read.cgi/')) elegeta('.number').forEach(e => e.innerText = Number(e.innerText)) //test 25 / 1sec
  3881. //ct(() => { if (ld(".5ch.net")) elegeta('.number').forEach(e => e.textContent = Number(e.innerText)) }) //test 26 / 1sec
  3882. //ct(() => { if (ld(".5ch.net")) elegeta('.number').forEach(e => e.innerText= Number(e.textContent)) }) //test 148 / 1sec
  3883. //ct(() => { if (ld(".5ch.net")) elegeta('.number').forEach(e => e.textContent = Number(e.textContent)) }) //test 158 / 1sec
  3884. },
  3885.  
  3886. func: () => {
  3887. for (let e of elegeta('//div[@class="meta"][not(@alt)]').slice(0, 1001)) { // レスの特定のために1行目をまとめてtitle属性に埋める
  3888. let id = e.innerText.replace(/>>.*/g, "").replace(/ |\s|:/g, "").trim();
  3889. e.setAttribute("alt", id); // e.style.pointerEvents="none";
  3890. };
  3891. SITE.funcQ();
  3892. },
  3893. hideSelectedWord: 1,
  3894. },
  3895. {
  3896. id: 'NICODOUGA',
  3897. urlRE: '//www.nicovideo.jp/ranking',
  3898. title: 'h2.NC-CardTitle.NC-CardTitle_fixed3Line',
  3899. box: 'div.NC-Card',
  3900. redoWhenRefocused: 1,
  3901. //listTitleXP: '//div/h2[@class="MediaObjectTitle VideoMediaObject-title MediaObjectTitle_fixed2Line"]',
  3902. //listTitleSearchXP: '//div/h2[@class="MediaObjectTitle VideoMediaObject-title MediaObjectTitle_fixed2Line"][+++]/../../../../..',
  3903. //listTitleMemoSearchXP: '//div/h2[@class="MediaObjectTitle VideoMediaObject-title MediaObjectTitle_fixed2Line"][+++]',
  3904. //listGen: 6,
  3905. },
  3906. {
  3907. id: 'NICODOUGA',
  3908. urlRE: '//www.nicovideo.jp/series/',
  3909. listTitleXP: '//div[@class="VideoMediaObject-title"]/a',
  3910. listTitleSearchXP: '//div[@class="VideoMediaObject-title"]/a[+++]/../../../..',
  3911. listTitleMemoSearchXP: '//div[@class="VideoMediaObject-title"]/a[+++]',
  3912. listGen: 5,
  3913. listTitleHelpXP: '//div[@class="VideoMediaObject-title"]/a/../../../..',
  3914. redoWhenRefocused: 1,
  3915. },
  3916. {
  3917. id: 'NICODOUGA', // nicosea::
  3918. urlRE: '//www.nicovideo.jp/search/|//www.nicovideo.jp/tag/|//www.nicovideo.jp/watch/',
  3919. title: 'ul.videoListInner li.item p.itemTitle>a,a.nrn-contributor-link,div h1.VideoTitle,.nrn-movie-tag-link,p.itemTitle>a',
  3920. box: 'ul.videoListInner li.item , div.WatchAppContainer-main',
  3921. redoWhenRefocused: 1,
  3922. observe: 1000,
  3923. forceTranslucentFunc: () => lh('https://www.nicovideo.jp/watch/'),
  3924.  
  3925. //listGen: 7,
  3926. preventHelpFunc: () => lh('https://www.nicovideo.jp/watch/') && document.fullscreenElement,
  3927. /*detailURLRE: /\/watch\//,
  3928. detailTitleXP: '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]',
  3929. detailTitleSearchXP: '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"][+++]',
  3930. */
  3931. wholeHelp: [() => 1, " A:ソート"],
  3932. keyFunc: [{
  3933. // key: "l", // l::
  3934. key: "s", // s::
  3935. func: (e, evt) => {
  3936. let targets = (elegeta('//div/p[@class="itemTitle"]/a|//h1[contains(@class,"VideoTitle")]'))
  3937. var one = document.elementFromPoint(mousex, mousey)
  3938. //let hover=(eleget0('yt-formatted-string:hover,a:hover'))
  3939. if (targets.includes(one)) {
  3940. //動画タイトル上でsキーでその動画を含む再生リストを検索する
  3941. let title = one?.innerText?.trim()
  3942. let u = encodeURIComponent(title)
  3943. if (u) {
  3944. evt.preventDefault();
  3945. evt.stopPropagation(); // 有効なlキーだったら本来の機能(10秒進む)をキャンセル
  3946. let searchurl1 = `https://www.google.co.jp/search?q=${title.trim()} site:https://www.nicovideo.jp/user/*/mylist/`
  3947. let searchurl = `https://www.google.co.jp/search?q=${u} site:https://www.nicovideo.jp/user/*/mylist/`
  3948. if (confirm(`s:指したタイトルを含む再生リストを検索する\n\n${searchurl1}\n\n${searchurl}\n\nを開きます。よろしいですか?`)) {
  3949. elegeta('video').forEach(v => v.pause());
  3950. window.open(searchurl, "", "noreferrer")
  3951. }
  3952. }
  3953. }
  3954. return false;
  3955. },
  3956. },
  3957. {
  3958. key: 'a', // a::
  3959. func: () => {
  3960. if (lh("/watch")) return;
  3961. var sorttype = GF.yhmSortType || 0;
  3962. let menu = [
  3963. { t: "メモ多", f: () => { sortdom(elegeta('ul.videoListInner li.item:visible'), v => Number(elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  3964. { t: "タイトル", f: () => { sortdom(elegeta('ul.videoListInner li.item:visible'), v => eleget0('//p[@class="itemTitle"]/a', v)?.textContent) } },
  3965. { t: "投稿者", f: () => { sortdom(elegeta('ul.videoListInner li.item:visible'), v => eleget0('//a[@class="nrn-contributor-link"]', v)?.textContent) } },
  3966. { t: "いいね+マイリス", f: () => { sortdom(elegeta('ul.videoListInner li.item:visible'), v => (0 + Number(eleget0('//li[4]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[3]/span[@class="value"]', v)?.textContent || 0)) || -1, 1) } },
  3967. { t: "いいね+マイリス+コメント", f: () => { sortdom(elegeta('ul.videoListInner li.item:visible'), v => (Number(eleget0('//li[2]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[4]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[3]/span[@class="value"]', v)?.textContent || 0)) || -1, 1) } },
  3968. { t: "いいね+マイリス+コメント+再生", f: () => { sortdom(elegeta('ul.videoListInner li.item:visible'), v => (Number(eleget0('//li[2]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[4]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('//li[3]/span[@class="value"]', v)?.textContent || 0) + Number(eleget0('li.count.view>span', v)?.textContent?.replace(/\,/gm, "") || 0) / 1000) || -1, 1) } },
  3969. ]
  3970. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  3971. menu[sorttype].f()
  3972. GF.yhmSortType = (++sorttype) % menu.length
  3973. }
  3974. }, {
  3975. key: 'u', // u::チャプターメモ
  3976. func: (e) => {
  3977. chapterMemo(/watch/, '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]', `https://www.nicovideo.jp/watch/${(location.href.match0(/\/watch\/([^/?]+)/))}?from=**time**`)
  3978. },
  3979. }, {
  3980. key: 'Shift+U', // Shift+U::チャプターメモをクリップボードにコピー
  3981. func: (e) => {
  3982. chapterMemo(/watch/, '//div/div[@class="HeaderContainer-topAreaLeft"]/h1[@class="VideoTitle"]', `https://www.nicovideo.jp/watch/${(location.href.match0(/\/watch\/([^/?]+)/))}?from=**time**`, 1)
  3983. },
  3984. }
  3985. ],
  3986. funcOnlyFirst: () => {
  3987. document.addEventListener('fullscreenchange', (event) => { if (document.fullscreenElement && $('video')[0] && $('video')[0].paused == false) { $("#yafuokuhelp").hide(200) } else { $("#yafuokuhelp").show(300) } })
  3988. var observeUrlHasChangedhref = location.href;
  3989. var observeUrlHasChanged = new MutationObserver(mutations => {
  3990. if (observeUrlHasChangedhref !== location.href) {
  3991. pauseAll = 1;
  3992. prefCacheClear();
  3993. observeUrlHasChangedhref = location.href;
  3994. elegeta('//span[contains(@class,"yhmMyMemo")]/..').forEach(e => e.remove());
  3995. setTimeout(() => {
  3996. pauseAll = 0;
  3997. run(document.body, "returned")
  3998. }, 3500);
  3999. }
  4000. });
  4001. observeUrlHasChanged.observe(document, { childList: true, subtree: true });
  4002. },
  4003. }, {
  4004. id: 'NICODOUGA', // タイトルをキーにする
  4005. urlRE: '//www.nicovideo.jp/user/.*/video|//www.nicovideo.jp/user/.*/series',
  4006. title: 'h2.NC-MediaObjectTitle.NC-VideoMediaObject-title.NC-MediaObjectTitle_fixed2Line',
  4007. box: 'div.NC-MediaObject',
  4008. redoWhenRefocused: 1,
  4009.  
  4010. /*listTitleXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2',
  4011. listTitleSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]/../../../../..',
  4012. listTitleMemoSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]',
  4013. listGen: 5,*/
  4014. observe: 500,
  4015. wholeHelp: [() => 1, " A:ソート"],
  4016. keyFunc: [{
  4017. key: 'a', // a::
  4018. func: () => {
  4019. let menu = [
  4020. { t: "メモ総長順", f: () => { sortdom(elegeta('.NC-MediaObject.NC-VideoMediaObject.VideoContainer-item'), v => (elegeta('.yhmMyMemoO', v)?.reduce((a, b) => b?.textContent?.length + a, 0) || 0) - (elegeta('.yhmMyMemoX', v).reduce((a, b) => b?.textContent?.length + a, 0) || 0), 1) } }, // ○メモとチャプターメモは+文字数、×メモは-文字数評価
  4021. ]
  4022. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == GF.yhmSortType ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  4023. menu[GF.yhmSortType].f()
  4024. GF.yhmSortType = ((GF?.yhmSortType + 1) % menu.length)
  4025. },
  4026. }],
  4027. // func: function(node) { for (let ele of elegeta('//div/p[@class="itemTitle"]/a', node)) ele.textContent = ele.title; }, // 長いタイトルが...で省略されているとヒットしないのでtitleプロパティから取り出す
  4028. }, {
  4029. id: 'NICODOUGA', // タイトルをキーにする
  4030. urlRE: '//www.nicovideo.jp/user/.*?/mylist/', // バグらなくなった
  4031. title: 'h2.NC-MediaObjectTitle.NC-VideoMediaObject-title.NC-MediaObjectTitle_fixed2Line',
  4032. box: 'div.NC-MediaObject',
  4033. redoWhenRefocused: 1,
  4034.  
  4035. /*listTitleXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2',
  4036. listTitleSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]/../../../../..',
  4037. listTitleMemoSearchXP: '//div[@class="NC-MediaObject-bodyTitle"]/h2[+++]',
  4038. listGen: 6,*/
  4039. observe: 500,
  4040. listTitleXPIgnoreNotExist: 1,
  4041. wholeHelp: [() => 1, " A:ソート"],
  4042. keyFunc: [{
  4043. key: 'a', // a::
  4044. func: () => {
  4045. let menu = [
  4046. { t: "メモ総長順", f: () => { sortdom(elegeta('div.NC-MediaObject.NC-VideoMediaObject.MylistItem.MylistItemList-item.NC-VideoMediaObject_thumbnailWidth192.NC-MediaObject_withAction.NC-MediaObject_withFooter'), v => (elegeta('.yhmMyMemoO', v)?.reduce((a, b) => b?.textContent?.length + a, 0) || 0) - (elegeta('.yhmMyMemoX', v).reduce((a, b) => b?.textContent?.length + a, 0) || 0), 1) } }, // ○メモとチャプターメモは+文字数、×メモは-文字数評価
  4047. ]
  4048. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == GF.yhmSortType ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  4049. menu[GF.yhmSortType].f()
  4050. GF.yhmSortType = ((GF?.yhmSortType + 1) % menu.length)
  4051. },
  4052. }],
  4053. // reloadWhenUrlHasChanged:1,
  4054. },
  4055. {
  4056. id: 'NICODOUGA',
  4057. urlRE: '//www.nicovideo.jp/my/mylist|www.nicovideo.jp/my/watchlater',
  4058. listTitleXP: '//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"]',
  4059. listTitleSearchXP: '//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"][+++]/../../../../../..',
  4060. listTitleMemoSearchXP: '//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"][+++]',
  4061. redoWhenRefocused: 1,
  4062. delay: 2000,
  4063. listGen: 5,
  4064. listTitleXPIgnoreNotExist: 1,
  4065. // reloadWhenUrlHasChanged:1,
  4066. wholeHelp: [() => 1, " A:ソート"],
  4067. keyFunc: [{
  4068. // key: "l", // l::
  4069. key: "s", // s::
  4070. func: (e, evt) => {
  4071. let targets = (elegeta('//h2[@class="NC-MediaObjectTitle NC-VideoMediaObject-title NC-MediaObjectTitle_fixed2Line"]'))
  4072. var one = document.elementFromPoint(mousex, mousey)
  4073. //let hover=(eleget0('yt-formatted-string:hover,a:hover'))
  4074. if (targets.includes(one)) {
  4075. //動画タイトル上でsキーでその動画を含む再生リストを検索する
  4076. let title = one?.innerText?.trim()
  4077. let u = encodeURIComponent(title)
  4078. if (u) {
  4079. evt.preventDefault();
  4080. evt.stopPropagation(); // 有効なlキーだったら本来の機能(10秒進む)をキャンセル
  4081. let searchurl1 = `https://www.google.co.jp/search?q=${title.trim()} site:https://www.nicovideo.jp/user/*/mylist/`
  4082. let searchurl = `https://www.google.co.jp/search?q=${u} site:https://www.nicovideo.jp/user/*/mylist/`
  4083. if (confirm(`s:指したタイトルを含む再生リストを検索する\n\n${searchurl1}\n\n${searchurl}\n\nを開きます。よろしいですか?`)) {
  4084. elegeta('video').forEach(v => v.pause());
  4085. window.open(searchurl, "", "noreferrer")
  4086. }
  4087. }
  4088. }
  4089. return false;
  4090. },
  4091. },
  4092. {
  4093. key: 'a', // a::
  4094. func: () => {
  4095. if (lh("https://www.nicovideo.jp/my/watchlater|https://www.nicovideo.jp/my/mylist/")) {
  4096. var sorttype = GF.yhmSortType || 0
  4097. let menu = [
  4098. // { t: "時間長", f: () => { sortdom(elegeta('//section[@class="WatchLaterContainer"]/div[last()]/div'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, "")), 1) } },
  4099. // { t: "時間短", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => Number(v?.querySelector('span.ytd-thumbnail-overlay-time-status-renderer')?.textContent?.replace(/[^0-9]/gmi, ""))) } },
  4100. { t: "メモ多", f: () => { sortdom(elegeta('//div[@class="VideoMediaObjectList"]/div'), v => (elegeta('.yhmMyMemoO', v)?.length || 0) - (elegeta('.yhmMyMemoX', v)?.length || 0), 1) } }, // ○メモとチャプターメモは+1、×メモは-1評価
  4101. // { t: "タイトル", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('#video-title', v)?.textContent?.trim()) } },
  4102. // { t: "投稿者", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('div.style-scope.ytd-channel-name yt-formatted-string a', v)?.textContent?.trim() || "") } },
  4103. // { t: "再生多", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 1) } },
  4104. // { t: "再生少", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//yt-formatted-string[@id="video-info"]/span[@dir="auto" and @class="style-scope yt-formatted-string" and contains(text(),"回視聴")]', v)?.textContent; return parseFloat(n) * (n?.match0("万") ? 10000 : n?.match0("億") ? 100000000 : 1) }, 0) } },
  4105. // { t: "古い", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 1) } },
  4106. //{ t: "新しい", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => { let n = eleget0('//div[@id="metadata"]/div/yt-formatted-string/span[contains(text(),"前")]', v)?.textContent; return parseFloat(n) * (n?.match0("時間") ? 0.0416 : n?.match0("分") ? 0.00025 : n?.match0("週間") ? 7 : n?.match0("か月") ? 31 : n?.match0("年") ? 365 : 1) }, 0) } },
  4107. // { t: "逆順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 1) } },
  4108. // { t: "元順", f: () => { sortdom(elegeta('#contents ytd-playlist-video-renderer'), v => eleget0('//yt-formatted-string[@id="index"]', v)?.textContent, 0) } },
  4109. ]
  4110. popup2("A:ソート\n" + (menu.map((c, i) => " " + c.t + (i == sorttype ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  4111. menu[sorttype].f()
  4112. GF.yhmSortType = (++sorttype) % menu.length
  4113. return
  4114. }
  4115. }
  4116. }
  4117. ],
  4118. },
  4119. {
  4120. id: 'RTINGS',
  4121. urlRE: 'www.rtings.com/.*?/tools/table|//www.rtings.com/.*?/reviews/',
  4122. listTitleXP: '//div/div[@class="table_cell_product-name"]',
  4123. listTitleSearchXP: '//div/div[@class="table_cell_product-name"][***]/../../../../..',
  4124. listTitleMemoSearchXP: '//div/div[@class="table_cell_product-name"][***]/..|//span[@class="e-page_title-primary"][***]',
  4125. listGen: 3,
  4126. listTitleXPIgnoreNotExist: 1,
  4127. delay: 3000,
  4128. observe: 1000,
  4129. detailURLRE: /\/\/www.rtings.com\/.*?\/reviews\//,
  4130. detailTitleXP: '//span[@class="e-page_title-primary"]',
  4131. detailTitleSearchXP: '//span[@class="e-page_title-primary"][***]/../../../../..',
  4132. },
  4133. {
  4134. id: 'TAMESHIYOMI',
  4135. urlRE: 'csbs.shogakukan.co.jp',
  4136. listTitleXP: '//div[1]/img[@class="is-item-cover loaded"]',
  4137. listTitleSearchXP: '//div[1]/img[@class="is-item-cover loaded" and ++alt++]/../../..',
  4138. listTitleMemoSearchXP: '//div[1]/img[@class="is-item-cover loaded" and ++alt++]',
  4139. listGen: 3,
  4140. listTitleXPIgnoreNotExist: 1,
  4141. delay: 1000,
  4142. observe: 1500,
  4143. redoWhenReturned: 1,
  4144. },
  4145. {
  4146. id: 'TAMESHIYOMI',
  4147. urlRE: '//sokuyomi.jp/free_',
  4148. listTitleXP: '//p[@class="title"]/a|//h1[@class="title"]',
  4149. listTitleSearchXP: '//p[@class="title"]/a[++title++]/../..',
  4150. listTitleMemoSearchXP: '//p[@class="title"]/a[++title++]', // 多分表示されない
  4151. listGen: 3,
  4152. observe: 900,
  4153. listHelpXP: '//div[@id="content"]/div/ul/li',
  4154. redoWhenReturned: 1,
  4155. },
  4156. {
  4157. id: 'TAMESHIYOMI',
  4158. urlRE: '//sokuyomi.jp/free\.',
  4159. listTitleXP: '//img[@class="waku"]',
  4160. listTitleSearchXP: '//img[@class="waku" and ++alt++]/../..',
  4161. listTitleMemoSearchXP: '//img[@class="waku" and ++alt++]',
  4162. listHelpXP: '//div[@id="content"]/div/ul/li',
  4163. listGen: 3,
  4164. observe: 600,
  4165. redoWhenReturned: 1,
  4166. },
  4167. {
  4168. urlRE: '//ebookjapan.yahoo.co.jp/viewer',
  4169. func: () => {
  4170. //$().ready(() => { setTimeout(() => { document.title = (eleget0('//div[@class="header__title"]').innerText || "") + " " + document.title; }, 2000); });
  4171. },
  4172. },
  4173. {
  4174. id: 'TAMESHIYOMI',
  4175. urlRE: '//ebookjapan.yahoo.co.jp/free|//ebookjapan.yahoo.co.jp/ranking/details/free/',
  4176. listTitleXP: '//p[@class="book-item__title"]',
  4177. listTitleSearchXP: '//p[@class="book-item__title"][***]/../..',
  4178. listTitleMemoSearchXP: '//p[@class="book-item__title"][***]',
  4179. listGen: 3,
  4180. titleProcessFunc: (title) => { return title.replace(/\s[0-90-9]+巻?$/gmi, "").replace(/[(\(][0-90-9]+巻?[)\)]$/gmi, "").replace(/【期間限定.*?】|【フルカラー】/g, "").replace(/\s\d+冊/gmi, "").replace(/\.\.\./gmi, "").trim() },
  4181. observe: 1000,
  4182. redoWhenReturned: 1,
  4183. },
  4184. {
  4185. id: 'TAMESHIYOMI',
  4186. urlRE: 'booklive.jp/index/no-charge',
  4187. listTitleXP: '//p[@class="p-no-charge-book-item__title"]/a',
  4188. listTitleSearchXP: '//p[@class="p-no-charge-book-item__title"]/a[***]/../../..',
  4189. listTitleMemoSearchXP: '//p[@class="p-no-charge-book-item__title"]/a[***]',
  4190. listGen: 5,
  4191. titleProcessFunc: (title) => { return title.replace(/\s[0-90-9]+巻?$/gmi, "").replace(/[(\(][0-90-9]+巻?[)\)]/gmi, "").replace(/【.*?】|(.*?)|分冊版[\s::]*|合冊版[\s::]*/g, "").replace(/第?[0-90-9]+話?$/gmi, "").trim() },
  4192. listTitleXPIgnoreNotExist: 1,
  4193. observe: 1000,
  4194. redoWhenReturned: 1,
  4195. },
  4196. {
  4197. id: 'WCA',
  4198. urlRE: 'webcomics\.jp',
  4199. title: '.entry-title>a:first-child,.entry-site>a:first-child,div.comic-title>h2>a:nth-child(1),.comic-site>a',
  4200. box: ".entry,#main-container #main",
  4201. trim: 1,
  4202. XP2name: 'サイト名 ',
  4203. XP2memo: 1,
  4204. listHelpJQS: 'div.entry',
  4205. helpInBlock: 1,
  4206. redoWhenReturned: 1,
  4207. func: function(node) { // width 880-600→1180-900
  4208. if (node === document.body && document.documentElement.clientWidth > 1200 && ($("#page").css("width")) == "880px") {
  4209. $("#main-container").css("width", "900px");
  4210. $("#page").css("width", "1180px");
  4211. }
  4212. },
  4213. autoTranslucentURLRE: /mylist|bookmark|https:\/\/webcomics\.jp\/[^\/]+\/\d+$/,
  4214. wholeHelp: [() => 1, ` u:重複作品を隠す h:ソート`],
  4215. keyFunc: [{
  4216. key: 'u', // u::uniq
  4217. func: () => {
  4218. let undup = [],
  4219. dup = []
  4220. elegeta('div.entry-title>a:first-child:visible').reverse().sort((a, b) => eleget0('.entry-site>a:first-child', a.closest(".entry")).innerText.match0(/ComicWalker|ヤンマガWeb|ガンマ/gmi) ? 1 : -1).forEach(e => {
  4221. if (undup.includes(e.textContent?.trim())) {
  4222. e.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
  4223. $(e.closest(".entry")).hide(999, function() { $(this).remove() }); //e?.closest(".entry")?.remove()
  4224. dup.push(e.textContent?.trim())
  4225. } else { undup.push(e.textContent?.trim()) }
  4226. })
  4227. popup2(`u:重複タイトルを隠す\n${dup.join("\n")}`, 6)
  4228. }
  4229. }, {
  4230. key: 'h', // h::
  4231. func: () => {
  4232. let menu = [
  4233. { t: "メモ総長順", f: () => { sortdom(elegeta('.entry'), v => (elegeta('.yhmMyMemoO,[data-gakusai]', v)?.reduce((a, b) => b?.textContent?.length + a, 0) || 0) - (elegeta('.yhmMyMemoX', v).reduce((a, b) => b?.textContent?.length + a, 0) || 0), 1) } }, // ○メモとチャプターメモは+文字数、×メモは-文字数評価
  4234. { t: "名前順", f: () => domsort("", elegeta('.entry'), (v) => { return ((v.querySelector('div.entry-title>a')).innerText?.trim()) || "" }, 3) },
  4235. { t: "作者順", f: () => domsort("", elegeta('.entry'), (v) => { return eleget0('//a[@class="autele aut autname"]', v)?.innerText?.trim() || "" }, 3) },
  4236. { t: "サイト順", f: () => domsort("", elegeta('.entry'), (v) => { return eleget0('//div[@class="entry-site"]/a', v).innerText?.trim() || "" }, 3) },
  4237. ]
  4238. popup2("h:ソート\n" + (menu.map((c, i) => " " + c.t + (i == GF.yhmSortType ? " ←\n" : "\n")).join("")), 6, `min-width:${menu.reduce((p,c)=>Math.max(p,c.t.length+3),0)}em;`);
  4239. menu[GF.yhmSortType].f()
  4240. GF.yhmSortType = ((GF?.yhmSortType + 1) % menu.length)
  4241. },
  4242. }],
  4243. },
  4244. {
  4245. id: 'YAJ2', // yafuoku::
  4246. urlRE: '://auctions.yahoo.co.jp/search/|://page.auctions.yahoo.co.jp/jp/auction/|://auctions.yahoo.co.jp/category/list/',
  4247. title: 'h3.Product__title>a,h1.ProductTitle__text,div.Product__sellerArea>a,div>p.Seller__name>a,div p.Seller__name>a',
  4248. titleSubstr: true,
  4249. box: 'li.Product,div.l-contentsBody',
  4250. forceTranslucentFunc: e => e?.closest('div.l-contentsBody') && lh("/auction/"),
  4251. trim: 1,
  4252. redoWhenRefocused: 1,
  4253. listTitleXP2: '//div[@class="Product__sellerArea"]/a|//span[@class="Seller__name"]/a[1]|//p[@class="Seller__name"]/a',
  4254. XP2name: '出品者名 ',
  4255. XP2memo: 1,
  4256. listGen: 6,
  4257. listHelpXP: '//li[@class="Product"]',
  4258. //helpInBlock: 1,
  4259. wholeHelp: [() => 1, " " + KEYMAXP + ":価格上限"],
  4260. detailURLRE: /:\/\/page.auctions.yahoo.co.jp\/jp\/auction\//, // automemoのために必要
  4261. detailTitleXP: '//h1[@class="ProductTitle__text"]', // automemoのために必要
  4262. detailTitleSearchXP: '//h1[@class="ProductTitle__text" and ***]/../../../..|//span[@class="Seller__name"]/a[+++]/../../../../../../../../../../..|.//span[@class="Seller__name"]/a[1][+++]|//p[@class="Seller__name"]/a[+++]/ancestor::div[@class="l-containerInner"]',
  4263. func: () => { elegeta(SITE.title).forEach(e => e.innerText = e.innerText?.trim()) },
  4264.  
  4265. maxpriceXP: '//input[@class="InputText__input" and @name="max"]',
  4266. automemoForceFunc: () => lh("://page.auctions.yahoo.co.jp/jp/auction/"),
  4267. automemoURLRE: "://page.auctions.yahoo.co.jp/jp/auction/",
  4268. automemoSearchFunc: () => { return eletext('//div[@class="ProductExplanation__commentArea"]') + "\n" + eletext('//div[@id="ProductProcedures"]') + "\n" + eletext('//h1[@class="ProductTitle__text"]') + '\n' + eletext('//ul[@class="ProductInformation__items"]/li[2]') + '\n' + eletext('//div/div[@class="ProductDetail"]') + '\n' + eletext('//ul/li[@class="ProductInformation__item"]/section[@class="Section"]'); },
  4269. automemoFunc: () => {
  4270. for (let am of CUSTOMAUTOMEMORE) { autoMemo(am); }
  4271. autoMemo(/(レターパック[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4272. autoMemo(/(クリックポスト[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4273. autoMemo(/(ゆうメール[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4274. autoMemo(/(ゆうパケット[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4275. autoMemo(/(ゆうパック[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4276. autoMemo(/(定形外[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4277. autoMemo(/(メール便[^0-90-9\n]*[0-9,0-9,]*円[-~]?)/m);
  4278. autoMemo(/送料.*(全国一律\s*[0-9,0-9,]*.*円[-~]?)/m);
  4279. autoMemo(/送料\s*[::]?(.*[都道府県]は[0-9,0-9,]*円[-~]?)/m);
  4280. autoMemo(/(Pentium.*?GHz)|(Celeron.*?GHz)|(Atom.*?GHz)|(Core\s?i\d.*?GHz)|(AMD.*APU)/mi) ? 0 :
  4281. autoMemo(/(CPU[\s\S]{1,30}?GHz)/mi) ? 0 :
  4282. autoMemo(/^(.*GHz)/gmi) ? 0 :
  4283. autoMemo(/(Pentium[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)|(Celeron[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)|(Atom\s[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)|(Core\s?i\d.[0-9A-Za-z\-_.]*)|(Ryzen\s?\d[0-9A-Za-z\-_.]*\W*[0-9A-Za-z\-_.]*)/mi);
  4284. autoMemo(/([0-90-9]{2,4}年製)/m) ? 0 :
  4285. autoMemo(/([0-90-9]{2,4}年)/m) ? 0 :
  4286. autoMemo(/([0-90-9]{2,4}年製)/m) ? 0 :
  4287. autoMemo(/([0-90-9]{2,4}年)/m);
  4288. autoMemo(/発送元:(.{1,4}[都道府県])/m);
  4289. autoMemo(/(認証制限[\s\S]{1,3}あり)/m);
  4290. },
  4291. showFunc: () => { run(document.body, "returned") },
  4292. },
  4293. {
  4294. id: 'YAJ2',
  4295. urlRE: '://auctions.yahoo.co.jp/seller/',
  4296. listTitleXP: '//a[@class="Product__titleLink"]|.//a[@class="Product__titleLink u-textBold"]|.//div[@class="a1wrp"]/h3/a',
  4297. listTitleXP2: '//div/div[@class="seller__subInfo"]/span[@class="seller__yid"]',
  4298. XP2name: '出品者名 ',
  4299. XP2memo: 1,
  4300. listGen: 4,
  4301. listHelpJQS: "div.a1,#list01 table tbody tr td",
  4302. listTitleSearchXP: '//div[@class="a1wrp"]/h3/a[***]/../../../..|.//div[@class="a1wrp"]/h3/a/em[***]/../../../../..|//div/div[@class="seller__subInfo"]/span[@class="seller__yid"][+++]',
  4303. listTitleMemoSearchXP: '//div[@class="a1wrp"]/h3/a[***]|.//div[@class="a1wrp"]/h3/a/em[***]/..|//div/div[@class="seller__subInfo"]/span[@class="seller__yid"][+++]',
  4304. redoWhenReturned: 1,
  4305. },
  4306. {
  4307. id: 'YAJ2',
  4308. urlRE: 'userbenchmark',
  4309. },
  4310. {
  4311. id: 'AMAZON',
  4312. urlRE: 'https://www.amazon.co.jp/product-reviews/',
  4313. title: '//a[@data-hook="product-link"]',
  4314. box: 'div#a-page',
  4315. forceTranslucentFunc: e => 1,
  4316. }, {
  4317. id: 'AMAZON', //amazon:: ama::
  4318. listTitleXPIgnoreNotExist: 1,
  4319. // urlRE: /www\.amazon\.co\.jp\/s\?k\=|www\.amazon\.co\.jp.*\/dp\/.*/,
  4320. urlRE: /www\.amazon\.co\.jp\/s\?|www\.amazon\.co\.jp.*\/dp\/.*/,
  4321. //title: 'a.a-link-normal.s-underline-text.s-underline-link-text.s-link-style.a-text-normal>span,div#title_feature_div.celwidget[data-feature-name="title"]>div#titleSection.a-section.a-spacing-none>h1#title>span#productTitle,h1#title span',
  4322. //box: 'div.s-asin,div#dp-container',
  4323. //title: 'h2.a-size-mini.a-spacing-none.a-color-base.s-line-clamp-4,span#productTitle.a-size-large.product-title-word-break',
  4324. title: 'span#productTitle.a-size-large.product-title-word-break,span.a-size-base-plus.a-color-base.a-text-normal', //'h2.a-size-mini.a-spacing-none.a-color-base.s-line-clamp-4,span#productTitle.a-size-large.product-title-word-break,span.a-size-base-plus.a-color-base.a-text-normal',
  4325. //title: 'h2.a-size-mini.a-spacing-none.a-color-base.s-line-clamp-4,span#productTitle.a-size-large.product-title-word-break,span.a-size-base-plus.a-color-base.a-text-normal',
  4326. box: 'div.s-asin,div#dp-container',
  4327. memoFunc: e => e.parentNode,
  4328. //delay:1600,observe:1600, // 非表示の前にヨドバシ量単価を先に処理させるため1500以上にしたほうがいい
  4329. redoWhenReturned: 1,
  4330.  
  4331. //memoFunc: e => e.parentNode.parentNode,
  4332. forceTranslucentFunc: e => e.closest('div#dp-container'),
  4333. detailTitleSearchXP: '//span[@id="productTitle" and ***]/../../../../../..|//h1/a[@class="a-link-normal" and ***]/../../../../../../../../../../../../..|//div[@class="p13n-sc-truncate-desktop-type2 p13n-sc-truncated"][***]/../../../../..',
  4334. listGen: 12,
  4335. listHelpXP: '//div[@data-asin][.//span[@class="a-size-base a-color-base a-text-normal"]]|.//div[@data-asin][.//span[contains(@class,"a-size-medium a-color-base a-text-normal")]]',
  4336. trim: true,
  4337. func: () => {
  4338. // !lh(/\/dp\/|\/gp\//)&&lh(/\/s\?|\/b\//)&&elegeta('[data-asin] span.a-icon-alt:not([data-starpop])').forEach(e=>{after(e?.parentNode,`<span style="float:right;" data-estars="${parseFloat(e?.textContent.match0(/5つ星のうち([0-9\.]+)/)) }">${e?.textContent}</span>`);e.dataset.starpop=1;})
  4339. //!lh(/\/dp\/|\/gp\//)&&lh(/\/s\?|\/b\//)&&elegeta('[data-asin] span.a-icon-alt:not([data-starpop])').forEach(e=>{after(e?.parentNode,` <span data-estars="${parseFloat(e?.textContent.match0(/5つ星のうち([0-9\.]+)/)) }">(${e?.textContent.match0(/5つ星のうち([0-9\.]+)/)})</span>`);e.dataset.starpop=1;})
  4340. !lh(/\/dp\/|\/gp\//) && lh(/\/s\?|\/b\//) && elegeta('[data-asin] span.a-icon-alt:not([data-starpop])').forEach(e => {
  4341. before(e?.parentNode, `<span data-estars="${parseFloat(e?.textContent.match0(/5つ星のうち([0-9\.]+)/)) }">${e?.textContent.match0(/5つ星のうち([0-9\.]+)/||"0")+" "||""}</span>`);
  4342. e.dataset.starpop = 1;
  4343. })
  4344.  
  4345. //elegeta('//*[@class="s-line-clamp-2"]|.//*[@class="s-line-clamp-3"]').forEach(e => e.style.maxHeight = "auto");
  4346. //elegeta('//div[@class="a-section a-spacing-none"]/div[1]/h2/a[@class="a-link-normal a-text-normal"]/span').forEach(e => e.style.display = "inline-block") // 商品名を広く表示する
  4347. },
  4348. observeTagName: "DIV",
  4349. // listHelpJQS: 'div[data-asin]',
  4350. detailURLRE: /\/dp\/|\/product-reviews\//,
  4351. detailTitleXP: '//h1[@id="title"]/span[@id="productTitle"]',
  4352. hideListEvenDetail: 1,
  4353.  
  4354. automemoURLRE: /https:\/\/www.amazon.co.jp.*\/dp\//,
  4355. // automemoSearchFunc: () => { return eletext(['//div[@id="ppd"]/div[4]', '//div/div[@data-template-name="productDescription" and @id="productDescription_feature_div"]', '//div[@data-template-name="productDescription"]', '//div[@id="important-information"]', '//div[@id="prodDetails"]']); },
  4356. automemoSearchFunc: () => { return eletext([`//div[contains(@class,"celwidget aplus-module module-9 aplus-standard")]`, '//div[@id="ppd"]/div[4]', '//div/div[@data-template-name="productDescription" and @id="productDescription_feature_div"]', '//div[@data-template-name="productDescription"]', '//div[@id="important-information"]', '//div[@id="prodDetails"]', '//div[@class="a-box a-last"]/div[@class="a-box-inner"]', 'div#buyBoxAccordion.a-box-group.a-accordion.a-spacing-large']); },
  4357. automemoFunc: () => {
  4358. if (eleget0('//div[@id="nav-subnav" and @data-category="beauty"]|//div[@id="nav-subnav" and @data-category="hpc"]|//div[@id="nav-subnav" and @class="spacious subnav-untied"]')) {
  4359. [/(イソプロピルメチルフェノール)/m, /(IPMP)/m, /(塩化セチルピリジニウム|塩化セシルピリジニウム|セチルピリジニウム塩化物)/m, /(CPC)/m, /(塩化ベンザルコニウム)/m, /(BKC)/m, /(ラウロイルサルコシンナトリウム|ラウロイルサルコシンNa|ラウロイルサルコシンNa)/m, /(LSS)/m, /(塩化ベンゼトニウム)/m, /(BTC)/m, /(クロルヘキシジン)/m, /(CHG)/m, /(グリチルリチン酸アンモニウム)/m, /(イプシロン.アミノカプロン酸)/m, /(ε.ACA)/m, /(トラネキサム酸)/m, /(TXA)/m, /(グリチルリチン酸ジカリウム|グリチルリチン酸二カリウム|グリチルリチン酸2K|グリチルリチン酸2K|GK2)/mi, /(1\,?450\s?ppm)/m, /(高?濃?度?フッ化ナトリウム|高?濃?度?フッ素)/m, /(ハイドロオ?キシアパタイト)/m, /(リン酸化オリゴ糖カルシウム)/m, /(POs-Ca|POs-Ca)/mi, /(カゼインホスホペプチド.非結晶性リン酸カルシウム|リカルデント)/m, /(CPP-ACP)/m, /(チモール)/m, /(サリチル酸メ?チ?ル?)/m, /(1\,8-シネオール)/m, /(トリクロサン)/m, /(トリクロカルバン)/m, /(オクトピロックス|オクトロピックス|ピロクトン.?オラミン)/m, /(Znピリチオン|ジンクピリチオン)/m, /(硫黄|イオウ)/m, /(アラントイン)/m, /(グリチルリチン酸アンモニウム)/m, /(ミコナゾール硝?酸?塩?)/m, /(クロラムフェニコール)/m, /(フラジオマイシン硫?酸?塩?)/m, /(ナイスタチン)/m, /(塩化亜鉛)/m, /(ポビドン.?ヨード)/m, /(ラウリルジアミノエチルグリシンナトリウム)/m, /(カキタンニン)/m, /(チャエキス)/m, /(ローズマリー)/m, /(カンゾウ)/m, /(クマザサ)/m, /(セージ)/m, /(シソエキス)/m, /(β?-?グリチルレチン酸?)/m, /(メントール)/m, /(ポリリン酸ナトリウム|ポリリン酸Na)/m, /(ヒノキチオール)/m, /(ティーツリー油オ?イ?ル?)/m, /(ティートゥリー油オ?イ?ル?)/m].forEach(m => autoMemo(m));
  4360. }
  4361. if (eleget0('//div/div[@id="nav-subnav" and @data-category="electronics"]|//div/div[@data-category="musical-instruments"]/a[1]')) {
  4362. [/([\d\s\,]+mAh)/m, /([\d\s\,]+mAh)/m, /([\d\s\,]{2,9}回)/m, /(感度.{1,20}dB)/mi].forEach(m => autoMemo(m));
  4363. // [/([\d\s\,]+mAh)/m, /([\d\s\,]+mAh)/m, /([\d\s\,]{2,9}回)/m].forEach(m => autoMemo(m));
  4364. }
  4365. if (eleget0('//div[@id="nav-subnav" and @data-category="kitchen"]|//div[@id="nav-subnav" and @data-category="home"]')) {
  4366. [/([0-90-9++]+?物質)/m, /([0-90-9++]+?項目)/m, /(交換.{1,19}[0-9.]+ヶ月)|(交換.{1,19}[0-9.]+年)|(取替.{1,19}[0-9.]+ヶ月)|(取替.{1,19}[0-9.]+年)/m].forEach(m => autoMemo(m));
  4367. [/(低圧\D?\d+kpa)/mi, /(高圧\D?\d+kpa)/mi, /(圧力[\::]\d+kPa)/mi].forEach(m => autoMemo(m));
  4368. }
  4369. if (eleget0('//div[@id="nav-subnav" and @data-category="food-beverage"]')) {
  4370. [/(食物繊維\D{0,9}[0-9.]+[gg])/m].forEach(m => autoMemo(m));
  4371. }
  4372. if (eleget0('//div/a/span/img[@alt="AMAZON FASHION"]|//span[@class="nav-a-content" and contains(text(),"産業・研究開発用品")]')) {
  4373. [/(ハイパーV)|(Hyper.?V)|(.?先芯.{0,3})/mi].forEach(m => autoMemo(m));
  4374. }
  4375. if (eleget0('//div[@data-category="diy"]/a[1]/span[contains(text(),"DIY・工具・ガーデン")]')) {
  4376. [/(容量[\s\S]{0,3}[0-9\.\, ]+(?:L|L|リットル))/mi, /(容量\((?:L|L|リットル)\):[0-9\.\, ]+)/mi].forEach(m => autoMemo(m));
  4377. }
  4378. if (eleget0('//span[@class="a-list-item"]/a[contains(text(),"カップ・マグ・ソーサー")]|//div[@id="wayfinding-breadcrumbs_container"]/div[@id="wayfinding-breadcrumbs_feature_div"]/ul/li/span/a[contains(text(),"ボウル")]|//a[@class="a-link-normal a-color-tertiary" and contains(text(),"食器・グラス・カトラリー")]')) {
  4379. [/(容量[\s約\:]*[0-9\.\,]+\s*(?:ml|cc|L|L|リットル))/mi, /(容量\((?:ml|cc|L|L|リットル)\):[0-9\.\,]+)/mi].forEach(m => autoMemo(m));
  4380. }
  4381.  
  4382. let cat = elegeta('//li/span[contains(@class,"a-list-item")]/a[contains(@class,"a-link-normal a-color-tertiary")]')
  4383. if (cat.find(e => e.textContent.match0("食器用洗剤")))[/(界面活性剤\s*[\((]+\s*\d+[\%%]+[^\))]*[\))]+)/m].forEach(m => autoMemo(m));
  4384.  
  4385. // [/(出荷元\s*Amazon)/mi, /(発送元\s*\:*\s*Amazon)/mi].forEach(m => autoMemo(m, t => t.replace(/\n/gm, " ")));
  4386. //[/(出荷元\s*\w+)/mi, /(発送元\s*\:*\s*\w+)/mi].forEach(m => autoMemo(m, t => t.replace(/\n/gm, " ")));
  4387. [/(出荷元\s*\S+)/mi, /(発送元\s*\:*\s*\S+)/mi].forEach(m => autoMemo(m, t => t.replace(/\n/gm, " ")));
  4388. },
  4389. funcOnlyFirst: () => {
  4390. Math.random() > 0.5 && addstyle.add('.s-line-clamp-2 { -webkit-line-clamp: none; max-height: 9em; text-align: initial; display: inline !important; } .s-line-clamp-1, .s-line-clamp-2, .s-line-clamp-3, .s-line-clamp-4, .s-line-clamp-5 { -webkit-box-orient: initial; }') // タイトルを…で省略させない
  4391.  
  4392. var observeUrlHasChangedhref = location.href;
  4393. var observeUrlHasChanged = new MutationObserver(mutations => {
  4394. if (observeUrlHasChangedhref !== location.href) {
  4395. prefCacheClear();
  4396. observeUrlHasChangedhref = location.href;
  4397. elegeta('//span[contains(@class,"yhmMyMemo")]').forEach(e => e.parentNode.remove());
  4398. setTimeout(() => { run(document.body, "returned") }, 2500);
  4399. }
  4400. });
  4401. observeUrlHasChanged.observe(document, { childList: true, subtree: true });
  4402. },
  4403. },
  4404. /* { // doc::
  4405. id: '', // GM_setValueで保存するグループ名 同じグループは設定が共通になる
  4406. urlRE: '', // 動作するサイトのURLの一部(正規表現)
  4407. necessaryToWorkFunc: null, // この関数がありfalseなら動作を停止する urlREだけでは非対応ページを絞り込めない時に使用
  4408. listTitleXP: '', // 項目一覧ページの項目名を特定できる要素のXPath title>text>altの順にあるものから利用される
  4409. listTitleXP2: '', // 項目一覧ページの項目名の第2候補を指すXPath これにホバーしていればQキーでこれのinnerTextでもNG登録できる
  4410. XP2name: '', // XP2にホバーした時のガイドに表示する文字列
  4411. XP2memo: 0, // 1だとXP2でも1-6キーのメモを許可
  4412. listTitleSearchXP: '', // 項目一覧ページの項目を消すブロック要素をサーチするXPath 通常listTitleXPにサーチ用マクロを付け/..をいくつかつけたもの
  4413. listTitleSearchFunc: null, // 項目一覧ページの項目を消すブロック要素をサーチする関数 5chのレス本文キーワードNGなどで使用
  4414. listTitleMemoSearchXP: '', // 項目一覧ページと詳細ページのメモを付ける要素をサーチするXPath(一覧と詳細の両方を|でOR記述) 通常listTitleXPやdetailTitleXPにサーチ用マクロを付け/..をいくつかつけたもの
  4415. listTitleMemoSearchXPSameGen: 0, // 1だとメモをタイトルと同じ世代の要素として付ける 0だと1つ親世代
  4416. // サーチ用マクロ; ***:textをcontainsで検索 +++:textを=で検索 ++alt++:altを=で検索 ++title++:titleを=で検索 **url**:hrefをcontainsで検索(要useURL) ++url++:hrefを=で検索(要useURL)
  4417. listGen: 3, // Q12を押した場所の要素からいくつ上まで遡った要素までを当たり判定にするか 必要最小限にする
  4418. listHelpJQS: '', // 項目一覧ページで操作ガイドを表示する要素のJQueryセレクタ ↓でも良い 両方を省略するとlistTitleXPの2つ親の要素で代用 当たり判定とは関係ない
  4419. listHelpXP: '', // 項目一覧ページで操作ガイドを表示する要素のXpath ↑でも良い 両方を省略するとlistTitleXPの2つ親の要素で代用 当たり判定とは関係ない
  4420. helpInBlock: 0, // 1だと操作ガイドを要素のブロック内に表示する
  4421. preventHelpFunc: null, // ()=>trueを返したらヘルプを表示しない判定関数
  4422. detailURLRE: //, // URLにmatchする正規表現、matchすると個別詳細画面だと判断する
  4423. detailTitleXP: '', // 詳細画面で項目名を指すXPath
  4424. detailTitleSearchXP: '', // 詳細画面で非表示化時に表示を薄くする要素をサーチするXPath
  4425. func: null, // 処理時にそのサイトでのみ実行したい関数があれば書く
  4426. funcQ: null, // Qキー処理時にそのサイトでのみ実行したい関数があれば書く
  4427. funcMemo: null, // 5/6などメモ関係処理時にそのサイトでのみ実行したい関数があれば書く
  4428. funcFinally: null, // そのサイトで非表示やメモの処理が終わった後に実行したい関数があれば書く
  4429. funcOnlyFirst: null, // ページ開始時に1回だけ実行したい関数 通常通りのDelayが効く
  4430. funcOnlyFirstWithoutDelay: null, // ページ開始時に1回だけ実行したい関数 Delayなしで最速で実行する
  4431. titleProcessFunc: null, // 項目名を保存する前に加工したければ関数を書く
  4432. autoTranslucentURLRE: //, // 強制的に半透明モードにするURLの正規表現 Web漫画アンテナのマイリスト等
  4433. listTitleXPIgnoreNotExist: 0, // 通常listTitleXPにヒットする要素が1つもなくobserveも0なら動作を停止するがこれがtrueだと停止をしない 項目が動的に追加されるページなどで使用
  4434. forceRunIffunc: null, // これがありtrueを返したらlistTitleXPIgnoreNotExist=1と同様に動作の停止をしない 項目が動的に追加されるページ、先に加工を要するページ(旧5ch)などで使用
  4435. delay: 0, // ミリ秒 ページ読み込み後処理を開始するまでの遅延
  4436. delayAutoWeighting: 0, // 0以外ならページ開始時から処理開始までの遅延の係数(省略可) delayと排他利用
  4437. observe: 0, // ミリ秒 1以上だと要素追加ごとにこのミリ秒の遅延を置いて再処理する(とても遅い) 項目が動的に追加されるページなどで使用
  4438. observeFunc:null, // これがあると追加された要素ごとにtrueを返した要素のみが処理対象になる判定関数 (addedElement)=>{return addedElement==~})
  4439. observeId: "", // これがあるとobserve有効時にこのIDの要素でないものは無視する YouTubeなどの高速化に重要
  4440. observeClass: [], // これがあるとobserve有効時にこれに含まれるClassNameでない要素は無視する futapoなどの高速化に重要
  4441. observeClassNameNot:[], // これがあるとobserve有効時にこのclassNameの要素は処理しない
  4442. observeTagName:"", // これがあるとobserve有効時にこのtagNameの要素は処理しない
  4443. trim: 0, // 1だと項目名をtrimしてから保存 Amazonでは項目名が一覧と詳細で揺れるため1にする
  4444. automemoURLRE: null, // 自動メモを収集するURL
  4445. automemoSearchFunc: null, // 自動メモの対象要素のテキストを収集する関数
  4446. automemoFunc: null, // 自動メモを実行する関数
  4447. redoWhenReturned: 0, // これが1かdetailTitleXPが存在すれば他ウインドウや他タブから戻ってきた時に全体を再処理する disableUrlREを見る
  4448. redoWhenRefocused: 0, // これが1なら他タブから戻ってきた時に全体を再処理する disableUrlREを無視
  4449. showFunc: null, // QWで項目を再表示した時に実行したい関数があれば書く
  4450. hideListEvenDetail: 0, // 1なら詳細画面でも一覧画面用の非表示を実行する ニコニコ静画(イラスト)などで使用
  4451. detailRangeFunc: null, // 詳細画面で項目対象が2つ以上ある場合に指した要素から遡る等の処理があれば書く関数
  4452. //useURL: 0, // 1なら項目名としてAタグのhrefを取り込み、使う ジモティ等、完全に同名の項目名が付けられやすいサイトで使用
  4453. useURL: 0, // 1なら項目名としてAタグのhrefを取り込み、使う(?以降は無視) ジモティ等、完全に同名の項目名が付けられやすいサイトで使用
  4454. useText: 0, // 1なら項目名としてtextContentを取り込み、使う Pubmed等IDではない@titleが設定されているためテキストを優先したいサイトで使用
  4455. hideSelectedWord: 1, // 1ならQキーを押した時に文字列選択中ならその文字列を非表示リストに入れる 5chのレス本文キーワードNGなどで使用
  4456. disableHelpForce: 0, // 1ならENABLE_HELP_CONCLUSIONを常に0にしヘルプやガイドを一切表示しない
  4457. disableHelpUrlRE: '', // 正規表現 URLにマッチすると全体ヘルプを抑制する
  4458. disableKeyB: 0, // 1ならBキーは効かなくする youtubeなどで使用
  4459. searchAllowLength: 0, // 1ならQ12キーの当たり判定をゆるくする(説明しづらい) 5chで使用
  4460. reloadWhenUrlHasChanged:0, // 1ならURLが変わった時にリロードする SPAサイトなどで使用
  4461. helpOnDNI: 0, // 1ならdniでの継ぎ足し時非表示にしたレポートを逐一表示する
  4462. disableUrlRE: "", // URLにマッチしたらキー操作を無効にする正規表現 YouTubeなどSPAサイトで動画視聴ページでキー操作の機能を無効にするために使用
  4463. urlHasChangedCommonFunc: null, // urlが変わったら実行する関数 uniqlo等シングルページアプリケーションで一覧と詳細を行き来するサイト等で使用
  4464. WhateverFirstAndEveryAPFunc: null, // 対象要素がなくてもurlREにマッチしたページならとにかく最初とAutoPagerize時に実行する関数
  4465. memoStyle:"", // メモのstyle=""指定に特別に追加する文字列
  4466. ignoreDNI:null, // これがあるとDOMNodeInsertedイベントでe.targetを受け取りtrueを返したらそのノードは無視する判定関数 ニコ動watch画面等で使用 (e)=>{if(e==無視すべきノード)return false} などと使う
  4467. forceTranslucentFunc:null, // これがあると非表示にした要素eがtrueを返すときは半透明に消す判定関数 e=>e.closest("***") のように使う
  4468. //isMemoPartialMatch: 0, // 全体ヘルプの表示だけメモを部分一致にする
  4469. isHidePartialMatch: 0, // 全体ヘルプの表示だけ非表示を部分一致にする=Bキーのガイドを出す 5ch/ふたばなどの特殊本文NGができるサイトでBキーのヘルプを出すためだけに使用
  4470. preventMemo: null, // (memo内容)=>return true だと通常のメモの内容表示を抑制する判定関数 futapoで使用
  4471. // 新方式(titleとboxで1セット、listTitle~を代替)
  4472. title: '', // 項目名を指すXPath/CSS これとboxだけで要素を特定する新フォーマット title→textContentの順に優先して同一判定する 現在===判定のみ
  4473. box: '', // titleを包含し項目全体の枠になる先祖要素(枠)を指すCSS(XPath不可) boxの中にtitleがある
  4474. titleSubstr: false, // これがtrueだとメモがtitleに対して部分一致でヒットするようになる ヤフオクでCPUスコアの自動メモを表示するために使用
  4475. memoFunc: null, // メモを付ける位置は通常はtitleのafterendだがこれがあるとtitle要素から辿って変更できる デフォルトは(titleEle)=>{return titleEle}
  4476. memoPosition: '', // メモを付ける位置は通常はtitleのafterendだがこれがあると変更できる afterbegin等
  4477. nfd: 0, // 1:項目のタイトルをすべてNFDエンコードにしてから一致判定する 壮絶に遅い タイトルのエンコードが一定でないサイトで使用 YouTubeの新仕様で必要になるかも
  4478. Bsyntax2: 0, // 1:bキーの非表示ワード直接入力で独自構文を使えるようにする
  4479. }, // doc::
  4480. */
  4481. ];
  4482.  
  4483. var siteinfo = Object.assign(SITEINFO, pref("MY_SITEINFO") || []); //alert(siteinfo);return;
  4484. // thissiteを決定
  4485. var thissite = null;
  4486. for (var i = 0; i < siteinfo.length; i++) {
  4487. if (siteinfo[i].urlRE === "") break;
  4488. if (typeof siteinfo[i].urlRE == "function" && siteinfo[i].urlRE() || location.href.match(siteinfo[i].urlRE)) {
  4489. // if (siteinfo[i].urlRE == "") break;
  4490. // if (location.href.match(siteinfo[i].urlRE)) {
  4491. thissite = i;
  4492. var SITE = Object.create(siteinfo[thissite]);
  4493. if (SITE.disableKeyB === undefined && (!(/\*\*\*|\*\*title\*\*|\*\*alt\*\*/.test(SITE.detailTitleSearchXP || "") || /\*\*\*|\*\*title\*\*|\*\*alt\*\*/.test((SITE.listTitleSearchXP || "") || /\*\*\*|\*\*title\*\*|\*\*alt\*\*/.test(SITE.listlTitleMemoSearchXP || ""))))) SITE.disableKeyB = 1;
  4494. break;
  4495. }
  4496. }
  4497. if (thissite === null || (!ENABLE_EXCEPT_YAJ && SITE.id != "YAJ2")) return;
  4498.  
  4499. // 実験的に全てON
  4500. //SITE.redoWhenRefocused = 1
  4501. //SITE.redoWhenReturned = 1
  4502.  
  4503. let ENABLE_HELP_CONCLUSION = lh(SITE?.disableHelpUrlRE || /$^/) ? 0 : SITE.disableHelpForce ? 0 : ENABLE_HELP;
  4504.  
  4505. const MEMOSTYLE = SITE.memoStyle ? SITE.memoStyle : "";
  4506. const CUSTOMAUTOMEMORE = [/(Windows.*bit)/gmi, /((?:HDD|HDD|SSD|SSD|ハードディスク|ストレージ).*?(?:GB|TB|GB|TB|無し|なし|無|欠品|欠))/mi, /((?:10|テン)(?:key|キー))/mi, /(768.{1,3}576)|(800.{1,3}600)|(832.{1,3}624)|(1024.{1,3}768)|(1152.{1,3}864)|(1,?280.{1,3}960)|(1400.{1,3}1050)|(1440.{1,3}1080)|(1600.{1,3}1200)|(2048.{1,3}1536)|(2304.{1,3}1728)|(3200.{1,3}2400)|(854.{1,3}480)|(1024.{1,3}576)|(1136.{1,3}640)|(1280.{1,3}720)|(1,?36\d?.{1,3}768)|(1,?920.{1,3}1,?080)|(2048.{1,3}1152)|(2,?560.{1,3}1,?440)|(3200.{1,3}1800)|(3,?840.{1,3}2,?160)|(7680.{1,3}4320)|(640.{1,3}400)|(1280.{1,3}800)|(1,?440.{1,3}900)|(1680.{1,3}1050)|(1,?920.{1,3}1,?200)|(2560.{1,3}1600)|(2880.{1,3}1800)|(3840.{1,3}2400)|(480.{1,3}320)|(960.{1,3}640)|(176.{1,3}144)|(400.{1,3}240)|(352.{1,3}288)|(640.{1,3}350)|(720.{1,3}480)|(800.{1,3}480)|(864.{1,3}480)|(1024.{1,3}480)|(1024.{1,3}600)|(1280.{1,3}600)|(1120.{1,3}750)|(1280.{1,3}768)|(1152.{1,3}870)|(1280.{1,3}1024)|(1,?600.{1,3}900)|(1,?600.{1,3}1024)|(2048.{1,3}1080)|(4096.{1,3}2160)|(8192.{1,3}4320)/m, /(非光沢|ノングレア|ノーグレア|アンチグレア|光沢|グレア)/m, /((?:30|40)\s?(?:pin|ピン))/mi, /(LVDS.*$|eDP)/mi, /^(.*リカバリ.*)$/mi, /(仕事率[^0-90-9\n]*[0-9,0-9,]*\s*[wW])/mi, /(\[?\s?関東[^0-9,0-9,\n]*[0-9,0-9,]*\s*円[-~]?)/m, /(\[?\s?本州[^0-9,0-9,\n]*[0-9,0-9,]*\s*円[-~]?)/m, /(HDMI.{0,10}入力.{2,3}|入力.{0,20}HDMI.{2,3})/mi, /(電源入り.{2,10})/mi, /(\d\d鍵)/m];
  4507. //const CUSTOMAUTOMEMORE = [/$()^/]; // 無指定
  4508. // ,/(フルHD|Full\s?HD|FHD|WXGA|FWXGA|QVGA|WXGA\+|SXGA|SXGA\+|HD\+|WXGA\+\+|WSXGA|WSXGA\+|UXGA|FHD|2K|WUXGA|FHD\+|UltraWideFHD|QXGA|WQHD|WQXGA|UltraWideQHD\+|QUXGA|QFHD|UHD4K|DCI4K|8KFUHD)/m
  4509. const alsoClearBenchMemoWhenClearAutoMemo = 0; // 1:Shift+"で自動メモのみ削除する時CPUスコアのメモも削除する 0:CPUスコアのメモは残す
  4510.  
  4511. const LogMatch = 0;
  4512.  
  4513. debug && sw("start")
  4514. var mousex = 0;
  4515. var mousey = 0;
  4516. //var maey = 0;
  4517.  
  4518. // userbenchmarkでの動作
  4519. if (location.href.match(/cpu.userbenchmark.com\/.*\/Rating\/|cpu.userbenchmark.com\/SpeedTest\//i)) { //userbenchmark
  4520. setTimeout(() => {
  4521. let cpuscore = $(eleget0('//td[@class="mcs-hl-col" and contains(text(),"64-Core")]/span')).css("border", "4px dotted blue").text();
  4522. let cpuscore1t = "1C:" + $(eleget0('//td[@class="mcs-hl-col" and contains(text(),"1-Core")]/span')).css("border", "4px dotted blue").text();
  4523. cpuscore = cpuscore.replace(/(.*\%).*/, "$1").trim();
  4524. let ubmodel = eleget0('//h1[@class="pg-head-title"]/a[@class="stealthlink"]').innerText.trim();
  4525. let lasttitle = pref("lastItemName") || "";
  4526. let modelno = (ubmodel.replace(/^core i\d-?(\S?\s?\d{3,5}.*$)/gi, "$1").replace(/^Core2 Duo (.?\d{3,5}.*$)/gi, "$1").trim());
  4527. for (let title of (lasttitle ? lasttitle.indexOf(modelno) != -1 ? [modelno] : [lasttitle, modelno] : [modelno])) {
  4528. //for (let memo of [
  4529. [document?.body?.innerText?.match(/(TDP\s*\d+\s*W)/mi)?.[1]?.replace(/\s/gm, " ") || "",
  4530. cpuscore, cpuscore1t,
  4531. ].forEach((memo, i) => {
  4532. //]) {
  4533. var tmp = pref('YAJ2 : SearchMyMemo') || [];
  4534. var isExist = tmp.filter(e => e.t == title && e.m == memo);
  4535. popup3(title + "\n" + memo, i * 3);
  4536. if (isExist.length == 0) {
  4537. if (title && memo) {
  4538. let tmp = pref('YAJ2 : SearchMyMemo') || [];
  4539. tmp.push({ t: title, m: memo, c: COLORCPUSCORE })
  4540. pref('YAJ2 : SearchMyMemo', tmp)
  4541. }
  4542. }
  4543. })
  4544. }
  4545. pref("lastItemName", "");
  4546. //popup3("Task completed");
  4547. }, 500);
  4548. //return;
  4549. }
  4550. if (location.href.indexOf("userbenchmark.com") != -1) {} else {
  4551. pref("lastItemName") ? (pref("lastItemName", ""), popup3("UBM Task has been cleared")) : 0;
  4552. }
  4553.  
  4554. if (SITE.id == "5CH") {
  4555. var oldmemo = pref(SITE.id + ' : SearchMyMemo') || []
  4556. var newmemo = JSON.parse(JSON.stringify(oldmemo)) || []
  4557. newmemo.forEach(c => {
  4558. c.t = c.t.replace(document.title, "").replace(/ |\s|:/g, "").trim()
  4559. })
  4560. if (JSON.stringify(oldmemo) != JSON.stringify(newmemo)) {
  4561. pref(SITE.id + ' : SearchMyMemo', newmemo)
  4562. alert("前バージョンからのメモの変換に成功しました") //JSON.stringify(newmemo))
  4563. }
  4564. }
  4565.  
  4566. //ct1(()=>{
  4567. // メモのc属性を7文字から4文字に削減 12ms
  4568. var oldmemo = pref(SITE.id + ' : SearchMyMemo') || []
  4569. let memoRE = new RegExp(`\"c\"\:\"${OLD_COLOR1}\"|\"c\"\:\"${OLD_COLOR2}\"|\"c\"\:\"${OLD_COLOR3}\"|\"c\"\:\"${OLD_COLORVIDEOTIME}\"|\"c\"\:\"${OLD_COLORCPUSCORE}\"`)
  4570. if (memoRE.test(JS(oldmemo))) {
  4571. var newmemo = JSON.parse(JSON.stringify(oldmemo)) || []
  4572. newmemo = newmemo?.map(v => {
  4573. if (v?.c) {
  4574. let i = [OLD_COLOR1, OLD_COLOR2, OLD_COLOR3, OLD_COLORVIDEOTIME, OLD_COLORCPUSCORE].indexOf(v?.c)
  4575. if (i >= 0) v.c = [COLOR1, COLOR2, COLOR3, COLORVIDEOTIME, COLORCPUSCORE][i]
  4576. }
  4577. return v;
  4578. })
  4579. if (JSON.stringify(oldmemo) != JSON.stringify(newmemo)) {
  4580. pref(SITE.id + ' : SearchMyMemo', newmemo)
  4581. //alert(`ヤフオクで非表示とメモ:\nメモの旧形式からの変換に成功しました\n`) //JSON.stringify(newmemo)
  4582. }
  4583. }
  4584. //})
  4585. oldmemo = null;
  4586. newmemo = null;
  4587.  
  4588. if (SITE.funcOnlyFirstWithoutDelay) SITE.funcOnlyFirstWithoutDelay();
  4589. if (SITE.funcOnlyFirst) setTimeout(() => { SITE.funcOnlyFirst(); }, (SITE.delayAutoWeighting || 0) * WAIT || (SITE.delay || 0));
  4590. if (SITE.WhateverFirstAndEveryAPFunc) {
  4591. setTimeout(() => { SITE.WhateverFirstAndEveryAPFunc(); }, (SITE.delayAutoWeighting || 0) * WAIT || (SITE.delay || 0));
  4592. document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { SITE.WhateverFirstAndEveryAPFunc(evt.target); }, false);
  4593. }
  4594.  
  4595. if (SITE.keyFunc) { // SITEINFOにあるkeyFunc
  4596. document.addEventListener('keydown', e => {
  4597. if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;
  4598. let ele = document.elementFromPoint(mousex, mousey)
  4599. var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
  4600. keyFuncDispatch(key, e, ele)
  4601. /*SITE.keyFunc.forEach(c => {
  4602. if (typeof c.key === "string" ? key === c.key : key.match0(c.key)) { c.func(key) }
  4603. })*/
  4604. //}
  4605. // }, false)
  4606. }, true)
  4607.  
  4608. function keyFuncDispatch(key, opt = null) {
  4609. SITE.keyFunc.forEach(c => {
  4610. if (typeof c.key === "string" ? key === c.key : key.match0(c.key)) { c.func(key, opt) }
  4611. })
  4612. }
  4613. }
  4614.  
  4615. if (SITE.reloadWhenUrlHasChanged) {
  4616. var observeUrlHasChangedhref = location.href;
  4617. var observeUrlHasChanged = new MutationObserver(mutations => { if (observeUrlHasChangedhref !== location.href) location.reload() });
  4618. observeUrlHasChanged.observe(document, { childList: true, subtree: true });
  4619. }
  4620. if (SITE.runWhenUrlHasChanged) {
  4621. var observeUrlHasChangedhrefRun = location.href;
  4622. var observeUrlHasChangedRun = new MutationObserver(mutations => {
  4623. if (observeUrlHasChangedhrefRun !== location.href) {
  4624. prefCacheClear();
  4625. setTimeout(() => { run(document.body, "returned") }, 2500);
  4626. }
  4627. });
  4628. observeUrlHasChangedRun.observe(document, { childList: true, subtree: true });
  4629. }
  4630.  
  4631. // 詳細画面?
  4632. var isDetail = (SITE.detailURLRE && location.href.match(SITE.detailURLRE)) ? 1 : 0;
  4633. debug && dc("isDetail : " + isDetail)
  4634.  
  4635. var isHidePartialMatch = SITE.isHidePartialMatch || (SITE.listTitleSearchXP && SITE.listTitleSearchXP.indexOf("**") != -1) ? 1 : 0;
  4636. var isMemoPartialMatch = SITE.isMemoPartialMatch || (SITE.listTitleMemoSearchXP && SITE.listTitleMemoSearchXP.indexOf("**") != -1) ? 1 : 0;
  4637.  
  4638. // ヤフオク上限価格はIME offにする
  4639. if (SITE.id == "YAJ2") $(eleget0('//input[@class="InputText__input" and @name="max"]')).css('ime-mode', 'inactive');
  4640.  
  4641. // 自動的に半透明モードにするページ
  4642. var disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
  4643.  
  4644. // 非対応ページ
  4645. if (!isDetail && ((SITE.listTitleXP && !eleget0(SITE.listTitleXP)) || (SITE.title && !elegeta(SITE.title)))) {
  4646. if ((SITE.listTitleXPIgnoreNotExist) || (SITE.observe) || (SITE.forceRunIffunc && SITE.forceRunIffunc())) {} else {
  4647. if (debug) popup3("対象要素がないのでこのページでは働きません");
  4648. return;
  4649. }
  4650. }
  4651. if (SITE.necessaryToWork && (document.body.innerText.match(SITE.necessaryToWork)) == null) { //prompt(document.body.innerText,document.body.innerText.match(SITE.necessaryToWork))
  4652. if (debug) popup3("非対応ページなのでこのページでは働きません");
  4653. return;
  4654. }
  4655.  
  4656. if (SITE.selectedHelp) {
  4657. $('body').on('mouseup', function(e) {
  4658. var selectedStr;
  4659. if (window.getSelection) {
  4660. selectedStr = window.getSelection().toString();
  4661. if (selectedStr !== '' && selectedStr !== '\n') {
  4662. if (selectedStr.indexOf("\n") !== -1) SITE.selectedHelp.multi ? popup3(SITE.selectedHelp.multi, 11, 5000) : 0;
  4663. else SITE.selectedHelp.help ? popup3(`『${sani(selectedStr)}』を\n` + SITE.selectedHelp.help.join("\n"), 11, 5000) : 0;
  4664. }
  4665. }
  4666. });
  4667. }
  4668.  
  4669. String.prototype.replaceTitle = function(title) {
  4670. if (title && SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
  4671. if (!title) title = "空の文字列";
  4672. return this.replace(/\*\*\*/g, "contains(text(),\"" + title + "\")").replace(/\+\+\+/g, "text()=\"" + title + "\"").replace(/\+\+alt\+\+/g, "@alt=\"" + title + "\"").replace(/\*\*alt\*\*/g, "contains(@alt,\"" + title + "\")").replace(/\*\*title\*\*/g, "contains(@title,\"" + title + "\")").replace(/\+\+title\+\+/g, "@title=\"" + title + "\"").replace(/\+\+url\+\+/g, "@href=\"" + title + "\"").replace(/\*\*url\*\*/g, "contains(@href,\"" + title + "\")");
  4673. };
  4674.  
  4675. var keyListen = function(e) {
  4676. if (SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) {
  4677. var one = document.elementFromPoint(mousex, mousey);
  4678. // if (!SITE.listTitleXP || !elegeta(SITE.listTitleXP).concat(elegeta(SITE.listTitleXP2)).concat(elegeta(SITE.title)).find(v => v == one)) { return; }
  4679. if (!SITE.listTitleXP || ![...elegeta(SITE.listTitleXP), ...elegeta(SITE.listTitleXP2), ...elegeta(SITE.title)].some(e => e.contains(one))) { return; }
  4680. } //youtube視聴画面では反応する項目にホバーしているとき以外はキーを無効にする
  4681.  
  4682. if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;
  4683. var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
  4684. if (key === KEYCHANGE_DEBUG) { // D::change debug mode
  4685. debug = (debug + 1) % 4;
  4686. popup3("debug mode : " + debug)
  4687. }
  4688. if (key === KEYHIDE) { // Q::hide
  4689. e.preventDefault();
  4690. if (SITE.hideSelectedWord) { // 選択された文字列をNG / 5ch等
  4691. let sel = String(window.getSelection());
  4692. if (sel) {
  4693. if (sel.indexOf("\n") !== -1) { popup2("複数行の選択は NG に入れられません", 1); } else { addNG(sel); }
  4694. if (SITE.funcB) SITE.funcB();
  4695. return false;
  4696. }
  4697. }
  4698. if (SITE.title) { // 直接ホバーしている要素が非表示対象ならそれで非表示登録(1つのbox内に複数の対象(作品名に対する作者名など)がある時にどちらで登録するかを選べるための処理)
  4699. var ele = document.elementFromPoint(mousex, mousey);
  4700. ele = elegeta(SITE.title)?.find(e => e.contains(ele))
  4701. if (ele) { // if (elegeta(SITE.title)?.some(e=>e.contains(ele) )) {
  4702. debug && dc(`Direct element Q : ${ele?.textContent?.trim()||ele?.title?.trim() }』\nbox : ${e2sel(ele)}`)
  4703. addNG(ele?.textContent?.trim() || ele?.title?.trim())
  4704. if (SITE.funcQ) SITE.funcQ(ele);
  4705. return false;
  4706. }
  4707. }
  4708. if (SITE.listTitleXP2) { // 2つ目の項目名がありそこにホバーしていればそれで非表示登録
  4709. var ele = document.elementFromPoint(mousex, mousey);
  4710. ele = elegeta(SITE.title)?.find(e => e.contains(ele))
  4711. if (ele) { // if (elegeta(SITE.listTitleXP2).indexOf(ele) != -1) {
  4712. blockElement(ele); //hideByTitle(ele.innerText);
  4713. if (SITE.funcQ) SITE.funcQ(ele);
  4714. return false;
  4715. }
  4716. }
  4717. var ele = (SITE.detailTitleXP && isDetail) ? (eleget0(SITE.detailTitleXP, (SITE.detailRangeFunc ? SITE.detailRangeFunc(document.elementFromPoint(mousex, mousey)) : document.elementFromPoint(mousex, mousey))) || eleget0(SITE.detailTitleXP)) : document.elementFromPoint(mousex, mousey);
  4718. debug && dc("Q start element : " + ele.tagName);
  4719. blockElement(ele);
  4720. if (SITE.funcQ) SITE.funcQ(ele);
  4721. return false;
  4722. }
  4723. if (key == KEYUNDO) { // W::undo
  4724. e.preventDefault();
  4725. let resist = pref(SITE.id + ' : SearchHideTitle') || [];
  4726. let title = resist.pop();
  4727. let title2 = resist.slice(-1)[0] || "";
  4728. title2 = title2 ? ("。次のアンドゥ対象は\n『" + title2 + "』") : ""
  4729. pref(SITE.id + ' : SearchHideTitle', resist) || [];
  4730. showByTitle(title);
  4731. if (isDetail && SITE.showFunc) SITE.showFunc();
  4732. if (title) popup2("『" + title + "』\nを非表示登録から削除しました" + title2, 1);
  4733. else popup2("登録された非表示項目はありません", 1);
  4734. // }
  4735. if (SITE.funcQ) SITE.funcQ();
  4736. return false;
  4737. }
  4738. if (key == KEYBW && !SITE.disableKeyB) { // B::NGword
  4739. e.preventDefault();
  4740. addNGWord();
  4741. if (SITE.funcB) SITE.funcB();
  4742. return false;
  4743. }
  4744. if (key == KEYTOGGLEtranslucent) { // T:: 半透明
  4745. e.preventDefault();
  4746. if (pref("translucent") == "on") restoreHidden();
  4747. pref("translucent", pref("translucent") == "on" ? "off" : "on");;
  4748. popup2(KEYTOGGLEtranslucent + ": 半透明モードを" + pref("translucent") + "にします");
  4749. disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
  4750. if (pref("translucent") == "on") {
  4751. restoreTranslucent();
  4752. run(document.body, "returned");
  4753. }
  4754. // location.reload();
  4755. // else restoreHidden();
  4756. return false;
  4757. }
  4758.  
  4759. if (key === KEYEDIT) { // shift+Q:: edit NGs
  4760. e.preventDefault();
  4761. prefRestrict(SITE.id + ' : SearchHideTitle', "array");
  4762. let sht = (JSON.stringify(pref(SITE.id + ' : SearchHideTitle') || ""));
  4763. if (sht === '""') sht = "";
  4764. // let tmp = prompt(SITE.id + "\n\n" + KEYEDIT + ":\n非表示にするタイトル(現在" + (pref(SITE.id + ' : SearchHideTitle') || []).length + ")をJSON形式で編集してください\n正規表現ではありません\n空欄を入力すれば全削除できます\n先頭の[の前に+を付けると現在のデータに追加(マージ)します\n\n" + sht, sht);
  4765. let tmp = prompt(`${SITE.id}\n\n${ KEYEDIT }:\n非表示にするタイトル(現在${ (pref(SITE.id + ' : SearchHideTitle') || []).length })をJSON形式で編集してください${SITE.QRule||"\n正規表現ではありません"}\n空欄を入力すれば全削除できます\n先頭の[の前に+を付けると現在のデータに追加(マージ)します\n\n${ sht}`, sht);
  4766. if (tmp !== null) { // ESCで抜けたのでなければ
  4767. try {
  4768. if (tmp.match(/^\+|^+/)) {
  4769. tmp = tmp.replace(/^\+|^+/, "")
  4770. var tmp2 = pref(SITE.id + ' : SearchHideTitle') || []
  4771. tmp = JSON.parse(tmp || "") || []
  4772. var tmp3 = tmp.concat(tmp2)
  4773. tmp = JSON.stringify(tmp3)
  4774. }
  4775. tmp = tmp ? JSON.parse(tmp) : []
  4776. pref(SITE.id + ' : SearchHideTitle', tmp)
  4777. prefRestrict(SITE.id + ' : SearchHideTitle', "array");
  4778. var a = pref(SITE.id + ' : SearchHideTitle')
  4779. var b = [...new Set(a)]; // uniq
  4780. pref(SITE.id + ' : SearchHideTitle', b || []);
  4781. // document.body.remove();
  4782. location.reload();
  4783. } catch (e) {
  4784. alert(e + "\n入力された文字列がうまくparseできなかったので設定を変更しません\n正しいJSON書式になっているか確認してください");
  4785. return false
  4786. }
  4787. return false
  4788. }
  4789. }
  4790. if (key == KEYMEMO5EDIT || key == KEYMEMO6EDIT) { // Shift+5::5memo設定 Shift+6::6memo設定
  4791. e.preventDefault();
  4792. //var date = new Date();
  4793. var memo = window.getSelection().toString().trim() || prompt((key == KEYMEMO5EDIT ? KEYMEMO5 : KEYMEMO6) + "キーのメモ内容を設定してください", (key == KEYMEMO5EDIT ? MEMO5WORD : MEMO6WORD) || getDefault56memo())
  4794. if (key == KEYMEMO5EDIT) {
  4795. MEMO5WORD = memo;
  4796. key = KEYMEMO5
  4797. } else {
  4798. MEMO6WORD = memo;
  4799. key = KEYMEMO6
  4800. }
  4801. if (SITE.funcMemo) SITE.funcMemo();
  4802. if (memo == false) return false;
  4803. }
  4804. if (key == KEYMEMO5 || key == KEYMEMO6) { // 5::5memo 6::6memo
  4805. e.preventDefault();
  4806. if (SITE.title) { // 直接ホバーしている要素が対象ならそれで登録(1つのbox内に複数の対象(作品名と作者名など)がある時にどちらで登録するかを選べるための処理)
  4807. var ele = document.elementFromPoint(mousex, mousey);
  4808. ele = elegeta(SITE.title)?.find(e => e.contains(ele))
  4809. if (ele) { // if (elegeta(SITE.title)?.some(e=>e.contains(ele) )) {//if (elegeta(SITE.title).find(e => e == ele)) {
  4810. //var date = new Date();
  4811. var dateStr = (key == KEYMEMO5 ? MEMO5WORD : MEMO6WORD) || getDefault56memo();
  4812. // memoElement(ele.innerText, document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
  4813. memoElement(ele.textContent?.trim(), document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
  4814. if (SITE.funcMemo) SITE.funcMemo();
  4815. return false;
  4816. }
  4817. }
  4818.  
  4819. if (SITE.listTitleXP2 && SITE.XP2memo) { // 2つ目の項目名がありそこにホバーしていればそれで56
  4820. var ele = document.elementFromPoint(mousex, mousey);
  4821. ele = elegeta(SITE.listTitleXP2)?.find(e => e.contains(ele))
  4822. if (ele) { //if (elegeta(SITE.listTitleXP2).indexOf(ele) != -1) {
  4823. //var date = new Date();
  4824. var dateStr = (key == KEYMEMO5 ? MEMO5WORD : MEMO6WORD) || getDefault56memo();
  4825. memoElement(ele.innerText, document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
  4826. if (SITE.funcMemo) SITE.funcMemo();
  4827. return false;
  4828. }
  4829. }
  4830.  
  4831. var ele = (SITE.detailTitleXP && isDetail) ? (eleget0(SITE.detailTitleXP, (SITE.detailRangeFunc ? SITE.detailRangeFunc(document.elementFromPoint(mousex, mousey)) : document.elementFromPoint(mousex, mousey))) || eleget0(SITE.detailTitleXP)) : document.elementFromPoint(mousex, mousey);
  4832. //var date = new Date();
  4833. var dateStr = (key == KEYMEMO5 ? MEMO5WORD : MEMO6WORD) || getDefault56memo();
  4834. memoElement(ele, document, key == KEYMEMO5 ? COLOR5 : COLOR6, window.getSelection().toString().trim() || dateStr);
  4835. if (SITE.funcMemo) SITE.funcMemo();
  4836. return false;
  4837. }
  4838. if (key == KEYMEMO1 || key == KEYMEMO2) { // 1::1memo 2::2memo
  4839. e.preventDefault();
  4840. var ele = document.elementFromPoint(mousex, mousey);
  4841. if (SITE.listTitleXP2 && SITE.XP2memo) { // 2つ目の項目名がありそこにホバーしていればそれで12
  4842. // var ele = document.elementFromPoint(mousex, mousey);
  4843. ele = elegeta(SITE.listTitleXP2)?.find(e => e.contains(ele))
  4844. if (ele) { // if (elegeta(SITE.listTitleXP2).indexOf(ele) != -1) {
  4845. //memoElement(ele.innerText, document, key == KEYMEMO2 ? COLOR2 : COLOR1);
  4846. memoElement(ele?.textContent, document, key == KEYMEMO2 ? COLOR2 : COLOR1); // ここはtextContentじゃないと連続半角スペースの省略で違う項目名と判定されてしまう
  4847. if (SITE.funcMemo) SITE.funcMemo();
  4848. return false;
  4849. }
  4850. }
  4851. if (SITE.title) { // 直接ホバーしている要素が対象ならそれで登録(1つのbox内に複数の対象(作品名と作者名など)がある時にどちらで登録するかを選べるための処理)
  4852. // var ele = document.elementFromPoint(mousex, mousey);
  4853. ele = elegeta(SITE.title)?.find(e => e.contains(ele))
  4854. if (ele) { // if (elegeta(SITE.title).find(e => e == ele)) {
  4855. //memoElement(ele.innerText?.trim(), document, key == KEYMEMO2 ? COLOR2 : COLOR1) //, window.getSelection().toString().trim() || dateStr);
  4856. memoElement(ele?.textContent?.trim(), document, key == KEYMEMO2 ? COLOR2 : COLOR1) //, window.getSelection().toString().trim() || dateStr);// ここはtextContentじゃないと連続半角スペースの省略で違う項目名と判定されてしまう
  4857. if (SITE.funcMemo) SITE.funcMemo();
  4858. return false;
  4859. }
  4860. }
  4861. // var ele = eleget0(SITE.detailTitleXP) ? eleget0(SITE.detailTitleXP) : document.elementFromPoint(mousex, mousey);
  4862. var ele = (SITE.detailTitleXP && isDetail) ? (eleget0(SITE.detailTitleXP, (SITE.detailRangeFunc ? SITE.detailRangeFunc(document.elementFromPoint(mousex, mousey)) : document.elementFromPoint(mousex, mousey))) || eleget0(SITE.detailTitleXP)) : document.elementFromPoint(mousex, mousey);
  4863. memoElement(ele, document, key == KEYMEMO2 ? COLOR2 : COLOR1);
  4864. if (SITE.funcMemo) SITE.funcMemo();
  4865. return false;
  4866. }
  4867. if ((key == KEYMEMO1S || key == KEYMEMO2S)) { // 3:: 4:: free memo
  4868. e.preventDefault();
  4869. var target = (prompt(`メモを付けたい項目のタイトルが含むキーワードを入力してください\nこのページでは${SITE?.listTitleMemoSearchXP?.indexOf("**")!=-1?"部分一致です":"全体一致です"}\n\n`) || "")?.trim();
  4870. if (!target) return;
  4871. var memo = (prompt("『" + target + "』\nに付けるメモを書いてください") || "").trim();
  4872. if (!memo) return;
  4873. storeMemo(target.trim(), memo, key == KEYMEMO1S ? COLOR1 : COLOR2)
  4874. if (SITE.funcMemo) SITE.funcMemo();
  4875. return false;
  4876. }
  4877. if (key == KEYRESETMEMO) { // Shift+1::!::reset memo
  4878. e.preventDefault();
  4879. prefRestrict(SITE.id + 'SearchMyMemo', "array");
  4880. let smm = JSON.stringify(pref(SITE.id + ' : SearchMyMemo') || []);
  4881. if (smm === '[]') smm = "";
  4882. var tmp = prompt(SITE.id + "\n\n" + KEYRESETMEMO + ":\nメモ(現在" + (pref(SITE.id + ' : SearchMyMemo') || []).length + ")をJSON形式で編集してください\n重複は自動的に削除されます\n空欄を入力すれば全削除されます\n先頭の[の前に+を付けると現在のデータに追加(マージ)します\n\n" + smm, smm);
  4883.  
  4884. if (tmp === smm) return false;
  4885. if (tmp !== null) { // ESCで抜けたのでなければ
  4886. //pref(SITE.id + ' : SearchMyMemo', tmp.trim() || []);
  4887. try {
  4888. var mergemode = tmp?.trim()?.match(/^\+|^+/)
  4889. if (mergemode) {
  4890. tmp = tmp?.trim()?.replace(/^\+|^+/, "")?.trim()
  4891. var tmp2 = pref(SITE.id + ' : SearchMyMemo') || []
  4892. tmp = JSON.parse(tmp || "") || []
  4893. var tmp3 = tmp.concat(tmp2)
  4894. tmp = JSON.stringify(tmp3)
  4895. }
  4896. tmp = tmp ? JSON.parse(tmp) : []
  4897. pref(SITE.id + ' : SearchMyMemo', tmp);
  4898. prefRestrict(SITE.id + 'SearchMyMemo', "array");
  4899. var a = pref(SITE.id + ' : SearchMyMemo') || []
  4900. var b = (Array.from(new Set(a.map(v => JSON.stringify(v))))).map(v => JSON.parse(v)) // uniq:オブジェクトの配列→JSON文字列配列→uniq→オブジェクトの配列//var b = a.reduce((a, v) => { if (!a.some((e) => (e.t === v.t && e.m === v.m && e.c === v.c))) { a.push(v); } return a; }, []); // uniq
  4901.  
  4902. var found = 0; // 同一タイトルに5/6キーの日時メモが日時違いで重複していたら削除
  4903. var dups = []
  4904. var c = [...b]
  4905. if (mergemode) {
  4906. do {
  4907. found = 0
  4908. for (let v of b) {
  4909. if (v?.m?.match(/^\d\d\d\d\.\d\d\.\d\d(?:\s\(.\))?$/)) {
  4910. var e2 = b.find(v2 => nfd(v?.t) == nfd(v2?.t) && v?.c == v2?.c && v2?.m?.match(/^\d\d\d\d\.\d\d\.\d\d(?:\s\(.\))?$/) && v2 != v)
  4911. //var e2 = b.find(v2 => v?.t == v2?.t && v?.c == v2?.c && v2?.m?.match(/^\d\d\d\d\.\d\d\.\d\d(?:\s\(.\))?$/) && v2 != v)
  4912. if (e2) {
  4913. var ea = [v, e2].sort((a, b) => a?.m > b?.m ? 1 : -1)
  4914. var dup = b.find(v3 => JS(v3) == JS(ea[1]))
  4915. dups.push(dup);
  4916. b = b.filter(f => f != dup)
  4917. found = 1
  4918. break
  4919. }
  4920. }
  4921. }
  4922. } while (found)
  4923. }
  4924. if (mergemode && dups.length) {
  4925. if (confirm(`同一のタイトルに5/6キーの日時メモが複数付いているものが${dups.length}個ありました\nこれを重複とみなし最も古い日時のメモ以外を削除することもできますが\nそうしますか?\n\n削除する項目:\n${JS(dups).replace(/\},{\"t\"\:/g,'},\n{"t":')}`)) {
  4926. c = b
  4927. }
  4928. }
  4929. pref(SITE.id + ' : SearchMyMemo', c || []);
  4930. //document.body.remove();
  4931. setTimeout(() => {
  4932. location.reload();
  4933. }, 1000)
  4934. return false
  4935. } catch (e) {
  4936. alert(e + "\n入力された文字列がうまくparseできなかったので設定を変更しません\n正しいJSON書式になっているか確認してください");
  4937. return false
  4938. }
  4939. }
  4940. }
  4941. if (key == KEYRESETMEMOAUTO) { // Shift+2::reset automemo
  4942. e.preventDefault();
  4943. var str = pref(SITE.id + ' : SearchMyMemo') || [];
  4944. if (alsoClearBenchMemoWhenClearAutoMemo) {
  4945. var newstr = str.filter(e => !(e.c == COLOR3 || e.c == COLORCPUSCORE)); // CPUスコアもリセット
  4946. var newstr2 = str.filter(e => (e.c == COLOR3 || e.c == COLORCPUSCORE)); // CPUスコアもリセット
  4947. } else {
  4948. var newstr = str.filter(e => !([COLOR3, COLOR_ALERT_WORD].includes(e.c)));
  4949. var newstr2 = str.filter(e => !(newstr.includes(e)));
  4950. }
  4951. if (confirm(SITE.id + "\n\n" + KEYRESETMEMOAUTO + ":\n自動メモ(" + newstr2.length + ")のみ全て削除します。良いですか?\n\n消すもの:\n" + JSON.stringify(newstr2))) {
  4952. pref(SITE.id + ' : SearchMyMemo', JSON.stringify(newstr));
  4953. popup2("自動メモをクリアしました", 1);
  4954. document.body.remove();
  4955. location.reload();
  4956. }
  4957. return false;
  4958. }
  4959. if (key == "Shift+#") { // Shift+3::#::hide/show memo
  4960. e.preventDefault();
  4961. GF.numbersign = ((GF.numbersign || 0) + 1) % 4
  4962. if (GF.numbersign == 1) $('#pickbox:visible,.setSlider:visible,[floated]:visible,.relallArea,span#notiApiOn.ignoreMe,table#ftbl input[name="upfile"]:visible').hide()
  4963. if (GF.numbersign == 2) $(`[data-mbt]:visible`).attr("data-numbersign", "1").hide()
  4964. if (GF.numbersign == 3) $(`.ignoreMe.shibo:visible,#shiboButton:visible,#5chVerticalThreadTitle:visible,.setSlider:visible,#ftxa:visible,.quoteSpeechBalloon:visible,.quoteSpeechBalloonImg:visible`).attr("data-numbersign", "1").hide()
  4965. if (GF.numbersign == 0) $(`[data-mbt]:hidden,.ignoreMe.shibo:hidden,#shiboButton:hidden,#5chVerticalThreadTitle:hidden,.setSlider:hidden,#ftxa:hidden,.quoteSpeechBalloon:hidden,.quoteSpeechBalloonImg:hidden,[floated]:hidden,.relallArea,span#notiApiOn.ignoreMe,table#ftbl input[name="upfile"]:hidden`).attr("data-numbersign", "0").show()
  4966. if (SITE.funcMemo) SITE.funcMemo();
  4967. return false;
  4968. }
  4969. if (SITE.maxpriceXP && !isDetail) {
  4970. if (key == KEYMAXP) { // maxpriceXP
  4971. e.preventDefault();
  4972. let ele = eleget0(SITE.maxpriceXP);
  4973. if (ele) {
  4974. ele.focus();
  4975. ele.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
  4976. ele.select();
  4977. popup2("上限価格にフォーカス", 1);
  4978. }
  4979. }
  4980. return false;
  4981. //}
  4982. }
  4983. }
  4984. // document.addEventListener('keydown', keyListen, false)
  4985. document.addEventListener('keydown', keyListen, true) // youtube/watchで先取りするためにtrue
  4986.  
  4987. document.addEventListener("mousemove", e => ((mousex = e.clientX), (mousey = e.clientY), (hovertimer = 0), undefined), false)
  4988. //document.addEventListener("mousemove", function(e) { mousex = e.clientX; mousey = e.clientY; hovertimer = 0; }, false);
  4989.  
  4990. // AP継ぎ足しを監視
  4991. setTimeout(() => { run() }, (SITE.delayAutoWeighting || 0) * WAIT || (SITE.delay || 0));
  4992. document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { run(evt.target, "APed"); }, false);
  4993.  
  4994. // DOM追加を監視
  4995. var DNIDelay = null;
  4996. // if (!isDetail && SITE.observe) {
  4997. if (SITE.observe) {
  4998. debug && dc("observe DNI");
  4999. document.body.addEventListener('DOMNodeInserted', dnifunc, false);
  5000. //document.body.addEventListener('transitionend', dnifunc, false); // テスト
  5001.  
  5002. function dnifunc(e) {
  5003. let ele = e.target;
  5004. // if (DNIDelay) return;
  5005. if (ele?.classList?.contains("ignoreMe")) return;
  5006. if (SITE.observeId && (ele.id !== SITE.observeId)) return;
  5007. if (SITE.observeClass && !SITE.observeClass.includes(e.target.className)) return;
  5008. if (SITE.observeTagName && SITE.observeTagName !== ele.tagName) return;
  5009. if (SITE.ignoreDNI && SITE.ignoreDNI(ele)) return;
  5010. if (ele.className && SITE.observeClassNameNot && SITE.observeClassNameNot.includes(ele.className)) return;
  5011. //debug&&console.log(`accept dni:`,ele)
  5012. if (DNIDelay) {
  5013. if (dniCancel || SITE.dniCancel) { clearTimeout(DNIDelay) } else { return; }
  5014. }
  5015.  
  5016. DNIDelay = setTimeout(
  5017. // ((ele)=>{return ()=>{
  5018. (function(ele) {
  5019. return function() {
  5020. run(document.body, "observed", ele); // ここで run(ele.parentNode.parentNode, "observed"); などとすると速くなるが~searchXPが何世代まで親を参照するか分からないので全サイトの動作確認が必要
  5021. // run(SITE.observeFunc?ele.parentNode:document.body, "observed", ele); // ここで run(ele.parentNode.parentNode, "observed"); などとすると速くなるが~searchXPが何世代まで親を参照するか分からないので全サイトの動作確認が必要
  5022. DNIDelay = null;
  5023. }
  5024. // })(ele), SITE.observe || 0);
  5025. })(ele), Math.max(GF?.runElapsed || 0, SITE?.observe || 0) || SITE.observe || 0);
  5026. // console.log(Math.max(GF?.runElapsed,SITE?.observe||0) || SITE.observe || 0)
  5027. }
  5028. }
  5029.  
  5030. // タブにフォーカスが戻ったら再実行
  5031. // if (SITE.redoWhenRefocused) window.addEventListener("focus", () => { restoreHidden() })
  5032. if (SITE.redoWhenRefocused) window.addEventListener("focus", () => {
  5033. // if (JS(prefCache[SITE.id + ' : SearchMyMemo'] || []) !== JS(pref(SITE.id + ' : SearchMyMemo') || []) || JS(prefCache[SITE.id + ' : SearchHideTitle'] || []) !== JS(pref(SITE.id + ' : SearchHideTitle') || [])) {
  5034. //if (!prefCacheEqual(SITE.id + ' : SearchMyMemo') || !prefCacheEqual(SITE.id + ' : SearchHideTitle')) {
  5035. // if (!prefCacheEqual(SITE.id + ' : SearchMyMemo') || !prefCacheEqual(SITE.id + ' : SearchHideTitle') ) {
  5036. //if (!(!prefChanged("translucent") && !prefChanged(SITE.id + ' : SearchMyMemo') && !prefChanged(SITE.id + ' : SearchHideTitle'))) {
  5037. if (prefChanged("translucent") || prefChanged(SITE.id + ' : SearchMyMemo') || prefChanged(SITE.id + ' : SearchHideTitle')) {
  5038. restoreHidden()
  5039. } // prefCache:キャッシュと保存されたデータが同一だったら再実行しない
  5040. })
  5041.  
  5042. // 詳細画面に対応しているサイトかredoWhenReturnedが1ならタブにフォーカスが戻ったら再実行する
  5043. if (SITE.detailTitleXP || SITE.redoWhenReturned) {
  5044. var hidden, visibilityChange;
  5045. if (typeof document.hidden !== "undefined") {
  5046. hidden = "hidden";
  5047. visibilityChange = "visibilitychange";
  5048. } else if (typeof document.msHidden !== "undefined") {
  5049. hidden = "msHidden";
  5050. visibilityChange = "msvisibilitychange";
  5051. } else if (typeof document.webkitHidden !== "undefined") {
  5052. hidden = "webkitHidden";
  5053. visibilityChange = "webkitvisibilitychange";
  5054. }
  5055. document.addEventListener(visibilityChange, handleVisibilityChange, false);
  5056.  
  5057. function handleVisibilityChange() {
  5058. if (SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) { return; }
  5059. if (document[hidden]) {} else {
  5060.  
  5061. // if (!(JS(prefCache[SITE.id + ' : SearchMyMemo'] || []) !== JS(pref(SITE.id + ' : SearchMyMemo') || []) || JS(prefCache[SITE.id + ' : SearchHideTitle'] || []) !== JS(pref(SITE.id + ' : SearchHideTitle') || []))) { return }
  5062. if (!prefChanged("translucent") && !prefChanged(SITE.id + ' : SearchMyMemo') && !prefChanged(SITE.id + ' : SearchHideTitle')) { return }
  5063.  
  5064. let prefHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
  5065. if (prefHide !== disableHide) {
  5066. disableHide = (SITE.autoTranslucentURLRE && location.href.match(SITE.autoTranslucentURLRE)) || (pref("translucent") == "on");
  5067. restoreTranslucent();
  5068. }
  5069. restoreHidden();
  5070. }
  5071. }
  5072. }
  5073.  
  5074. // タブにフォーカスが戻った時等用 隠していた要素のうち非表示登録から外されたものを再表示
  5075. function restoreHidden() {
  5076. if (isDetail) {
  5077. // showByTitle(eleget0(SITE.detailTitleXP).textContent.replaceTitle());
  5078. // var dtitle = eleget0(SITE.detailTitleXP).textContent.replaceTitle();
  5079. var d = eleget0(SITE.detailTitleXP)
  5080. if (d && !(/\"/.test(d.textContent?.normalize("NFC").replaceTitle()))) showByTitle(d.textContent?.normalize("NFC").replaceTitle());
  5081. }
  5082. if (!isDetail || SITE.hideListEvenDetail) {
  5083. //let resist = pref(SITE.id + ' : SearchHideTitle') || [];
  5084. let resist = JP(JS(pref(SITE.id + ' : SearchHideTitle') || []).normalize("NFC"))
  5085. debug && sw("")
  5086. for (let ele of elegeta('//*[@data-hidden="1" or @data-hidden="2"]')) {
  5087. //let title = getTitleFromParent(ele, 1); // これだとXP2はヒットしないので再表示されない:保留
  5088. let title = ele.dataset.yhmkey;
  5089. if (SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
  5090. let i = resist.indexOf(title); // ここは常に全体一致判定なのでcontains判定のサイトでは少し余計に再表示してしまう(でもまたすぐ隠す)
  5091. if (i === -1) {
  5092. showByTitle(title);
  5093. //if(debug)V&&dc(title + "は再表示")
  5094. }
  5095. }
  5096. debug && sw("show by returned")
  5097.  
  5098. }
  5099. setTimeout(() => { run(document.body, "returned"); }, 0);
  5100. if (SITE.funcQ) SITE.funcQ();
  5101. }
  5102.  
  5103. // ヤフオク キーワードの検索対象を切り替えるボタン
  5104. if (SITE.id == "YAJ2") {
  5105. if (location.href.indexOf("://page.auctions.yahoo.co.jp/jp/auction/") == -1) {
  5106. for (let kw of [{ t: "タイトルからのみ検索する", s: "&f=0x2" }, { t: "タイトルと商品説明から検索する", s: "&f=0x4" }]) {
  5107. var ele = eleget0('//div[@class="ptsOption"]/a/../../..');
  5108. if (ele && !(location.href.match(kw.s))) {
  5109. var ele2 = ele.parentNode.insertBefore(document.createElement("a"), ele.nextSibling);
  5110. ele2.innerHTML = kw.t + " ";
  5111. ele2.href = location.href.replace(/\&f\=.*(\&|$)/, "") + kw.s;
  5112. }
  5113. }
  5114. }
  5115. }
  5116.  
  5117. // URL変化を監視、変化したら再実行
  5118. if (SITE.urlHasChangedCommonFunc && !observeUrlHasChangedCommon) {
  5119. var observeUrlHasChangedhrefCommon = location.href;
  5120. var observeUrlHasChangedCommon = new MutationObserver(function(mutations) {
  5121. if (observeUrlHasChangedhrefCommon !== location.href) {
  5122. prefCacheClear();
  5123. observeUrlHasChangedhrefCommon = location.href;
  5124. SITE.urlHasChangedCommonFunc();
  5125. }
  5126. });
  5127. observeUrlHasChangedCommon.observe(document, { childList: true, subtree: true });
  5128. }
  5129.  
  5130. function run(node = document.body, runmode = "1st", ele = null) { // 1st observed returned
  5131. GF.runStart = Date.now()
  5132. // if(debug)V&&dc("runmode : " + runmode + " / node tag: " + node?.tagName + " / ele.tag : " + ele?.tagName + " / ele.class : " + ele?.className + " ele.id : " + ele?.id); // beautify
  5133. debug && dc("runmode : " + runmode + " / node tag: " + (node.tagName ? node.tagName : "-") + (ele ? (" / ele.tag : " + (ele.tagName ? ele.tagName : "-") + " | ele.class : " + (ele.className ? ele.className : "-") + " | ele.id : " + (ele.id ? ele.id : "-")) : ""));
  5134. debug && sw("reset");
  5135. if (pauseAll) return;
  5136. debug && sw("run");
  5137.  
  5138. // if (debug>=3) { elegeta(SITE.listTitleXP).forEach(e => debugEle(e, "force"));elegeta(SITE.listTitleXP2).forEach(e => debugEle(e, "force")) }
  5139. if (debug >= 3 && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE)))) {
  5140. elegeta(SITE.listTitleXP).concat(elegeta(SITE.listTitleXP2)).forEach(e => {
  5141. debugEle(e, "force autoRemove");
  5142. //setTimeout(()=>{debugEle(e,"remove");},2000);
  5143. });
  5144. }
  5145. // サイトごとの個別処理
  5146. if (SITE.func) { SITE.func(node); }
  5147.  
  5148. //if (SITE.disableUrlRE && (SITE.disableUrlRE.test(location.href))) { return; }
  5149.  
  5150. // ホバー時の操作案内のポップアップを登録
  5151. // if (ENABLE_HELP_CONCLUSION) {
  5152. if ((debug >= 1 || ENABLE_HELP_CONCLUSION) && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))) && (!SITE?.preventHelpFunc || !SITE?.preventHelpFunc())) {
  5153. var lh = (!isDetail && SITE.helpInBlock) ? $("<span class='ignoreMe phov' id='yafuokuhelp' style='cursor:pointer; color:#505050; font-size:15px; background:#ffffffb0; padding:0px 4px 0px 4px; border-radius:9px;border:#505050 1px solid; position: absolute; bottom:2px; right: 20em;' title='クリックでこのガイドを一時的に消す'>Q:非表示 W:アンドゥ 1:○メモ 2:×メモ</span>") : $("<span class='ignoreMe phov' id='yafuokuhelp' style='all:initial; cursor:pointer; z-index:1000; color:#505050; font-size:15px; background:#ffffffc0; padding:3px; border-radius:9px;border:#505050 1px solid; position:fixed; bottom:1em; right: 1em;' title='クリックでこのガイドを一時的に消す'>Q:非表示 W:アンドゥ 1:○メモ 2:×メモ</span>");
  5154. var lh2 = $(`<span class='ignoreMe phov2' id='yafuokuhelp' style='all:initial; cursor:pointer; z-index:2147483647; color:#505050; font-size:15px; background:#ddeeffc0; padding:3px; border-radius:9px;border:#304050 1px solid; position:fixed; bottom:1em; right: 1em;' title='クリックでこのガイドを一時的に消す'>${SITE.XP2name||""}Q:非表示 W:アンドゥ${ SITE.XP2memo?" 1:○メモ 2:×メモ":""}</span>`);
  5155. // 画面全体で1つだけ=詳細画面の方
  5156. if (SITE.detailURLRE && location.href.match(SITE.detailURLRE)) {
  5157. $('span.phov').remove();
  5158. lh.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
  5159. debug && sw("zentai help");
  5160. //SITE.listTitleXP2 + "" → SITE.listTitleXP2 + "/../.."
  5161. $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
  5162. $('span.phov').fadeTo(0, 0);
  5163. lh2.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
  5164. }, function() {
  5165. $(".phov2").remove();
  5166. $('span.phov').fadeTo(0, 1);
  5167. }); // test
  5168. } else {
  5169. // 一画面に複数ある=検索結果&セラー画面の方
  5170. if (runmode !== "observed") { // 初処理+追記部分のみ=重複しない処理
  5171. $(elegeta(SITE?.box, node).concat(elegeta(SITE.listHelpJQS, node)).concat(elegeta(SITE.listHelpXP, node)) || (elegeta(SITE.listTitleXP ? SITE.listTitleXP + "/../.." : "", node))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
  5172.  
  5173. $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
  5174. $('span.phov').fadeTo(0, 0);
  5175. lh2.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
  5176. }, function() {
  5177. $(".phov2").remove();
  5178. $('span.phov').fadeTo(0, 1);
  5179. }); // test
  5180. } else { // 重複ありの処理
  5181. $(elegeta(SITE?.box, node).concat(elegeta(SITE.listHelpJQS, node)).concat(elegeta(SITE.listHelpXP, node)) || (elegeta(SITE.listTitleXP ? SITE.listTitleXP + "/../.." : "", node))).off("mouseenter mouseleave").hover(function() { lh.appendTo(SITE.helpInBlock ? this : document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) }); }, function() { $(".phov").remove() });
  5182. $(node).find(elegeta(SITE.listHelpXP2 || (SITE.listTitleXP2 ? SITE.listTitleXP2 + "" : undefined))).off("mouseenter mouseleave").hover(function() {
  5183. $('span.phov').fadeTo(0, 0);
  5184. lh2.appendTo(document.body).click(function() { $(this).fadeOut(100).queue(function() { $(this).remove() }) });
  5185. }, function() {
  5186. $(".phov2").remove();
  5187. $('span.phov').fadeTo(100, 1);
  5188. }); // test
  5189. }
  5190. debug && sw("1gyou help");
  5191. }
  5192. }
  5193.  
  5194. // 高速化のためにtitleXP/2の要素のtextContentに含まれるメモ・NGだけの集合を作る>documemtのtextContent>documemtのinnerHTML の順
  5195. let fastmode = !fasttest ? null : SITE.listTitleSearchFunc ? null : SITE.title || (!(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc);
  5196. // let fasttext = !fasttest ? null : fastmode ? node.textContent || "" : node.innerHTML || "";
  5197. let fasttext = !fasttest ? null : fastmode ? node.textContent || "" : node.innerHTML + node.textContent || ""; // +node.textContentはnew5chで必要 他にバグ出るかも?
  5198. if (fasttext > "") fasttext = fasttext.replace(/\\u0026|&amp;/gm, "&"); //prompt(fasttext,fasttext) // node.innerText中の&がunicodeエスケープされているのでもとに戻す youtubeで必要
  5199. fasttext = fasttext?.normalize("NFC")
  5200. var fastMatch = null; // !fasttest ? null : fastmode ? (SITE.title ? elegeta(SITE.title, node) : []).concat(SITE.listTitleXP ? elegeta(SITE.listTitleXP, node) : []).concat((SITE.listTitleXP2 ? elegeta(SITE.listTitleXP2, node) : [])).concat((SITE.detailTitleXP ? elegeta(SITE.detailTitleXP, node) : [])) : null;
  5201. debug && sw(fastmode ? "use fast test" : "NOT fast mode")
  5202. if (fasttest && fastmode) { debug && sw("draft by fastMatch") } else { debug && sw("draft by innerHTML") }
  5203.  
  5204. // メモ貼りを実行 memo::
  5205. if (runmode === "observed" || runmode === "returned") {
  5206. debug && sw("reset");
  5207. $('span[data-mbt="1"]').remove();
  5208. debug && sw("removing memo");
  5209. }
  5210. var isnotChrome = (window.navigator.userAgent.toLowerCase().indexOf('chrome') == -1);
  5211.  
  5212. var titles = pref(SITE.id + ' : SearchMyMemo') || []
  5213. if (SITE?.memoOnRead) titles = SITE.memoOnRead(titles)
  5214. if (titles) { // if (pref(SITE.id + ' : SearchMyMemo')) {
  5215. var i = 0;
  5216. var hitTitle = [];
  5217. // var titles = pref(SITE.id + ' : SearchMyMemo')
  5218. //var titles = JP(JS(pref(SITE.id + ' : SearchMyMemo')).normalize("NFC"))
  5219. if (fasttest) {
  5220. if (fastMatch) {
  5221. for (let ele of fastMatch) { hitTitle = hitTitle.concat(titles.filter(t => { return ele.textContent.indexOf(t.t?.normalize("NFC")) !== -1 })); } debug && sw("mymemo draft-test");
  5222. debug && sw("memo/fastMatch")
  5223. } else { // document.innerHTMLにタイトルが含まれるメモに絞り込む
  5224. // hitTitle = hitTitle.concat(titles.filter(t => fasttext.indexOf(t.t?.normalize("NFC")) !== -1)); //453,463
  5225. hitTitle = hitTitle.concat(titles.filter(t => fasttext.includes(t.t?.normalize("NFC")))); //453,463
  5226. debug && sw(`memo/indexOf ${hitTitle.length}`)
  5227. }
  5228. hitTitle = [...new Set(hitTitle)];
  5229. for (let a of hitTitle.sort(function(a, b) { return isnotChrome ? (a.c == COLORCPUSCORE && b.c !== COLORCPUSCORE ? 1 : 0) : (a.c != COLORCPUSCORE && b.c == COLORCPUSCORE ? -1 : 0); })) {
  5230. memoByTitle(a.t, a.m, node, a.c || COLOR1, a.u);
  5231. }
  5232. debug && sw("memo/fastTest")
  5233. } else {
  5234. for (let a of pref(SITE.id + ' : SearchMyMemo').sort(function(a, b) { return isnotChrome ? (a.c == COLORCPUSCORE && b.c !== COLORCPUSCORE ? 1 : 0) : (a.c != COLORCPUSCORE && b.c == COLORCPUSCORE ? -1 : 0); })) {
  5235. memoByTitle(a.t, a.m, node, a.c || COLOR1, a.u);
  5236. }
  5237. debug && sw("memo/slow")
  5238. }
  5239. }
  5240. debug && sw("mymemo ( draft-matched : " + ((hitTitle || []).length) + " )"); //JSON.stringify(hitTitle)
  5241.  
  5242. // 非表示を実行 hide::
  5243. var help = (KEYHIDE + ":非表示 " + KEYUNDO + ":アンドゥ " + (isHidePartialMatch ? (SITE.disableKeyB ? "" : KEYBW + ":NGワード ") : "") + KEYEDIT + ":NG編集 " + KEYMEMO1 + KEYMEMO2 + ":メモを追加 " + KEYMEMO1S + KEYMEMO2S + ":自由メモ " + KEYMEMO5 + KEYMEMO6 + ":定型メモ " + KEYRESETMEMO + ":メモを編集 " + (SITE.automemoURLRE ? KEYRESETMEMOAUTO + ":自動メモのみ全削除 " : "") + KEYTOGGLEtranslucent + ":半透明") + ((SITE.wholeHelp && SITE.wholeHelp[0]() && SITE.wholeHelp[1]) || "");
  5244. if (pref(SITE.id + ' : SearchHideTitle')) {
  5245. var i = 0;
  5246. var hitTitle = [];
  5247. // var titles = pref(SITE.id + ' : SearchHideTitle') //.map(q=>q?.nfd())
  5248. var titles = JP(JS(pref(SITE.id + ' : SearchHideTitle')).normalize("NFC")) //.map(q=>q?.nfd())
  5249. if (fasttest) {
  5250. if (fastMatch) {
  5251. for (let ele of fastMatch) {
  5252. var a = titles.filter(t => ele.textContent.indexOf(t) !== -1);
  5253. if (a) hitTitle = hitTitle.concat(a);
  5254. } //console.log(hitTitle)
  5255. } else { // document.innerHTMLにタイトルが含まれるメモに絞り込む
  5256. hitTitle = titles.filter(t => { return fasttext.indexOf(t) !== -1 });
  5257. }
  5258. hitTitle = [...new Set(hitTitle)];
  5259. debug && sw("block draft-test");
  5260. for (let title of hitTitle || []) { i += hideByTitle(title, node); }
  5261. debug && sw("block ( actually : " + i + " / draft-matched : " + ((hitTitle || []).length) + (fastMatch ? " / target : " + fastMatch.length : "") + " )");
  5262. } else {
  5263. for (let title of pref(SITE.id + ' : SearchHideTitle') || []) { i += hideByTitle(title, node); }
  5264. debug && sw("block ( actually : " + i + " )");
  5265. }
  5266. if (i) { help = i + "個を非表示にしました\n" + help + (debug && fasttest ? " \n\nドラフトでマッチ:" + (JSON.stringify(hitTitle.slice(0, 9))) : ""); }
  5267. }
  5268. // 全体ヘルプを表示
  5269. // if (debug || (ENABLE_HELP_CONCLUSION && (SITE.helpOnDNI || (runmode === "1st" && SITE.listTitleXP)) && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))))) popup2(help, 1);
  5270. if (debug || (ENABLE_HELP_CONCLUSION && (SITE.helpOnDNI || (runmode === "1st" && (SITE.title || SITE.listTitleXP))) && !(SITE.disableUrlRE && (location.href.match(SITE.disableUrlRE))))) popup2(help, 1.5);
  5271.  
  5272. // 自動メモを探索&製作
  5273. function mekeautomemo() {
  5274. if (ENABLE_AUTOMEMO && SITE?.automemoFunc &&
  5275. (SITE?.automemoURLRE && location?.href?.match(SITE.automemoURLRE) || isDetail || (SITE?.automemoForceFunc && SITE?.automemoForceFunc()))
  5276. ) { SITE?.automemoFunc(); }
  5277. }
  5278. mekeautomemo()
  5279. for (let t = 0; t < ENABLE_AUTOMEMO; t++) {
  5280. setTimeout(() => {
  5281. mekeautomemo()
  5282. }, (t + 1) * 2000)
  5283. }
  5284. debug && sw("automemo")
  5285. //debug&&t>0?popup3( t * t / 2 * 1000,2,1):0; }
  5286. //}
  5287.  
  5288. if (SITE.funcFinally) SITE.funcFinally(disableHide, i); // Qが有効、非表示にした個数
  5289. GF.runElapsed = Date.now() - GF.runStart
  5290. debug && sw(`run total : ${GF.runElapsed}`)
  5291. return;
  5292. }
  5293.  
  5294. function restoreTranslucent() {
  5295. if (pref(SITE.id + ' : SearchHideTitle')) {
  5296. let fastmode = !fasttest ? null : SITE.listTitleSearchFunc ? null : SITE.title || (!(/\*\*alt\*\*|\+\+alt\+\+|\+\+title\+\+|\+\+url\+\+|\*\*url\*\*/.test(SITE.listTitleSearchXP + " " + SITE.detailTitleSearchXP + " " + SITE.listTitleMemoSearchXP)) && !SITE.listTitleSearchFunc);
  5297. // var fasttext = !fasttest ? null : fastmode ? document.body.textContent?.nfd() || "" : document.body.innerHTML?.nfd() || "";
  5298. var fasttext = !fasttest ? null : fastmode ? document.body.textContent || "" : document.body.innerHTML || "";
  5299. fasttext = fasttext?.normalize("NFC")
  5300.  
  5301. var fastMatch = null //!fasttest ? null : fastmode ? (SITE.title ? elegeta(SITE.title) : []).concat(SITE.listTitleXP ? elegeta(SITE.listTitleXP) : []).concat((SITE.listTitleXP2 ? elegeta(SITE.listTitleXP2) : [])).concat((SITE.detailTitleXP ? elegeta(SITE.detailTitleXP) : [])) : null;
  5302.  
  5303. debug && dc(fastmode ? "restoreTranslucent : use fastmode" : "restoreTranslucent : not use fastmode")
  5304. debug && sw("reset")
  5305. var i = 0;
  5306. var hitTitle = [];
  5307. //var titles = pref(SITE.id + ' : SearchHideTitle').map(e => e = e)
  5308. var titles = JP(JS(pref(SITE.id + ' : SearchHideTitle')).normalize("NFC"))
  5309. if (fasttest) {
  5310. if (fastMatch) {
  5311. for (let ele of fastMatch) {
  5312. //var a = titles.filter(t => ele.textContent.indexOf(t) !== -1);
  5313. var a = titles.filter(t => ele.textContent?.normalize("NFC")?.indexOf(t) !== -1);
  5314. if (a) hitTitle = hitTitle.concat(a);
  5315. }
  5316. } else {
  5317. hitTitle = titles.filter(t => { return fasttext.indexOf(t) !== -1 });
  5318. }
  5319. hitTitle = [...new Set(hitTitle)];
  5320. } else {
  5321. hitTitle = pref(SITE.id + ' : SearchHideTitle') || []
  5322. }
  5323. for (let title of hitTitle) showByTitle(title, 0);
  5324. debug && sw("restoreTranslucent")
  5325. }
  5326. if (SITE.funcOnTOn) SITE.funcOnTOn();
  5327. }
  5328.  
  5329. function eletext(xpa, xp) {
  5330. if (typeof xpa == "string") { // string
  5331. let e = eleget0(xpa);
  5332. if (e) debugEle(e);
  5333. return e ? e.innerText : "";
  5334. } else { // array
  5335. let text = "";
  5336. xpa.forEach(xp => {
  5337. elegeta(xp).forEach(e => {
  5338. e = e.cloneNode(true, true) // 繰り替えさないようにメモは除外
  5339. elegeta('.yhmMyMemo', e).forEach(v => v.remove())
  5340. debugEle(e);
  5341. text = text + (e.innerText + "\n");
  5342. })
  5343. })
  5344. return text;
  5345. }
  5346. }
  5347.  
  5348. function autoMemo2(automemotarget, re) {
  5349. let node = document.body;
  5350. let sou = automemotarget?.match(re);
  5351. if (sou && sou.length) {
  5352. sou.shift();
  5353. var memo = Array.from(new Set(sou)).join(" ").replace(/[A-Za-z0-9.,]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248) }).replace(/\s{2,99}| /gm, " ").trim();
  5354. var title = getDetailTitle()
  5355. if (!title) return;
  5356. var tmp = pref(SITE.id + ' : SearchMyMemo') || [];
  5357. var isExist = tmp.filter(e => e.t == title && e.m == memo);
  5358. if (isExist.length == 0) {
  5359. if (debug) popup3(memo, 2, 5000);
  5360. storeMemo(title, memo, COLOR3, node);
  5361. }
  5362. return true;
  5363. }
  5364. return false;
  5365. }
  5366.  
  5367. function autoMemo(re, func) {
  5368. let automemotarget = SITE.automemoSearchFunc();
  5369. if (func) automemotarget = func(automemotarget)
  5370. let node = document.body;
  5371. let sou = automemotarget.match(re);
  5372. if (sou && sou.length) {
  5373. sou.shift();
  5374. var memo = Array.from(new Set(sou)).join(" ").replace(/[A-Za-z0-9.,]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248) }).replace(/\s{2,99}| /gm, " ").trim();
  5375. // node.innerHTML=node.innerHTML.replace(re,"<mark>$1</mark>");
  5376. var title = getDetailTitle()
  5377. if (!title) return;
  5378. var tmp = pref(SITE.id + ' : SearchMyMemo') || [];
  5379. var isExist = tmp.filter(e => e.t == title && e.m == memo);
  5380. if (isExist.length == 0) {
  5381. if (debug) popup3(memo, 2, 5000);
  5382. storeMemo(title, memo, COLOR3, node);
  5383. }
  5384. return true;
  5385. }
  5386. return false;
  5387. }
  5388.  
  5389. function getDetailTitle(x, y) {
  5390. var ele = ((SITE.detailTitleXP && isDetail) && eleget0(SITE.detailTitleXP)) || (eleget0(SITE?.title)) || document.elementFromPoint(mousex, mousey);
  5391. if (!ele) return;
  5392. var title = getTitleFromParent(ele);
  5393. if (!title) return;
  5394. return title;
  5395. }
  5396.  
  5397. function getTitleFromParent(ele, nodisplay = 0) { // ele要素の親の出品物タイトルを返す
  5398. if (!nodisplay)
  5399. debug && dc("start at : " + ele.innerText);
  5400. if (SITE.title) {
  5401. let box = ele?.closest(SITE.box)
  5402. if (box) {
  5403. let title = eleget0(SITE.title, box)?.textContent?.trim()
  5404. if (title) { return title }
  5405. return
  5406. }
  5407. }
  5408. // if (isDetail) return tri((SITE.useText ? ele.textContent.replace(/\|/g, '\|') : ele.title || ele.textContent.replace(/\|/g, '\|') || ele.alt));
  5409. if (isDetail) return tri((SITE.useText ? ele.textContent.replace(/\|/g, '\|') : SITE.useURL ? ele.getAttribute("href").replace(/\?.*$/, "") : ele.title || ele.textContent.replace(/\|/g, '\|') || ele.alt));
  5410. for (let i = 0; i < (SITE.listGen); i++) {
  5411. if (!nodisplay)
  5412. debug && dc("go up (" + i + ") : " + ele.innerText)
  5413. var ele2 = elegeta(SITE.listTitleXP, ele);
  5414. if (!nodisplay)
  5415. debug && dc("length:" + ele2.length)
  5416. if (ele2.length === 1 || (SITE.searchAllowLength && ele2.length)) {
  5417. if (!nodisplay)
  5418. debug && dc("href : " + ele2[0].getAttribute("href") + "\ntitle : " + tri((ele2[0].title + " \ntextContent : " + ele2[0].textContent.replace(/\|/g, '\|') + " \nalt : " + ele2[0].alt)));
  5419. return SITE.useURL ? ele2[0].getAttribute("href").replace(/\?.*$/, "") : SITE.useText ? tri(ele2[0].textContent.replace(/\|/g, '\|')) : tri((ele2[0].title || ele2[0].textContent.replace(/\|/g, '\|') || ele2[0].alt));
  5420. }
  5421. if (ele === document) return;
  5422. ele = ele.parentNode;
  5423. }
  5424. return;
  5425. }
  5426.  
  5427. function tri(str) {
  5428. if (!str) return "";
  5429. if (str.match(/\"/)) { popup3("項目名に \" を含むので多分うまく処理できません"); return ""; }
  5430. return (SITE.trim) ? str.trim() : str;
  5431. }
  5432.  
  5433. function memoElement(ele, node, color = COLOR1, memoword = "") { //12 memo
  5434. if (!ele) return;
  5435. var title = typeof ele === "string" ? ele : getTitleFromParent(ele);
  5436. if (!title) return;
  5437. if (SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
  5438. if (!title) return;
  5439. var memo = memoword || (prompt("『" + title + "』\nのメモを書いてください") || "").trim();
  5440. // storeMemo(title, sani(memo), color, node);
  5441. storeMemo(title, memo, color, node);
  5442. return true;
  5443. }
  5444.  
  5445. function storeMemo(title, memo, color = COLOR1, node = document, jumpUrl = null) {
  5446. if (title && memo) {
  5447. memo = sani(memo)
  5448. let tmp = pref(SITE.id + ' : SearchMyMemo') || [];
  5449.  
  5450. var isExist = tmp.filter(e => e.t === title && e.c === color && e.m === memo); // 重複してなければ
  5451. if (isExist.length == 0) {
  5452.  
  5453. jumpUrl ? tmp.push({ t: title, m: memo, c: color, u: jumpUrl }) : tmp.push({ t: title, m: memo, c: color })
  5454. pref(SITE.id + ' : SearchMyMemo', tmp)
  5455. memoByTitle(title, memo, node, color, jumpUrl);
  5456. }
  5457. }
  5458. }
  5459.  
  5460. function memoByTitle(title, memo, node, color, jumpUrl = null) {
  5461. let titleNfc = title?.normalize("NFC")
  5462.  
  5463. if ((SITE.preventMemo && SITE.preventMemo(memo)) || (title.indexOf('"') !== -1 && !SITE.box)) return; // todo:タイトルに"があると正しく検索できないので処理しない
  5464. // var xp = SITE?.listTitleMemoSearchXP?.replaceTitle(title?.nfd());
  5465. var xp = SITE?.listTitleMemoSearchXP?.replaceTitle(title);
  5466. let isChapterMemo = color === COLORVIDEOTIME; // && memo.match0(/^([\d:]+)\s/)
  5467. let memoPosition = SITE.memoPosition || "afterend"
  5468. for (let titleEle of
  5469. SITE.title ?
  5470. // SITE.titleSubstr ? elegeta(SITE.title, node).filter(e => e?.textContent.indexOf(title) !== -1) :
  5471. // elegeta(SITE.title, node).filter(e => e?.textContent === title || e?.title === title || SITE.trim && e?.textContent?.trim() === title) :
  5472. SITE.titleSubstr ? elegeta(SITE.title, node).filter(e => e?.textContent?.normalize("NFC").indexOf(titleNfc) !== -1) :
  5473. elegeta(SITE.title, node).filter(e => e?.textContent?.normalize("NFC") === titleNfc || e?.title?.normalize("NFC") === titleNfc || SITE.trim && e?.textContent?.normalize("NFC")?.trim() === titleNfc) :
  5474. elegeta(xp, node)) {
  5475. //for (let titleEle of SITE.title ? elegeta(SITE.title, node).filter(e => e?.textContent?.trim()?.nfd() === title?.nfd() || e?.title?.nfd() === title?.nfd() || SITE.trim && e?.textContent?.trim()?.nfd() === title?.nfd()) : elegeta(xp, node)) {
  5476. if (titleEle) {
  5477. var ele1 = SITE.memoFunc ? SITE.memoFunc(titleEle) : // titleノードから位置をずらす関数
  5478. SITE.listTitleMemoSearchXPSameGen ? titleEle :
  5479. titleEle.parentNode;
  5480. if (!ele1) return;
  5481. let isCPU = memo.match(/Pentium|Celeron|Core\s?i\d|Ryzen|GHz|AMD.*APU/i);
  5482.  
  5483. if (isChapterMemo && GF?.isNico && titleEle?.href) jumpUrl = `${titleEle?.href?.replace(/\?.*$/,"")}?from=${hms2sec(memo.match0(/^([\d:]+)\s/))}`;
  5484.  
  5485. //ele1.insertAdjacentHTML(memoPosition, '<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo yhmMyMemo' + (color === COLOR2 ? "X" : "O") + '" id="' + escape(title + memo + color) + '" title="『' + title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/\`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>") + '』についたメモ(クリックで削除)' + (isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "") + '" style="' + MEMOSTYLE + (isCPU ? " cursor:help; " : "") + ' background-color:' + color + ';">' + memo + '</span>')
  5486. ele1.insertAdjacentHTML(memoPosition, `<span data-mbt="1" class="ignoreMe"><span class="ignoreMe yhmMyMemo yhmMyMemo${color === COLOR2 ? "X" : "O"}" data-yhmc="${color}" id="${escape(title + memo + color)}" title="『${ title.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/\`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>")}』についたメモ(クリックで削除)${(isCPU ? "\n\n右クリックでuserbenchmark検索\nhttps://duckduckgo.com/?q=!ducky+" + memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+") + "+userbenchmark" : "") + (isChapterMemo ? "\n右クリックでこの位置から再生\n" + (jumpUrl ? jumpUrl + "\n" : "") + "Shift+Uで再生位置の列挙をコピー" : "")}" style="${ MEMOSTYLE + (isCPU ? " cursor:help; " : "") } background-color:${color};">${ memo }</span>`)
  5487. var ele = memoPosition !== "afterend" ? ele1.firstElementChild : ele1.nextElementSibling.firstElementChild
  5488. //if (!memofast) $(ele).hide().fadeIn(SITE.observe ? 0 : 150);
  5489. $(ele).hide().fadeIn(SITE.observe || memofast ? 0 : 150);
  5490. //$(ele).hide().fadeIn(SITE.observe ? 0 : 150);
  5491.  
  5492.  
  5493. if (SITE?.callGKSIafterMemo) {
  5494. clearTimeout(GF?.gksiAfterMemo)
  5495. GF.gksiAfterMemo = setTimeout(() => document.dispatchEvent(new CustomEvent('plzGKSI')), 999)
  5496. }
  5497.  
  5498. // CPUモデルナンバーを右クリックでuserbenchmark検索
  5499. if (isCPU) {
  5500. $(ele).on('contextmenu', (function(title, memo) {
  5501. return function() {
  5502. if (pref("lastItemName") == undefined) { // 前回の処理が終わってないとだめ
  5503. pref("lastItemName", title);
  5504. popup3(title);
  5505. memo = memo.replace(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf\s]+/g, "+");
  5506. window.open("https://duckduckgo.com/?q=!ducky+" + memo + "+userbenchmark", "", "noreferrer");
  5507. setTimeout(() => {
  5508. if (pref("lastItemName")) {
  5509. popup3("Investigating " + memo + " timed out");
  5510. pref("lastItemName", "");
  5511. }
  5512. }, 30000); // 30秒以内に見ないとだめ
  5513. }
  5514. return false;
  5515. }
  5516. })(title, memo));
  5517. }
  5518. // チャプターメモメモを右クリックでその場所に移動 u::
  5519. if (isChapterMemo) {
  5520. ele.dataset.cm = "1"
  5521. // if(!GF.plNotFlex){GM_addStyle("#meta.ytd-playlist-panel-video-renderer{display:block}"),GF.plNotFlex=1;} // プレイリストがdisplay:flexで1行に詰め込めないので外す試用
  5522. // var p=ele.closest('#meta');if(p)p.style.display="block !important"
  5523. if (/\/watch/.test(location.href) && (ele.closest("#title,.ytd-video-primary-info-renderer") || ele1?.classList?.contains("HeaderContainer-topAreaLeft"))) {
  5524. // $(ele).on('contextmenu', (function(title, memo) {
  5525. ele.addEventListener('contextmenu', e => {
  5526. var videoEle = eleget0('//video');
  5527. if (!videoEle) return
  5528. videoEle.currentTime = hms2sec(memo.match0(/^([\d:]+)\s/)) || videoEle.currentTime
  5529. //videoEle.scrollIntoView({ block: "center", behavior: "smooth" })
  5530. e.preventDefault()
  5531. return false;
  5532. })
  5533. //})(title, memo));
  5534. } else {
  5535. var p = ele.closest('.ytd-playlist-panel-video-renderer')?.style?.display;
  5536. p = "block !important"
  5537. if (jumpUrl) ele.dataset.url = jumpUrl
  5538. ele.addEventListener('contextmenu', e => {
  5539. var jumpUrl = e.target.dataset.url || null
  5540. if (jumpUrl) {
  5541. (eleget0('//video') && !eleget0('//video')?.paused) || e.ctrlKey ? (eleget0('//video')?.pause(), window.open(jumpUrl, "", "noreferrer")) : location.href = jumpUrl;
  5542. e.preventDefault()
  5543. return false;
  5544. }
  5545. })
  5546. }
  5547. }
  5548. setRemoveMemo(ele, title, memo, color)
  5549. }
  5550. }
  5551. }
  5552.  
  5553. function setRemoveMemo(ele, title, memo, color) { // メモをクリックで消す処理
  5554. $(ele).on("click", e => { // 遅いかも?
  5555. e.preventDefault();
  5556. e.stopPropagation();
  5557. //pref(SITE.id + ' : SearchMyMemo', (pref(SITE.id + ' : SearchMyMemo') || []).filter(n => !(n.t == title && n.m == memo && n.c == color)))
  5558. pref(SITE.id + ' : SearchMyMemo', (pref(SITE.id + ' : SearchMyMemo') || []).filter(n => !(n.t?.normalize("NFC") == title?.normalize("NFC") && n.m == memo && n.c == color)))
  5559. for (let e of elegeta('//span[contains(@class,"yhmMyMemo") and @id="' + escape(title + memo + color) + '"]')) $(e).hide(200).queue(function() { $(this.parentNode).remove() }); //e.remove(); //ele.remove();
  5560. document.body.dispatchEvent(new Event('yhmMyMemoRemoved'))
  5561. //adja(document.body, "afterbegin", "<yhmmymemoremoved></yhmmymemoremoved>");
  5562. //eleget0('yhmmymemoremoved')?.remove(); // 学園祭用に消去を告知
  5563. })
  5564. }
  5565.  
  5566. function blockElement(ele) { //Q:: toggle
  5567. if (!ele) return;
  5568. var title = getTitleFromParent(ele);
  5569. debug && dc(`got (${SITE?.box}→${SITE?.title}): ${ title}』`)
  5570. addNG(title);
  5571. }
  5572.  
  5573. function hideByTitle(titleOrEle, node, targetXP = SITE.listTitleSearchXP) {
  5574. if (typeof titleOrEle === "object") { titleOrEle = titleOrEle.textContent }
  5575. var titleNfcH = titleOrEle.normalize("NFC")
  5576. let i = 0;
  5577. if (!isDetail || SITE.hideListEvenDetail) {
  5578. let resHit = [];
  5579. if (SITE.listTitleSearchFunc) resHit = SITE.listTitleSearchFunc(titleOrEle); // 主に5ch用、レス中キーワードNG
  5580. // 1項目ずつ
  5581. // for (let ele of typeof titleOrEle === "object" ? [titleOrEle] : elegeta(targetXP.replaceTitle(titleOrEle), node).concat(resHit)) { // titleがテキストなら項目タイトルにヒットする要素、DOM要素なら直接それを隠す
  5582. // for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title, node).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.trim()) : v.textContent?.trim()) === titleOrEle).map(v => v.closest(SITE.box)) : elegeta(targetXP.replaceTitle(titleOrEle), node)).concat(resHit)) { // titleがテキストなら項目タイトルにヒットする要素、DOM要素なら直接それを隠す
  5583. for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title, node).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.normalize("NFC")?.trim()) : v.textContent?.normalize("NFC")?.trim()) === titleNfcH).map(v => v.closest(SITE.box)).concat(resHit) : elegeta(targetXP.replaceTitle(titleOrEle), node)).concat(resHit)) { // titleがテキストなら項目タイトルにヒットする要素、DOM要素なら直接それを隠す
  5584. //for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title, node).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.normalize("NFC")?.trim()) : v.textContent?.normalize("NFC")?.trim()) === titleNfc).map(v => v.closest(SITE.box)) : elegeta(targetXP.replaceTitle(titleOrEle), node)).concat(resHit)) { // titleがテキストなら項目タイトルにヒットする要素、DOM要素なら直接それを隠す
  5585.  
  5586. if (!ele) continue;
  5587. i++;
  5588. // ele.dataset.hidden = "1";
  5589. // if (!disableHide && !SITE.forceTranslucentFunc?.includes(ele?.tagName)) {
  5590. // if (!disableHide && !SITE.forceTranslucentFunc?.test(ele?.tagName)) {
  5591. // if (!disableHide && (!SITE.forceTranslucentFunc || !ele.closest(SITE.forceTranslucentFunc))) {
  5592. // if (!disableHide && (!SITE.forceTranslucentFunc || !ele.closest(SITE.forceTranslucentFunc)) && (!SITE.forceTranslucentFunc || !SITE.forceTranslucentFunc(ele))) {
  5593. gmDataList_add(ele, "gmHideByyhm");
  5594. if (!disableHide && (!SITE.forceTranslucentFunc || !SITE.forceTranslucentFunc(ele))) {
  5595. // if (!disableHide && (!SITE.forceTranslucentFunc || (typeof SITE.forceTranslucentFunc==="String"? !ele.closest(SITE.forceTranslucentFunc)):(!SITE.forceTranslucentFunc(ele)))) {
  5596. $(ele).fadeOut(17);
  5597. ele.dataset.hidden = "1";
  5598. // ele.dataset.yhmkey = titleOrEle;
  5599. ele.dataset.yhmkey = titleNfcH
  5600. } else {
  5601. ele.style.opacity = "0.75";
  5602. setTimeout(function() { ele.style.opacity = "0.50" }, 17 * 2);
  5603. ele.dataset.hidden = "2"; // 必要?
  5604. // ele.dataset.yhmkey = titleOrEle;
  5605. ele.dataset.yhmkey = titleNfcH
  5606. elegeta('//*[text()="' + titleOrEle + '"]').forEach(e => { debugEle(e, "autoRemove") });
  5607. // if (!ele.title && typeof titleOrEle === "string") { ele.dataset.whyitishidden = `非表示登録『${titleOrEle}』にヒット` }
  5608. // if (!ele.title && typeof titleOrEle === "string") { ele.dataset.whyitishidden = `非表示登録『${titleOrEle}』にヒット`; ele.title=`非表示登録『${titleOrEle}』にヒット` }
  5609. if (!ele.title) ele.title = `非表示登録『${titleOrEle}』にヒット`
  5610. ele.dataset.whyitishidden = `非表示登録『${titleOrEle}』にヒット`
  5611. }
  5612. }
  5613. }
  5614. if (isDetail) {
  5615. // 詳細:画面全体
  5616. if (isDetail && SITE.detailTitleXP && SITE.detailTitleSearchXP) {
  5617. var xp = SITE.detailTitleSearchXP.replaceTitle(titleOrEle) // isearでハイライトされていると×
  5618. for (let ele of elegeta(xp, node)) {
  5619. if (!ele) continue;
  5620. gmDataList_add(ele, "gmHideByyhm");
  5621. debug && dc(xp, ele, ele.textContent);
  5622. i++;
  5623. ele.style.opacity = "0.5";
  5624. if (!ele.title) ele.title = `非表示登録『${titleOrEle}』にヒット`
  5625. ele.dataset.whyitishidden = `非表示登録『${titleOrEle}』にヒット`
  5626. }
  5627. }
  5628. }
  5629. return i;
  5630. }
  5631.  
  5632. function showByTitle(titleOrEle, time = 34, xpath = SITE.listTitleSearchXP) {
  5633. if (typeof titleOrEle === "object") { titleOrEle = titleOrEle.textContent }
  5634. if (typeof titleOrEle === "string") { var titleNfcH = titleOrEle.normalize("NFC") }
  5635.  
  5636. // if (!xpath) return
  5637. if (!isDetail || SITE.hideListEvenDetail) {
  5638. let resHit = [];
  5639. if (SITE.listTitleSearchFunc) resHit = SITE.listTitleSearchFunc(titleOrEle);
  5640. // 1項目ずつ
  5641. //var xp = xpath.replaceTitle(titleOrEle);
  5642. // SITE.title ? elegeta(SITE.title, node).filter(v => (SITE.titleProcessFunc?SITE.titleProcessFunc(v.textContent):v.textContent) === titleOrEle).map(v => v.closest(SITE.box)) :
  5643. // for (let ele of typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title).filter(e => e?.textContent == titleOrEle).map(e => e?.closest(SITE.box)) : elegeta(xpath.replaceTitle(titleOrEle)).concat(resHit)) {
  5644.  
  5645. // for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.trim()) : v.textContent?.trim()) === titleOrEle).map(e => e?.closest(SITE.box)) : elegeta(xpath.replaceTitle(titleOrEle))).concat(resHit)) {
  5646. for (let ele of (typeof titleOrEle === "object" ? [titleOrEle] : SITE.title ? elegeta(SITE.title).filter(v => (SITE.titleProcessFunc ? SITE.titleProcessFunc(v.textContent?.normalize("NFC")?.trim()) : v.textContent?.normalize("NFC")?.trim()) === titleNfcH).map(e => e?.closest(SITE.box)).concat(resHit) : elegeta(xpath.replaceTitle(titleNfcH))).concat(resHit)) {
  5647.  
  5648. if (!ele) continue;
  5649.  
  5650. gmDataList_remove(ele, "gmHideByyhm");
  5651. if (!gmDataList_includesPartial(ele, 'gmHideBy')) {
  5652.  
  5653. if (ele) ele.style.opacity = "1";
  5654. $(ele).fadeIn(time);
  5655. // delete ele.dataset.hidden;
  5656. if (ele) ele.dataset.hidden = null; //ele.dataset.yhmkey=null;
  5657. //setTimeout(function() { ele.style.opacity = "1" }, 17 * 2);
  5658. }
  5659. }
  5660. }
  5661. if (isDetail) {
  5662. // 詳細:画面全体
  5663. if (isDetail && SITE.detailTitleXP && SITE.detailTitleSearchXP) {
  5664. var xp = SITE.detailTitleSearchXP.replaceTitle(titleOrEle) // isearでハイライトされていると×
  5665. for (let ele of elegeta(xp)) {
  5666. if (!ele) continue;
  5667. gmDataList_remove(ele, "gmHideByyhm");
  5668. if (!gmDataList_includesPartial(ele, 'gmHideBy')) {
  5669. ele.style.opacity = "1";
  5670. }
  5671. }
  5672. }
  5673. }
  5674. }
  5675.  
  5676. function addNGWord() {
  5677. let tips = SITE?.Bsyntax2 ? "独自構文Tips:\n「ABCやDEFを含まず、GHIかJKLを含み、かつMNOとPQRも含む」\n!ABC|DEF GHI|JKL MNO PQR\n\n" : "";
  5678. var newWord = (prompt(`非表示にしたい項目が含むNGワードを入力してください${SITE.QRule||""}\nすでに登録されている文字列を入力するとそれを削除します\n\n${tips}現在の全体\n${JSON.stringify(pref(SITE.id + ' : SearchHideTitle') || []) }\n\n`) || "").trim();
  5679. newWord = SITE?.Bsyntax2 ? newWord.replace(/^S$/, "??").replace(/^S([\s \||])/, "??$1").replace(/([\s \||!!])S([\s \||])/, "$1??$2").replace(/([\s \||!!])S$/, "$1??").replace(/|/gm, "|").replace(/^[\!|!](\S*)/, "^(?!.*($1)).*").replace(/(\S*)[  ](\S*)/gm, "^(?=.*($1))(?=.*\($2\))").replace(/\s| /gm, ".*") : newWord // 独自構文を正規表現に変換
  5680. if (newWord && (pref(SITE.id + ' : SearchHideTitle') || []).includes(newWord) && confirm(`${newWord}\nはすでに存在します\n削除しますか?\n\n`) == false) return;
  5681. addNG(newWord);
  5682. }
  5683. /* function addNGWord() {
  5684. var newWord = (prompt(`非表示にしたい項目が含むNGワードを入力してください${SITE.QRule||""}\nすでに登録されている文字列を入力するとそれを削除します\n\n現在の全体\n${JSON.stringify(pref(SITE.id + ' : SearchHideTitle') || []) }\n\n`) || "").trim();
  5685. if (newWord && (pref(SITE.id + ' : SearchHideTitle') || []).includes(newWord) && confirm(`${newWord}\nはすでに存在します\n削除しますか?\n\n`) == false) return;
  5686. addNG(newWord);
  5687. }
  5688. */
  5689.  
  5690. function addNG(title) {
  5691. if (!title) return;
  5692. if (SITE.titleProcessFunc) title = SITE.titleProcessFunc(title);
  5693. if (!title) return;
  5694. let resist = pref(SITE.id + ' : SearchHideTitle') || [];
  5695. let i = resist.indexOf(title);
  5696. if (i !== -1) {
  5697. resist.splice(i, 1);
  5698. pref(SITE.id + ' : SearchHideTitle', resist);;
  5699. popup2("『" + title + "』\nを非表示登録から削除しました", 1);
  5700. showByTitle(title);
  5701. if (isDetail && SITE.showFunc) SITE.showFunc();
  5702. } else {
  5703. resist.push(title);
  5704. pref(SITE.id + ' : SearchHideTitle', resist);
  5705. popup2("『" + title + "』\nを非表示登録しました(" + KEYUNDO + ":取り消し " + KEYEDIT + ":編集)", 1);
  5706. hideByTitle(title);
  5707. }
  5708. }
  5709.  
  5710. // キャッシュ付き
  5711. var elegetaCacheXP = "";
  5712. var elegetaCacheLastTime = new Date();
  5713. var elegetaCacheResult = [];
  5714. var elegetaCacheNode = "";
  5715. var ehit = 0;
  5716. var emiss = 0;
  5717.  
  5718. function elegeta(xpath, node = document) {
  5719. if (!xpath || !node) return [];
  5720. //if (typeof xpath === "function") return xpath() // !!!
  5721. if (Array.isArray(xpath)) return xpath.map(v => elegeta(v, node)).filter(v => v.length).flat();
  5722. // let xpath2 = xpath.replace(/:inv?screen|:visible|:text\*=[^:]*/g, "") // text*=~中で:は使えない
  5723. let xpath2 = xpath.replace(/:inscreen|:visible|:text\*=[^:]*/g, "") // text*=~中で:は使えない
  5724. let array = []
  5725. try {
  5726. if (!/^\.?\//.test(xpath)) {
  5727. array = [...node.querySelectorAll(xpath2)]
  5728. } else {
  5729. // var snap = document.evaluate("." + xpath2, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)
  5730. var snap = document.evaluate("." + xpath2, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
  5731. let l = snap.snapshotLength
  5732. for (var i = 0; i < l; i++) array[i] = snap.snapshotItem(i)
  5733. }
  5734. if (/:visible/.test(xpath)) array = array.filter(e => e.offsetHeight)
  5735. //if (/:invscreen/.test(xpath)) array = array.filter(e => { var eler = e.getBoundingClientRect(); return (eler.bottom >= 0 && eler.top <= document.documentElement.clientHeight) }) // 画面縦内に1ピクセルでも入っている
  5736. if (/:inscreen/.test(xpath)) array = array.filter(e => { var eler = e.getBoundingClientRect(); return (eler.bottom >= 0 && eler.right >= 0 && eler.left <= document.documentElement.clientWidth && eler.top <= document.documentElement.clientHeight) }) // 画面内に1ピクセルでも入っている
  5737. if (/:text\*=./.test(xpath)) { let text = xpath.replace(/^.*:text\*=([^:]*)$/, "$1"); if (text) array = array.filter(e => new RegExp(text).test(e?.textContent)) }
  5738. } catch (e) { alert(`XPath/CSS構文にエラーがあるかもしれません\n2023/12以前にインストールしたFirefoxを使っている場合はabout:configlayout.css.has-selector.enabled true にすると解決するかもしれません\n\n${e}\n\n${xpath}\n\n${JSON.stringify(node)}`); return []; }
  5739. //} catch (e) { return []; }
  5740. return array
  5741. }
  5742.  
  5743. function eleget0(xpath, node = document) {
  5744. if (!xpath || !node) return null;
  5745. //if (typeof xpath === "function") return xpath() // !!!
  5746. // if (/:inv?screen|:visible|:text\*=/.test(xpath)) return elegeta(xpath, node)?.shift();
  5747. if (/:inscreen|:visible|:text\*=/.test(xpath)) return elegeta(xpath, node)?.shift();
  5748. if (!/^\.?\//.test(xpath)) return node.querySelector(xpath);
  5749. try {
  5750. // var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  5751. var ele = document.evaluate("." + xpath, node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  5752. return ele.snapshotLength > 0 ? ele.snapshotItem(0) : null;
  5753. } catch (e) { alert(`XPath/CSS構文にエラーがあるかもしれません\n2023/12以前にインストールしたFirefoxを使っている場合はabout:configlayout.css.has-selector.enabled true にすると解決するかもしれません\n\n${e}\n\n${xpath}\n\n${JSON.stringify(node)}`); return null; }
  5754. //} catch (e) { alert(e + "\n" + xpath + "\n" + JSON.stringify(node)); return null; }
  5755. }
  5756.  
  5757. function dc(str, force = 0) {
  5758. //if (debug == 1) console.log(str);
  5759. if (debug >= 1 || force) popup3(str, 0, 31000, "top");
  5760. return str;
  5761. }
  5762.  
  5763. function popup3(text, i = 0, timer = 5000, alignY = "bottom") {
  5764. if (!ENABLE_HELP_CONCLUSION) return;
  5765. if (text === undefined || text === null) text = "<null>"
  5766. if (typeof text == "string") text = text.slice(0, 200);
  5767. // if (typeof text == "number") text = String(text);
  5768. if (typeof text == "number") text = String(text);
  5769. text = text.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>")
  5770. let id = Math.random().toString(36).substring(2);
  5771. let maey = alignY == "bottom" ? 0 : elegeta(".wcspu3top").map(e => e.getBoundingClientRect().bottom).reduce((a, b) => Math.max(a, b), 0) + 2;
  5772. if (i > 0) $(`.pu3line${i}s`).remove()
  5773. var ele = $(`<span id="wcspu3${id}" class="ignoreMe wcspu3${alignY} pu3line${i}s" style="all:initial; max-width:33%; max-height:100vh; overflow-y:auto; scrollbar-width:thin; font-family:sans-serif; position: fixed; right:0em; ${ alignY }:${((maey) + i * 18)}px; z-index:2147483647; opacity:1; font-size:15px; margin:0px 1px; text-decoration:none !important; padding:1px 6px 1px 6px; word-break: break-all !important; border-radius:12px; background-color:#6080ff; color:white; ">${ text }</span>`).appendTo('body');
  5774. let ey = ele[0]?.getBoundingClientRect()?.height
  5775. // if (ele[0].getBoundingClientRect().bottom >= (window.innerHeight)) {
  5776. if (ele[0].getBoundingClientRect().bottom >= (window.innerHeight)) {
  5777. elegeta('.wcspu3top').forEach(e => { e.style.top = parseFloat(e?.style?.top) - (ey) - 2 + "px" })
  5778. }
  5779. if (typeof text == "string") { maey += (text.match(/<br>/gmi) || []).length || 0; } //console.log((text.match(/<br>/gmi) || [] ).length) }
  5780. setTimeout(() => {
  5781. eleget0('//span[@id="wcspu3' + id + '"]')?.remove();
  5782. }, timer);
  5783. }
  5784. var maet;
  5785.  
  5786. function popup2(text, i = 0, style = "", position = "bottom") {
  5787. if (!ENABLE_HELP_CONCLUSION) return;
  5788. text = String(text).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/'/g, "&#39;").replace(/`/g, '&#x60;').replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\n/gm, "<br>")
  5789. var mae = eleget0('//span[@id="yhmbox"]');
  5790. if (maet && mae) {
  5791. mae.remove();
  5792. clearTimeout(maet);
  5793. }
  5794. let bgcol = (pref("translucent") != "on") ? "#6080ff" : "#909090";
  5795. var ele = $(`<span id="yhmbox" class="ignoreMe" style="all:initial; max-height:100vh; overflow-y:auto; scrollbar-width:thin; font-family:sans-serif; cursor:pointer; position: fixed; right:0em; ${position}:${(i * 2 + 2) }em; z-index:2147483647; opacity:1; font-size:15px; margin:0px 1px; text-decoration:none !important; padding:1px 6px 1px 6px; word-break: break-all !important; border-radius:12px; background-color:${bgcol}; color:white; ${style}">${text}</span>`).appendTo('body');
  5796. maet = setTimeout(function() {
  5797. var mae = eleget0('//span[@id="yhmbox"]');
  5798. if (mae) { mae.remove(); }
  5799. }, 5000);
  5800. $(ele).attr("title", "クリックでこのガイドを一時的に消す").click(function() {
  5801. $(this).fadeOut(200).queue(function() {
  5802. $(this).remove();
  5803. clearTimeout(maet);
  5804. })
  5805. });
  5806. }
  5807.  
  5808. function prefChanged(id) { // prefのkeyをキャッシュと見比べて変化したか?他タブで変更されていることを想定している
  5809. let cache = prefCache[id] || null
  5810. let present = pref(id) || null
  5811. if (typeof cache === "object") cache = JS(cache)
  5812. if (typeof present === "object") present = JS(present)
  5813. return cache !== present
  5814. //return JS(prefCache[key] || []) !== JS(pref(key) || [])
  5815. }
  5816.  
  5817. function prefCacheEqual(id) {
  5818. return JS(prefCache[id] || []) === JS(pref(id) || [])
  5819. }
  5820.  
  5821. function prefCacheClear() { prefCache = [] }
  5822.  
  5823. function pref(name, store = null) { // prefs(name,data)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)、prefs(name)で読み出し
  5824. if (store === null) { // 読み出し
  5825. let data = GM_getValue(name) || GM_getValue(name);
  5826. if (data == undefined) return null; // 値がない
  5827. if (data.substring(0, 1) === "[" && data.substring(data.length - 1) === "]") { // 配列なのでJSONで返す
  5828. // try { return JSON.parse(data || '[]'); } catch (e) {
  5829. try {
  5830. let a = JSON.parse(data || '[]');
  5831. prefCache[name] = a;
  5832. return a
  5833. } catch (e) {
  5834. alert("データベースがバグってるのでクリアします\n" + e);
  5835. pref(name, []);
  5836. prefCache[name] = []
  5837. return;
  5838. }
  5839. // } else return data;
  5840. } else {
  5841. prefCache[name] = data;
  5842. return data;
  5843. }
  5844. }
  5845. if (store === "" || (Array.isArray(store) && store?.length == 0)) { // 書き込み、削除
  5846. GM_deleteValue(name);
  5847. prefCache[name] = store;
  5848. return;
  5849. } else if (typeof store === "string") { // 書き込み、文字列
  5850. GM_setValue(name, store);
  5851. prefCache[name] = store
  5852. return store;
  5853. } else { // 書き込み、配列
  5854. // try { GM_setValue(name, JSON.stringify(store)); } catch (e) {
  5855. try {
  5856. let a = JSON.stringify(store);
  5857. GM_setValue(name, a);
  5858. prefCache[name] = a
  5859. } catch (e) {
  5860. alert("データベースがバグってるのでクリアします\n" + e);
  5861. pref(name, "");
  5862. }
  5863. return store;
  5864. }
  5865. }
  5866.  
  5867. function prefRestrict(name, type) {
  5868. let data = pref(name);
  5869. if (!data) return data;
  5870. if (type === "array") {
  5871. if (typeof data === "object") {
  5872. // alert("correct");
  5873. return data;
  5874. } else {
  5875. alert("データベースの形式に誤りがある(配列/オブジェクトでない)ためクリアします\n");
  5876. pref(name, "");
  5877. return [];
  5878. }
  5879. }
  5880. return data;
  5881. }
  5882.  
  5883. function prefl(name, store = undefined, logLen = 50) { // prefl(name,data,len)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)・"name+Log"にlen個の履歴保存、prefl(name)で読み出し
  5884. if (store === undefined) { // 読み出し
  5885. return pref(name);
  5886. } else { // 書き込み、削除
  5887. if (store) {
  5888. var a = pref(name + "Log") || [];
  5889. a.unshift(store);
  5890. a = [...new Set(a)];
  5891. pref(name + "Log", a.slice(0, logLen));
  5892. }
  5893. return pref(name, store);
  5894. }
  5895. }
  5896.  
  5897. function debugEle(ele, command = "") {
  5898. if (!ele) return
  5899. if (command.indexOf("remove") !== -1) {
  5900. ele.style.outline = "";
  5901. ele.style.boxShadow = "";
  5902. return;
  5903. }
  5904. if (ENABLE_HELP_CONCLUSION && (debug || command.indexOf("force") !== -1)) {
  5905. var col = getColorFromText(ele.innerText);
  5906. if (command.indexOf("random") !== -1) col = '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
  5907. ele.style.outline = "3px dotted " + col;
  5908. ele.style.boxShadow = " 0px 0px 4px 4px " + col + "30, inset 0 0 100px " + col + "20";
  5909. // ele.title='\n@class="'+ele.className+'"\n@id="'+ele.id+'"';
  5910. if (command.indexOf("autoRemove") !== -1) {
  5911. setTimeout(() => {
  5912. ele.style.outline = "";
  5913. ele.style.boxShadow = "";
  5914. }, 60000)
  5915. }
  5916. }
  5917. }
  5918.  
  5919. function getColorFromText(str) {
  5920. if (!str) return "#808080"
  5921. var col = 0;
  5922. for (letter of str) { col = (col + str.charCodeAt(letter) ** 3); }
  5923. return '#' + (0x1000000 + col % 0xffffff).toString(16).substr(1, 6);
  5924. }
  5925.  
  5926. function advertiseEle(ele, force = "") {
  5927. if (debug || force == "force") {
  5928. if (ele) ele.style.outline = "4px dotted red";
  5929. }
  5930. }
  5931.  
  5932. function sw(job, mode = "dc") {
  5933. // if (ENABLE_MEASURE_TIME_SPENT == 0) return;
  5934. if (debug < 2 && !ENABLE_MEASURE_TIME_SPENT) return;
  5935. if (job !== "reset") {
  5936. if (mode === "dc")
  5937. debug && dc(job + " : " + ((new Date().getTime()) - (swb.getTime())) + " ms");
  5938. if (mode === "notify") notifyMe(job + " : " + ((new Date().getTime()) - (swb.getTime())) + " ms");
  5939. }
  5940. if (job !== "reset")
  5941. swb = new Date();
  5942. }
  5943.  
  5944. function isSeller() {
  5945. return location.href.match(/\/seller\//);
  5946. }
  5947.  
  5948. function proInput(prom, defaultval, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
  5949. let r = window.prompt(prom, defaultval)
  5950. if (r === null) return null
  5951. return Math.min(Math.max(
  5952. Number(r.replace(/[A-Za-z0-9.]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248); }).replace(/[^-^0-9^\.]/g, "")), min), max);
  5953. }
  5954.  
  5955. // function notifyMe(body, title = "", clickfunc = null, img = null,requireInteraction=false) {
  5956.  
  5957. function notifyMe(body, title = "", clickfunc = null, img = null, command = false) {
  5958. if (!("Notification" in window)) return;
  5959. else if (Notification.permission == "granted") {
  5960. var notify = img ? new Notification(title, { body: body, icon: img, requireInteraction: command }) : new Notification(title, { body: body, requireInteraction: command });
  5961. if (clickfunc) {
  5962. notify.onclick = clickfunc
  5963. }
  5964. } else if (Notification.permission !== "denied") Notification.requestPermission().then(function(permission) {
  5965. if (permission === "granted") new Notification(title, { body: body });
  5966. });
  5967. }
  5968.  
  5969. function setupbutton(id, title, func, tips, command) {
  5970. $(`<span id='${id}' class='ignoreMe' title='${tips}' style='cursor:pointer; color:#505050; font-size:15px; background:#ffffffc0; padding:3px; border-radius:9px;border:#505050 1px solid; position:fixed; bottom:3em; right: 1em;'>${title}</span>`).appendTo(document.body).click(function() { func(); if (/removeWhenClicked/.test(command)) { $(this).remove(); } });
  5971. }
  5972.  
  5973. // eleはスクロール画面内に入ってる?
  5974. function isinscreen(ele, evencorner = 0, borderHeight = 0) {
  5975. if (!ele) return;
  5976. var eler = ele.getBoundingClientRect();
  5977. if (evencorner) return (eler.top > 0 - eler.height - borderHeight && eler.left > 0 && eler.left < document.documentElement.clientWidth && eler.top < Math.min(window.innerHeight, document.documentElement.clientHeight) + borderHeight);
  5978. else return (eler.top > 0 - 0 && eler.left > 0 && eler.left + eler.width < document.documentElement.clientWidth && eler.top + eler.height < Math.min(window.innerHeight, document.documentElement.clientHeight) + 0);
  5979. }
  5980.  
  5981. function autoPagerized(callback, command) { // 複数回呼んではいけない
  5982. if (command !== "not1st") callback(document.body)
  5983. document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { callback(evt.target); }, false);
  5984. // document.body.addEventListener('2chanReloaded', function() { setTimeout(() => { callback() }, 1) }, false);
  5985. if (lh(".2chan.")) document.body.addEventListener('2chanReloaded', function() {
  5986. setTimeout(() => {
  5987. GF.fromSecond = 1;
  5988. callback()
  5989. }, 1)
  5990. }, false);
  5991. }
  5992.  
  5993. function autoPagerizedD(id, callback, command) { // 複数回呼んで良い、連続で呼んだ時は収まるまで遅延する
  5994. if (command !== "not1st") callback(document.body)
  5995. if (!GF?.[id]) {
  5996. document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) {
  5997. clearTimeout(GF?.apdTO)
  5998. GF.apdTO = setTimeout(callback, 500)
  5999. }, false);
  6000. GF[id] = 1;
  6001. }
  6002. }
  6003.  
  6004. function searchWithHistory(id, sitename, url, orSeparator = "|") {
  6005. var selection = null;
  6006. url = [url].flat()
  6007. let prev = pref(id + " : searchWithHistory")
  6008. if (orSeparator) {
  6009. let query = prompt(`${sitename}で全体検索します\n|でOR\n\n履歴(${id}):\n${ (pref(id + " : searchWithHistoryLog") || []).slice(0, 50).join("\n") }\n\n` + url.map(v => v.replace(/\*\*\*/, "${キーワード}")).join("\n") + '\nを開きます\n\n', selection || (prev ? prev + "|" : ""))
  6010. if (query) {
  6011. query = Array.from(new Set(query.replace(/\|/g, "|").replace(/|+/gmi, "|").split("|"))).join("|").replace(/^[|\|]+|[|\|]+$/gmi, "").trim() // 重複自動削除
  6012. if (!selection) prefl(id + " : searchWithHistory", query.replace(/\|/g, "|"))
  6013. url.forEach((v, i) => {
  6014. setTimeout(() => { GM.openInTab(`${v.replace(/\*\*\*/,encodeURI(query.replace(/|/g,orSeparator)))}`); }, i * 333)
  6015. })
  6016. }
  6017. } else {
  6018. let query = prompt(`${sitename}で全体検索します\n\n履歴(${id}):\n${ (pref(id + " : searchWithHistoryLog") || []).slice(0, 50).join("\n") }\n\n` + url.map(v => v.replace(/\*\*\*/, "${キーワード}")).join("\n") + '\nを開きます\n\n', selection || prev || "")
  6019. if (query) {
  6020. if (!selection) prefl(id + " : searchWithHistory", query?.trim())
  6021. url.forEach((v, i) => {
  6022. setTimeout(() => { GM.openInTab(`${v.replace(/\*\*\*/,encodeURI(query?.trim()))}`); }, i * 333)
  6023. })
  6024. }
  6025. }
  6026. return false;
  6027. }
  6028.  
  6029. function sec2hms(s) {
  6030. return new Date(s * 1000).toISOString().substr(11, 8).replace(/^00\:0|^00\:/, "");
  6031. }
  6032.  
  6033. function hms2sec(s) {
  6034. return ((s.match0(/^(\d+):\d+:\d+$/) || 0) * 60 * 60) + ((s.match0(/^\d+:(\d+):\d+$/) || 0) * 60) + ((s.match0(/^(\d+):\d+$/) || 0) * 60) + ((s.match0(/^\d+:\d+:(\d+)$/) || 0) * 1) + ((s.match0(/^\d+:(\d+)$/) || 0) * 1);
  6035. }
  6036.  
  6037. // function chapterMemo(requireUrlRE, videoTitleXP, newUrl, copy = 0) {
  6038. function chapterMemo(requireUrlRE, videoTitleXP, newUrl, copy = 0) {
  6039. if (!location.href.match0(requireUrlRE)) return
  6040. var videoEle = eleget0('//video');
  6041. if (!videoEle) { return; } else { var currentTime = sec2hms(Math.floor(videoEle.currentTime)); }
  6042. if (typeof videoTitleXP == "string") {
  6043. var videoTitleEle = eleget0(videoTitleXP);
  6044. if (!videoTitleEle) return;
  6045. var videoTitle = videoTitleEle.textContent;
  6046. } else { var videoTitle = videoTitleXP(); if (!videoTitle) return false; } //eleget0(videoTitleXP);
  6047.  
  6048. var curMemos = pref(SITE.id + ' : SearchMyMemo') || [];
  6049. var chaMemos = curMemos.filter(e => (e.t == videoTitle && e.c == COLORVIDEOTIME)).sort((a, b) => hms2sec(a.m.match0(/^([\d:]+)\s/)) > hms2sec(b.m.match0(/^([\d:]+)\s/)) ? 1 : -1);
  6050. var chaMemoTU = "";
  6051. //chaMemos.forEach(c => { chaMemoTU += `${videoTitle} ${c.m}\n${newUrl.replace(/\*\*time\*\*/,hms2sec(c.m.match0(/^([\d:]+)\s/)))}\n` })
  6052. chaMemos.forEach(c => { chaMemoTU += `${videoTitle} - YouTube ${c.m}\n${newUrl.replace(/\*\*time\*\*/,hms2sec(c.m.match0(/^([\d:]+)\s/)))}\n` })
  6053. if (!copy) {
  6054. var jumpUrl = location.href.match0(/https:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9_\-]{11})/);
  6055. if (jumpUrl) jumpUrl = `https://youtu.be/${jumpUrl}&t=${Math.floor(videoEle.currentTime)}`;
  6056.  
  6057. var word = window.getSelection().toString().trim() || (prompt(`『${videoTitle}』\n${currentTime=="0:00"?"に付ける":"の "+currentTime+" に付けるチャプター"}メモを入力してください\n${chaMemoTU?"\n\n列挙(Shift+Uでコピー):\n"+chaMemoTU:""}\n`) || "").trim();
  6058. if (!word) return;
  6059. storeMemo(videoTitle, (currentTime != "0:00" ? currentTime + " " : "") + word.trim(), currentTime == "0:00" ? COLOR1 : COLORVIDEOTIME, document, jumpUrl || "")
  6060. } else {
  6061. GM.setClipboard(chaMemoTU)
  6062. popup2(chaMemoTU, -1, "", "top")
  6063. //var newstr = (pref(SITE.id + ' : SearchMyMemo') || []).filter(e => (e.c === COLORVIDEOTIME));
  6064. //prompt(`チャプターメモから再生するURLの列挙をコピーしました\n\n入力フォームよりチャプターメモのエクスポートとマージが行えます\nコピーしてテキストファイル等に保存すればエクスポートとなり、他環境からエクスポートしたものを入力すればマージになります\n変更せずにEnterかEscを押せば何もしません\n\n${JSON.stringify(newstr)}`, JSON.stringify(newstr))
  6065. }
  6066. }
  6067.  
  6068. // intervalが1以上かつ設定値がdefValueと違っていればintervalミリ秒事に再処理、そうでなければ割り込みはせず、初回の実行もしない
  6069. function setSlider(placeEle, min = 0, max = 100, defValue = 0, title = "", key = "SliderValue", onchangecallback, interval = 0, addProperty = "") { // interval:1なら初回一度だけcallbackも実行、2~ならそのms間隔で定期実行
  6070. if (placeEle && !eleget0(`//input[@id="setSlider${key}"]`)) {
  6071. let val = pref(key) || defValue;
  6072. placeEle.insertAdjacentHTML("afterend", `<input type="range" class="setSlider" id="setSlider${key}" min="${min}" max="${max}" value="${val}" ${addProperty} title="${title.replace("***",val)}\n右クリック:デフォルトに戻す" oninput="this.title='${title}\\n右クリック:デフォルトに戻す'.replace('***',this.value);" oncontextmenu="this.value='${defValue}'; this.dispatchEvent(new Event('input')); return false;">`)
  6073.  
  6074. let adjustFunc = function(key, interval = 0, defValue = 0, onchange = 0) {
  6075. //popup2(`${interval} ${onchange}`)
  6076. let sliderEle = eleget0(`#setSlider${key}`)
  6077. let sliderEleNum = Number(sliderEle.value)
  6078. onchangecallback(sliderEleNum)
  6079. if (onchange) pref(key, sliderEleNum)
  6080. if (interval && sliderEleNum != defValue) setTimeout(() => { adjustFunc(key, interval, defValue) }, interval)
  6081. // if (interval>0 && sliderEleNum != defValue) setTimeout(() => { adjustFunc(key, interval, defValue) }, interval)
  6082. }
  6083. let sliderEle = eleget0(`#setSlider${key}`)
  6084. if (sliderEle) {
  6085. sliderEle.addEventListener('input', () => adjustFunc(key, interval, defValue, 1));
  6086. if (Number(sliderEle.value) != defValue) adjustFunc(key, interval, defValue)
  6087. }
  6088. //if (interval == 1) adjustFunc(key, 0, defValue)
  6089. if (interval == 1) onchangecallback(Number(eleget0(`#setSlider${key}`)?.value || defValue))
  6090. }
  6091. }
  6092.  
  6093. function domsort(container, doms, func, prepend = 0) { // container:domsの入っている大枠、省略時はdomsの1つ親 doms:並べ替える要素たち prepend:0:containerの最後に付ける 1:最初に付ける(逆順) 2:最後につける(逆順)(0or2) 3:最初に付ける(昇順) // 1と3のほうが継ぎ足し位置マーカーが上に来ないので多分良い
  6094. if (container === "") container = doms[0]?.parentNode
  6095. if (!container || !doms.length) return
  6096. if (Array.isArray(container)) container = container.shift()
  6097. let col = new Intl.Collator("ja", { numeric: true, sensitivity: 'base' })
  6098. if (prepend == 2 || prepend == 3) doms.map(function(v, i) { return { dom: v, value: func(v, i) } }).sort(function(b, a) { return (!isNaN(b.value) && !isNaN(a.value) ? b.value == a.value ? 0 : (b.value - a.value) : b.value == a.value ? 0 : (col.compare(a.value, b.value))) }).forEach(function(v) { prepend == 3 ? container?.prepend(v.dom) : container?.appendChild(v.dom) })
  6099. if (prepend == 1 || prepend == 0) doms.map(function(v, i) { return { dom: v, value: func(v, i) } }).sort(function(a, b) { return (!isNaN(b.value) && !isNaN(a.value) ? b.value == a.value ? 0 : (b.value - a.value) : b.value == a.value ? 0 : (col.compare(a.value, b.value))) }).forEach(function(v) { prepend ? container?.prepend(v.dom) : container?.appendChild(v.dom) })
  6100. }
  6101.  
  6102. function sortdom(doms, func, prepend = 0) { // doms:並べ替える要素たち prepend:0:昇順 1:降順
  6103. let position = doms[0]?.previousElementSibling
  6104. let container = doms[0]?.parentNode
  6105. if (!container || !doms.length) return
  6106. let col = new Intl.Collator("ja", { numeric: true, sensitivity: 'base' })
  6107. let fragment = new DocumentFragment();
  6108. doms.map((v, i) => { return { dom: v, value: func(v, i) } }).sort((a, b) => (prepend == 0 ?
  6109. (!isNaN(b.value) && !isNaN(b.value) ? a.value == b.value ? 0 : (a.value - b.value) : a.value == b.value ? 0 : (col.compare(a.value, b.value))) :
  6110. (!isNaN(a.value) && !isNaN(b.value) ? a.value == b.value ? 0 : (b.value - a.value) : a.value == b.value ? 0 : (col.compare(b.value, a.value)))
  6111. )).forEach(v => fragment?.append(v.dom))
  6112. position ? position.parentNode.insertBefore(fragment, position.nextSibling) : container.prepend(fragment)
  6113. }
  6114.  
  6115. function before(e, html) { e?.insertAdjacentHTML('beforebegin', html); return e?.previousElementSibling; }
  6116.  
  6117. function begin(e, html) { e?.insertAdjacentHTML('afterbegin', html); return e?.firstChild; }
  6118.  
  6119. function end(e, html) { e?.insertAdjacentHTML('beforeend', html); return e?.lastChild; }
  6120.  
  6121. function after(e, html) { e?.insertAdjacentHTML('afterend', html); return e?.nextElementSibling; }
  6122.  
  6123. function ct1(callback, name = "test", time = 10) {
  6124. console.time(name);
  6125. callback();
  6126. console.timeEnd(name)
  6127. } // 速度測定(1回だけ)
  6128. function ctLong(callback, name = "test", time = 10) { console.time(name); for (let i = time; i--;) { callback() } console.timeEnd(name) } // 速度測定(もともと長くかかるもの)
  6129. function ct(callback, name = "test", time = 10) { let i = 0; let st = Date.now(); while (Date.now() - st < 1000) { i++, callback() } console.log(`${name} ${i} / 1sec`) } // 速度測定(一瞬で終わるもの)
  6130. function lh(re) { let tmp = location.href.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可
  6131. function ld(re) { let tmp = location.hostname.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可
  6132. function JS(v) { try { return JSON.stringify(v) } catch { return null } }
  6133.  
  6134. function JP(v) { try { return JSON.parse(v) } catch { return null } }
  6135.  
  6136. function e2sel(ele) { return `${ele.tagName?.toLowerCase()}${ele.id?"#"+ele.id:""}${ele.className?"."+ele.className.replace(/\s/g,"."):""}` }
  6137.  
  6138. function han(str) { return str?.replace(/[A-Za-z0-9]/g, function(s) { return String.fromCharCode(s.charCodeAt(0) - 65248) }) || "" }
  6139.  
  6140. function sani(s) { return s?.replace(/&/g, "&amp;")?.replace(/"/g, "&quot;")?.replace(/'/g, "&#39;")?.replace(/`/g, '&#x60;')?.replace(/</g, "&lt;")?.replace(/>/g, "&gt;") || "" }
  6141.  
  6142. function gettime(_fmt = 'YYYY/MM/DD hh:mm:ss.iii', _dt = new Date()) {
  6143. return [
  6144. ['YYYY', _dt.getFullYear()],
  6145. ['MM', _dt.getMonth() + 1],
  6146. ['DD', _dt.getDate()],
  6147. ['hh', _dt.getHours()],
  6148. ['mm', _dt.getMinutes()],
  6149. ['ss', _dt.getSeconds()],
  6150. ['iii', _dt.getMilliseconds()],
  6151. ].reduce((s, a) => s.replace(a[0], `${a[1]}`.padStart(a[0].length, '0')), _fmt)
  6152. }
  6153.  
  6154. function isValidRE(str) {
  6155. try { new RegExp(str) } catch (e) { return false }
  6156. return true
  6157. }
  6158.  
  6159. function matchGG(str, re) {
  6160. return str?.match(new RegExp(re, "gm"))?.map(v => v?.match(new RegExp(re, "m"))?.[1])
  6161. }
  6162.  
  6163. // element.dataset.gmDataListプロパティにclassList.add/removeのような命令セット
  6164. function gmDataList_add(ele, name) {
  6165. let data = ele?.dataset?.gmDataList?.split(" ") || []
  6166. if (!data.includes(name)) {
  6167. data.push(name);
  6168. ele.dataset.gmDataList = data.join(" ")
  6169. }
  6170. }
  6171.  
  6172. function gmDataList_remove(ele, name) {
  6173. let data = ele?.dataset?.gmDataList?.split(" ") || []
  6174. if (data.includes(name)) {
  6175. data = data.filter(v => v !== name)
  6176. if (data.length) ele.dataset.gmDataList = data.join(" ");
  6177. else delete ele.dataset.gmDataList;
  6178. }
  6179. }
  6180.  
  6181. function gmDataList_includesPartial(ele, name) {
  6182. let data = ele?.dataset?.gmDataList?.split(" ") || []
  6183. return data.find(v => v.includes(name))
  6184. }
  6185.  
  6186. function sound(type, sec, freq = 440) { // type:sine, square, sawtooth, triangleがある
  6187. let ctx = new AudioContext();
  6188. let osc = ctx.createOscillator();
  6189. osc.type = type;
  6190. osc.frequency.setValueAtTime(freq, ctx.currentTime); // 440HzはA4(4番目のラ)
  6191. osc.connect(ctx.destination);
  6192. osc.start();
  6193. osc.stop(sec);
  6194. }
  6195.  
  6196. function clientHeight() { return Math.min(document.documentElement.clientHeight, window.innerHeight) }
  6197.  
  6198. function clientWidth() { return document.documentElement.clientWidth }
  6199.  
  6200. function cldtd(title) { debug && console.log(title + " : " + (new Date()).toLocaleString("ja-JP", { timeZone: "Asia/Tokyo" })) } // console.log date time
  6201. function cldt(title) { debug && console.log(title + " : " + gettime()) } // console.log date time
  6202.  
  6203. function getDefault56memo() {
  6204. var date = new Date();
  6205. // return date.getFullYear() + "." + ("0" + (date.getMonth() + 1)).slice(-2) + "." + ("0" + date.getDate()).slice(-2) + " (" + ["日", "月", "火", "水", "木", "金", "土"][date.getDay()] + ")"
  6206. //return `${date.getFullYear()}.${("0" + (date.getMonth() + 1)).slice(-2)}.${("0" + date.getDate()).slice(-2)} (${["日", "月", "火", "水", "木", "金", "土"][date.getDay()]})`
  6207. return `${date.getFullYear()}.${("0" + (date.getMonth() + 1)).slice(-2)}.${("0" + date.getDate()).slice(-2)}`
  6208. }
  6209.  
  6210. function img2dhash(img) {
  6211. if (!img || !img.complete || !img.naturalWidth || !img.naturalHeight) return null;
  6212. var canvas = document.createElement("canvas");
  6213. canvas.width = 8;
  6214. canvas.height = 7;
  6215. var context = canvas.getContext("2d", { alpha: false });
  6216. try {
  6217. context.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight, 0, 0, canvas.width, canvas.height);
  6218. } catch (e) {
  6219. return null;
  6220. }
  6221. var pixels = context.getImageData(0, 0, canvas.width, canvas.height);
  6222. var gray = [...Array(pixels.width * pixels.height)].map((v, i) => pixels.data[i * 4] + pixels.data[i * 4 + 1] + pixels.data[i * 4 + 2])
  6223. var dHash = gray.reduce((a, v, i) => ((i + 1) % canvas.width !== 0) ? (v < gray[i + 1] ? "1" : "0") + a : a, "");
  6224. return parseInt(dHash, 2).toString(16);
  6225. }
  6226.  
  6227. function keyFuncAdd(keyarr) {
  6228. if (!GF?.keyFuncC) {
  6229. document.addEventListener('keydown', e => {
  6230. if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement.closest('#chat-messages,ytd-comments-header-renderer')))) return;
  6231. var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
  6232. let f = GF?.keyFuncC?.find(v => v.key == key)
  6233. if (f) f.func();
  6234. })
  6235. }
  6236. keyarr.forEach(v => {
  6237. if (!GF?.keyFuncC?.includes(v)) GF.keyFuncC = GF?.keyFuncC ? GF.keyFuncC.push(v) : [v];
  6238. })
  6239. }
  6240.  
  6241. function minmax(v, min, max) {
  6242. return Math.min(Math.max(v, min), max)
  6243. }
  6244.  
  6245. function dragElement(ele, handleSel = "*", cancelSel = "") {
  6246. let x, y;
  6247. (handleSel == "*" ? [ele] : elegeta(handleSel, ele)).forEach(e => e.onmousedown = dragMouseDown)
  6248.  
  6249. function dragMouseDown(e) {
  6250. if (e.target.closest(cancelSel) || e.button != 0) return;
  6251. e = e || window.event;
  6252. e.preventDefault();
  6253. ele.style.minWidth = `${$(ele).width()}px`;
  6254. [x, y] = [e.clientX, e.clientY];
  6255. document.onmouseup = closeDragElement;
  6256. document.onmousemove = elementDrag;
  6257. }
  6258.  
  6259. function elementDrag(e) {
  6260. e = e || window.event;
  6261. e.preventDefault();
  6262.  
  6263. if (ele.style.right) { // right:かbottom:で張り付いてるものなら剥がしてleft/topにする
  6264. ele.style.left = `${ele.offsetLeft}px`
  6265. ele.style.right = ""
  6266. }
  6267. if (ele.style.bottom) { // right:かbottom:で張り付いてるものなら剥がしてleft/topにする
  6268. ele.style.top = `${ele.offsetTop}px`
  6269. ele.style.bottom = ""
  6270. }
  6271.  
  6272. ele.style.top = `${(ele.offsetTop - (y - e.clientY))}px`;
  6273. ele.style.left = `${(ele.offsetLeft - (x - e.clientX))}px`;
  6274. [x, y] = [e.clientX, e.clientY];
  6275. }
  6276.  
  6277. function closeDragElement() {
  6278. document.onmouseup = null;
  6279. document.onmousemove = null;
  6280. }
  6281. }
  6282.  
  6283. function waitdo(checkFunc, func, timeout = 3000, start = Date.now()) { // checkFuncがtrueになったらfuncを実行
  6284. let ret = checkFunc();
  6285. if (ret || ret?.length > 0) { func(ret) } else if (Date.now() - start < timeout) { setTimeout(waitdo, 111, checkFunc, func, timeout, start) }
  6286. }
  6287.  
  6288. function nfd(str) { return str?.normalize("NFD") || "" }
  6289.  
  6290. function hoverHelp(cb) {
  6291. let latest, helpEle;
  6292. SITE.preventHelpFunc = () => 1,
  6293. document.addEventListener("mousemove", e => {
  6294. if (latest != e?.target) {
  6295. helpEle?.remove()
  6296. let text = cb(e.target)
  6297. if (text) helpEle = end(document.body, `<div id="hoverHelpPopup" style="z-index:999999999; bottom:1em; right:1em; position:fixed; background-color:#ffffffe0; padding:1px 0.5em; border:1px solid #505050; font-size:15px; color:#505050; border-radius:0.75em;">${text}</div>`)
  6298. latest = e.target
  6299. if (document.elementFromPoint(e.clientX, e.clientY) == helpEle) {
  6300. helpEle.style.bottom = "";
  6301. helpEle.style.top = "1em";
  6302. }
  6303. }
  6304. })
  6305. }
  6306.  
  6307. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址