Greasy Fork is available in English.

¥+クリックした要素を削除

¥+^:指した要素を非表示登録 Ctrl+^:非表示登録をundo Shift+^:非表示登録を編集 | ¥+クリック:要素を削除 ^+クリック:親要素を削除 | Shift+¥:文字列を指定して一括削除 Shift+[:一括削除を保存して自動実行 | Shift+Alt+¥:非表示の要素を削除

スクリプトをインストール?
作者が勧める他のスクリプト

学園祭カレンダー絞り込みも気に入るかもしれません。

スクリプトをインストール
質問やレビューの投稿はこちらへ、スクリプトの通報はこちらへお寄せください。
// ==UserScript==
// @name ¥+クリックした要素を削除
// @description ¥+^:指した要素を非表示登録 Ctrl+^:非表示登録をundo Shift+^:非表示登録を編集 | ¥+クリック:要素を削除 ^+クリック:親要素を削除 | Shift+¥:文字列を指定して一括削除 Shift+[:一括削除を保存して自動実行 | Shift+Alt+¥:非表示の要素を削除
// @match *://*/*
// @version     0.5.7
// @grant       GM.setClipboard
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_deleteValue
// @namespace https://greasyfork.org/users/181558
// ==/UserScript==

(function() {
  const commonHidingXPath = ''; //全ページ共通で非表示にしたい要素

  const ENABLEREPORTXPATH = 1; //0なら登録要素を非表示にしたことをポップアップで表示しない
  const POPUPMS = 5000; //ポップアップの表示時間(ミリ秒)
  const TRYMS = 300; //¥+^で一回のXPathの自動生成にかける試行時間の上限、ただし最低限の生成ができない時は5000msまでかける

  const maxLines = 5; // 一度に提案する最大数調整 大きいほど少ない(maxLines/縦解像度)
  const TryMulti = 15; // 一度に生成する試行回数調整 増やすと沢山試す=遅い代わりに結果が増える
  var excludeRE = "block;|@data|@href=|width|height|@title=|@alt=|@src="; //"@href=|text\\(\\)|@title=|@alt=|@src="; // o,pキーではこれを含むXPath式は除外する 例:/href|text\(\)/ or /\0/
  var requireRE = "";
  var requireHits = 1;
  const CancelStyle = /box-shadow: none;|\@style=\"\"|(\sand\s)\sand\s|\[\]|\sand\s(\])/gmi;
  const cancelrep = "$1$2";

  var mousex = 0;
  var mousey = 0;
  var shiftYenText = "";
  var bubparent = 0;
  var shiftYenText = pref('shiftYenText') || "";
  var shiftYenbubparent = pref('shiftYenbubparent') || 0;

  var block = function(blockXPath) {
    var i = 0;
    for (let ele of elegeta(blockXPath)) {
      if (ele.offsetHeight) {
        ele.style.display = "none"; //ele.remove();
        i++;
      }
    }
    if (ENABLEREPORTXPATH && i) { popup2(i + "個の要素を自動で非表示化しました(Shift+^で編集)"); }
  }

  var blockXP = pref('blockXP') || "";
  if (commonHidingXPath) block(commonHidingXPath + (blockXP ? "|" : "") + blockXP);

  if (blockXP) {
    setInterval(() => { block(blockXP) }, 3000);
  }
  var popupY = 0;

  var BrightStyle = "0px 0px 6px 6px rgba(0, 250, 0, 0.5), inset 0 0 12px rgba(0, 250, 0, 0.2)";
  var panel;
  var frameOldEle, frameOldStyle, frameOldTimer;
  var ap1, ap2;

  const bekijou = (((window.navigator.userAgent.toLowerCase()).indexOf('chrome') != -1) ? 222 : 160);
  if (shiftYenText) deleteByTextAndBp(shiftYenText, shiftYenbubparent, true);
  document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) {
    if (shiftYenText) deleteByTextAndBp(shiftYenText, shiftYenbubparent, true);
  }, false); // uAutoPagerizeの継ぎ足し部分だけに付ける

  function removeInherit() { // shift+alt+¥
    var i = 0;
    for (let ele of elegeta('//table|.//li|.//a|.//*[@class="style-scope ytd-grid-renderer"]|.//*[@class="style-scope ytd-playlist-video-list-renderer"]|.//div|.//ytd-playlist-renderer|.//ytd-channel-renderer|.//ytd-movie-renderer|.//ytd-horizontal-card-list-renderer|.//*[@class="style-scope ytd-section-list-renderer"]')) {
      if (getComputedStyle(ele, null).getPropertyValue("display") == "none" || getComputedStyle(ele, null).getPropertyValue("visibility") == "inherit" || ele.style.display == "none;") {
        //        console.log("#" + (++i) + " " + ele.innerText.replace(/[\n\r]|\s\s/gm, "") + " is invisible,so removed.");
        ele.remove();
        i++;
      }
    }
    popup2(i + "個の不可視要素を削除しました");
  }
  //リアルタイムキー入力
  var input_key_buffer = new Array();
  document.addEventListener('keyup', function(e) {
    if (/input|textarea/i.test(e.target.tagName)) return;
    input_key_buffer[e.keyCode] = false;
    if (e.keyCode === 220) { //¥
      restoreMark();
    }
    if (e.keyCode === bekijou) { //^
      restoreMark();
    }
  }, false);
  document.addEventListener('blur', function(e) { input_key_buffer.length = 0; }, false);
  document.addEventListener('keydown', function(e) {
    if (/input|textarea/i.test(e.target.tagName) == false) {
      input_key_buffer[e.keyCode] = true;
      if (input_key_buffer[220] && !e.shiftKey && !e.altKey) {
        removePanel();
        mark();
      }
      if (input_key_buffer[bekijou] && !e.shiftKey && !e.altKey) {
        removePanel();
        mark((document.elementFromPoint(mousex, mousey)).parentNode);
      }
      if (input_key_buffer[220] && e.shiftKey && e.altKey) { removeInherit(); } // shift+alt+^ 不可視要素を削除

      if (input_key_buffer[220] && input_key_buffer[bekijou] && !e.shiftKey && !e.altKey) { // ¥+^
        e.preventDefault();
        var ele = document.elementFromPoint(mousex, mousey);
        if (!isBody(ele, 0)) blockElement(ele);
      }

      if (input_key_buffer[bekijou] && e.ctrlKey && !e.altKey) { // ctrl+^
        let undoXP = blockXP.match(/\|[^\|]*$|^[^|]*$/);
        if (undoXP) {
          //console.log(undoXP[0].replace(/^\|/, ""))
          for (let ele of elegeta(undoXP[0].replace(/^\|/, ""))) { ele.style.display = "block"; }
        }
        blockXP = blockXP.replace(/\|[^\|]*$|^[^|]*$/, "");
        pref('blockXP', blockXP);
        popup2(undoXP[0] + "<br>を自動非表示登録から削除しました<br><br>編集後:<br>" + blockXP);
        if (blockXP == "") pref('blockXP', "");
      }

      if (!input_key_buffer[220] && input_key_buffer[bekijou] && e.shiftKey && !e.ctrlKey) { // Shift+^
        let tmp = prompt("Shift+^\nこのドメインで自動で非表示にする要素をXPathで指定してください\n|で区切ると複数指定できます\n                                                                                                                                                                                           ", blockXP || "");
        if (tmp !== null) blockXP = tmp;
        for (let ele of elegeta(blockXP)) ele.remove();
        pref('blockXP', blockXP);
        if (blockXP == "") pref('blockXP', "");
        location.reload()
      }
    }
  }, false);

  document.addEventListener("click", function(e) {
    if (input_key_buffer[220] && e.button == 0) { //¥+左クリック
      e.preventDefault();
      var ele = document.elementFromPoint(e.clientX, e.clientY);
      if (isBody(ele, 0)) return;
      ele.parentNode.removeChild(ele);
    }
    if (input_key_buffer[bekijou] && e.button == 0) { //^+左クリック
      e.preventDefault();
      var ele = document.elementFromPoint(e.clientX, e.clientY);
      if (isBody(ele, 1)) return;
      ele.parentNode.parentNode.removeChild(ele.parentNode);
    }
  }, false);

  document.addEventListener("mousemove", function(e) {
    mousex = e.clientX;
    mousey = e.clientY;
    if (input_key_buffer[220]) mark(); //¥
    if (input_key_buffer[bekijou]) mark((document.elementFromPoint(mousex, mousey)).parentNode);
  }, false);

  document.addEventListener('keydown', function(e) {
    if (/input|textarea/i.test(e.target.tagName) == false) {
      if (e.keyCode === 219 && e.shiftKey && !e.altKey) { // shift+[
        input_key_buffer.length = 0;
        if (confirm("Shift+[:                           \r\n" + document.domain + "でShift+¥の自動実行を下記情報で保存しますか?\r\nキャンセルだと登録を削除します\r\n\r\n検索キーワード:" + shiftYenText + "\r\n遡る親ノード数:" + shiftYenbubparent + "\r\n\n")) {
          pref('shiftYenText', shiftYenText);
          pref('shiftYenbubparent', shiftYenbubparent);
        } else {
          pref('shiftYenText', null);
          pref('shiftYenbubparent', null);
        }
      }

      if (e.keyCode === 220 && e.shiftKey && !e.altKey) { // shift+¥
        input_key_buffer.length = 0;
        shiftYenText = prompt("Shift+¥: 1/2 削除したいテキストを入力してください。|で区切ると複数指定できます", shiftYenText);
        if (!shiftYenText) return;
        shiftYenbubparent = str2numMinMax(prompt("Shift+¥: 2/2 遡る親ノード数を入力してください", shiftYenbubparent), 0, 99);
        deleteByTextAndBp(shiftYenText, shiftYenbubparent);
      }
    }
  }, false);

  return;

  function isBody(ele, alsoParent = 0) { // eleがbodyならtrue
    if (alsoParent && (ele != document.body && ele.parentNode != document.body)) return false;
    if (!alsoParent && ele != document.body) return false;
    popup2("body要素です");
    return true;
  }

  function blockElement(ele) {
    restoreMark();
    var xp = getElementXPath0(ele);
    removePanel();
    if (xp == "//HTML" || xp == "//HTML/BODY") return;
    for (let ele of elegeta(xp)) ele.style.display = "none"; //ele.remove();
    if (blockXP) blockXP += "|" + xp;
    else blockXP = xp;
    pref('blockXP', blockXP);
    popup2(xp + "<br>を自動非表示登録しました(Ctrl+^:取り消し Shift+^:編集)<br><br>編集後:<br>" + blockXP);
  }

  function getElementXPath0(ele) {
    var paths = makecontent(0, ele);
    var path = paths[0];
    for (let p of paths) {
      if (p.match(/@class|@id/)) { path = p; break; }
    }
    return path;
  }

  function makecontent(mode, ele) {
    var retStr = [];
    var maxline = 3000;
    var maxtrial = 3000;
    var retStrl = 0;
    var tried = 0;
    hajime();
    let startTime = hajime2();
    for (var i = 0; i < maxtrial && retStrl < maxline && owari2(startTime) < (tried < 2 ? 5000 : TRYMS); i++) {
      var xp = getElementXPath(mode, ele);
      if (xp && !(mode !== 9 && RegExp(excludeRE, "i").test(xp))) {
        retStr.push(xp);
        tried++; //console.log("made:"+tried)
        var retStr = retStr.sort().reduce(function(previous, current) { if (previous[previous.length - 1] !== current) { previous.push(current); } return previous; }, []).sort(function(a, b) { return a.replace(/(@class=|@id=)\"[^\"]*\"|(contains\((@class|@id),\"[^\"]*\"\))/g, "").length - b.replace(/(@class=|@id=)\"[^\"]*\"|(contains\((@class|@id),\"[^\"]*\"\))/g, "").length < 0 ? -1 : 1; }); // 重複を削除&ソート、class/id="..."の表記を長さ0と評価する
        retStrl = retStr.length;
        //        console.log(tried + " : " + xp.replace(/(@class=|@id=)\"[^\"]*\"/g,""));
        if (xp.length < 60 && xp.match(/@class|@id=/)) {
          i += 100
        }
      }
    }
    //console.log(retStr)
    owari();
    //    console.log(owari2(startTime) + "ms");
    //console.log("trymax:" + maxtrial + "\nmakemax:" + maxline + "\ntried:" + tried + "\nmake:" + retStr.length);
    // 1つは全属性を記述しただけのもの
    if (getAttrOfEle(mode, ele, true)) {
      var path = "//" + ele.tagName + "[" + getAttrOfEle(mode, ele, true) + "";
      retStr.push(path.replace(CancelStyle, cancelrep).replace(CancelStyle, cancelrep));
    }
    // 1つはフルパスを辿っただけのもの
    retStr.push(getElementXPathFullPath(ele).replace(CancelStyle, cancelrep).replace(CancelStyle, cancelrep));
    // 1つはフルパス全属性を辿っただけのもの
    retStr.push(getElementXPathFullpathAndFullproperty(mode, ele).replace(CancelStyle, cancelrep).replace(CancelStyle, cancelrep));

    return retStr;
  }

  function getElementXPath(mode, ele) {
    var path = "";
    var origele = ele;
    for (let i = 0; i == 0 || (ele && ele.nodeType == 1 && Math.random() > 0.5); ele = ele.parentNode, i++) {

      //兄弟番号を調べる
      var ps = getPrevSib(ele);
      var ns = getNextSib(ele);

      var idx = 0;
      var arg = "";
      if (!ns && ps && Math.random() > 0.2) {
        var arg = "[last()]";
      } else
      if (!ps && ns && Math.random() > 0.2) {
        var arg = "[1]";
      } else {
        for (var idx = 1, sib = getPrevSib(ele); sib; sib = getPrevSib(sib)) { idx++; }
      }
      //属性を調べる
      var att = getAttrOfEle(mode, ele); //console.log(ele.tagName,att)/*
      if (att) att = "[" + att;
      //背番号かfirst/lastか属性か何も付けないか
      var rnd = Math.random();
      if (att.match(/@id|@class/)) { var opt = att; } else if ((rnd > 0.5) && arg) var opt = arg;
      else if (idx >= 1) var opt = "[" + idx + "]";
      else var opt = "";
      path = "/" + ele.tagName.toLowerCase() + (opt) + path;
    }
    if (!path) return "";

    path = "/" + path;
    path = path.replace(CancelStyle, cancelrep).replace(CancelStyle, cancelrep);
    if (requireRE > "" && !(RegExp(requireRE, "i").test(path))) return "";

    let hits = elegeta(path).length; // 検算
    if (hits == 0 || (mode == 8 && hits < 2) || (mode == 0 && requireHits != hits)) return false;
    return path;
  }

  function getAttrOfEle(mode, ele, allFlag = false) {
    if (ele.tagName.match(/html|body/gmi)) return "";
    let xp = "";
    let att2 = [];
    for (let att of ele.attributes) {
      if (att.value.length < 100) {
        if (att.name == "class" && Math.random() > 0.1 && !allFlag) {
          att2.push({ name: "contains(@class,", value: "\"" + att.value + "\")" })
        } else
        if (att.name == "id" && Math.random() > 0.1 && !allFlag) {
          att2.push({ name: "contains(@id,", value: "\"" + att.value + "\")" })
        } else {
          att2.push({ name: "@" + att.name + "=", value: "\"" + att.value + "\"" })
        }
      }
    }

    //text
    if (!allFlag) {
      if (Math.random() > (0.7)) {
        if (ele.innerText && !ele.innerText.match(/[\r\n]/)) { att2.push({ name: "text()=", value: "\"" + ele.innerText + "\"" }) }
      } else {
        if (ele.innerText && !ele.innerText.match(/[\r\n]/)) { att2.push({ name: "contains(text(),", value: "\"" + ele.innerText + "\")" }) }
      }
    }

    for (let j = 0; j < att2.length; j++) {
      if ((Math.random() > (att2[j].name.match(/@id|@class/) ? 0.3 :
          allFlag ? 0 :
          att2[j].name.match(/href/) ? 0.7 :
          0.5))) {
        xp += att2[j].name + att2[j].value + " and ";
      }
    }
    xp = xp.replace(/ and $/, "]").replace(/^(.*)\[$/, "$1");
    return xp;
  }

  function getElementXPathFullPath(ele) {
    var path = "";
    for (; ele && ele.nodeType == 1; ele = ele.parentNode) {
      for (var idx = 1, sib = ele.previousSibling; sib; sib = sib.previousSibling) {
        if (sib.nodeType == 1 && sib.tagName == ele.tagName) idx++
      }
      path = "/" + ele.tagName + (!ele.tagName.match(/html|body/gi) ? "[" + idx + "]" : "") + path;
    }
    return path;
  }

  function getElementXPathFullpathAndFullproperty(mode, ele) {
    var path = "";
    for (; ele && ele.nodeType == 1; ele = ele.parentNode) {
      if (getAttrOfEle(mode, ele, true)) { path = "/" + ele.tagName + "[" + getAttrOfEle(mode, ele, true) + path; } else { path = "/" + ele.tagName + path; }
    }
    path = "/" + path;
    return path;
  }

  function mark(ele = document.elementFromPoint(mousex, mousey)) {
    restoreMark();
    if (!ele || ele == document.body) return;
    if (ele.outerHTML.length < 700) popup(ele.outerHTML.replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/[\r\n]/gm, "<br>") + " (" + ele.outerHTML.length + "文字)", ele.outerHTML);
    setMark(ele);
    ele.addEventListener("mouseout", function(e) { restoreMark(); }, false);
  }

  function elegeta(xpath, node = document) {
    if (!xpath) return [];
    try {
      var array = [];
      var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
      for (var i = 0; i < ele.snapshotLength; i++) array[i] = ele.snapshotItem(i);
      return array;
    } catch (e) { return []; }
  }

  function str2numMinMax(str, min, max) {
    var ans = Number(str.replace(/[A-Za-z0-9.]/g, function(s) {
      return String.fromCharCode(s.charCodeAt(0) - 65248);
    }).replace(/[^-^0-9^\.]/g, ""));
    if (ans > max) ans = max;
    if (ans < min) ans = min;
    return ans;
  }

  function deleteByTextAndBp(shiftYenText, bubparent, isAuto = false) {
    var texta = "";
    var did = [];
    var count = 0;
    for (let text of shiftYenText.split("|")) {
      //console.log("text='" + text + "'")
      var eles = elegeta('//*[contains(text(),"' + text + '")]');
      if (eles) {
        for (let ele of eles) {
          var didkouho = text + ":";
          var toptext = "";
          var ret = backParent(ele, bubparent, isAuto);
          if ((ret.ele != document.body)) {
            ret.ele.remove();
            did.push(didkouho + ret.toptext);
            count++;
          }
        }
      }
    }
    popup("Shift+[:<BR><BR>削除キーワード:<BR>" + shiftYenText + "<BR>遡る親ノード数:<BR>" + shiftYenbubparent + "<BR><BR>" + did.join("<BR>") + "<BR><BR>" + (count - ret.failed) + "項目削除しました<BR>" + (ret.failed ? ret.failed + "項目削除失敗<BR>" : "") + "<BR>(設定を削除:Shift+[)");
    if (ret.failed > 0 && !isAuto) alert("body要素まで遡ってしまう要素が" + ret.failed + "項目ありました。この要素は削除されません。\n検索テキストをもっとユニークにするか、遡るノード数を減らすと良いかもしれません。");
    return;
  }

  function backParent(ele, bubparent, isAuto) {
    var toptext = bubparent ? "" : ele.innerText.slice(0, 100);
    var failed = 0;
    for (var i = 0; i < bubparent; i++) {
      if (ele == document.body || ele.parentNode == document.body || ele.parentNode == null) {
        failed++;
        break;
      }
      toptext += ele.innerText.slice(0, 100) + " ";
      ele = ele.parentNode;
    }
    return { ele: ele, toptext: toptext, failed: failed };
  }

  // バルーン表示
  function popup(txt, unRCtxt) {
    clearTimeout(frameOldTimer);
    if (panel) {
      panel.remove();
      panel = null;
    }
    txt = txt.replace(/outline: 3px dotted red;|\s?style=\"\s*\"\s?/gmi, "");
    if (unRCtxt) unRCtxt = unRCtxt.replace(/outline: 3px dotted red;|\s?style=\"\s*\"\s?/gmi, "");
    var ele = eleget0("//span[@id='ctrlc']");
    if (ele) ele.parentElement.removeChild(ele);
    var opa = 0.8;
    panel = document.createElement("span");
    panel.setAttribute("style", "max-width:95%; right:0; bottom:0; z-index:2147483646; opacity:" + opa + "; text-align:left; line-height:1.1em; position:fixed; font-size:12px; margin:15px;  text-decoration:none; padding:15px 15px; border-radius:7px; background-color:#d0e8ff; color:#000000;  box-shadow:5px 5px 8px #0003; border:2px solid #fff; font-family: 'MS UI Gothic','Meiryo UI','Yu Gothic UI','Arial',sans-serif;");
    panel.innerHTML = txt;
    panel.id = "ctrlc";
    panel.onclick = function() {
      GM.setClipboard(unRCtxt || txt);
      panel.style.opacity = 0;
    };
    document.body.appendChild(panel);
    frameOldTimer = setTimeout(function() {
      panel.remove();
      panel = null;
    }, POPUPMS);
    return;
  }

  function eleget0(xpath) {
    var ele = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
    return ele.snapshotLength > 0 ? ele.snapshotItem(0) : "";
  }

  function removePanel() {
    if (frameOldTimer) clearTimeout(frameOldTimer);
    if (panel) {
      panel.remove();
      panel = null;
    }
  }

  function restoreMark() {
    if (frameOldEle) {
      frameOldEle.style.outline = frameOldStyle;
      frameOldEle = null;
    }
  }

  function setMark(ele) {
    frameOldStyle = ele.style.outline;
    frameOldEle = ele;
    ele.style.outline = "red dotted 3px";
  }

  var maet;

  function popup2(text, i = 0) {
    var mae = eleget0('//span[@id="mllboxYenToDelete"]');
    if (maet && mae) {
      mae.remove();
      clearTimeout(maet);
    }
    var ele = document.body.appendChild(document.createElement("span"));
    ele.outerHTML = '<span id="mllboxYenToDelete" style="all:initial; position: fixed; right:1em; bottom: ' + (i * 2 + 1) + 'em; z-index:2147483647; opacity:1; font-size:90%; 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>';
    maet = setTimeout(function() {
      var mae = eleget0('//span[@id="mllboxYenToDelete"]');
      if (mae) { mae.remove(); }
    }, 5000);
  }

  function str2numMinMax(str, min, max) {
    var ans = Number(str.replace(/[A-Za-z0-9.]/g, function(s) {
      return String.fromCharCode(s.charCodeAt(0) - 65248);
    }).replace(/[^-^0-9^\.]/g, ""));
    if (ans > max) ans = max;
    if (ans < min) ans = min;
    return ans;
  }

  function eleget1(xpath) {
    if (!xpath) return "Err";
    try { var ele = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null) } catch (err) { return "Err"; }
    return ele.snapshotLength > 0 ? ele.snapshotItem(0) : ele;
  }

  function getNextSib(ele) { // 同じタグの弟ノードを走査
    if (!ele.nextElementSibling) return null;
    let orgtag = ele.tagName;
    do {
      ele = ele.nextElementSibling;
      if (!ele) return null;
      if (ele.tagName == orgtag) return ele;
    } while (1)
    return null;
  }

  function getPrevSib(ele) { // 同じタグの兄ノードを走査
    if (!ele.previousElementSibling) return null;
    let orgtag = ele.tagName;
    do {
      ele = ele.previousElementSibling;
      if (!ele) return null;
      if (ele.tagName == orgtag) return ele;
    } while (1)
    return null;
  }

  function proInput(prom, defaultval, min, max = Number.MAX_SAFE_INTEGER) {
    return Math.min(Math.max(
      Number(window.prompt(prom, defaultval).replace(/[A-Za-z0-9]/g, function(s) {
        return String.fromCharCode(s.charCodeAt(0) - 65248);
      }).replace(/[^-^0-9^\.]/g, "")), min), max);
  }

  var start_ms;

  function hajime() { start_ms = new Date().getTime(); }

  function owari() {
    var elapsed_ms = new Date().getTime() - start_ms;
    //console.log('処理時間:' + elapsed_ms + "ms");
  }

  function hajime2() { return new Date().getTime(); }

  function owari2(hajimeTime) {
    return new Date().getTime() - hajimeTime;
  }

  function pref(name, store = undefined) { // prefs(name,data)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)、prefs(name)で読み出し
    var domain = (location.href.match(/^https?:\/{2,}(.*?)(?:\/|\?|#|$)/)[1] || location.href);
    if (store === undefined) { // 読み出し
      let data = GM_getValue(domain + " ::: " + name)
      if (data == undefined) return; // 値がないなら終わり
      if (data.substr(0, 1) === "[") { // 配列なのでJSONで返す
        try { return JSON.parse(data || '[]'); } catch (e) {
          console.log("データベースがバグっているのでクリアします\n" + e);
          pref(name, []);
          return;
        }
      } else return data;
    }
    if (store === "" || store === [] || store === null) { // 書き込み、削除
      GM_deleteValue(domain + " ::: " + name);
      return;
    } else if (typeof store === "string") { // 書き込み、文字列
      GM_setValue(domain + " ::: " + name, store);
      return store;
    } else { // 書き込み、配列
      try { GM_setValue(domain + " ::: " + name, JSON.stringify(store)); } catch (e) {
        console.log("データベースがバグっているのでクリアします\n" + e);
        pref(name, "");
      }
      return store;
    }
  }

})();