显示转发的日期和时间。

您还可以显示推特蓝徽章、推文来源标签。

目前为 2023-05-30 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Show ctime of retweets
  3. // @name:ja リツイート自体の日時を表示
  4. // @name:ko 리트윗 날짜와 시간을 표시합니다.
  5. // @name:zh-CN 显示转发的日期和时间。
  6. // @name:zh-TW 顯示轉發的日期和時間。
  7. // @namespace https://gf.qytechs.cn/en/scripts/462070-show-ctime-of-retweets
  8. // @version 1.2.0
  9. // @description Also shows Twitter Blue badges and tweet source labels.
  10. // @description:ja Twitter Blue バッジ、ツイートソースラベルも表示できます。
  11. // @description:ko Twitter Blue 배지, 트윗 소스 라벨도 표시할 수 있습니다.
  12. // @description:zh-CN 您还可以显示推特蓝徽章、推文来源标签。
  13. // @description:zh-TW 您還可以顯示推特藍徽章、推文來源標籤。
  14. // @author AeamaN
  15. // @contributionURL bitcoin:1DC6uWJWzzwU3iRJDXhUquv6QAYaRvtfFJ
  16. // @match https://twitter.com/*
  17. // @match https://mobile.twitter.com/*
  18. // @match https://twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/*
  19. // @match https://mobile.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/*
  20. // @require https://gf.qytechs.cn/scripts/467232-legacy-verified-12/code/Legacy%20verified%2012.js
  21. // @require https://gf.qytechs.cn/scripts/467238-legacy-verified-15/code/Legacy%20verified%2015.js
  22. // @require https://gf.qytechs.cn/scripts/467255-legacy-verified-19/code/Legacy%20verified%2019.js
  23. // @require https://gf.qytechs.cn/scripts/467256-legacy-verified-24/code/Legacy%20verified%2024.js
  24. // @require https://gf.qytechs.cn/scripts/467257-legacy-verified-29/code/Legacy%20verified%2029.js
  25. // @require https://gf.qytechs.cn/scripts/467258-legacy-verified-3/code/Legacy%20verified%203.js
  26. // @require https://gf.qytechs.cn/scripts/467259-legacy-verified-4/code/Legacy%20verified%204.js
  27. // @require https://gf.qytechs.cn/scripts/467260-legacy-verified-5/code/Legacy%20verified%205.js
  28. // @require https://gf.qytechs.cn/scripts/467262-legacy-verified-6/code/Legacy%20verified%206.js
  29. // @require https://gf.qytechs.cn/scripts/467263-legacy-verified-7/code/Legacy%20verified%207.js
  30. // @require https://gf.qytechs.cn/scripts/467264-legacy-verified-8/code/Legacy%20verified%208.js
  31. // @require https://gf.qytechs.cn/scripts/467265-legacy-verified-9/code/Legacy%20verified%209.js
  32. // @grant GM.getValue
  33. // @grant GM.registerMenuCommand
  34. // @grant GM.setValue
  35. // @run-at document-idle
  36. // ==/UserScript==
  37. //
  38. // ES2017(ES8) or later.
  39. //
  40. // ES2017(ES8) 以降が必要です。
  41.  
  42.  
  43. (async function() { /* START */
  44.  
  45.  
  46. 'use strict';
  47.  
  48.  
  49. // //////////// Settings //////////// //
  50. // No GUI Settings
  51. // Default values are used.
  52. const NOGUI = false;
  53. // ////////////////////////////////// //
  54.  
  55. // ///////// Default valuse ///////// //
  56. // Date formats
  57. // 1. 31.12.70 23:59
  58. // 2. 31.12.70(Th) 23:59
  59. // 3. 31.12.70 23:59:59
  60. // 4. 31.12.70(Th) 23:59:59
  61. //
  62. // 5. 70-12/31 23:59
  63. // 6. 70-12/31(Th) 23:59
  64. // 7. 70-12/31 23:59'59
  65. // 8. 70-12/31(Th) 23:59'59
  66. //
  67. // 9. 70/12/31 23:59
  68. // 10. 70/12/31(Th) 23:59
  69. // 11. 70/12/31 23:59:59
  70. // 12. 70/12/31(Th) 23:59:59 [ye/mo/da(we) ho:mi:se]
  71. //
  72. // 0. Not Shown
  73. const FMT = 10;
  74.  
  75. // Substitute TB badge
  76. // when TB without legacy verification
  77. const TB = false;
  78.  
  79. // Show source labels
  80. // 1. Tweet only
  81. // 2. Tweet and (Retweet)
  82. // 0. Not shown
  83. const SSL = 2;
  84.  
  85. // Loop interval(ms)
  86. // const INTL = 1000;
  87. const INTL = 800;
  88. // ////////////////////////////////// //
  89.  
  90. const MYNAME = 'sctrt120';
  91. const BTKN = 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs'
  92. + '=1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';
  93. const EBTKN = encodeURIComponent(BTKN);
  94.  
  95. let top_sr = '1';
  96. let json_sr = [];
  97. let json_sr_new = [];
  98. let timeout_sr = false;
  99. let s_mus = true;
  100. let observer = new MutationObserver(function(mutations) {
  101. s_mus = mutations;
  102. });
  103. let fmt, tb, ssl, intl;
  104. let dalg;
  105.  
  106. /*
  107. let cookie
  108.  
  109. async function main_track()
  110.  
  111. async function touid(sn)
  112. async function getuid(s_name)
  113.  
  114. async function statsrt(uid, rtto)
  115. async function statsrt_new(uid, rtto)
  116. async function statsrt_old(uid, rtto)
  117. async function gettl(id, cs)
  118.  
  119. async function subsall()
  120. function chklv(id)
  121.  
  122. async function addsl()
  123. async function getdetl(tid)
  124.  
  125. function mkreq(url, eq, ebt, controller)
  126.  
  127. function datef(date, f)
  128.  
  129. function makeDialog()
  130. function makeFunc(dalg)
  131. async function initgui()
  132. */
  133.  
  134.  
  135. let cookie = { // "https://qiita.com/aqril_1132/items/925a7cb04276d9f916d7"
  136. getObj: function() {
  137. let cookie = document.cookie;
  138. let cookieObj = {};
  139. if (!!cookie) {
  140. Array.prototype.forEach.call(cookie.split(';'), function(c) {
  141. let array = [c][0].split('=').map(function(a) {return a.trim()});
  142. let key = ~c.indexOf('=') ? unescape(array[0]) : '';
  143. let val = ~c.indexOf('=') ? unescape(array[1]) : unescape(array[0]);
  144. if (!cookieObj.hasOwnProperty(key)) {
  145. cookieObj[key] = [val];
  146. } else {
  147. cookieObj[key].push(val);
  148. }
  149. });
  150. }
  151. return cookieObj;
  152. },
  153. getByName: function(name) {
  154. let ret = [];
  155. let cookieObj = this.getObj();
  156. if (cookieObj.hasOwnProperty(name)) {
  157. ret = cookieObj[name];
  158. }
  159. return ret;
  160. },
  161. deleteByName : function(name, path) {
  162. var str = escape(name)
  163. + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'
  164. + (path ? '; path=' + path : '');
  165. document.cookie = str;
  166. }
  167. };
  168.  
  169.  
  170. async function main_track() {
  171. s_mus = null; // 不要?
  172. const SEL_END = 'main div[data-testid="primaryColumn"] section article span.css-cens5h.r-b88u0q:not([aria-label])';
  173. const SEL_RTTO = `div[data-testid^="User-Name"] a.css-901oao.r-qvutc0:not(.us-${MYNAME})`; // UTL, HTL
  174. const SEL_RTTO_2 = 'main div[data-testid="primaryColumn"] section article '
  175. + `div.css-1dbjc4n.r-1d09ksm.r-1471scf.r-18u37iz.r-1wbh5a2 a.css-901oao.r-qvutc0:not(.us-${MYNAME})`;
  176. // Retweet def-ja, def-en, ble-ja, ble-en
  177. const SEL_ADD = `a.us-${MYNAME}`;
  178. let elms;
  179. let pe, fpe, xpe, elm2, old, span, span2, a;
  180. let sn, rtto, date;
  181. let id, stats;
  182. elms = document.querySelectorAll(SEL_END);
  183. for(let elm of elms) {
  184. pe = elm.parentNode;
  185. fpe = elm.parentNode.parentNode.parentNode.parentNode;
  186. sn = pe.getAttribute('href').slice(1);
  187. xpe = elm.closest('article');
  188. elm2 = xpe.querySelector(SEL_RTTO);
  189. if(!elm2) elm2 = xpe.querySelector(SEL_RTTO_2);
  190. rtto = elm2.getAttribute('href').split('/')[3];
  191. id = await touid(sn); // screen name -> id, blue, created_at, screen_name, verified
  192. if(!id) continue;
  193. stats = await statsrt(id[0], rtto); // id, rtto -> tid, tca
  194. if(!fmt) continue;
  195. old = fpe.querySelector(SEL_ADD)
  196. if(!old) {
  197. span = document.createElement('span');
  198. span.className = `us-${MYNAME}`;
  199. span.style.margin = '0px 3px 0px 3px';
  200. span.textContent = '·';
  201. span.style.color = getComputedStyle(elm, null).color;
  202. span.style.font = getComputedStyle(elm, null).font;
  203. span.style.lineHeight = getComputedStyle(pe, null).lineHeight;
  204. span2 = document.createElement('span');
  205. span2.className = `us-${MYNAME}`;
  206. span2.style.lineHeight = getComputedStyle(pe, null).lineHeight;
  207. span2.style.display = 'inline-block';
  208. a = document.createElement('a');
  209. a.className = `us-${MYNAME}`;
  210. a.setAttribute('dir', 'ltr');
  211. a.setAttribute('role', 'link');
  212. a.setAttribute('href', `/${sn}/status/${stats[0]}`);
  213. a.setAttribute('target', '_blank');
  214. a.setAttribute('rel', 'noopener noreferrer');
  215. date = datef(new Date(stats[1]), fmt);
  216. a.textContent = date;
  217. a.style.color = getComputedStyle(elm, null).color;
  218. a.style.font = getComputedStyle(elm, null).font;
  219. a.style.textDecoration = getComputedStyle(elm, null).textDecoration;
  220. fpe.appendChild(span);
  221. fpe.appendChild(span2);
  222. span2.appendChild(a);
  223. s_mus = null;
  224. } else {
  225. date = datef(new Date(stats[1]), fmt);
  226. if(old.textContent != date) old.textContent = date; // TZ change
  227. }
  228. }
  229. }
  230.  
  231.  
  232. async function touid(sn) {
  233. if(localStorage.getItem(`${MYNAME}_idl`) === null) { // 無い時
  234. let r = await getuid(sn); // screen name -> id, blue, created_at, screen_name, verified
  235. if(r) {
  236. localStorage.setItem(`${MYNAME}_idl`, JSON.stringify(r));
  237. } else {
  238. console.log(`${MYNAME}: touid:error.`);
  239. return null; // エラー
  240. }
  241. }
  242. let str = localStorage.getItem(`${MYNAME}_idl`); // ある時はココから
  243. let json = JSON.parse(str);
  244. for(let e of json) {
  245. if(e[3] == sn) return e;
  246. }
  247. json = json.concat(await getuid(sn)); // あるけど、無い時
  248. str = JSON.stringify(json);
  249. localStorage.setItem(`${MYNAME}_idl`, str);
  250. for(let e of json) {
  251. if(e[3] == sn) return e;
  252. }
  253. console.log(`${MYNAME}: touid:error:end.`);
  254. return null; // エラー
  255. }
  256.  
  257.  
  258. async function getuid(s_name) {
  259. let url = 'https://api.twitter.com/graphql/rePnxwe9LZ51nQ7Sn_xN_A/UserByScreenName';
  260. if(/^[^:]+:\/\/[^/]+\.onion\//i.test(document.URL)) {
  261. url = 'https://api.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/'
  262. + 'graphql/rePnxwe9LZ51nQ7Sn_xN_A/UserByScreenName';
  263. }
  264. let q = '?variables={'
  265. + `"screen_name":"${s_name}",`
  266. + '"withSafetyModeUserFields":true,'
  267. + '"withSuperFollowsUserFields":true'
  268. + '}'
  269. + '&features={'
  270. + '"responsive_web_twitter_blue_verified_badge_is_enabled":true,'
  271. + '"responsive_web_graphql_exclude_directive_enabled":false,' // false
  272. + '"verified_phone_label_enabled":true,' // false
  273. + '"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,'
  274. + '"responsive_web_graphql_timeline_navigation_enabled":true'
  275. + '}';
  276. let eq = encodeURI(q);
  277. let controller = new AbortController();
  278. let req = mkreq(url, eq, EBTKN, controller);
  279. let res = {};
  280. try {
  281. setTimeout(function() {controller.abort()}, 60000);
  282. res = await fetch(req);
  283. if(!res.ok) {
  284. console.log(`${MYNAME}: getuid:notok:` + res.ok + '.');
  285. return null;
  286. } // 失敗なら空で終わり
  287. } catch(err) {
  288. console.log(`${MYNAME}: getuid:error:` + err + '.');
  289. return null; // 失敗なら空で終わり
  290. }
  291. let json = JSON.parse(await res.text());
  292. let id, bl, ca, sn, vf;
  293. id = json.data.user.result.rest_id;
  294. bl = json.data.user.result.is_blue_verified;
  295. ca = json.data.user.result.legacy.created_at;
  296. sn = json.data.user.result.legacy.screen_name;
  297. vf = json.data.user.result.legacy.verified;
  298. return [[id, bl, ca, sn, vf]];
  299. }
  300.  
  301.  
  302. async function statsrt(uid, rtto) { // 連続している事、entries[]の順序が正しい事
  303. let num = localStorage.length;
  304. let keys = [];
  305. let str = '';
  306. let time = null;
  307. top_sr = '1';
  308. json_sr = [];
  309. json_sr_new = [];
  310. timeout_sr = false; // 初期化
  311. for(let i = 0; i < num; i++) {
  312. keys.push(localStorage.key(i));
  313. }
  314. if(!keys.includes(`${MYNAME}_tl_` + uid)) { // 無い時
  315. let r = await gettl(uid, null); // id, cursor -> tid, tca, s, rtid, rtca
  316. if(r) {
  317. localStorage.setItem(`${MYNAME}_tl_` + uid, JSON.stringify(r));
  318. } else {
  319. console.log(`${MYNAME}: statsrt:error.`);
  320. return ['0000000000000000000', 'Thu Jan 01 00:00:00 +0000 1970']; // エラー
  321. }
  322. }
  323. if(localStorage.getItem(`${MYNAME}_timerl`) === null) {
  324. time = Date.now();
  325. localStorage.setItem(`${MYNAME}_timerl`, JSON.stringify([[uid, time]]));
  326. } else {
  327. let j = JSON.parse(localStorage.getItem(`${MYNAME}_timerl`));
  328. for(let e of j) if(e[0] == uid) time = e[1];
  329. if(!time) { // 項目が無い時
  330. time = Date.now(); // この時点の保存値にセットされる
  331. j = j.concat([[uid, time]]);
  332. localStorage.setItem(`${MYNAME}_timerl`, JSON.stringify(j));
  333. }
  334. }
  335. str = localStorage.getItem(`${MYNAME}_tl_` + uid); // ある時はココから
  336. json_sr = JSON.parse(str);
  337. for(let e of json_sr) {
  338. if(e[3] == rtto) return [e[0], e[1]]; // あれば終わり
  339. }
  340. for(let e of json_sr) {
  341. if(/^[0-9]/i.test(e[0])) {
  342. top_sr = e[0];
  343. break;
  344. }
  345. } // 上作成
  346. await statsrt_new(uid, rtto); // json_sr、json_sr_new更新
  347. json_sr = json_sr_new.concat(json_sr); // json_sr更新
  348. str = JSON.stringify(json_sr); // str更新
  349. localStorage.setItem(`${MYNAME}_tl_` + uid, str); // とりあえず、ストレージに保存
  350. for(let e of json_sr) {
  351. if(e[3] == rtto) return [e[0], e[1]]; // あれば終わり
  352. }
  353. let ret = await statsrt_old(uid, rtto); // json_sr更新、保存
  354. if(ret) return ret;
  355. let j = JSON.parse(localStorage.getItem(`${MYNAME}_timerl`));
  356. for(let e of j) if(e[0] == uid) time = e[1]; // time更新
  357. if(!timeout_sr && Date.now() - time > 600000) {
  358. localStorage.removeItem(`${MYNAME}_tl_${uid}`); // センシティブ
  359. console.log(`${MYNAME}: statsrt:remove:${MYNAME}_tl_${uid}.`);
  360. j = j.filter(function(e) {
  361. return e[0] != uid;
  362. });
  363. localStorage.setItem(`${MYNAME}_timerl`, JSON.stringify(j));
  364. time = null;
  365. }
  366. console.log(`${MYNAME}: statsrt:end.`);
  367. return ['0000000000000000000', 'Thu Jan 01 00:00:00 +0000 1970'];
  368. // TLがとても古いか、センシティブか、エラー
  369. }
  370.  
  371.  
  372. async function statsrt_new(uid, rtto) { // json_sr、json_sr_new更新
  373. let btmtmp = '';
  374. outer_block:
  375. for(const start = Date.now(); 1;) { // 新しい方、top_srを見る
  376. let ret = await gettl(uid, btmtmp);
  377. json_sr_new = json_sr_new.concat(ret); // json_sr_new更新
  378. for(let e of json_sr_new.slice().reverse()) { // 不要
  379. if(/^[0-9]/i.test(e[0])) {
  380. btmtmp = e[0];
  381. break;
  382. }
  383. } // 下更新
  384. if(ret.length < 2) {
  385. json_sr = []; // 非連続
  386. let j = JSON.parse(localStorage.getItem(`${MYNAME}_timerl`));
  387. j = j.filter(function(e) {
  388. return e[0] != uid;
  389. });
  390. j = j.concat([[uid, Date.now()]]);
  391. localStorage.setItem(`${MYNAME}_timerl`, JSON.stringify(j));
  392. break;
  393. } // 空の時は終了、一回目は無い(一個の時以外)
  394. for(let e of json_sr_new) {
  395. if(e[0] == top_sr) break outer_block; // あれば終了
  396. }
  397. if(Date.now() - start > 150000) { // 時間経過時打ち切り
  398. json_sr = []; // 非連続かも
  399. let j = JSON.parse(localStorage.getItem(`${MYNAME}_timerl`));
  400. j = j.filter(function(e) {
  401. return e[0] != uid;
  402. });
  403. j = j.concat([[uid, Date.now()]]);
  404. localStorage.setItem(`${MYNAME}_timerl`, JSON.stringify(j));
  405. break;
  406. }
  407. await new Promise(resolve => setTimeout(resolve, 200));
  408. }
  409. }
  410.  
  411.  
  412. async function statsrt_old(uid, rtto) {
  413. let btm = '';
  414. for(const start = Date.now(); 1;) { // 古い方、rttoを見る
  415. for(let e of json_sr.slice().reverse()) { // 不要
  416. if(/^[0-9]/i.test(e[0])) {
  417. btm = e[0];
  418. break;
  419. }
  420. } // 下更新
  421. let ret = await gettl(uid, btm);
  422. json_sr = json_sr.concat(ret); // json_sr更新
  423. let s = JSON.stringify(json_sr);
  424. localStorage.setItem(`${MYNAME}_tl_` + uid, s); // とりあえず、ストレージに保存
  425. if(ret.length < 2) {
  426. break;
  427. } // 空の時は終了
  428. for(let e of json_sr) {
  429. if(e[3] == rtto) return [e[0], e[1]]; // あれば終わり
  430. }
  431. if(Date.now() - start > 300000) {
  432. timeout_sr = true;
  433. break;
  434. } // 時間経過時打ち切り
  435. await new Promise(resolve => setTimeout(resolve, 200));
  436. }
  437. }
  438.  
  439.  
  440. async function gettl(id, cs) {
  441. let url = 'https://api.twitter.com/1.1/statuses/user_timeline.json';
  442. if(/^[^:]+:\/\/[^/]+\.onion\//i.test(document.URL)) {
  443. url = 'https://api.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/'
  444. + '1.1/statuses/user_timeline.json';
  445. }
  446. let kav = '';
  447. if(cs) kav = `&max_id=${cs}`;
  448. let q = `?user_id=${id}&count=50${kav}`;
  449. let eq = encodeURI(q);
  450. let controller = new AbortController();
  451. let req = mkreq(url, eq, EBTKN, controller);
  452. let res = {};
  453. let ret = [];
  454. try {
  455. setTimeout(function() {controller.abort()}, 60000);
  456. res = await fetch(req);
  457. if(!res.ok) {
  458. console.log(`${MYNAME}: gettl:notok:` + res.ok + '.');
  459. return null;
  460. } // 失敗なら空で終わり
  461. } catch(err) {
  462. console.log(`${MYNAME}: gettl:error:` + err + '.');
  463. return null; // 失敗なら空で終わり
  464. }
  465. let json = JSON.parse(await res.text());
  466. let num = Object.keys(json).length;
  467. let tid, tca, s, rtid, rtca;
  468. for(let i = 0; i < num; i++) {
  469. tid = json[i].id_str;
  470. tca = json[i].created_at;
  471. s = json[i].source;
  472. if(typeof(json[i].retweeted_status) !== 'undefined') {
  473. rtid = json[i].retweeted_status.id_str;
  474. rtca = json[i].retweeted_status.created_at;
  475. } else {
  476. rtid = 'none';
  477. rtca = 'none';
  478. }
  479. ret.push([tid, tca, s, rtid, rtca]);
  480. }
  481. return ret;
  482. }
  483.  
  484.  
  485. async function subsall() {
  486. const SEL_V = 'path[d^="M20.396 11c-.018-.646-.215-1.275-.57-1"]';
  487. const SEL_B = 'path[d^="M16.5 3H2v18h15c3.038 0 5.5-2.46 5.5-5"]';
  488. const SEL_E = 'svg.r-4qtqp9.r-yyyyoo.r-lwhw9o.r-dnmrzs.r-bnwqim.r-1plcrui.r-lrvibr.r-cnnz9e';
  489. // def-ja, def-en, ble-ja, ble-en
  490. const SEL_E2 = 'svg.r-4qtqp9.r-yyyyoo.r-1xvli5t.r-dnmrzs.r-bnwqim.r-1plcrui.r-f5ekn1.r-17h40o6.r-lrvibr';
  491. // def-ja, def-en, ble-ja, ble-en
  492. const D_V = 'M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-'
  493. + '.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-'
  494. + '.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 '
  495. + '1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1'
  496. + '.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 '
  497. + '1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02'
  498. + '.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 '
  499. + '1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 '
  500. + '1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 '
  501. + '1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 '
  502. + '1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 '
  503. + '1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816zM9.662 14.85l-3.429-3.428 '
  504. + '1.293-1.302 2.072 2.072 4.4-4.794 1.347 1.246z';
  505. const D_B = 'M16.5 3H2v18h15c3.038 0 5.5-2.46 5.5-5.5 0-1.4-.524-2.68-1.385-3.65-.08-.09-.089-'
  506. + '.22-.023-.32.574-.87.908-1.91.908-3.03C22 5.46 19.538 3 16.5 3zm-.796 5.99c.457-.05'
  507. + '.892-.17 1.296-.35-.302.45-.684.84-1.125 1.15.004.1.006.19.006.29 0 2.94-2.269 '
  508. + '6.32-6.421 6.32-1.274 0-2.46-.37-3.459-1 .177.02.357.03.539.03 1.057 0 2.03-.35 '
  509. + '2.803-.95-.988-.02-1.821-.66-2.109-1.54.138.03.28.04.425.04.206 0 '
  510. + '.405-.03.595-.08-1.033-.2-1.811-1.1-1.811-2.18v-.03c.305.17.652.27 '
  511. + '1.023.28-.606-.4-1.004-1.08-1.004-1.85 0-.4.111-.78.305-1.11 1.113 1.34 2.775 2.22 '
  512. + '4.652 2.32-.038-.17-.058-.33-.058-.51 0-1.23 1.01-2.22 2.256-2.22.649 0 '
  513. + '1.235.27 1.647.7.514-.1.997-.28 1.433-.54-.168.52-.526.96-.992 1.23z';
  514. const SEL_P_KS = 'form div[data-testid="TypeaheadUser"]'; // キーワード検索
  515. const SEL_P_KSR = 'form div[data-testid="typeaheadRecentSearchesItem"]'; // キーワード検索(最新)
  516. const SEL_P_DS = 'div[aria-labelledby="modal-header"] article div[data-testid^="User-Name"]'; // 表示をカスタマイズする
  517. const SEL_P_VRRT = 'main section article div[data-testid="card.layoutLarge.detail"]'; // ビデオ引用RT
  518. const SEL_P_T2 = 'main div[data-testid="primaryColumn"] div[data-testid="UserName"]'; // トップ2
  519. const SEL_P_RRT = 'main section article div[data-testid^="User-Name"]'; // 引用RT
  520. const SEL_KSD = 'div.css-1dbjc4n.r-1awozwy.r-18u37iz.r-1wbh5a2 div.css-1hf3ou5.r-14j79pv span'; // バグ?対策 def-ja, def-en
  521. const SEL_KSB = 'div.css-1dbjc4n.r-1awozwy.r-18u37iz.r-1wbh5a2 div.css-1hf3ou5.r-115tad6 span'; // バグ?対策 ble-ja, ble-en
  522. const SEL = 'div.css-1dbjc4n.r-18u37iz.r-1wbh5a2.r-13hce6t span.css-901oao.css-16my406.r-bcqeeo.r-qvutc0'; // def-ja, def-en, ble-ja, ble-en
  523. const SEL_2 = 'div.css-1dbjc4n.r-1awozwy.r-18u37iz.r-1wbh5a2 span.css-901oao.css-16my406.r-bcqeeo.r-qvutc0'; // def-ja, def-en, ble-ja, ble-en
  524. let elms = document.querySelectorAll(SEL_V + ', ' + SEL_B);
  525. for(let e of elms) {
  526. let spe = e.parentNode.parentNode;
  527. let tpe = e.parentNode.parentNode.parentNode;
  528. let sn;
  529. if(tpe.querySelector(SEL_E + ', ' + SEL_E2)) continue;
  530. if(spe.style.color == 'rgb(232, 134, 143)') {
  531. spe.style.color = 'rgb(29, 155, 240)';
  532. s_mus = null;
  533. }
  534. let xpe = e.closest('main div[data-testid="primaryColumn"] h2[role="heading"]'); // トップ
  535. if(xpe) {
  536. sn = document.URL.split('/')[3];
  537. }
  538. if(!sn && spe.getAttribute('data-testid') == 'verificationBadge') sn = document.URL.split('/')[3]; // 認証済アカウントポップアップ
  539. if(!sn) {
  540. let xpe = e.closest(SEL_P_KS)
  541. let sne;
  542. if(xpe) sne = xpe.querySelector(SEL_KSD);
  543. if(xpe && !sne) sne = xpe.querySelector(SEL_KSB);
  544. if(sne) sn = sne.textContent.split('@')[1];
  545. }
  546. if(!sn) {
  547. let xpe = e.closest(SEL_P_KSR)
  548. let sne;
  549. if(xpe) sne = xpe.querySelector(SEL_KSD);
  550. if(xpe && !sne) sne = xpe.querySelector(SEL_KSB);
  551. if(sne) sn = sne.textContent.split('@')[1];
  552. }
  553. if(!sn) {
  554. let xpe = e.closest(SEL_P_DS)
  555. let sne;
  556. if(xpe) sne = xpe.querySelector(SEL);
  557. if(sne) sn = sne.textContent.split('@')[1];
  558. }
  559. if(!sn) {
  560. let xpe = e.closest(SEL_P_VRRT)
  561. let sne;
  562. if(xpe) sne = xpe.querySelector(SEL);
  563. if(sne) sn = sne.textContent.split('@')[1];
  564. }
  565. if(!sn) {
  566. let xpe = e.closest(SEL_P_T2)
  567. let sne;
  568. if(xpe) sne = xpe.querySelector(SEL_2);
  569. if(sne) sn = sne.textContent.split('@')[1];
  570. }
  571. if(!sn) {
  572. let xpe = e.closest(SEL_P_RRT)
  573. let sne;
  574. if(xpe) sne = xpe.querySelector(SEL);
  575. if(sne) sn = sne.textContent.split('@')[1];
  576. }
  577. if(!sn) {
  578. let xpe = e.closest('a'); // TL等
  579. if(xpe) {
  580. sn = xpe.getAttribute('href').split('/')[1];
  581. }
  582. }
  583. if(!sn) {
  584. spe.style.color = 'rgb(232, 134, 143)';
  585. s_mus = null;
  586. continue;
  587. }
  588. let a = [
  589. '', 'compose', 'explore', 'home', 'i', 'login', 'messages',
  590. 'notifications', 'search', 'search-advanced','settings'
  591. ];
  592. if(a.indexOf(sn) > -1) {
  593. spe.style.color = 'rgb(232, 134, 143)';
  594. s_mus = null;
  595. continue;
  596. }
  597. let pr = await touid(sn);
  598. let r = chklv(pr[0]);
  599. if(r === true) {
  600. e.setAttribute('d', D_V);
  601. s_mus = null;
  602. } else if(r === false) {
  603. e.setAttribute('d', D_B);
  604. s_mus = null;
  605. } else {
  606. spe.style.color = 'rgb(232, 134, 143)';
  607. s_mus = null;
  608. }
  609. }
  610. }
  611.  
  612.  
  613. function chklv(id) {
  614. let ud = +id.substring(0, 2);
  615. let l;
  616. ud < 13 ? l = LVL_12
  617. : ud < 16 ? l = LVL_15
  618. : ud < 20 ? l = LVL_19
  619. : ud < 25 ? l = LVL_24
  620. : ud < 30 ? l = LVL_29
  621. : ud < 40 ? l = LVL_3
  622. : ud < 50 ? l = LVL_4
  623. : ud < 60 ? l = LVL_5
  624. : ud < 70 ? l = LVL_6
  625. : ud < 80 ? l = LVL_7
  626. : ud < 90 ? l = LVL_8
  627. : l = LVL_9;
  628. return l.includes(id);
  629. }
  630.  
  631.  
  632. async function addsl() {
  633. s_mus = null; // 不要?
  634. const SEL_END = 'main div[data-testid="primaryColumn"] section article div.css-1dbjc4n.r-1d09ksm.r-1471scf.r-18u37iz.r-1wbh5a2';
  635. const SEL_END_RT = 'main div[data-testid="primaryColumn"] section article span.css-cens5h.r-b88u0q:not([aria-label])';
  636. const SEL_ADD = `span.us-${MYNAME}`;
  637. let old;
  638. let ca, span, span2, a, a2;
  639. let elms_end = document.querySelectorAll(SEL_END);
  640. for(let elm of elms_end) {
  641. let uid;
  642. let tid;
  643. let tsl = '?';
  644. let rtsl = '(?)';
  645. let thref = 'https://help.twitter.com/using-twitter/how-to-tweet#source-labels';
  646. if(/^[^:]+:\/\/[^/]+\.onion\//i.test(document.URL)) {
  647. thref = 'https://help.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/using-twitter/how-to-tweet#source-labels';
  648. }
  649. let rthref = thref;
  650. ca = elm.querySelector('a');
  651. tid = ca.getAttribute('href').split('/')[3];
  652. let detl = await getdetl(tid); // tid -> tca, s, uid, sn, uca
  653. if(detl) {
  654. tsl = detl[1].split('<')[1].split('>')[1];
  655. thref = detl[1].split('"')[1];
  656. }
  657. let elm_end_rt = document.querySelector(SEL_END_RT);
  658. if(elm_end_rt) {
  659. let pe = elm_end_rt.parentNode;
  660. let sn = pe.getAttribute('href').slice(1);
  661. uid = await touid(sn); // screen name -> id, blue, created_at, screen_name, verified
  662. // リツイートした人のuid
  663. }
  664. if(ssl == 1 || !elm_end_rt) {
  665. ;
  666. } else if(uid && localStorage.getItem(`${MYNAME}_tl_${uid[0]}`) !== null) {
  667. let str = localStorage.getItem(`${MYNAME}_tl_${uid[0]}`);
  668. let json = JSON.parse(str);
  669. for(let e of json) {
  670. if(e[3] == tid) {
  671. rtsl = '(' + e[2].split('<')[1].split('>')[1] + ')';
  672. rthref = e[2].split('"')[1];
  673. }
  674. }
  675. }
  676. old = elm.querySelectorAll(SEL_ADD)
  677. if(!old.length) {
  678. span = document.createElement('span');
  679. span.className = `us-${MYNAME}`;
  680. span.style.margin = '0px 3px 0px 3px';
  681. span.textContent = '·';
  682. span.style.color = getComputedStyle(ca, null).color;
  683. span.style.font = getComputedStyle(ca, null).font;
  684. span.style.lineHeight = getComputedStyle(elm, null).lineHeight;
  685. span2 = document.createElement('span');
  686. span2.className = `us-${MYNAME}`;
  687. span2.style.lineHeight = getComputedStyle(elm, null).lineHeight;
  688. span2.style.display = 'inline-block';
  689. a = document.createElement('a');
  690. a.className = `us-${MYNAME}`;
  691. a.setAttribute('role', 'link');
  692. a.setAttribute('href', thref);
  693. a.setAttribute('target', '_blank');
  694. a.setAttribute('rel', 'nofollow noopener noreferrer');
  695. a.textContent = tsl;
  696. a.style.color = getComputedStyle(ca, null).color;
  697. a.style.font = getComputedStyle(ca, null).font;
  698. a.style.textDecoration = getComputedStyle(ca, null).textDecoration;
  699. a2 = document.createElement('a');
  700. a2.className = `us-${MYNAME}`;
  701. a2.setAttribute('role', 'link');
  702. a2.setAttribute('href', rthref);
  703. a2.setAttribute('target', '_blank');
  704. a2.setAttribute('rel', 'nofollow noopener noreferrer');
  705. a2.textContent = rtsl;
  706. a2.style.color = getComputedStyle(ca, null).color;
  707. a2.style.font = getComputedStyle(ca, null).font;
  708. a2.style.textDecoration = getComputedStyle(ca, null).textDecoration;
  709. elm.appendChild(span);
  710. elm.appendChild(span2);
  711. span2.appendChild(a);
  712. if(ssl == 2 && elm_end_rt) span2.appendChild(a2);
  713. s_mus = null;
  714. }
  715. }
  716. }
  717.  
  718.  
  719. async function getdetl(tid) {
  720. let url = 'https://api.twitter.com/1.1/statuses/show.json';
  721. if(/^[^:]+:\/\/[^/]+\.onion\//i.test(document.URL)) {
  722. url = 'https://api.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/'
  723. + '1.1/statuses/show.json';
  724. }
  725. let q = `?id=${tid}`;
  726. let eq = encodeURI(q);
  727. let controller = new AbortController();
  728. let req = mkreq(url, eq, EBTKN, controller);
  729. let res = {};
  730. try {
  731. setTimeout(function() {controller.abort()}, 60000);
  732. res = await fetch(req);
  733. if(!res.ok) {
  734. console.log(`${MYNAME}: getdtl:notok:` + res.ok + '.');
  735. return null;
  736. } // 失敗なら空で終わり
  737. } catch(err) {
  738. console.log(`${MYNAME}: getdtl:error:` + err + '.');
  739. return null; // 失敗なら空で終わり
  740. }
  741. let json = JSON.parse(await res.text());
  742. let num = 1; // 一個しかない
  743. let tca, s, uid, sn, uca;
  744. for(let i = 0; i < num; i++) {
  745. tca = json.created_at;
  746. s = json.source;
  747. if(typeof(json.user) !== 'undefined') {
  748. uid = json.user.id_str;
  749. sn = json.user.screen_name;
  750. uca = json.user.created_at;
  751. } else {
  752. uid = 'none';
  753. sn = 'none';
  754. uca = 'none';
  755. }
  756. }
  757. return [tca, s, uid, sn, uca];
  758. }
  759.  
  760.  
  761. function mkreq(url, eq, ebt, controller) {
  762. let req;
  763. if(cookie.getByName('gt').length && !cookie.getByName('twid').length) {
  764. req = new Request(`${url}${eq}`,{
  765. headers: {
  766. 'authorization': `Bearer ${ebt}`,
  767. 'x-csrf-token': cookie.getByName('ct0')[0],
  768. 'x-guest-token': cookie.getByName('gt')[0]
  769. },
  770. cache: 'force-cache',
  771. redirect: 'follow',
  772. signal: controller.signal
  773. });
  774. } else {
  775. req = new Request(`${url}${eq}`,{
  776. headers: {
  777. 'authorization': `Bearer ${ebt}`,
  778. 'x-csrf-token': cookie.getByName('ct0')[0],
  779. 'x-twitter-auth-type': 'OAuth2Session'
  780. },
  781. cache: 'force-cache',
  782. redirect: 'follow',
  783. mode: 'cors',
  784. credentials: 'include',
  785. signal: controller.signal
  786. });
  787. }
  788. return req;
  789. }
  790.  
  791.  
  792. function datef(date, f) {
  793. let week_l;
  794. let l = document.documentElement.getAttribute('lang');
  795. l == 'ja' ? week_l = ['日', '月', '火', '水', '木', '金', '土']
  796. : l == 'ko' ? week_l = ['일', '월', '화', '수', '목', '금', '토']
  797. : l == 'zh-Hant' ? week_l = ['日', '一', '二', '三', '四', '五', '六']
  798. : l == 'zh' ? week_l = ['日', '一', '二', '三', '四', '五', '六']
  799. : l == 'ru' ? week_l = ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб']
  800. : l == 'de' ? week_l = ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam']
  801. : l == 'it' ? week_l = ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab']
  802. : l == 'fr' ? week_l = ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam']
  803. : l == 'pt' ? week_l = ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'] // Add your language
  804. : week_l = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
  805. let ye, mo, da, we, ho, mi, se;
  806. ye = date.getFullYear().toString().slice(-2);
  807. mo = ('0' + (date.getMonth() + 1)).slice(-2);
  808. da = ('0' + date.getDate()).slice(-2);
  809. we = week_l[date.getDay()];
  810. ho = ('0' + date.getHours()).slice(-2);
  811. mi = ('0' + date.getMinutes()).slice(-2);
  812. se = ('0' + date.getSeconds()).slice(-2);
  813. return f == 1 ? `${da}.${mo}.${ye} ${ho}:${mi}`
  814. : f == 2 ? `${da}.${mo}.${ye}(${we}) ${ho}:${mi}`
  815. : f == 3 ? `${da}.${mo}.${ye} ${ho}:${mi}:${se}`
  816. : f == 4 ? `${da}.${mo}.${ye}(${we}) ${ho}:${mi}:${se}`
  817. : f == 5 ? `${ye}-${mo}/${da} ${ho}:${mi}`
  818. : f == 6 ? `${ye}-${mo}/${da}(${we}) ${ho}:${mi}`
  819. : f == 7 ? `${ye}-${mo}/${da} ${ho}:${mi}'${se}`
  820. : f == 8 ? `${ye}-${mo}/${da}(${we}) ${ho}:${mi}'${se}`
  821. : f == 9 ? `${ye}/${mo}/${da} ${ho}:${mi}`
  822. : f == 10 ? `${ye}/${mo}/${da}(${we}) ${ho}:${mi}`
  823. : f == 11 ? `${ye}/${mo}/${da} ${ho}:${mi}:${se}`
  824. : f == 12 ? `${ye}/${mo}/${da}(${we}) ${ho}:${mi}:${se}`
  825. : `${ye}/${mo}/${da}(${we}) ${ho}:${mi}:${se}`;
  826. }
  827.  
  828.  
  829. function makeDialog() {
  830. let dalg = document.createElement('div');
  831. dalg.className = `us-${MYNAME}`;
  832. dalg.style.all = 'initial';
  833. dalg.style.backgroundColor = 'rgb(235, 235, 235)';
  834. dalg.style.border = '3px outset';
  835. dalg.style.borderRadius = '1%';
  836. dalg.style.display = 'none';
  837. dalg.style.fontFamily = 'monospace';
  838. dalg.style.fontSize = '12px';
  839. dalg.style.height = '340px';
  840. dalg.style.width = '400px';
  841. dalg.style.paddingLeft = '2px';
  842. dalg.style.paddingRight = '2px';
  843. dalg.style.position = 'fixed';
  844. dalg.style.right = '8px';
  845. dalg.style.top = '8px';
  846. dalg.style.zIndex = '2147483647';
  847. let html = '<span style="all: initial; font-size: 120%; line-height: 140%">'
  848. + `${GM.info.script.name} ${GM.info.script.version} Settings`
  849. + '</span><br />\n'
  850. + `<input type="radio" name="fmt" value="1" class="top_r" />31.12.70 23:59`
  851. + `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`
  852. + `<input type="radio" name="fmt" value="9" class="top_r" />70/12/31 23:59<br />\n`
  853. + `<input type="radio" name="fmt" value="2" class="mid_r" />31.12.70(Th) 23:59`
  854. + `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`
  855. + `<input type="radio" name="fmt" value="10" class="mid_r" />70/12/31(Th) 23:59<br />\n`
  856. + `<input type="radio" name="fmt" value="3" class="mid_r" />31.12.70 23:59:59`
  857. + `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`
  858. + `<input type="radio" name="fmt" value="11" class="mid_r" />70/12/31 23:59:59<br />\n`
  859. + `<input type="radio" name="fmt" value="4" class="mid_r" />31.12.70(Th) 23:59:59`
  860. + `&nbsp;&nbsp;&nbsp;&nbsp;`
  861. + `<input type="radio" name="fmt" value="12" class="mid_r" />70/12/31(Th) 23:59:59<br />\n`
  862. + `<input type="radio" name="fmt" value="5" class="mid_r" />70-12/31 23:59`
  863. + `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;`
  864. + `<input type="radio" name="fmt" value="0" class="mid_r" />Not Shown<br />\n`
  865. + `<input type="radio" name="fmt" value="6" class="mid_r" />70-12/31(Th) 23:59<br />\n`
  866. + `<input type="radio" name="fmt" value="7" class="mid_r" />70-12/31 23:59'59<br />\n`
  867. + `<input type="radio" name="fmt" value="8" class="btm_r" />70-12/31(Th) 23:59'59<br />\n`
  868. + `<input type="checkbox" name="tb" class="top_c" />Substitute TB badge<br />\n`
  869. + `<input type="radio" name="ssl" value="1" class="top_r" />Tweet source labels only`
  870. + `&nbsp;&nbsp;&nbsp;&nbsp;`
  871. + `<input type="radio" name="ssl" value="0" class="top_r" />Not shown<br />\n`
  872. + `<input type="radio" name="ssl" value="2" class="btm_r" />Tweet and (Retweet)<br />\n`
  873. + '<span style="all: initial; font-size: 100%">'
  874. + 'Loop interval(ms)&nbsp;'
  875. + '</span><input type="text" name="intl" size="10" class="top_t" /><br />\n'
  876. + '<input type="button" class="top_b" value="Cancel" />\n'
  877. + '<input type="button" class="top_b" value="Set default" />\n'
  878. + '<input type="button" class="top_b" value="Save & Close" />\n';
  879. dalg.innerHTML = html;
  880. for(let e of dalg.querySelectorAll('input.top_r')) {
  881. e.style.all = 'initial';
  882. e.style.appearance = 'auto';
  883. e.style.marginRight = '1px';
  884. e.style.marginTop = '1px';
  885. }
  886. for(let e of dalg.querySelectorAll('input.mid_r, input.btm_r')) {
  887. e.style.all = 'initial';
  888. e.style.appearance = 'auto';
  889. e.style.marginRight = '1px';
  890. e.style.marginTop = '1px';
  891. }
  892. for(let e of dalg.querySelectorAll('input.top_c')) {
  893. e.style.all = 'initial';
  894. e.style.appearance = 'auto';
  895. e.style.marginRight = '1px';
  896. e.style.marginTop = '1px';
  897. }
  898. for(let e of dalg.querySelectorAll('input.top_t')) {
  899. e.style.all = 'initial';
  900. e.style.backgroundColor = 'rgb(255, 255, 255)';
  901. e.style.fontFamily = 'monospace';
  902. e.style.fontSize = '100%';
  903. e.style.marginLeft = '1px';
  904. e.style.marginRight = '1px';
  905. e.style.marginTop = '8px';
  906. e.style.marginBottom = '0px';
  907. e.style.paddingLeft = '1px';
  908. e.style.paddingRight = '1px';
  909. e.style.paddingTop = '1px';
  910. e.style.paddingBottom = '1px';
  911. }
  912. for(let e of dalg.querySelectorAll('input.top_b')) {
  913. e.style.all = 'initial';
  914. e.style.backgroundColor = 'rgb(190, 190, 190)';
  915. e.style.borderRadius = '10%';
  916. e.style.cursor = 'default';
  917. e.style.fontSize = '110%';
  918. e.style.marginTop = '10px';
  919. e.style.marginBottom = '0px';
  920. e.style.paddingTop = '6px';
  921. e.style.paddingBottom = '6px';
  922. e.style.textAlign = 'center';
  923. e.style.width = '90px';
  924. }
  925. return dalg;
  926. }
  927.  
  928.  
  929. function makeFunc(dalg) {
  930. dalg.addEventListener('click', function(event) {
  931. event.stopPropagation();
  932. }, false);
  933. dalg.querySelector('input[value="Cancel"]').addEventListener('click', function() {
  934. dalg.style.display = 'none';
  935. }, false);
  936. dalg.querySelector('input[value="Cancel"]').addEventListener('mouseenter', function(event) {
  937. event.target.style.backgroundColor = 'rgb(170, 170, 170)';
  938. }, false);
  939. dalg.querySelector('input[value="Cancel"]').addEventListener('mouseleave', function(event) {
  940. event.target.style.backgroundColor = 'rgb(190, 190, 190)'
  941. }, false);
  942. dalg.querySelector('input[value="Set default"]').addEventListener('click', function() {
  943. dalg.querySelector(`input[name="fmt"][value="${FMT}"]`).checked = true;
  944. dalg.querySelector('input[name="tb"]').checked = TB;
  945. dalg.querySelector(`input[name="ssl"][value="${SSL}"]`).checked = true;
  946. dalg.querySelector('input[name="intl"]').value = INTL;
  947. }, false);
  948. dalg.querySelector('input[value="Set default"]').addEventListener('mouseenter', function(event) {
  949. event.target.style.backgroundColor = 'rgb(170, 170, 170)';
  950. }, false);
  951. dalg.querySelector('input[value="Set default"]').addEventListener('mouseleave', function(event) {
  952. event.target.style.backgroundColor = 'rgb(190, 190, 190)'
  953. }, false);
  954. dalg.querySelector('input[value="Save & Close"]').addEventListener('click', async function() {
  955. for(let e of dalg.querySelectorAll('input[name="fmt"]')) {
  956. if(e.checked) {
  957. fmt = +e.value;
  958. break;
  959. }
  960. }
  961. tb = dalg.querySelector('input[name="tb"]').checked;
  962. for(let e of dalg.querySelectorAll('input[name="ssl"]')) {
  963. if(e.checked) {
  964. ssl = +e.value;
  965. break;
  966. }
  967. }
  968. intl = +dalg.querySelector('input[name="intl"]').value;
  969. await GM.setValue('fmt', fmt);
  970. await GM.setValue('tb', tb);
  971. await GM.setValue('ssl', ssl);
  972. await GM.setValue('intl', intl);
  973. dalg.style.display = 'none';
  974. }, false);
  975. dalg.querySelector('input[value="Save & Close"]').addEventListener('mouseenter', function(event) {
  976. event.target.style.backgroundColor = 'rgb(170, 170, 170)';
  977. }, false);
  978. dalg.querySelector('input[value="Save & Close"]').addEventListener('mouseleave', function(event) {
  979. event.target.style.backgroundColor = 'rgb(190, 190, 190)'
  980. }, false);
  981. }
  982.  
  983.  
  984. async function initgui() {
  985. if(await GM.getValue('fmt') === undefined) {
  986. await GM.setValue('fmt', FMT);
  987. } else {
  988. fmt = await GM.getValue('fmt');
  989. }
  990. if(await GM.getValue('tb') === undefined) {
  991. await GM.setValue('tb', TB);
  992. } else {
  993. tb = await GM.getValue('tb');
  994. }
  995. if(await GM.getValue('ssl') === undefined) {
  996. await GM.setValue('ssl', SSL);
  997. } else {
  998. ssl = await GM.getValue('ssl');
  999. }
  1000. if(await GM.getValue('intl') === undefined) {
  1001. await GM.setValue('intl', INTL);
  1002. } else {
  1003. intl = await GM.getValue('intl');
  1004. }
  1005. dalg = makeDialog();
  1006. makeFunc(dalg);
  1007. document.body.appendChild(dalg);
  1008. GM.registerMenuCommand('Settings', function() {
  1009. if(dalg.style.display == 'none') {
  1010. dalg.querySelector(`input[name="fmt"][value="${fmt}"]`).checked = true;
  1011. dalg.querySelector('input[name="tb"]').checked = tb;
  1012. dalg.querySelector(`input[name="ssl"][value="${ssl}"]`).checked = true;
  1013. dalg.querySelector('input[name="intl"]').value = intl;
  1014. dalg.style.display = 'block';
  1015. }
  1016. });
  1017. }
  1018.  
  1019.  
  1020. console.log(`${MYNAME}: start.`);
  1021.  
  1022. fmt = FMT;
  1023. tb = TB;
  1024. ssl = SSL;
  1025. intl = INTL;
  1026.  
  1027. if(!NOGUI) await initgui();
  1028. observer.observe(document.documentElement, {childList:true, subtree:true});
  1029.  
  1030. while(1) {
  1031. if(s_mus) {
  1032. if(fmt || ssl == 2) await main_track();
  1033. if(tb) await subsall();
  1034. if(ssl) await addsl();
  1035. s_mus = null; // 初期値がtrue、非同期処理用
  1036. }
  1037. await new Promise(resolve => setTimeout(resolve, intl)); // intl は外から非同期に変更する
  1038. }
  1039.  
  1040.  
  1041. })(); /* END */

QingJ © 2025

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