Greasy Fork

Greasy Fork is available in English.

YouTube検索結果「全てキューに入れて再生」ボタンを追加

musictonicの代わり 右クリックだとシャッフル再生

当前为 2021-01-18 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name YouTube検索結果「全てキューに入れて再生」ボタンを追加
// @description musictonicの代わり 右クリックだとシャッフル再生
// @version      0.1.6
// @run-at document-idle
// @match *://www.youtube.com/*
// @match *://www.youtube.com/
// @grant none
// @require https://code.jquery.com/jquery-3.4.1.min.js
// @namespace http://greasyfork.icu/users/181558
// ==/UserScript==

(function() {
  const HIDE_FOR_YOU = 1; // 1:検索結果に割り込む「あなたへのおすすめ」を隠す
  const HIDE_ALSO_WATCHED = 1; // 1:検索結果に割り込む「他の人はこちらも視聴しています」を隠す
  const WAIT_MIN = 100; // 取りこぼす時は大きく
  const WAIT_MAX = 300; // 取りこぼす時は大きく
  const DEBUG = 0; // 1:wait値を表示

  const waitLast = performance.now() * 1; // 係数
  const wait = Math.round((window.navigator.userAgent.toLowerCase().indexOf('chrome') != -1) ? 250 : Math.min(WAIT_MAX, Math.max(WAIT_MIN, waitLast / 20)));

  var playAllCount;

  //URLの変化を監視
  var href = location.href;
  var observer = new MutationObserver(function(mutations) {
    if (href !== location.href) {
      href = location.href;
      $('#playAllButton').remove();
      setTimeout(() => { run() }, 1000);
    }
  });
  observer.observe(document, { childList: true, subtree: true });
  setTimeout(() => { run() }, 1000);
  return;

  function run(node = document) {
    if (location.href == "https://www.youtube.com/") {
      var place = eleget0('//div[@id="center" and @class="style-scope ytd-masthead"]');
    } else if (location.href.match(/https:\/\/www\.youtube\.com\/results\?.*(q=|search_query=)/)) {
      if (HIDE_FOR_YOU) $(elegeta('//h2/span[@id="title" and @class="style-scope ytd-shelf-renderer" and contains(text(),"あなたへのおすすめ")]/../../../..|//span[@id="title" and contains(text(),"For you")]/../../../../..')).hide(1000, function() { $(this).remove() }); // 検索結果に割り込む「あなたへのおすすめ」を隠す
      if (HIDE_ALSO_WATCHED) $(elegeta('//span[@id="title" and contains(text(),"他の人はこちらも視聴しています")]/../../../..|//span[@id="title" and contains(text(),"People also watched")]/../../../../..')).hide(1000, function() { $(this).remove() }); // 検索結果に割り込む「他の人はこちらも視聴しています」を隠す
      var place = eleget0('//div[@id="center" and @class="style-scope ytd-masthead"]'); ////div[@id="filter-menu"]');
    } else if (location.href.match("//www.youtube.com/channel/.*/search|//www.youtube.com/user/.*/search")) {
      var place = eleget0('//div[@id="center" and @class="style-scope ytd-masthead"]'); //'//div[@id="tabsContainer"]');
      //    } else if (location.href.match("//www.youtube.com/channel/|//www.youtube.com/c/|//www.youtube.com/user/") && location.href.match("/videos|/featured")) {
    } else if (location.href.match("//www.youtube.com/channel/|//www.youtube.com/c/|//www.youtube.com/user/") && !(location.href.match("/community|/channels|/about|/playlists"))) {
      var place = eleget0('//div[@id="center" and @class="style-scope ytd-masthead"]'); //'//div[@id="primary-items"]');
    } else if (location.href.match("//www.youtube.com/watch")) {
      var place = eleget0('//div[@id="center" and @class="style-scope ytd-masthead"]'); //'//div[@id="upnext" and @class="style-scope ytd-compact-autoplay-renderer"]');
    } else if (location.href.match("//www.youtube.com/playlist")) {
      var place = eleget0('//div[@id="center" and @class="style-scope ytd-masthead"]'); //'//div[@id="items"]/ytd-playlist-sidebar-secondary-info-renderer');
    } else return;

    if (place) {
      $('#playAllButton').remove();
      var playAllButton = $('<span style="cursor:pointer;color: #000; text-shadow: 1px 0px 0 #fff, -1px 0px 0 #fff, 0px -1px 0 #fff, 0px 1px 0 #fff;" title="クリックで画面に出ている動画を全てキューに入れて再生(右クリックだとシャッフル)\nEnqueue all displayed videos and start playing (right-click to shuffle)" id="playAllButton">Play All</span>')
      playAllButton.insertAfter(place);
      playAllButton.on("contextmenu", () => { playAll("shuffle"); return false; });
      playAllButton.on("click", () => { playAll(); return false; });
      if (!playAllCount) {
        playAllCount = setInterval(() => { $('#playAllButton').html("Play All (" + elegeta('//yt-icon[@class="style-scope ytd-menu-renderer"]').length + ")" + (DEBUG ? "<br>wait:" + wait : "")); }, 1000);
      }
    }

    function pauseVideo() {
      let e = eleget0('//video');
      if (e) { e.pause(); } else { setTimeout(pauseVideo, 17) }
    }

    function playAll(option = false) {
      setTimeout(pauseVideo, 17);
      let d = 0;
      let videoEle = elegeta('//yt-icon[@class="style-scope ytd-menu-renderer"]');
      for (let e of (option == "shuffle" ? shuffle(videoEle) : videoEle)) {
        setTimeout(() => { e.click() }, d);
        setTimeout(() => {
          let queue = eleget0('//yt-formatted-string[text()="キューに追加"]|//yt-formatted-string[text()="Add to queue"]');
          if (queue) queue.click();
        }, d + wait / 2);
        if (d == 0) d += 100; // ?
        d += wait;
      }
      d += wait * Math.min(7000, Math.max(2000, waitLast)) / 1000;
      cli('//div[contains(@class,\"ytp-miniplayer-play-button-container\")]/button[@aria-label=\"再生(k)\"]|//button[@class="ytp-play-button ytp-button" and @aria-label="Play (k)"]', d);
      d += wait * Math.min(7000, Math.max(2000, waitLast)) / 1000;
      cli('//div[@class="ytp-miniplayer-scrim"]/button[@aria-label="拡大(i)"]|//div[@class="ytp-miniplayer-scrim"]/button[@aria-label="Expand (i)"]', d);
      d += wait;
      setTimeout(() => { let e = eleget0('//video'); if (e) { e.play(); } }, d);
    }
  }

  function shuffle(array) {
    for (let i = array.length - 1; i >= 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  }

  function cli(xpath, wait) {
    setTimeout(() => {
      let ele = eleget0(xpath);
      if (ele) ele.click();
    }, wait);
  }

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

  function eleget0(xpath, node = document) {
    if (!xpath) return null;
    try {
      var ele = document.evaluate(xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
      if (ele.snapshotLength < 1) return "";
      let ei = ele.snapshotItem(0);
      if (ei.offsetHeight) return ei;
      return "";
    } catch (e) { return null; }
  }

})()