Greasy Fork

Greasy Fork is available in English.

画像のホバーで拡大

 Shift+H:オンオフ切替 y:ホバー中の画像をyandexで画像検索

当前为 2021-10-20 提交的版本,查看 最新版本

// ==UserScript==
// @name 画像のホバーで拡大
// @description  Shift+H:オンオフ切替 y:ホバー中の画像をyandexで画像検索
// @version      0.1
// @run-at document-idle
// @match *://*/*
// @exclude *://*.5ch.net/*
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_deleteValue
// @namespace http://greasyfork.icu/users/181558
// ==/UserScript==

(function() {
  const hoverTimeDefault = 3; // デフォルト設定 0:オフ 1:画像に乗った瞬間 2-:画像に乗せてn/60秒静止したら
  const defaultDelay = 3; // マウスを乗せてから拡大表示するまでの遅延 1:画像に乗った瞬間 2-:画像に乗せてn/60秒静止したら
  const CONFIRM_FOR_Y = 1; // 1:yキーでyandex検索をする時URLの確認を求める
  const KEY_SELECT_DELAY = "Shift+H"; // 設定キー
  const FORCE_USE_HALF_WIDTH = 0; // 1だとホバーズームで必ず画面の横半分のサイズ(縦長の画像だと上下がはみ出す)

  const verbose = 0; // 1:debug
  var domain = new URL(location.href).hostname;
  var hovertime = pref(domain + " : delay") || hoverTimeDefault;
  const minWidth = location.href.match(/twitter/) ? 1000 : (window.innerWidth / 2);
  const minHeight = location.href.match(/twitter/) ? 1000 : (window.innerHeight / 2);

  var mousex = 0;
  var mousey = 0;
  var lastEle = "";

  var hovertimer = 0;
  var poppedUrl = "";
  var yandexUrl = "";

  document.addEventListener("keypress", e => {
    if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true') return;
    var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
    if (key === "y" && poppedUrl) { // y::ホバー中の画像をyandex画像検索で検索
      if (!CONFIRM_FOR_Y || window.confirm(yandexUrl + "\n\nを開きます。よろしいですか?")) window.open(yandexUrl);
      return false;
    }
    if (key === KEY_SELECT_DELAY) { // Shift+H::ホバーの設定
      elegeta('//img[@class="ignoreMe hzP"]').forEach(e => e.remove());
      let ret = hovertime > 0 ? -1 : defaultDelay;
      if (ret === "") {
        pref(domain + " : delay", "");
        hovertime = hoverTimeDefault;
      } else {
        if (ret !== null) {
          hovertime = ret || hoverTimeDefault;
          pref(domain + " : delay", hovertime);
          popup(`${domain}<br>${KEY_SELECT_DELAY}:ホバーズームを${hovertime>0?"有効":"無効"}にしました${hovertime>0?"("+hovertime+"/60秒)":""}`, hovertime > 0 ? "#6080ff" : "#808080")
        }
      }
    }
  });

  var input_key_buffer = new Array();

  document.addEventListener('keyup', function(e) {
    if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true') return;
    input_key_buffer[e.keyCode] = false;
  }, false);

  document.addEventListener('blur', function(e) { input_key_buffer.length = 0; }, false);

  document.addEventListener('keydown', function(e) {
    if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.getAttribute('contenteditable') === 'true') return;
    input_key_buffer[e.keyCode] = true;
  }, false);

  document.addEventListener("mousemove", function(e) {
    mousex = e.clientX;
    mousey = e.clientY;
    hovertimer = 0;
  }, false);

  document.addEventListener("wheel", function(e) {
    hovertimer = 0;
  }, false);

  setInterval(onint, 16.667);

  function onint() {
    if (hovertime < 1) return;
    hovertimer++;
    let ele = document.elementFromPoint(mousex, mousey);
    if (lastEle !== ele) {
      hovertimer = 0;
      if (poppedUrl) {
        elegeta('//img[@class="ignoreMe hzP"]').forEach(e => e.remove());
        elegeta('//span[@class="ignoreMe hzP"]').forEach(e => e.remove());
        poppedUrl = "";
      }
    }
    if (ele)
      if (ele.tagName === "IMG" && hovertimer >= hovertime && poppedUrl == "" && (ele.clientWidth < minWidth || ele.clientHeight < minHeight)) {
        poppedUrl = pe(ele);
        yandexUrl = poppedUrl.match(/\;base64\,/i) ? null : "https://yandex.com/images/search?rpt=imageview&url=" + poppedUrl;
      }
    lastEle = ele;
  }

  function pe(a) {
    let imgAspect = a.naturalWidth / a.naturalHeight;
    let clientAspect = window.innerWidth / 2 / window.innerHeight;

    if (a.parentNode.tagName == "A" && a.parentNode.href.match(/.mp4$|.webm$/i)) { // 動画
      var ext = a.parentNode.href.match(/.mp4$|.webm$/i)[0]; //console.log(ext,a.parentNode.href)
      var ve = document.createElement("video")
      var panel = document.createElement("span");
      panel.className = "ignoreMe hzP";
      panel.appendChild(ve)
      panel.src = a.parentNode.href;
      panel.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 1000, fill: 'forwards' });
      ve.outerHTML = `<video className="ignoreMe hzP" id="hzPv" controls autoplay loop ${(imgAspect < clientAspect && !FORCE_USE_HALF_WIDTH)?`height="${window.innerHeight*0.98-5}px"`:`width="${window.innerWidth*0.48-5}px"`} ><source src="${a.parentNode.href}" type="video/mp4">Sorry, your browser doesn't support embedded videos.</video>`;
      panel.maxWidth = "48%";
    } else { // 画像
      var panel = a.cloneNode(true);
      panel.className = "ignoreMe hzP";
      if (a.parentNode.tagName == "A" && a.parentNode.href.match(/.png$|.jpg$|.jpeg$|.gif$|.bmp$|.webp$/i)) {
        panel.src = a.parentNode.href;
      } else if (a.parentNode.parentNode.tagName == "A" && a.parentNode.parentNode.href.match(/.png$|.jpg$|.jpeg$|.gif$|.bmp$|.webp$/i)) {
        panel.src = a.parentNode.parentNode.href;
      }
      panel.src = panel.src.replace(/(https:\/\/pbs\.twimg\.com\/.*\?format=.+\&name=).+/, "$1orig");
    }

    let boxPos = (mousey < (window.innerHeight / 2) ? "bottom:0px;" : "top:0px;") + ((mousex < window.innerWidth / 2) ? "right:0px; " : "left:0px;");
    panel.className = "ignoreMe hzP";
    if (imgAspect > clientAspect || FORCE_USE_HALF_WIDTH) {
      panel.setAttribute("style", "all:initial; width:48%;" + boxPos + " z-index:2147483647; position:fixed; margin:5px; border-radius:3px; color:#ffffff;  box-shadow:3px 3px 8px #0008; border:2px solid #fff; ");
    } else {
      panel.setAttribute("style", "all:initial;height:98%;" + boxPos + " z-index:2147483647; position:fixed; margin:5px; border-radius:3px; color:#ffffff;  box-shadow:3px 3px 8px #0008; border:2px solid #fff; ");
    }
    if (a.clientWidth < window.innerWidth * 0.48) document.body.appendChild(panel);
    if (verbose) popup(panel.src);
    return panel.src;
  }

  function elegeta(xpath, node = document) {
    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;
  }

  function pref(name, store = null) { // prefs(name,data)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)、prefs(name)で読み出し
    if (store === null) { // 読み出し
      let data = GM_getValue(name) || GM_getValue(name);
      if (data == undefined) return null; // 値がない
      if (data.substring(0, 1) === "[" && data.substring(data.length - 1) === "]") { // 配列なのでJSONで返す
        try { return JSON.parse(data || '[]'); } catch (e) {
          alert("データベースがバグってるのでクリアします\n" + e);
          pref(name, []);
          return;
        }
      } else return data;
    }
    if (store === "" || store === []) { // 書き込み、削除
      GM_deleteValue(name);
      return;
    } else if (typeof store === "string") { // 書き込み、文字列
      GM_setValue(name, store);
      return store;
    } else { // 書き込み、配列
      try { GM_setValue(name, JSON.stringify(store)); } catch (e) {
        alert("データベースがバグってるのでクリアします\n" + e);
        pref(name, "");
      }
      return store;
    }
  }

  function prefRestrict(name, type) {
    let data = pref(name);
    if (!data) return data;
    if (type === "array") {
      if (typeof data === "object") {
        return data;
      } else {
        alert("データベースの形式に誤りがある(配列/オブジェクトでない)ためクリアします\n");
        pref(name, "");
        return [];
      }
    }
    return data;
  }

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

  function popup(text, color = "#6080ff") {
    var e = document.getElementById("hzbox");
    if (e) { e.remove(); }
    var e = document.body.appendChild(document.createElement("span"));
    e.innerHTML = '<span id="hzbox" style="all:initial; position: fixed; right:1em; bottom: 1em; z-index:2147483647; opacity:1; font-size:90%; font-weight:bold; margin:0px 1px; text-decoration:none !important; text-align:left; padding:1px 6px 1px 6px; border-radius:12px; background-color:' + color + '; color:white; white-space: nowrap;" onclick=\'var a = document.createElement(\"textarea\"); a.value = \"' + text.replace(/<br>/gm, "\\n") + '\"; document.body.appendChild(a); a.select(); document.execCommand(\"copy\"); a.parentElement.removeChild(a);\'">' + text + '</span>';
    setTimeout((function(e) { return function() { e.remove(); } })(e), 5000);
  }

})();