- // ==UserScript==
- // @name Show ctime of retweets
- // @name:ja リツイート自体の日時を表示
- // @name:ko 리트윗 날짜와 시간을 표시합니다.
- // @name:zh-CN 显示转发的日期和时间。
- // @name:zh-TW 顯示轉發的日期和時間。
- // @namespace https://gf.qytechs.cn/en/scripts/462070-show-ctime-of-retweets
- // @version 1.11.9
- // @description Also shows Twitter Blue badges and tweet source labels.
- // @description:ja Twitter Blue バッジ、ツイートソースラベルも表示できます。
- // @description:ko Twitter Blue 배지, 트윗 소스 라벨도 표시할 수 있습니다.
- // @description:zh-CN 您还可以显示推特蓝徽章、推文来源标签。
- // @description:zh-TW 您還可以顯示推特藍徽章、推文來源標籤。
- // @author AeamaN
- // @contributionURL bitcoin:1DC6uWJWzzwU3iRJDXhUquv6QAYaRvtfFJ
- // @match https://twitter.com/*
- // @match https://mobile.twitter.com/*
- // @match https://twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/*
- // @match https://mobile.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/*
- // @match https://x.com/*
- // @match https://mobile.x.com/*
- // @require https://update.gf.qytechs.cn/scripts/467232/1197541/Legacy%20verified%2012.js
- // @require https://update.gf.qytechs.cn/scripts/467238/1197542/Legacy%20verified%2015.js
- // @require https://update.gf.qytechs.cn/scripts/467255/1197539/Legacy%20verified%2019.js
- // @require https://update.gf.qytechs.cn/scripts/467256/1197544/Legacy%20verified%2024.js
- // @require https://update.gf.qytechs.cn/scripts/467257/1197545/Legacy%20verified%2029.js
- // @require https://update.gf.qytechs.cn/scripts/467258/1197546/Legacy%20verified%203.js
- // @require https://update.gf.qytechs.cn/scripts/467259/1197547/Legacy%20verified%204.js
- // @require https://update.gf.qytechs.cn/scripts/467260/1197548/Legacy%20verified%205.js
- // @require https://update.gf.qytechs.cn/scripts/467262/1197549/Legacy%20verified%206.js
- // @require https://update.gf.qytechs.cn/scripts/467263/1197550/Legacy%20verified%207.js
- // @require https://update.gf.qytechs.cn/scripts/467264/1197553/Legacy%20verified%208.js
- // @require https://update.gf.qytechs.cn/scripts/467265/1197554/Legacy%20verified%209.js
- // @grant GM.getValue
- // @grant GM.registerMenuCommand
- // @grant GM.setValue
- // @run-at document-body
- // ==/UserScript==
-
- // ES2017(ES8) or later.
- // ES2017(ES8) 以降が必要です。
-
-
- (async function () { /* START */
-
-
- 'use strict';
-
-
- // //////////// Settings //////////// //
- // No GUI Settings
- // Default values are used
- const NO_GUI = false;
- // ////////////////////////////////// //
-
- // ///////// Default valuse ///////// //
- // Substitute TB badge
- // when TB without legacy verification
- const TB = false;
-
- // Show source labels
- // 1. Tweet only
- // 2. Tweet and (Retweet)
- // 0. Not show
- const SHOW_SL = 2;
-
- // Date formats
- // 1. Show
- // 0. Not show
- const FMT = 1;
-
- // YE(70), YF(1970), YEU(UTC), YFU(UTC), YM(60),
- // MO(12), MN(Dec), DA(31), WE(Th), HO(23), HH(11), MI(59), SE(59) and AP(PM)
- const FMTS = 'YE/MO/DA(WE) HO:MI:SE';
-
- // Month name
- const JAN = 'Jan';
- const FEB = 'Feb';
- const MAR = 'Mar';
- const APR = 'Apr';
- const MAY = 'May';
- const JUN = 'Jun';
- const JUL = 'Jul';
- const AUG = 'Aug';
- const SEP = 'Sep';
- const OCT = 'Oct';
- const NOV = 'Nov';
- const DEC = 'Dec';
-
- // Week label
- const SUN = '😊';
- const MON = '😭';
- const TUE = 'Tu';
- const WED = 'We';
- const THU = 'Th';
- const FRI = 'Fr';
- const SAT = 'Sa';
-
- // AM and PM
- const AM = 'AM';
- const PM = 'PM';
-
- // Loop interval(ms)
- const INTL = 800;
- // ////////////////////////////////// //
-
-
- const MYNAME = 'sctrt1119';
-
- const BTKN =
- 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs=' +
- '1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';
- const EBTKN = encodeURIComponent(BTKN);
-
- const SETS = {
- 'fmt': ['r', FMT], 'fmts': ['t', FMTS],
- 'jan': ['t', JAN, 'm', 0], 'feb': ['t', FEB, 'm', 1], 'mar': ['t', MAR, 'm', 2], 'apr': ['t', APR, 'm', 3],
- 'may': ['t', MAY, 'm', 4], 'jun': ['t', JUN, 'm', 5], 'jul': ['t', JUL, 'm', 6], 'aug': ['t', AUG, 'm', 7],
- 'sep': ['t', SEP, 'm', 8], 'oct': ['t', OCT, 'm', 9], 'nov': ['t', NOV, 'm', 10], 'dec': ['t', DEC, 'm', 11],
- 'sun': ['t', SUN, 'w', 0], 'mon': ['t', MON, 'w', 1], 'tue': ['t', TUE, 'w', 2], 'wed': ['t', WED, 'w', 3],
- 'thu': ['t', THU, 'w', 4], 'fri': ['t', FRI, 'w', 5], 'sat': ['t', SAT, 'w', 6],
- 'am': ['t', AM], 'pm': ['t', PM],
- 'tb': ['c', TB],
- 'show_sl': ['r', SHOW_SL],
- 'intl': ['t', INTL]
- };
-
- const SEL_SB_V = 'path[d^="M20.396 11c-.018-.646-.215-1.275-.57-1"]';
- const SEL_SB_B = 'path[d^="M16.5 3H2v18h15c3.038 0 5.5-2.46 5.5-5"]';
- const SEL_SB_E =
- 'svg.r-4qtqp9.r-yyyyoo.r-lwhw9o.r-dnmrzs.r-bnwqim.' +
- 'r-1plcrui.r-lrvibr.r-cnnz9e';
- // def-ja, def-en, ble-ja, ble-en
- const SEL_SB_E2 =
- 'svg.r-4qtqp9.r-yyyyoo.r-1xvli5t.r-dnmrzs.r-bnwqim.' +
- 'r-1plcrui.r-f5ekn1.r-17h40o6.r-lrvibr';
- // def-ja, def-en, ble-ja, ble-en
- const DATA_SB_V =
- 'M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.6' +
- '07.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.8' +
- '82-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.' +
- '604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.90' +
- '2-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.1' +
- '44 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 ' +
- '1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634' +
- '.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.' +
- '586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.5' +
- '67s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.90' +
- '7.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.' +
- '246.354-.54.551-1.17.569-1.816zM9.662 14.85l-3.429-3.428 1.293-1.302 2.072 2.072' +
- ' 4.4-4.794 1.347 1.246z';
- const DATA_SB_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' +
- '-.22-.023-.32.574-.87.908-1.91.908-3.03C22 5.46 19.538 3 16.5 3zm-.796 5.99c.457' +
- '-.05.892-.17 1.296-.35-.302.45-.684.84-1.125 1.15.004.1.006.19.006.29 0 2.94-2.2' +
- '69 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 2.803-.95-.988-.02-1.821-.66-2.109-1.54.138.03.28.04.425.04.206 0 .405-.03.59' +
- '5-.08-1.033-.2-1.811-1.1-1.811-2.18v-.03c.305.17.652.27 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 4.652 2.32-.038-.17-.' +
- '058-.33-.058-.51 0-1.23 1.01-2.22 2.256-2.22.649 0 1.235.27 1.647.7.514-.1.997-.' +
- '28 1.433-.54-.168.52-.526.96-.992 1.23z';
- const SEL_SB_P_KS = 'form button[data-testid="TypeaheadUser"]'; // キーワード検索
- const SEL_SB_P_DS =
- 'div[aria-labelledby="modal-header"] div.css-175oi2r.r-1wbh5a2.r-dnmrzs.r-1ny4l3l>' +
- 'div[data-testid^="User-Name"]'; // 表示をカスタマイズする、ノート
- const SEL_SB_P_VRRT = 'main section article div[data-testid="card.layoutLarge.detail"]'; // ビデオ引用RT
- const SEL_SB_P_T2 = 'main div[data-testid="primaryColumn"] div[data-testid="UserName"]'; // トップ2
- const SEL_SB_P_RRT = 'main section article div[data-testid^="User-Name"]'; // 引用RT
- const SEL_SB_P_RRT_M = 'main div.css-175oi2r.r-1ua6aaf.r-th6na.r-1phboty article div[data-testid^="User-Name"]';
- // モバイル引用RT
- const SEL_SB = ':scope div.css-175oi2r.r-1awozwy.r-18u37iz.r-1wbh5a2 span.css-1jxf684.r-bcqeeo.r-qvutc0';
- // def-ja, def-en, ble-ja, ble-en
- const SEL_SB_2 = ':scope div.css-175oi2r.r-18u37iz.r-1wbh5a2.r-1ez5h0i span.css-1jxf684.r-bcqeeo.r-qvutc0';
- // def-ja, def-en, ble-ja, ble-en
-
- const SEL_AS_END =
- 'main div[data-testid="primaryColumn"] section article ' +
- 'div.css-175oi2r.r-1d09ksm.r-1471scf.r-18u37iz.r-1wbh5a2';
- const SEL_AS_END_RT =
- 'main div[data-testid="primaryColumn"] section article ' +
- 'span.css-1jxf684.r-8akbws.r-krxsd3.r-b88u0q[id][data-testid="socialContext"]';
-
- const SEL_ADD_SPAN = `span.us-${MYNAME}`;
-
- const SEL_MT_END_RT =
- 'main div[data-testid="primaryColumn"] section article ' +
- 'span.css-1jxf684.r-8akbws.r-krxsd3.r-b88u0q[id][data-testid="socialContext"]';
-
- const SEL_MT_RTTO = `:scope div[data-testid^="User-Name"] a.css-146c3p1.r-qvutc0:not(.us-${MYNAME})`;
- // UTL, HTL
- const SEL_MT_RTTO_2 =
- `:scope div.css-175oi2r.r-1d09ksm.r-1471scf.r-18u37iz.r-1wbh5a2 a.css-1jxf684.r-qvutc0:not(.us-${MYNAME})`;
- // Retweet def-ja, def-en, ble-ja, ble-en
-
- const SEL_ADD_A = `a.us-${MYNAME}`;
-
- let sets = {};
- let dtbs = {};
- let time_ref = {};
- let muts = true;
- let observer = new MutationObserver(function (mutations) {
- muts = mutations;
- });
- let orig_xhr_open;
-
-
- async function loadDB(key) {
- let str = await GM.getValue(key);
-
- if (str === undefined && key.indexOf('cntr') == 0) { // 何も無い時
- return [0, false];
- } else if (str === undefined) {
- return [];
- } else { // ある時
- return JSON.parse(str);
- }
- }
-
-
- function getCV(name) {
- let cookie = document.cookie;
- if (!cookie) return [];
- let obj = {};
-
- cookie.split(';').forEach(function (rec) {
- let kav = rec.split('=');
- let key, val;
- [key, val] =
- rec.includes('=') ?
- [unescape(kav[0].trim()), unescape(kav[1].trim())] :
- ['', unescape(kav[0].trim())];
- if (!obj[key]) obj[key] = [val];
- else obj[key].push(val);
- });
-
- return obj[name] ?? [];
- }
-
-
- function pathExists(obj, path) {
- for (let key of path) {
- if (!(obj = obj[key])) return false;
- }
- return true;
- }
-
-
- function makeDalg() {
- let dalg = document.createElement('div');
-
- dalg.className = `us-${MYNAME}`;
-
- dalg.style.all = 'initial';
- dalg.style.backgroundColor = 'rgb(235, 235, 235)';
- dalg.style.border = '3px outset';
- dalg.style.borderRadius = '1%';
- dalg.style.display = 'none';
- dalg.style.fontFamily = 'monospace';
- dalg.style.fontSize = '12px';
- dalg.style.height = '420px';
- dalg.style.width = '480px';
- dalg.style.paddingLeft = '2px';
- dalg.style.paddingRight = '2px';
- dalg.style.position = 'fixed';
- dalg.style.right = '8px';
- dalg.style.top = '8px';
- dalg.style.zIndex = '2147483647';
- dalg.style.overflow = 'auto';
-
- const HTML =
- '<span style="all: initial; font-size: 130%; font-weight: bold; line-height: 210%">' +
- `Settings - ${GM.info.script.name} ${GM.info.script.version}` +
- '</span><br />\n' +
-
- '<input type="radio" name="fmt" value="1" class="top_r" />' +
- 'Format:<br />\n' +
- ' ' +
- '<input type="text" name="fmts" class="top_t1" />(*1)<br />\n' +
- ' ' +
- 'MN in the format:<br />\n' +
- ' ' +
- '<input type="text" name="jan" class="top_t2" />' +
- '<input type="text" name="feb" class="top_t2" />' +
- '<input type="text" name="mar" class="top_t2" />' +
- '<input type="text" name="apr" class="top_t2" />' +
- '<input type="text" name="may" class="top_t2" />' +
- '<input type="text" name="jun" class="top_t2" /><br />\n' +
- ' ' +
- '<input type="text" name="jul" class="top_t2" />' +
- '<input type="text" name="aug" class="top_t2" />' +
- '<input type="text" name="sep" class="top_t2" />' +
- '<input type="text" name="oct" class="top_t2" />' +
- '<input type="text" name="nov" class="top_t2" />' +
- '<input type="text" name="dec" class="top_t2" /><br />\n' +
- ' ' +
- 'WE in the format:<br />\n' +
- ' ' +
- '<input type="text" name="sun" class="top_t2" />' +
- '<input type="text" name="mon" class="top_t2" />' +
- '<input type="text" name="tue" class="top_t2" />' +
- '<input type="text" name="wed" class="top_t2" />' +
- '<input type="text" name="thu" class="top_t2" />' +
- '<input type="text" name="fri" class="top_t2" />' +
- '<input type="text" name="sat" class="top_t2" />(*2)<br />\n' +
- ' ' +
- 'AP in the format:<br />\n' +
- ' ' +
- '<input type="text" name="am" class="btm_t" />' +
- '<input type="text" name="pm" class="btm_t" /><br />\n' +
- '<input type="radio" name="fmt" value="0" class="btm_r" />Not show<br /><br />\n' +
-
- '<input type="checkbox" name="tb" class="top_c" />Substitute TB badge<br /><br />\n' +
-
- '<input type="radio" name="show_sl" value="1" class="top_r" />Tweet source labels only' +
- ' ' +
- '<input type="radio" name="show_sl" value="2" class="top_r" />Tweet and (Retweet)<br />\n' +
- '<input type="radio" name="show_sl" value="0" class="btm_r" />Not show<br /><br />\n' +
-
- '<span style="all: initial; font-size: 100%">' +
- 'Loop interval(ms) ' +
- '</span><input type="text" name="intl" class="top_t3" /><br />\n' +
-
- '<br />\n' +
- '<span style="all: initial; font-size: 100%; line-height: 140%">' +
- '(*1)Symbols YE, YF, YEU(UTC), YFU(UTC), YM,<br />\n' +
- ' ' +
- 'MO, MN, DA, WE, HO, HH, MI, SE and AP are available<br />\n' +
- '(*1)Example:<br />\n' +
- ' ' +
- 'YE/MO/DA(WE) HO:MI:SE >> 70/12/31(Th) 23:59:59<br />\n' +
- ' ' +
- 'WE, MN DA, YF-HH:MI:SE AP >> Th, Dec 31, 1970-11:59:59 PM<br />\n' +
- ' ' +
- 'YFU/MO/DA HO:MI(UTC) >> 1970/12/31 23:59(UTC)<br />\n' +
- ' ' +
- 'MYM/MO/DA HO:MI >> M60/01/01 07:59<br />\n' +
- '(*2)Sunday origin' +
- '</span><br />\n' +
-
- ' ' +
- ' ' +
- '<input type="button" class="top_b" value="Cancel" />\n' +
- '<input type="button" class="top_b" value="Set default" />\n' +
- '<input type="button" class="top_b" value="Save & Close" />\n' +
- '<br /><br /><br /><br /><br /><br /><br /><br />\n';
-
- dalg.innerHTML = HTML;
-
- for (let e of dalg.querySelectorAll('input.top_r')) {
- e.style.all = 'initial';
- e.style.appearance = 'auto';
- e.style.marginRight = '1px';
- e.style.marginTop = '1px';
- }
- for (let e of dalg.querySelectorAll('input.mid_r, input.btm_r')) {
- e.style.all = 'initial';
- e.style.appearance = 'auto';
- e.style.marginRight = '1px';
- e.style.marginTop = '1px';
- }
- for (let e of dalg.querySelectorAll('input.top_c')) {
- e.style.all = 'initial';
- e.style.appearance = 'auto';
- e.style.marginRight = '1px';
- e.style.marginTop = '1px';
- }
- for (let e of dalg.querySelectorAll('input.top_t1')) {
- e.style.all = 'initial';
- e.style.backgroundColor = 'rgb(255, 255, 255)';
- e.style.fontFamily = 'monospace';
- e.style.fontSize = '100%';
- e.style.marginLeft = '4px';
- e.style.marginRight = '1px';
- e.style.marginTop = '2px';
- e.style.marginBottom = '0px';
- e.style.paddingLeft = '1px';
- e.style.paddingRight = '1px';
- e.style.paddingTop = '1px';
- e.style.paddingBottom = '1px';
- e.style.width = '38%';
- e.setAttribute('size', '28');
- }
- for (let e of dalg.querySelectorAll('input.top_t2')) {
- e.style.all = 'initial';
- e.style.backgroundColor = 'rgb(255, 255, 255)';
- e.style.fontFamily = 'monospace';
- e.style.fontSize = '100%';
- e.style.marginLeft = '4px';
- e.style.marginRight = '1px';
- e.style.marginTop = '2px';
- e.style.marginBottom = '0px';
- e.style.paddingLeft = '1px';
- e.style.paddingRight = '1px';
- e.style.paddingTop = '1px';
- e.style.paddingBottom = '1px';
- e.style.width = '9%';
- e.setAttribute('size', '5');
- }
- for (let e of dalg.querySelectorAll('input.top_t3')) {
- e.style.all = 'initial';
- e.style.backgroundColor = 'rgb(255, 255, 255)';
- e.style.fontFamily = 'monospace';
- e.style.fontSize = '100%';
- e.style.marginLeft = '4px';
- e.style.marginRight = '1px';
- e.style.marginTop = '2px';
- e.style.marginBottom = '0px';
- e.style.paddingLeft = '1px';
- e.style.paddingRight = '1px';
- e.style.paddingTop = '1px';
- e.style.paddingBottom = '1px';
- e.style.width = '14%';
- e.setAttribute('size', '10');
- }
- for (let e of dalg.querySelectorAll('input.btm_t')) {
- e.style.all = 'initial';
- e.style.backgroundColor = 'rgb(255, 255, 255)';
- e.style.fontFamily = 'monospace';
- e.style.fontSize = '100%';
- e.style.marginLeft = '4px';
- e.style.marginRight = '1px';
- e.style.marginTop = '2px';
- e.style.marginBottom = '0px';
- e.style.paddingLeft = '1px';
- e.style.paddingRight = '1px';
- e.style.paddingTop = '1px';
- e.style.paddingBottom = '1px';
- e.style.width = '9%';
- e.setAttribute('size', '5');
- }
- for (let e of dalg.querySelectorAll('input.top_b')) {
- e.style.all = 'initial';
- e.style.backgroundColor = 'rgb(190, 190, 190)';
- e.style.borderRadius = '10%';
- e.style.cursor = 'default';
- e.style.fontSize = '110%';
- e.style.marginTop = '26px';
- e.style.marginBottom = '0px';
- e.style.paddingTop = '6px';
- e.style.paddingBottom = '6px';
- e.style.textAlign = 'center';
- e.style.width = '90px';
- }
-
- return dalg;
- }
-
-
- function makeFunc(dalg) {
- dalg.addEventListener(
- 'click',
- function (event) { event.stopPropagation(); },
- false
- );
-
- dalg.querySelector('input[value="Cancel"]').addEventListener(
- 'click',
- function () { dalg.style.display = 'none'; },
- false
- );
- dalg.querySelector('input[value="Cancel"]').addEventListener(
- 'mouseenter',
- function (event) { event.target.style.backgroundColor = 'rgb(170, 170, 170)'; },
- false
- );
- dalg.querySelector('input[value="Cancel"]').addEventListener(
- 'mouseleave',
- function (event) { event.target.style.backgroundColor = 'rgb(190, 190, 190)'; },
- false
- );
-
- dalg.querySelector('input[value="Set default"]').addEventListener(
- 'click',
- function () {
- for (let v in SETS) {
- if (SETS[v][0] == 'r') {
- dalg.querySelector(`input[name="${v}"][value="${SETS[v][1]}"]`).checked = true;
- } else if (SETS[v][0] == 'c') {
- dalg.querySelector(`input[name="${v}"]`).checked = SETS[v][1];
- } else {
- dalg.querySelector(`input[name="${v}"]`).value = SETS[v][1];
- }
- }
- },
- false
- );
- dalg.querySelector('input[value="Set default"]').addEventListener(
- 'mouseenter',
- function (event) { event.target.style.backgroundColor = 'rgb(170, 170, 170)'; },
- false
- );
- dalg.querySelector('input[value="Set default"]').addEventListener(
- 'mouseleave',
- function (event) { event.target.style.backgroundColor = 'rgb(190, 190, 190)'; },
- false
- );
-
- dalg.querySelector('input[value="Save & Close"]').addEventListener(
- 'click',
- async function () {
- for (let v in SETS) {
- if (SETS[v][0] == 'r') {
- for (let e of dalg.querySelectorAll(`input[name="${v}"]`)) {
- if (e.checked) {
- sets[v] = +e.value;
- break;
- }
- }
- } else if (v == 'intl') {
- sets[v] = +dalg.querySelector(`input[name="${v}"]`).value;
- } else if (SETS[v][0] == 't') {
- sets[v] = dalg.querySelector(`input[name="${v}"]`).value;
- } else {
- sets[v] = dalg.querySelector(`input[name="${v}"]`).checked;
- }
- }
-
- for (let v in SETS) {
- await GM.setValue(v, sets[v]);
- }
-
- dalg.style.display = 'none';
- },
- false
- );
- dalg.querySelector('input[value="Save & Close"]').addEventListener(
- 'mouseenter',
- function (event) { event.target.style.backgroundColor = 'rgb(170, 170, 170)'; },
- false
- );
- dalg.querySelector('input[value="Save & Close"]').addEventListener(
- 'mouseleave',
- function (event) { event.target.style.backgroundColor = 'rgb(190, 190, 190)'; },
- false
- );
- }
-
-
- async function initGUI() {
- for (let v in SETS) {
- if ((await GM.getValue(v)) === undefined) {
- await GM.setValue(v, SETS[v][1]);
- } else {
- sets[v] = await GM.getValue(v);
- }
- }
-
- let dalg = makeDalg();
- makeFunc(dalg);
- document.body.appendChild(dalg);
-
- GM.registerMenuCommand('Settings', function () {
- if (dalg.style.display == 'none') {
- for (let v in SETS) {
- if (SETS[v][0] == 'r') {
- dalg.querySelector(`input[name="${v}"][value="${sets[v]}"]`).checked = true;
- } else if (SETS[v][0] == 'c') {
- dalg.querySelector(`input[name="${v}"]`).checked = sets[v];
- } else {
- dalg.querySelector(`input[name="${v}"]`).value = sets[v];
- }
- }
-
- dalg.style.display = 'block';
- }
- });
- }
-
-
- function fmtDate(fmt, date) {
- let datetime;
-
- if (sets.fmts.indexOf('YEU') >= 0 || sets.fmts.indexOf('YFU') >= 0) {
- const MO_N = date.getUTCMonth();
- const WE_N = date.getUTCDay();
- const HO_N = date.getUTCHours();
- datetime = {
- 'YEU': date.getUTCFullYear().toString().slice(-2),
- 'YFU': date.getUTCFullYear(),
- 'MO': ('0' + (MO_N + 1)).slice(-2),
- 'MN': sets[
- Object.entries(SETS).filter(function (e) {
- if (e[1][2] == 'm' && e[1][3] == MO_N) return true;
- })[0][0]
- ],
- 'DA': ('0' + date.getUTCDate()).slice(-2),
- 'WE': sets[
- Object.entries(SETS).filter(function (e) {
- if (e[1][2] == 'w' && e[1][3] == WE_N) return true;
- })[0][0]
- ],
- 'HO': ('0' + HO_N).slice(-2),
- 'HH':
- HO_N == 0 ? '12' :
- HO_N >= 1 && HO_N <= 12 ? ('0' + HO_N).slice(-2) :
- HO_N >= 13 ? ('0' + (HO_N - 12)).slice(-2) :
- '?',
- 'MI': ('0' + date.getUTCMinutes()).slice(-2),
- 'SE': ('0' + date.getUTCSeconds()).slice(-2),
- 'AP': HO_N < 12 ? sets.am : sets.pm
- };
- } else if (sets.fmts.indexOf('YM') >= 0) {
- date.setUTCHours(date.getUTCHours() + 8);
-
- const MO_N = date.getUTCMonth();
- const WE_N = date.getUTCDay();
- const HO_N = date.getUTCHours();
- datetime = {
- 'YM': date.getUTCFullYear() - 1911,
- 'MO': ('0' + (MO_N + 1)).slice(-2),
- 'MN': sets[
- Object.entries(SETS).filter(function (e) {
- if (e[1][2] == 'm' && e[1][3] == MO_N) return true;
- })[0][0]
- ],
- 'DA': ('0' + date.getUTCDate()).slice(-2),
- 'WE': sets[
- Object.entries(SETS).filter(function (e) {
- if (e[1][2] == 'w' && e[1][3] == WE_N) return true;
- })[0][0]
- ],
- 'HO': ('0' + HO_N).slice(-2),
- 'HH':
- HO_N == 0 ? '12' :
- HO_N >= 1 && HO_N <= 12 ? ('0' + HO_N).slice(-2) :
- HO_N >= 13 ? ('0' + (HO_N - 12)).slice(-2) :
- '?',
- 'MI': ('0' + date.getUTCMinutes()).slice(-2),
- 'SE': ('0' + date.getUTCSeconds()).slice(-2),
- 'AP': HO_N < 12 ? sets.am : sets.pm
- };
- } else {
- const MO_N = date.getMonth();
- const WE_N = date.getDay();
- const HO_N = date.getHours();
- datetime = {
- 'YE': date.getFullYear().toString().slice(-2),
- 'YF': date.getFullYear(),
- 'MO': ('0' + (MO_N + 1)).slice(-2),
- 'MN': sets[
- Object.entries(SETS).filter(function (e) {
- if (e[1][2] == 'm' && e[1][3] == MO_N) return true;
- })[0][0]
- ],
- 'DA': ('0' + date.getDate()).slice(-2),
- 'WE': sets[
- Object.entries(SETS).filter(function (e) {
- if (e[1][2] == 'w' && e[1][3] == WE_N) return true;
- })[0][0]
- ],
- 'HO': ('0' + HO_N).slice(-2),
- 'HH':
- HO_N == 0 ? '12' :
- HO_N >= 1 && HO_N <= 12 ? ('0' + HO_N).slice(-2) :
- HO_N >= 13 ? ('0' + (HO_N - 12)).slice(-2) :
- '?',
- 'MI': ('0' + date.getMinutes()).slice(-2),
- 'SE': ('0' + date.getSeconds()).slice(-2),
- 'AP': HO_N < 12 ? sets.am : sets.pm
- };
- }
-
- let ret = sets.fmts;
- for (let d in datetime) {
- ret = ret.replace(d, datetime[d]);
- }
- return ret;
- }
-
-
- function makeReq(url, eqs, ebtkn, controller) {
- const OPTION = {
- cache: 'force-cache',
- redirect: 'follow',
- credentials: 'include',
- signal: controller.signal
- };
-
- let req;
-
- if (getCV('gt').length && !getCV('twid').length) {
- req = new Request(`${url}${eqs}`, {
- headers: {
- 'authorization': `Bearer ${ebtkn}`,
- 'x-guest-token': getCV('gt')[0]
- },
- ...OPTION
- });
- } else {
- req = new Request(`${url}${eqs}`, {
- headers: {
- 'authorization': `Bearer ${ebtkn}`,
- 'x-csrf-token': getCV('ct0')[0],
- 'x-twitter-auth-type': 'OAuth2Session'
- },
- ...OPTION
- });
- }
-
- return req;
- }
-
-
- async function getUID(s_name) {
- let url = 'https://api.x.com/graphql/Yka-W8dz7RaEuQNkroPkYw/UserByScreenName';
- if (/^[^:]+:\/\/[^/]+\.onion\//i.test(document.URL)) {
- url =
- 'https://api.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion/' +
- 'graphql/Yka-W8dz7RaEuQNkroPkYw/UserByScreenName';
- }
-
- const QS =
- '?variables={' +
- `"screen_name":"${s_name}",` +
- '"withSafetyModeUserFields":true' +
- '}' +
- '&features={' +
- '"hidden_profile_subscriptions_enabled":true,' +
- '"rweb_tipjar_consumption_enabled":true,' +
- '"responsive_web_graphql_exclude_directive_enabled":false,' + // true
- '"verified_phone_label_enabled":true,' + // false
- '"subscriptions_verification_info_is_identity_verified_enabled":true,' +
- '"subscriptions_verification_info_verified_since_enabled":true,' +
- '"highlights_tweets_tab_ui_enabled":true,' +
- '"responsive_web_twitter_article_notes_tab_enabled":true,' +
- '"subscriptions_feature_can_gift_premium":true,' +
- '"creator_subscriptions_tweet_preview_api_enabled":true,' +
- '"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,' +
- '"responsive_web_graphql_timeline_navigation_enabled":true' +
- '}' +
- '&fieldToggles={' +
- '"withAuxiliaryUserLabels":false' +
- '}';
- const EQS = encodeURI(QS);
-
- let controller = new AbortController();
- let req = makeReq(url, EQS, EBTKN, controller);
- let res = {};
-
- try {
- setTimeout(function () { controller.abort(); }, 60000);
- res = await fetch(req);
- if (!res.ok) {
- console.log(`${MYNAME}: getUID:notok:${res.ok}.`);
- return null;
- } // 失敗なら空で終わり
- } catch (err) {
- console.log(`${MYNAME}: getUID:error:${err}.`);
- return null; // 失敗なら空で終わり
- }
-
- let json = JSON.parse(await res.text());
-
- let id, bl, ca, sn, vf;
- id = json.data.user.result.rest_id;
- bl = json.data.user.result.is_blue_verified;
- ca = json.data.user.result.legacy.created_at;
- sn = json.data.user.result.legacy.screen_name;
- vf = json.data.user.result.legacy.verified;
-
- return [id, bl, ca, sn, vf];
- }
-
-
- async function saveDtbs(key) {
- if (dtbs[`cntr_${key}`][1] && Date.now() - time_ref[key] > 8000) {
- dtbs[`cntr_${key}`][1] = false;
- time_ref[key] = Date.now();
-
- let limit;
- limit = key == 'idl' ? 100 : 50;
-
- if (dtbs[`cntr_${key}`][0] >= limit) {
- dtbs[key] = [...new Set(dtbs[key].map(JSON.stringify))].map(JSON.parse);
- dtbs[`cntr_${key}`][0] = 0;
- }
-
- dtbs[key].push([Date.now()]);
- await GM.setValue(key, JSON.stringify(dtbs[key]));
- await GM.setValue(`cntr_${key}`, JSON.stringify(dtbs[`cntr_${key}`]));
- }
- }
-
-
- async function toUID(s_name) {
- let n = dtbs.idl.findIndex(function (a) {
- const NOW = Date.now();
- return typeof a[0] === 'number' && a[0] > NOW - 3600000;
- });
-
- if (n >= 0) {
- for (let i = dtbs.idl.length; i > n; i--) { // 下から
- if (typeof dtbs.idl[i - 1][1] === 'undefined') continue;
-
- if (dtbs.idl[i - 1][3].toLowerCase() == s_name.toLowerCase())
- return dtbs.idl[i - 1];
- }
- }
-
- let r = await getUID(s_name);
- // 無い時
- // screen name -> id, blue, created_at, screen_name, verified
- if (r) {
- dtbs.idl = dtbs.idl.concat([r]);
- dtbs.cntr_idl[0]++;
- dtbs.cntr_idl[1] = true;
-
- return r.includes(s_name) ? r : null;
- }
- console.log(`${MYNAME}: toUID:error.`);
- return null; // エラー
- }
-
-
- function get10xN(path_result, tl) {
- let path_t = path_result.rest_id ? path_result : path_result.tweet; // ある前提
- let path_t_1 = null;
- let path_t_2 = null;
-
- let path_qt = null;
-
- if (pathExists(path_t, ['legacy', 'retweeted_status_result', 'result', 'legacy'])) {
- path_t_1 = path_t.legacy.retweeted_status_result.result;
- } else if (pathExists(path_t, ['legacy', 'retweeted_status_result', 'result', 'tweet'])) {
- path_t_1 = path_t.legacy.retweeted_status_result.result.tweet;
- }
-
- if (path_t_1) {
- if (pathExists(path_t_1, ['edit_control', 'edit_tweet_ids'])) {
- path_t_2 = path_t_1.edit_control;
- } else { // 他も必ずある?
- path_t_2 = path_t_1.edit_control.edit_control_initial;
- }
- }
-
- if (pathExists(path_result, ['quoted_status_result', 'result', 'rest_id'])) {
- path_qt = path_result.quoted_status_result.result;
- } else if (pathExists(path_result, ['quoted_status_result', 'result', 'tweet', 'rest_id'])) {
- path_qt = path_result.quoted_status_result.result.tweet;
- }
-
- let tuid, tsn, tid, tca, ts, rtuid, rtsn, rtid, rtca, rts;
- let ret = [];
-
- tid = path_t.rest_id;
- ts = path_t.source;
-
- if (!path_t.legacy) { // 何も無い
- tuid = 'none';
- tsn = 'none'; // 未確認
- tca = 'none';
- rtuid = 'none';
- rtsn = 'none';
- rtid = 'none';
- rtca = 'none';
- rts = 'none';
- } else if (!path_t_1) { // リツイートでは無い
- tuid = path_t.legacy.user_id_str;
- tsn = path_t.core.user_results.result.legacy.screen_name;
- tca = path_t.legacy.created_at;
- rtuid = 'none';
- rtsn = 'none'; // 未確認
- rtid = 'none';
- rtca = 'none';
- rts = 'none';
- } else {
- tuid = path_t.legacy.user_id_str;
- tsn = path_t.core.user_results.result.legacy.screen_name;
- tca = path_t.legacy.created_at;
- rtuid = path_t_1.legacy.user_id_str;
- rtsn = path_t_1.core.user_results.result.legacy.screen_name;
- rtid =
- tl ? path_t_2.edit_tweet_ids[5 - path_t_2.edits_remaining] :
- path_t_1.rest_id;
- rtca = path_t_1.legacy.created_at;
- rts = path_t_1.source;
- }
-
- ret.push([tuid, tsn, tid, tca, ts, rtuid, rtsn, rtid, rtca, rts]);
-
- if (!ret.length) {
- console.log(`${MYNAME}: get10xN:error:t.`);
- return null; // エラー
- }
-
- // tuid, tsn, tid, tca, ts, rtuid, rtsn, rtid, rtca, rts再利用
- if (path_qt) {
- tid = path_qt.rest_id;
- ts = path_qt.source;
-
- if (!path_qt.legacy) { // 何も無い
- tuid = 'none';
- tsn = 'none';
- tca = 'none';
- rtuid = 'none';
- rtsn = 'none';
- rtid = 'none';
- rtca = 'none';
- rts = 'none';
- } else {
- tuid = path_qt.legacy.user_id_str;
- tsn = path_qt.core.user_results.result.legacy.screen_name;
- tca = path_qt.legacy.created_at;
- rtuid = 'none';
- rtsn = 'none';
- rtid = 'none';
- rtca = 'none';
- rts = 'none';
- }
-
- if (!tid || !ts) {
- console.log(`${MYNAME}: get10xN:error:qt.`);
- return null; // エラー
- }
-
- ret.push([tuid, tsn, tid, tca, ts, rtuid, rtsn, rtid, rtca, rts]);
- }
-
- return ret; // 最大2
- }
-
-
- async function getDetl(twt_id) {
- const URL = 'https://api.x.com/graphql/sCU6ckfHY0CyJ4HFjPhjtg/TweetResultByRestId';
- // 一つだけ、これが基本、自身でfetch
-
- const QS =
- '?variables={' +
- `"tweetId":"${twt_id}",` +
- '"withCommunity":false,' +
- '"includePromotedContent":false,' +
- '"withVoice":false' +
- '}' +
- '&features={' +
- '"creator_subscriptions_tweet_preview_api_enabled":true,' +
- '"communities_web_enable_tweet_community_results_fetch":true,' +
- '"c9s_tweet_anatomy_moderator_badge_enabled":true,' +
- '"articles_preview_enabled":true,' +
- '"responsive_web_edit_tweet_api_enabled":true,' +
- '"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,' +
- '"view_counts_everywhere_api_enabled":true,' +
- '"longform_notetweets_consumption_enabled":true,' +
- '"responsive_web_twitter_article_tweet_consumption_enabled":true,' +
- '"tweet_awards_web_tipping_enabled":false,' +
- '"creator_subscriptions_quote_tweet_preview_enabled":false,' +
- '"freedom_of_speech_not_reach_fetch_enabled":true,' +
- '"standardized_nudges_misinfo":true,' +
- '"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,' +
- '"rweb_video_timestamps_enabled":true,' +
- '"longform_notetweets_rich_text_read_enabled":true,' +
- '"longform_notetweets_inline_media_enabled":true,' +
- '"rweb_tipjar_consumption_enabled":true,' +
- '"responsive_web_graphql_exclude_directive_enabled":false,' + // true
- '"verified_phone_label_enabled":true,' + // false
- '"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,' +
- '"responsive_web_graphql_timeline_navigation_enabled":true,' +
- '"responsive_web_enhance_cards_enabled":false' +
- '}' +
- '&fieldToggles={' +
- '"withArticleRichContentState":true,' +
- '"withArticlePlainText":false,' +
- '"withGrokAnalyze":false,' +
- '"withDisallowedReplyControls":false' +
- '}';
- const EQS = encodeURI(QS);
-
- let controller = new AbortController();
- let req = makeReq(URL, EQS, EBTKN, controller);
- let res = {};
-
- try {
- setTimeout(function () { controller.abort(); }, 60000);
- res = await fetch(req);
- if (!res.ok) {
- console.log(`${MYNAME}: getDetl:notok:${res.ok}.`);
- return null;
- } // 失敗なら空で終わり
- } catch (err) {
- console.log(`${MYNAME}: getDetl:error:${err}.`);
- return null; // 失敗なら空で終わり
- }
-
- let json = JSON.parse(await res.text());
- let path_result = json.data.tweetResult.result;
- let ret = null;
-
- if (path_result) ret = get10xN(path_result, false);
-
- if (ret) {
- dtbs.twts = dtbs.twts.concat(ret);
- dtbs.cntr_twts[0]++;
- dtbs.cntr_twts[1] = true;
- }
-
- return (
- ret ? [
- ret[0][0], ret[0][1], ret[0][2], ret[0][3], ret[0][4],
- ret[0][5], ret[0][6], ret[0][7], ret[0][8], ret[0][9]
- ] :
- ret
- );
- }
-
-
- function getTwtsR(stat, text) {
- if (stat < 200 || stat > 299) {
- console.log(`${MYNAME}: getTwtsR:error:${stat}.`);
- return null; // エラー
- }
-
- let json = JSON.parse(text);
- let path_result = json.data.tweetResult.result;
- let ret = null;
-
- if (path_result) ret = get10xN(path_result, false);
-
- if (ret) {
- dtbs.twts = dtbs.twts.concat(ret);
- dtbs.cntr_twts[0]++;
- dtbs.cntr_twts[1] = true;
- }
- }
-
-
- function getTwtsD(stat, text) {
- if (stat < 200 || stat > 299) {
- console.log(`${MYNAME}: getTwtsD:error:${stat}.`);
- return null; // エラー
- }
-
- let json = JSON.parse(text);
- let ret = [];
-
- if (json.errors) {
- console.log(`${MYNAME}: getTwtsD:error:errors.`);
- return null; // エラー
- }
-
- let path_instructions =
- json.data.threaded_conversation_with_injections_v2.instructions;
-
- for (let n in path_instructions) {
- if (path_instructions[+n].type == 'TimelineAddEntries') {
- let path_entries = path_instructions[+n].entries;
-
- for (let n in path_entries) {
- let path_result = null;
- if (/^tweet-/i.test(path_entries[+n].entryId)) {
- if (
- pathExists(path_entries[+n], [
- 'content',
- 'itemContent',
- 'tweet_results',
- 'result',
- 'rest_id'
- ])
- ) {
- path_result =
- path_entries[+n].content.itemContent.tweet_results.result;
- } else if (
- pathExists(path_entries[+n], [
- 'content',
- 'itemContent',
- 'tweet_results',
- 'result',
- 'tweet'
- ])
- ) {
- path_result =
- path_entries[+n].content.itemContent.tweet_results.result.tweet;
- }
- } else if (/^conversationthread-/i.test(path_entries[+n].entryId)) {
- if (
- pathExists(path_entries[+n], [
- 'content',
- 'items',
- 0,
- 'item',
- 'itemContent',
- 'tweet_results',
- 'result',
- 'rest_id'
- ])
- ) {
- path_result =
- path_entries[+n].content.items[0].item.itemContent.tweet_results.result;
- // 0だけ
- } else if (
- pathExists(path_entries[+n], [
- 'content',
- 'items',
- 0,
- 'item',
- 'itemContent',
- 'tweet_results',
- 'result',
- 'tweet'
- ])
- ) {
- path_result =
- path_entries[+n].content.items[0].item.itemContent.tweet_results.result.tweet;
- }
- } else {
- continue;
- }
-
- if (path_result) ret = ret.concat(get10xN(path_result, false));
- }
- } else if (path_instructions[+n].type == 'TimelineAddToModule') {
- let path_moduleitems = path_instructions[+n].moduleItems;
-
- for (let n in path_moduleitems) {
- let path_result = null;
- if (/^conversationthread-/i.test(path_moduleitems[+n].entryId)) {
- if (
- pathExists(path_moduleitems[+n], [
- 'item',
- 'itemContent',
- 'tweet_results',
- 'result',
- 'rest_id'
- ])
- ) {
- path_result =
- path_moduleitems[+n].item.itemContent.tweet_results.result;
- } else if (
- pathExists(path_moduleitems[+n], [
- 'item',
- 'itemContent',
- 'tweet_results',
- 'result',
- 'tweet'
- ])
- ) {
- path_result =
- path_moduleitems[+n].item.itemContent.tweet_results.result.tweet;
- }
- } else {
- continue;
- }
-
- if (path_result) ret = ret.concat(get10xN(path_result, false));
- }
- }
- }
-
- if (ret.length) dtbs.twts = dtbs.twts.concat(ret);
-
- dtbs.cntr_twts[0]++;
- dtbs.cntr_twts[1] = true;
- }
-
-
- function getTwts(stat, text, path) {
- if (stat < 200 || stat > 299) {
- console.log(`${MYNAME}: getTwts:error:${stat}.`);
- return null; // エラー
- }
-
- let json = JSON.parse(text);
- let path_instructions =
- path.length == 4 ? json['data'][path[0]][path[1]][path[2]][path[3]]['instructions'] :
- path.length == 3 ? json['data'][path[0]][path[1]][path[2]]['instructions'] :
- json['data'][path[0]][path[1]]['instructions'];
- let n = 0;
- let ret = [];
-
- while (path_instructions[n].type != 'TimelineAddEntries')
- if (typeof path_instructions[++n] === 'undefined') return null;
-
- let path_entries = path_instructions[n].entries;
- let num = Object.keys(path_entries).length;
-
- for (let n in path_entries) {
- let path_result = null;
- if (/^tweet-/i.test(path_entries[+n].entryId)) {
- if (pathExists(
- path_entries[+n],
- ['content', 'itemContent', 'tweet_results', 'result', 'rest_id']
- )) {
- path_result =
- path_entries[+n].content.itemContent.tweet_results.result;
- } else if (pathExists(
- path_entries[+n],
- ['content', 'itemContent', 'tweet_results', 'result', 'tweet']
- )) {
- path_result =
- path_entries[+n].content.itemContent.tweet_results.result.tweet;
- }
- } else if (/^conversationthread-/i.test(path_entries[+n].entryId)) {
- if (pathExists(
- path_entries[+n],
- ['content', 'items', 0, 'item','itemContent', 'tweet_results', 'result', 'rest_id']
- )) {
- path_result =
- path_entries[+n].content.items[0].item.itemContent.tweet_results.result;
- // 0だけ
- } else if (pathExists(
- path_entries[+n],
- ['content', 'items', 0, 'item','itemContent', 'tweet_results', 'result', 'tweet']
- )) {
- path_result =
- path_entries[+n].content.items[0].item.itemContent.tweet_results.result.tweet;
- }
- } else {
- continue;
- }
-
- if (path_result) ret = ret.concat(get10xN(path_result, false));
- }
-
- if (ret.length) dtbs.twts = dtbs.twts.concat(ret);
-
- dtbs.cntr_twts[0]++;
- dtbs.cntr_twts[1] = true;
- }
-
-
- function statsSN(s_name) {
- let sn_l = s_name.toLowerCase();
-
- let n = dtbs.twts.findIndex(function (a) {
- const NOW = Date.now();
- return typeof a[0] === 'number' && a[0] > NOW - 3600000;
- });
-
- if (n >= 0) {
- for (let i = dtbs.twts.length; i > n; i--) { // 下から
- if (typeof dtbs.twts[i - 1][1] === 'undefined') continue;
-
- let t = dtbs.twts[i - 1][1].toLowerCase() == sn_l;
- let rt;
- if (!t) rt = dtbs.twts[i - 1][6].toLowerCase() == sn_l;
-
- if (t || rt) return t ? [dtbs.twts[i - 1][0], dtbs.twts[i - 1][1]] :
- [dtbs.twts[i - 1][5], dtbs.twts[i - 1][6]];
- }
- }
-
- return null;
- }
-
-
- function chkLV(id) {
- const UD = +id.substring(0, 2);
-
- const L =
- UD < 13 ? LVL_12 :
- UD < 16 ? LVL_15 :
- UD < 20 ? LVL_19 :
- UD < 25 ? LVL_24 :
- UD < 30 ? LVL_29 :
- UD < 40 ? LVL_3 :
- UD < 50 ? LVL_4 :
- UD < 60 ? LVL_5 :
- UD < 70 ? LVL_6 :
- UD < 80 ? LVL_7 :
- UD < 90 ? LVL_8 :
- LVL_9;
-
- return L.includes(id);
- }
-
-
- function statsRT(u_id, rt_id) {
- for (let i = dtbs.twts.length; i > 0; i--) { // 下から
- if (typeof dtbs.twts[i - 1][1] === 'undefined') continue;
-
- if (dtbs.twts[i - 1][0] == u_id && dtbs.twts[i - 1][7] == rt_id)
- return [dtbs.twts[i - 1][2], dtbs.twts[i - 1][3]]; // あれば終わり
- }
-
- console.log(`${MYNAME}: statsRT:end.`);
- return ['0000000000000000000', 'Thu Jan 01 00:00:00 +0000 1970'];
- // エラー
- }
-
-
- function twtXHRStateHandler({ target: xhr }, res) {
- if (xhr.readyState === 4) {
- const STAT = xhr.status;
- const RAW_TEXT = xhr.responseText;
-
- if (res == 1)
- getTwtsR(STAT, RAW_TEXT);
- else if (res == 2)
- getTwtsD(STAT, RAW_TEXT);
- else if (res == 3)
- getTwts(STAT, RAW_TEXT, ['user', 'result', 'timeline_v2', 'timeline']);
- else if (res == 4)
- getTwts(STAT, RAW_TEXT, ['home', 'home_timeline_urt']);
- else if (res == 5)
- getTwts(STAT, RAW_TEXT, ['home', 'home_timeline_urt']);
- else if (res == 6)
- getTwts(STAT, RAW_TEXT, ['list', 'tweets_timeline', 'timeline']);
- else if (res == 7)
- getTwts(STAT, RAW_TEXT, ['search_by_raw_query', 'search_timeline', 'timeline']);
- }
- }
-
-
- function isTwtsURL(url) {
- if (!url.includes('/graphql/')) return 0;
- else if (url.includes('/TweetResultByRestId?')) return 1;
- else if (url.includes('/TweetDetail?')) return 2;
- else if (url.includes('/UserTweets?')) return 3;
- else if (url.includes('/HomeTimeline')) return 4;
- else if (url.includes('/HomeLatestTimeline')) return 5;
- else if (url.includes('/ListLatestTweetsTimeline?')) return 6;
- else if (url.includes('/SearchTimeline?')) return 7;
- else return 0;
- }
-
-
- function overrideXHROpen() {
- orig_xhr_open = XMLHttpRequest.prototype.open;
- XMLHttpRequest.prototype.open = function () {
- const RES = isTwtsURL(arguments[1]);
- if (RES) {
- this.addEventListener(
- 'readystatechange',
- function (evt) { twtXHRStateHandler(evt, RES); }
- );
- }
- return orig_xhr_open.apply(this, arguments);
- };
-
- console.log(`${MYNAME}: XMLHttpRequest.open overriden.`);
- }
-
-
- async function subsBadge() {
- let elms = document.querySelectorAll(`${SEL_SB_V}, ${SEL_SB_B}`);
-
- for (let e of elms) {
- let spe = e.parentNode.parentNode;
- let tpe = e.parentNode.parentNode.parentNode;
- let sn;
- let ss; // Temp.
-
- if (tpe.querySelector(`${SEL_SB_E}, ${SEL_SB_E2}`)) continue;
-
- if (spe.style.color == 'rgb(232, 134, 143)') {
- ss = muts;
- spe.style.color = 'rgb(29, 155, 240)';
- muts = ss;
- }
-
- let xpe = e.closest('main div[data-testid="primaryColumn"] h2[role="heading"]'); // トップ
- if (!xpe) xpe = e.closest('div#layers div[data-testid="TopNavBar"] h2[role="heading"]'); // モバイルトップ
- if (xpe) {
- sn = document.URL.split('/')[3];
- }
-
- if (!sn && spe.getAttribute('data-testid') == 'verificationBadge')
- sn = document.URL.split('/')[3];
- // 認証済アカウントポップアップ
-
- if (!sn) {
- let xpe = e.closest(SEL_SB_P_KS);
- let sne;
- if (xpe) sne = xpe.querySelector(SEL_SB);
- if (sne) sn = sne.textContent.split('@')[1];
- }
- if (!sn) {
- let xpe = e.closest(SEL_SB_P_DS);
- let sne;
- if (xpe) sne = xpe.querySelector(SEL_SB_2);
- if (sne) sn = sne.textContent.split('@')[1];
- }
- if (!sn) {
- let xpe = e.closest(SEL_SB_P_VRRT);
- let sne;
- if (xpe) sne = xpe.querySelector(SEL_SB_2);
- if (sne) sn = sne.textContent.split('@')[1];
- }
- if (!sn) {
- let xpe = e.closest(SEL_SB_P_T2);
- let sne;
- if (xpe) sne = xpe.querySelector(SEL_SB);
- if (sne) sn = sne.textContent.split('@')[1];
- }
- if (!sn) {
- let xpe = e.closest(SEL_SB_P_RRT);
- let sne;
- if (xpe) sne = xpe.querySelector(SEL_SB_2);
- if (sne) sn = sne.textContent.split('@')[1];
- }
- if (!sn) {
- let xpe = e.closest(SEL_SB_P_RRT_M);
- let sne;
- if (xpe) sne = xpe.querySelector(SEL_SB_2);
- if (sne) sn = sne.textContent.split('@')[1];
- }
-
- if (!sn) {
- let xpe = e.closest('a'); // ビデオ引用TW、TL等
- if (xpe) {
- let a = xpe.getAttribute('href').split('/')[1];
- let b = xpe.getAttribute('href').split('/')[2];
- let c = xpe.getAttribute('href').split('/')[3];
-
- if (a == 'i' && b == 'status') {
- for (let i = dtbs.twts.length; i > 0; i--) { // 下から
- if (typeof dtbs.twts[i - 1][1] === 'undefined') continue;
-
- if (dtbs.twts[i - 1][2] == c) {
- sn = dtbs.twts[i - 1][1];
- break;
- } else if (dtbs.twts[i - 1][7] == c) {
- sn = dtbs.twts[i - 1][6];
- break;
- }
- }
-
- if (!sn) {
- let detl = await getDetl(c);
- if (detl) sn = detl[1];
- }
- } else {
- sn = a;
- }
- }
- }
-
- if (!sn) {
- ss = muts;
- spe.style.color = 'rgb(232, 134, 143)';
- muts = ss;
- continue;
- }
-
- let sp = [
- '', 'compose', 'explore', 'home', 'i',
- 'login', 'messages', 'notifications', 'search', 'search-advanced',
- 'settings'
- ];
-
- if (sp.includes(sn.toLowerCase())) {
- ss = muts;
- spe.style.color = 'rgb(232, 134, 143)';
- muts = ss;
- continue;
- }
-
- let pr = statsSN(sn); // screen name -> id, screen_name
- if (!pr) pr = await toUID(sn); // screen name -> id, blue, created_at, screen_name, verified
- let r = pr ? chkLV(pr[0]) : pr;
-
- ss = muts;
- if (r === true) {
- e.setAttribute('d', DATA_SB_V);
- } else if (r === false) {
- e.setAttribute('d', DATA_SB_B);
- } else {
- spe.style.color = 'rgb(232, 134, 143)';
- }
- muts = ss;
- }
- }
-
-
- async function addSL() {
- let uid, tid, tsl, rtsl, thref, rthref, detl;
- let ca, span, span2, a, a2;
-
- let elm_end = document.querySelector(SEL_AS_END);
- let elm_end_rt = document.querySelector(SEL_AS_END_RT);
- if (!elm_end) return;
-
- let old = elm_end.querySelectorAll(SEL_ADD_SPAN);
- if (old.length) return;
-
- tsl = '?';
- rtsl = '(?)';
- thref = 'https://help.twitter.com/using-twitter/how-to-tweet#source-labels';
- if (/^[^:]+:\/\/[^/]+\.onion\//i.test(document.URL)) {
- thref =
- 'https://help.twitter3e4tixl4xyajtrzo62zg5vztmjuricljdp2c5kshju4avyoid.onion' +
- '/using-twitter/how-to-tweet#source-labels';
- }
- rthref = thref;
-
- ca = elm_end.querySelector('a');
- tid = ca.getAttribute('href').split('/')[3];
-
- if (elm_end_rt) {
- let pe = elm_end_rt.parentNode;
- let sn = pe.getAttribute('href').slice(1);
-
- uid = statsSN(sn); // screen name -> id, screen_name
- if (!uid) uid = await toUID(sn);
- // screen name -> id, blue, created_at, screen_name, verified
- // リツイートした人のuid
- }
-
- let i = 2;
- if (document.URL.split('/')[5] != tid) i = 7;
-
- for (let j = dtbs.twts.length; j > 0; j--) { // 下から
- if (typeof dtbs.twts[j - 1][1] === 'undefined') continue;
-
- if (dtbs.twts[j - 1][i] == tid) {
- detl = dtbs.twts[j - 1];
- break;
- }
- }
-
- if (!detl) detl = await getDetl(tid); // ツイートはtid、rtidどちらにもなり得る
-
- if (detl) {
- tsl = detl[4].split('<')[1].split('>')[1];
- thref = detl[4].split('"')[1];
- } else {
- console.log(`${MYNAME}: addSL:error.`); // エラー
- }
-
- if (sets.show_sl != 1 && elm_end_rt && uid) {
- for (let j = dtbs.twts.length; j > 0; j--) { // 下から
- if (typeof dtbs.twts[j - 1][1] === 'undefined') continue;
-
- if (dtbs.twts[j - 1][0] == uid[0] && dtbs.twts[j - 1][7] == tid) { // リツイートは一つしか無い
- rtsl = `(${dtbs.twts[j - 1][4].split('<')[1].split('>')[1]})`;
- rthref = dtbs.twts[j - 1][4].split('"')[1];
- break;
- }
- }
- }
-
- span = document.createElement('span');
- span.className = `us-${MYNAME}`;
- span.style.margin = '0px 3px 0px 3px';
- span.textContent = '·';
- span.style.color = getComputedStyle(ca, null).color;
- span.style.font = getComputedStyle(ca, null).font;
- span.style.lineHeight = getComputedStyle(elm_end, null).lineHeight;
-
- span2 = document.createElement('span');
- span2.className = `us-${MYNAME}`;
- span2.style.lineHeight = getComputedStyle(elm_end, null).lineHeight;
- span2.style.display = 'inline-block';
-
- a = document.createElement('a');
- a.className = `us-${MYNAME}`;
- a.setAttribute('role', 'link');
- a.setAttribute('href', thref);
- a.setAttribute('target', '_blank');
- a.setAttribute('rel', 'nofollow noopener noreferrer');
- a.textContent = tsl;
- a.style.color = getComputedStyle(ca, null).color;
- a.style.font = getComputedStyle(ca, null).font;
- a.style.textDecoration = getComputedStyle(ca, null).textDecoration;
-
- a2 = document.createElement('a');
- a2.className = `us-${MYNAME}`;
- a2.setAttribute('role', 'link');
- a2.setAttribute('href', rthref);
- a2.setAttribute('target', '_blank');
- a2.setAttribute('rel', 'nofollow noopener noreferrer');
- a2.textContent = rtsl;
- a2.style.color = getComputedStyle(ca, null).color;
- a2.style.font = getComputedStyle(ca, null).font;
- a2.style.textDecoration = getComputedStyle(ca, null).textDecoration;
-
- let ss = muts;
-
- elm_end.appendChild(span);
- elm_end.appendChild(span2);
- span2.appendChild(a);
- if (sets.show_sl == 2 && elm_end_rt) span2.appendChild(a2);
-
- muts = ss;
- }
-
-
- async function mainTrack() {
- let elms = document.querySelectorAll(SEL_MT_END_RT);
-
- for (let elm of elms) {
- let pe = elm.parentNode;
- let fpe = elm.parentNode.parentNode.parentNode.parentNode;
- let xpe = elm.closest('article');
- let elm2 = xpe.querySelector(SEL_MT_RTTO);
- if (!elm2) elm2 = xpe.querySelector(SEL_MT_RTTO_2);
- let old = fpe.querySelector(SEL_ADD_A);
-
- let sn = pe.getAttribute('href').slice(1);
- if (sn.includes('/')) continue;
-
- let rtid = elm2.getAttribute('href').split('/')[3];
-
- let id = statsSN(sn); // screen name -> id, screen_name
- if (!id) id = await toUID(sn); // screen name -> id, blue, created_at, screen_name, verified
- if (!id) continue;
-
- let stats = statsRT(id[0], rtid); // id, rtid -> tid, tca
-
- let span, span2, a;
- let date;
- let ss; // Temp.
-
- if (!sets.fmt) continue;
-
- if (!old) {
- span = document.createElement('span');
- span.className = `us-${MYNAME}`;
- span.style.margin = '0px 3px 0px 3px';
- span.textContent = '·';
- span.style.color = getComputedStyle(elm, null).color;
- span.style.font = getComputedStyle(elm, null).font;
- span.style.setProperty(
- 'line-height',
- getComputedStyle(elm, null).lineHeight,
- 'important'
- );
-
- span2 = document.createElement('span');
- span2.className = `us-${MYNAME}`;
- span2.style.display = 'inline-block';
-
- a = document.createElement('a');
- a.className = `us-${MYNAME}`;
- a.setAttribute('dir', 'ltr');
- a.setAttribute('role', 'link');
- a.setAttribute('href', `/${sn}/status/${stats[0]}`);
- a.setAttribute('target', '_blank');
- a.setAttribute('rel', 'noopener noreferrer');
- date = fmtDate(sets.fmt, new Date(stats[1]));
- a.textContent = date;
- a.style.color = getComputedStyle(elm, null).color;
- a.style.font = getComputedStyle(elm, null).font;
- a.style.textDecoration = getComputedStyle(elm, null).textDecoration;
-
- ss = muts;
-
- fpe.appendChild(span);
- fpe.appendChild(a);
-
- muts = ss;
- } else {
- ss = muts;
-
- date = fmtDate(sets.fmt, new Date(stats[1]));
- if (old.textContent != date) old.textContent = date; // TZ change
-
- muts = ss;
- }
- }
- }
-
-
- console.log(`${MYNAME}: start.`);
-
- dtbs.idl = await loadDB('idl');
- dtbs.twts = await loadDB('twts');
- dtbs.cntr_idl = await loadDB('cntr_idl');
- dtbs.cntr_twts = await loadDB('cntr_twts');
- time_ref.idl = time_ref.twts = Date.now();
-
- for (let v in SETS) sets[v] = SETS[v][1];
-
- if (!NO_GUI) await initGUI();
- overrideXHROpen();
- observer.observe(document.documentElement, { childList: true, subtree: true });
-
- while (true) {
- if (muts) {
- muts = null; // 初期値がtrue、変更もしない
- if (sets.tb) await subsBadge();
- if (sets.show_sl) await addSL();
- if (sets.fmt || sets.show_sl == 2) await mainTrack();
- }
-
- await saveDtbs('idl');
- await saveDtbs('twts');
-
- await new Promise(function (resv) { setTimeout(resv, sets.intl); });
- // intl は外から非同期に変更する
- }
-
-
- })(); /* END */