// ==UserScript== // @name YouTube検索結果「全てキューに入れて再生」ボタンを追加 // @description musictonicの代わり 右クリックだとシャッフル再生 e:カーソル下の動画をキューに入れる y:再生開始 Alt+c/Ctrl+x:視聴中のキューリストをURLにしてコピー // @version 0.1.48 // @run-at document-idle // @match *://www.youtube.com/* // @match *://www.youtube.com/ // @match file:///* // @require https://code.jquery.com/jquery-3.6.4.min.js // @require https://code.jquery.com/ui/1.13.2/jquery-ui.min.js // @grant GM.setClipboard // @grant GM.openInTab // @grant GM.addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @noframe // @namespace https://greasyfork.org/users/181558 // @downloadURL none // ==/UserScript== // @match *://*/* (function() { const USE_INSTANT_PLAYLIST = 0; // 0:機能6-8を無効にする 1:有効にし使用時に確認を表示する 2:有効にし確認しない const YOUTUBE_WATCH_ALTC_VARIATIONS = 3; // Alt+cの機能を何番目まで使うか 1:連続再生URL 2:単独再生URLの列挙 3:iframe埋め込み用HTML const CLOSE_MINI_PLAYER_ALWAYS = 1; // 1:Escでミニプレイヤーを常に閉じる const AGREE_TO_CONTINUE_ALWAYS = 1; // 1:無操作一時停止を常に解除 const HIDE_SUGGEST = 1; // 1:検索結果に割り込む「あなたへのおすすめ」「他の人はこちらも視聴しています」「家にいながら学ぶ」等を隠す 0:無効 const PRESERVE_INDEX = 0; // 1:機能6-8で最初に再生するトラックを保持 const INCLUDE_REEL_SHORTS = 1; // 1:機能6-8でリール棚のShorts動画を含める const USE_PLAYALL = 1; // 1:PlayAllボタンを有効 0:無効 const YOUTUBE_WATCH_ALTC_EMBED_PLAYER_SIZE = `width="498" height="280"`; // ALT+C3回目の埋め込みプレイヤーのサイズ指定 322x181~ const SEARCH_RESULTS_THUMBNAIL_VIDEOS_WIDTH = "12.5"; // 検索結果の動画のサムネイルのサイズ "":無効 const SEARCH_RESULTS_THUMBNAIL_SHORTS_HEIGHT = "17"; // 検索結果のshortsのサムネイルのサイズ "":無効 const WAIT_LOADING = Math.random() > 0.5 ? 1 : 0; // PLAY ALL押下時に読み込みを待つ const EXPERIMENTAL_ALTERNATIVE_URL_FOR_INSTANT_PLAYLIST = 1; // 2:Instant Playlist用のURLを不具合回避のembed版にして遷移するようにする 1:embed版を開いた時通常の視聴ページに遷移する機能だけオン const DEBUG = 0; // 1:wait値を表示 const IPURL = EXPERIMENTAL_ALTERNATIVE_URL_FOR_INSTANT_PLAYLIST >= 2 ? `https://www.youtube.com/embed/?playlist=` : `https://www.youtube.com/watch_videos?video_ids=`; var SHORTS = INCLUDE_REEL_SHORTS ? ",ytd-reel-item-renderer.style-scope.yt-horizontal-list-renderer div div a,ytd-rich-grid-slim-media div div a[href*='/shorts/']" : ""; const EXPERIMENTAL_FASTMODE = 1; // 1:実験的な高速モードを使用 0:旧モード const COE = 1; // chrome以外のウエイト係数 取りこぼす時は大きく const COE_CHROME = 1; // chromeのウエイト係数 取りこぼす時は大きく const CHROME = (window.navigator.userAgent.toLowerCase().indexOf('chrome') != -1); const WAIT_FIRST = CHROME ? 700 : 200; // 取りこぼす時は大きく const WAIT_MIN = CHROME ? 190 : 160; // 取りこぼす時は大きく 50- const WAIT_MAX = 300; // 取りこぼす時は大きく 250- const waitLast = performance.now() * 1; // 現在の負荷 const wait = EXPERIMENTAL_FASTMODE ? (CHROME ? 40 : 40) : Math.round((Math.min(WAIT_MAX, Math.max(WAIT_MIN, waitLast / 10))) * (CHROME ? COE_CHROME : COE)); String.prototype.match0 = function(re) { let tmp = this.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可 function adja(place = document.body, pos, html) { return place ? (place.insertAdjacentHTML(pos, html), place) : null; } let inYOUTUBE = location.hostname.match0(/^www\.youtube\.com|^youtu\.be/); let GF = {} var videoDisplayedLast = 0; var mllID = 0; var kaisuu = 0; var equeueIP = [] var equeue = [] var playAllCount, playAllCount2; var myqueue = []; let addstyle = { added: [], add: function(str) { if (this.added.some(v => v[1] === str)) return; var S = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // var S="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" var d = Date.now() var uid = Array.from(Array(12)).map(() => S[Math.floor((d + Math.random() * S.length) % S.length)]).join('') document.head.insertAdjacentHTML("beforeend", ``); this.added.push([uid, str]); return uid; }, remove: function(str) { // str:登録したCSSでもaddでreturnしたuidでも良い let uid = this.added.find(v => v[1] === str || v[0] === str)?.[0] if (uid) { eleget0(`#${uid}`)?.remove() this.added = this.added.filter(v => v[0] !== uid) } } } if ((window.parent == window) && EXPERIMENTAL_ALTERNATIVE_URL_FOR_INSTANT_PLAYLIST >= 1 && lh(/https:\/\/www.youtube.com\/embed\/\?playlist\=/)) { // 匿名プレイリストの埋め込み用ページだったら正規視聴ページに遷移 GF.avoidID = setInterval(() => { let err = eleget0('//div[contains(@class,"ytp-error-content-wrap")]/div/span[text()="動画を再生できません"]|//div[@class="ytp-error-content-wrap-reason"]/span[text()="Video unavailable"]') // 多分外部サイトでの埋め込み再生を禁止している動画 if (err) { clearInterval(GF.avoidID) if (Math.random() > 0.33) { // 2/3の確率で順番を変えてみる(1つめを埋め込み禁止動画じゃなくせるかも) var sm = location.href.split(/\s/).map(v => { return [...v?.matchAll(/^(?:h?t?tps?:\/\/)?(?:youtu\.be\/|(?:m\.|www\.|)?youtube\.com\/(?:shorts\/|watch\?v=|embed\/|live\/))([a-zA-Z0-9_\-]{11})(?![a-zA-Z0-9_\-]{1})|^(?:h?t?tps?:\/\/)?www\.youtube\.com\/(?:watch_videos\?video_ids=|embed\/\?playlist=)([a-zA-Z0-9_\-,]{11,600})/gmi)]?.map(c => c.slice(1, 999)) })?.flat()?.flat()?.map(v => v?.split(","))?.flat()?.filter(c => /^[a-zA-Z0-9_\-]{11}$/.test(c)) // 書式が混在していても登場順に収納する sm = sm.map(a => ({ rnd: Math.random(), val: a })).sort((a, b) => a.rnd - b.rnd).map(a => a.val); location.href = `https://www.youtube.com/embed/?playlist=${sm.join(",")}`; } else { location.href = location.href?.replace(/https:\/\/www.youtube.com\/embed\/\?playlist\=/, "https://www.youtube.com/watch_videos?video_ids="); } return; } let err2 = eleget0('//div[contains(@class,"ytp-error-content-wrap-reason")]/span[text()="この動画は再生できません"]|//div[contains(@class,"ytp-error-content-wrap-reason")]/span[contains(text(),"This video is unavailable")]') // 多分TLGGが間に合ってない if (err2) { clearInterval(GF.avoidID) if (pref("lastURL") != location.href) { pref("lastURL", location.href); begin(document.body, `

Wait a few seconds...

`) setTimeout(() => location.reload(), 2000); return } alert("数秒待ってリロードしてみると良いかもしれません") return; } let t = eleget0('a.ytp-title-link.yt-uix-sessionlink')?.href?.match0(/^https:\/\/www\.youtube\.com\/watch\?list=.*$/) if (t) { clearInterval(GF.avoidID) location.href = t; return; } }, 333) } else pref("lastURL", ""); if (USE_INSTANT_PLAYLIST) { document.addEventListener('keydown', e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement?.closest('#chat-messages,ytd-comments-header-renderer')))) return; var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key; //if (key === "Shift+Y") { // Shift+Y:: //let option = ""; if (key === "Shift+Ctrl+Y" || key === "Shift+Y") { // Shift+Y:: let option = key == "Shift+Ctrl+Y" ? "shuffle" : "" let inp = [...elegeta('a:visible').map(e => e.href.replace("//yewtu.be/watch?v=", "//www.youtube.com/watch?v=").replace("//yewtu.be/shorts/", "//www.youtube.com/shorts/").replace(/\/\/yewtu\.be\/([a-zA-Z0-9_\-,]{11})(.*)/, "//youtu.be/$1$2").replace(/\/\/youtube\.com\/([a-zA-Z0-9_\-,]{11})(.*)/, "//youtu.be/$1$2").replace("//yewtu.be/", "//www.youtube.com/")).filter(v => /youtube\.com|youtu\.be/.test(v)), ...document?.body?.innerText?.split(/\n|\s/)?.filter(v => /youtube\.com|youtu\.be/.test(v)), ...elegeta('iframe[src*="youtube"]').map(e => e?.src)].join(" "); if (inp || 1) { // var urlcap = []; var urlcap = inp.split(/\s/).map(v => { return [...v?.matchAll(/^(?:h?t?tps?:\/\/)?(?:youtu\.be\/|(?:m\.|www\.|)?youtube\.com\/(?:shorts\/|watch\?v=|embed\/|live\/))([a-zA-Z0-9_\-]{11})(?![a-zA-Z0-9_\-]{1})|^(?:h?t?tps?:\/\/)?www\.youtube\.com\/(?:watch_videos\?video_ids=|embed\/\?playlist=)([a-zA-Z0-9_\-,]{11,600})/gmi)]?.map(c => c.slice(1, 999)) })?.flat()?.flat()?.map(v => v?.split(","))?.flat()?.filter(c => /^[a-zA-Z0-9_\-]{11}$/.test(c)) // 書式が混在していても登場順に収納する // inp.split(/\s/).forEach(v => { urlcap = urlcap.concat(...[...v?.matchAll(/^(?:h?t?tps?:\/\/)?(?:m\.|www\.|)?youtube\.com\/(?:shorts\/|watch\?v=|embed\/|live\/)([a-zA-Z0-9_\-]{11})(?![a-zA-Z0-9_\-]{1})|^(?:h?t?tps?:\/\/)?youtu\.be\/([a-zA-Z0-9_\-]{11})(?![a-zA-Z0-9_\-]{1})|^(?:h?t?tps?:\/\/)?www\.youtube\.com\/(?:watch_videos\?video_ids=|embed\/\?playlist=)([a-zA-Z0-9_\-,]{11,600})/gmi)].map(c => c.slice(1, 999))).filter(w => w) }) // 書式が混在していても登場順に収納する inp = null; if (urlcap?.length || 1) { let urla = urlcap //urlcap.join(",").split(",").filter(c => /^[a-zA-Z0-9_\-]{11}$/.test(c)); // 動画IDは11桁 let urllen = urla.length; let urla2 = [...new Set(urla)]; // 重複削除 if (option == "shuffle") urla2 = shuffle(urla2); // シャッフル let urllen2 = urla2.length; let urla3 = [...urla2].slice(0, 50); // 50件まで let urlenum = urla3.join(",") let url = `${IPURL}${urla2.join(",")}` var enumUrl = [] for (let u = 0; u < urla2.length / 50; u++) { enumUrl.push(`${IPURL}${ (urla2.slice(u*50, u*50+50).join(",") ) }`) } let [url0, urls, videos] = urlExtractAndConcat(option, urllen2 ? enumUrl.join(" \n\n") : "", urla2?.length); //let [url0, urls, videos] = urlExtractAndConcat("", urllen2 ? enumUrl.join(" \n\n") : "", urla2?.length); if (urls?.length) { setTimeout(() => { confirm(`${videos}個の動画を${urls?.length}つのタブで開きますか?\n\n${urls?.join("\n\n")}`) && //GM.openInTab(enumUrl[0], true); openUrls(escape(JS(urls))) return; }, 222) } } } } }) if (!ld("youtube.com")) return; // youtube以外はここまで } // プレイリストの動画の合計時間を算出、全部読み込みが終わっていないとしない function gettotal(max = 99999) { let playlistItemLen = elegeta('ytd-playlist-panel-video-renderer#playlist-items.style-scope.ytd-playlist-panel-renderer:visible').slice(0, max).length if (playlistItemLen) { let palylistTime = elegeta('ytd-playlist-panel-video-renderer#playlist-items.style-scope.ytd-playlist-panel-renderer div.ytd-thumbnail-overlay-time-status-renderer:visible').slice(0, max) if (palylistTime?.length == playlistItemLen) { let sum = palylistTime.reduce((p, e) => { let t = e?.innerText?.trim() let h = t?.match0(/(\d+)\:\d+\:\d+$/) || 0 let m = t?.match0(/(\d+)\:\d+$/) || 0 let s = t?.match0(/(\d+)$/) || 0 p += h * 60 * 60 + m * 60 + s * 1 return p }, 0) let total = `${zeropad(2,sum/60/60|0)}:${zeropad(2,sum/60%60|0)}:${zeropad(2,sum%60)}` return total; } } return ""; } setInterval(() => { if (!GF.time && lh(/^https:\/\/www\.youtube\.com\/watch\?v=/) && document?.getElementById('playlist')) { let total = gettotal() if (total) { eleget0('div#publisher-container.style-scope.ytd-playlist-panel-renderer:visible').insertAdjacentHTML("beforeend", `
${total}
`); GF.time = 1; } } }, 4000); ["yt-navigate-finish", "yt-playlist-data-updated"].forEach(v => { window.addEventListener(v, () => { GF.time = 0 eleget0('#playlisttotaltime')?.remove() }) }) function zeropad(pad, num) { return String(num)?.padStart(pad, "0") } // Enhancer for YouTubeのミニプレイヤーをカーソルを避けるようにする GF.avoidminiplayer = 0 let css = '#efyt-progress,body.efyt-mini-player._top-right #movie_player:not(.ytp-fullscreen),body.efyt-mini-player._bottom-right #movie_player:not(.ytp-fullscreen){left:1em !important; right:auto !important;}' document.addEventListener("mousemove", e => { if (GF.avoidminiplayer && !e?.target?.closest('ytd-watch-next-secondary-results-renderer.style-scope.ytd-watch-flexy')) { GF.avoidminiplayer = 0 addstyle.remove(css) return; } else if (!GF.avoidminiplayer && e?.target?.closest('ytd-watch-next-secondary-results-renderer.style-scope.ytd-watch-flexy')) { // .closestの方が:hoverより40倍ぐらい速い addstyle.add(css) GF.avoidminiplayer = 1 } }) SEARCH_RESULTS_THUMBNAIL_VIDEOS_WIDTH && GM.addStyle(`.yt-lockup-view-model-wiz__content-image {max-width: ${SEARCH_RESULTS_THUMBNAIL_VIDEOS_WIDTH*1.9}em !important;} ytd-search ytd-video-renderer ytd-thumbnail.ytd-video-renderer,ytd-search ytd-playlist-thumbnail,div#avatar-section.style-scope.ytd-channel-renderer{max-width: ${SEARCH_RESULTS_THUMBNAIL_VIDEOS_WIDTH}em !important;}`); SEARCH_RESULTS_THUMBNAIL_SHORTS_HEIGHT && GM.addStyle(`.yt-lockup-view-model-wiz__content-image , ytd-search .yt-horizontal-list-renderer .yt-core-image--content-mode-scale-aspect-fill { object-fit: contain; } .yt-lockup-view-model-wiz__content-image , ytd-search .yt-horizontal-list-renderer ytd-thumbnail.ytd-reel-item-renderer{max-height:${SEARCH_RESULTS_THUMBNAIL_SHORTS_HEIGHT}em !important;}`); /*SEARCH_RESULTS_THUMBNAIL_VIDEOS_WIDTH && GM.addStyle(`ytd-search ytd-video-renderer ytd-thumbnail.ytd-video-renderer,ytd-search ytd-playlist-thumbnail,div#avatar-section.style-scope.ytd-channel-renderer{max-width: ${SEARCH_RESULTS_THUMBNAIL_VIDEOS_WIDTH} !important;}`); SEARCH_RESULTS_THUMBNAIL_SHORTS_HEIGHT && GM.addStyle(`ytd-search .yt-horizontal-list-renderer .yt-core-image--content-mode-scale-aspect-fill { object-fit: contain; } ytd-search .yt-horizontal-list-renderer ytd-thumbnail.ytd-reel-item-renderer{max-height:${SEARCH_RESULTS_THUMBNAIL_SHORTS_HEIGHT} !important;}`);*/ //URLの変化を監視 var href = location.href; var observer = new MutationObserver(function(mutations) { if (href !== location.href) { href = location.href; $('#playAllButton,#instantPlaylistButton').remove(); clearInterval(GF?.hideShort); GF.wari = 0 setTimeout(() => { GF.lastinner = ""; run() }, 1500); } }); observer.observe(document, { childList: true, subtree: true }); setTimeout(() => { run(); }, 1009); HIDE_SUGGEST && GM.addStyle(`ytd-search ytd-shelf-renderer,ytd-search ytd-horizontal-card-list-renderer{display:none !important;}`) //setInterval(() => { hideSuggest() }, 1511); if (AGREE_TO_CONTINUE_ALWAYS) { setInterval(() => { if (!lh(/youtube\.com\/watch\?v=/)) return; if (eleget0('YTD-APP YTD-POPUP-CONTAINER TP-YT-PAPER-DIALOG YT-CONFIRM-DIALOG-RENDERER DIV TP-YT-PAPER-DIALOG-SCROLLABLE DIV YT-FORMATTED-STRING:visible:text*=動画が一時停止されました。続きを視聴しますか|Video paused. Continue watching')) eleget0('//ytd-app/ytd-popup-container/tp-yt-paper-dialog[@style-target="host"]/yt-confirm-dialog-renderer/div[last()]/div[contains(@class,"buttons style-scope yt-confirm-dialog-renderer")]/yt-button-renderer[3]/yt-button-shape/button[@aria-label="Yes" or @aria-label="はい"]/yt-touch-feedback-shape/div[contains(@class,"yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response")]/div[last()]:visible')?.click() }, 3001) } var mousex = 0; var mousey = 0; document.addEventListener("mousemove", function(e) { mousex = e.clientX; mousey = e.clientY; }, false); /* if (location.href.match0(/nicovideo/)) { // ニコ動 document.addEventListener('keydown', e => { if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA' && e.target.getAttribute('contenteditable') != 'true') { var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key; if (key === "e" && location.href.match0(/nicovideo/)) { // e::enqueue e.preventDefault(); var ele = document.elementFromPoint(mousex, mousey); var ancestorEle = getTitleFromParent(ele, 0, '//div[3]/ul[@class="list" and @data-video-list=""]/li[@data-nicoad-video=""]'); if (!ancestorEle) return false let titleEle = eleget0('.//p[@class="itemTitle"]/a', ancestorEle); if (!titleEle) return false myqueue.push({ id: titleEle.href.replace(/^.+\/watch\/|\?.+/gmi, ""), title: titleEle.innerText.trim() }) myqueue = Array.from(new Set(myqueue.map(a => JSON.stringify(a)))).map(a => JSON.parse(a)); popup(`e:『${titleEle.textContent}』をキューに入れました(y:再生)\n${myqueue.map((c,i)=>`${1+i}) ${c.title} (${c.id})`).join("\n")}`) return false; } if (key === "y" && !/\/watch/.test(location.href)) { // y::start playing e.preventDefault(); var url = `${myqueue.map(c=>c.id).join(",")}を連続再生するURLがありません` alert(url) return false; } } }, false) return } */ // youtube検索結果画面で「ショート」や「他の人はこちらも視聴しています」類の見出しをクリックでその動画を隠したり出したり GM.addStyle('h2.style-scope.ytd-reel-shelf-renderer,h2.style-scope.ytd-shelf-renderer,div#title-text.style-scope.ytd-rich-list-header-renderer{cursor:pointer;}') GM.addStyle('.hiddenInstance{text-decoration:underline overline line-through;}') GM.addStyle('.zenqhidevideo{display:none !important; transition:all 0.5s;}') let hiddenTitle = new Set() document.addEventListener("mousedown", e => { if (e.button === 0 && lh(/^https:\/\/www\.youtube\.com\/results\?search_query=/) && (e?.target?.matches('h2.style-scope.ytd-reel-shelf-renderer') || e?.target?.closest('h2.style-scope.ytd-reel-shelf-renderer,h2.style-scope.ytd-shelf-renderer,div#title-text.style-scope.ytd-rich-list-header-renderer'))) { e.preventDefault(); e.stopPropagation(); if (e?.ctrlKey) { // Ctrl+左クリック:棚とショートをすべて消す hideShelfShort() } else { // 左クリック:その棚だけ隠したり出したり let reelinner = e?.target?.closest('ytd-reel-shelf-renderer.style-scope.ytd-item-section-renderer,ytd-shelf-renderer.style-scope.ytd-item-section-renderer,ytd-horizontal-card-list-renderer.style-scope.ytd-item-section-renderer')?.querySelector('div#contents.style-scope.ytd-reel-shelf-renderer,ytd-vertical-list-renderer.style-scope.ytd-shelf-renderer,div#items.style-scope.ytd-horizontal-card-list-renderer,div#scroll-outer-container.style-scope.yt-horizontal-list-renderer') if (!hiddenTitle.has(e.target)) { //.dataset.hide=((e.target?.dataset?.hide||0)+1)%2;alert(e.target.dataset.hide); hiddenTitle.add(e.target); $(reelinner).hide(111) } else { hiddenTitle.delete(e.target); $(reelinner).show(111) //toggleClass("hiddenInnerInstance").toggle(111) } $(e?.target?.closest('span#title,yt-formatted-string#title.style-scope.ytd-rich-list-header-renderer')).toggleClass("hiddenInstance") } return false; } }) document.addEventListener("dblclick", e => { if (e.button === 0 && lh(/^https:\/\/www\.youtube\.com\//) && !lh(/^https:\/\/www\.youtube\.com\/watch/) && e?.target?.matches('div#container.style-scope.ytd-search , div#container.style-scope.ytd-masthead , div#contentContainer.style-scope.tp-yt-app-drawer , div#guide-content.style-scope.ytd-app')) { e.preventDefault(); e.stopPropagation(); hideShelfShort() return false; } }) function hideShelfShort() { GF.wari = 1 - (GF?.wari || 0); popupCenter(`Shortsを${GF.wari?"すべて隠します":"表示します"}`, !GF.wari ? "#888" : "#35a") let css = `:is(ytd-reel-shelf-renderer.style-scope.ytd-item-section-renderer,ytd-shelf-renderer.style-scope.ytd-item-section-renderer,ytd-horizontal-card-list-renderer.style-scope.ytd-item-section-renderer) :is(div#contents.style-scope.ytd-reel-shelf-renderer,ytd-vertical-list-renderer.style-scope.ytd-shelf-renderer,div#items.style-scope.ytd-horizontal-card-list-renderer,div#scroll-outer-container.style-scope.yt-horizontal-list-renderer){display:none !important; } h2.style-scope.ytd-reel-shelf-renderer,h2.style-scope.ytd-shelf-renderer,div#title-text.style-scope.ytd-rich-list-header-renderer{opacity:0.5;}` GF.wari ? addstyle.add(css) : addstyle.remove(css); function popupCenter(text, bgcolor = text == "解除" ? "#888" : "#35a") { if (!text) return text = String(text).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/`/g, '`').replace(//g, ">").replace(/\n/gm, "
") let e = end(document.body, `${text}`) /*e.onclick = v => { GM.setClipboard(v.target.innerText); v.target.innerText = `「${v.target.innerText}」をクリップボードにコピーしました` }*/ $(e).hide(0).fadeIn(155, (function(e) { return function() { setTimeout(() => { $(e).fadeOut(155, () => $(e).remove()) }, 222) } })(e)) } if (GF.wari) { clearInterval(GF.hideShort); GF.hideShort = setInterval(() => { elegeta(':is(ytd-video-renderer.style-scope.ytd-item-section-renderer , ytd-rich-item-renderer):not(.zenqhidevideo)').filter(e => eleget0('ytd-thumbnail-overlay-time-status-renderer[overlay-style="SHORTS"]', e)) .concat(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-shelf-renderer')) .forEach(e => { (GF.wari) ? e.classList.add('zenqhidevideo'): e.classList.remove('zenqhidevideo'); }); }, 999); } else { clearInterval(GF.hideShort); elegeta(':is(ytd-video-renderer.style-scope.ytd-item-section-renderer , ytd-rich-item-renderer)').filter(e => eleget0('ytd-thumbnail-overlay-time-status-renderer[overlay-style="SHORTS"]', e)) .concat(elegeta('ytd-rich-item-renderer.style-scope.ytd-rich-shelf-renderer')) .forEach(e => { (GF.wari) ? e.classList.add('zenqhidevideo'): e.classList.remove('zenqhidevideo'); }); } } hoverHelp(e => e?.matches('h2.style-scope.ytd-reel-shelf-renderer') || e?.closest('h2.style-scope.ytd-reel-shelf-renderer,h2.style-scope.ytd-shelf-renderer,div#title-text.style-scope.ytd-rich-list-header-renderer') ? "クリック:隠す/再表示
Ctrl+クリック:この類の棚をすべて隠す/再表示" : "") function hoverHelp(cb) { let latest, helpEle; document.addEventListener("mousemove", e => { if (latest != e?.target) { helpEle?.remove() const text = cb(e.target) if (text) helpEle = end(document.body, `
${text}
`) latest = e.target if (document.elementFromPoint(e.clientX, e.clientY) == helpEle) { helpEle.style.bottom = ""; helpEle.style.top = "1em"; } } }) } GM.addStyle('.boxatt{ background-color:#efe !important; animation: pulse 1s 1; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 #00ff88f0; } 100% { box-shadow: 0 0 10px 35px #ffffff00; } } .yenClickHighlight {outline: rgba(0, 255,128,0.7) solid 4px !important; }') function boxatt(e) { [e].flat().forEach(v => { v.classList.add("boxatt") setTimeout(() => v.classList.remove("boxatt"), 1000) }) } document.addEventListener('keydown', e => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.isContentEditable || ((e.target.closest('#chat-messages,ytd-comments-header-renderer') || document.activeElement?.closest('#chat-messages,ytd-comments-header-renderer')))) return; var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key; if (key === "Escape" && CLOSE_MINI_PLAYER_ALWAYS) { // esc::ミニプレイヤーを常に閉じる for (let i = 0; i < 20; i++) { setTimeout(() => { elegeta('tp-yt-paper-dialog .yt-core-attributed-string.yt-core-attributed-string--white-space-no-wrap:visible').filter(e => /プレーヤーを閉じる/.test(e.textContent)).forEach(e => e?.click()) }, i * 200) equeue = [] } } if (key === "e") { // e::enqueue e.preventDefault(); var ele = document.elementFromPoint(mousex, mousey); var box = eleget0(`:is(ytd-video-renderer,ytd-rich-item-renderer,ytd-grid-video-renderer,ytd-playlist-video-renderer,ytd-reel-item-renderer.style-scope.yt-horizontal-list-renderer,ytd-compact-video-renderer , ytd-playlist-panel-video-renderer#playlist-items.style-scope.ytd-playlist-panel-renderer):hover`); //マウスが乗っている動画の枠 //var box = eleget0(`:is(ytd-video-renderer,ytd-rich-item-renderer,ytd-grid-video-renderer,ytd-playlist-video-renderer,ytd-reel-item-renderer.style-scope.yt-horizontal-list-renderer,ytd-compact-video-renderer):hover`); //マウスが乗っている動画の枠 if (box && USE_INSTANT_PLAYLIST) { //IP先頭用に独自キューを覚えておく var href = eleget0(':is(a[href*="/watch"],a[href*="/shorts/"])', box)?.href; var vID = href?.match0(/\?v=([a-zA-Z0-9_\-]{11})/) || href?.match0(/\/shorts\/([a-zA-Z0-9_\-]{11})/); if (vID) { equeueIP.push(vID) equeueIP = [...new Set(equeueIP)] equeue.push(vID) equeue = [...new Set(equeue)] $('#instantPlaylistButton').html(`Instant
Playlist (${equeueIP.length}+)`) if (USE_INSTANT_PLAYLIST) boxatt([box, eleget0('#instantPlaylistButton')]) //eleget0('#instantPlaylistButton')?.classList?.add("boxatt"); } } var prevcue = eleget0('//ytd-thumbnail-overlay-toggle-button-renderer[@aria-label="キューに追加"]/yt-icon[2]|.//ytd-thumbnail-overlay-toggle-button-renderer[@aria-label="Add to queue"]/yt-icon[2]', box) if (prevcue) { prevcue?.click(); return false; } var prevcue = eleget0('//a[@id="thumbnail"]/div/ytd-thumbnail-overlay-toggle-button-renderer[last()]/yt-icon[@class="style-scope ytd-thumbnail-overlay-toggle-button-renderer"]', box) var ances = box; if (ances) { var cuebutton = elegeta('ytd-thumbnail.style-scope.ytd-grid-video-renderer a div ytd-thumbnail-overlay-toggle-button-renderer:last-child yt-icon#icon,ytd-thumbnail.ytd-compact-video-renderer a div ytd-thumbnail-overlay-toggle-button-renderer:last-child yt-icon#icon', ances)[0] if (cuebutton) { cuebutton?.click() /*ances.style.opacity = "0.25" setTimeout(() => { ances.style.opacity = "0.5" }, 17 * 2) setTimeout(() => { ances.style.opacity = "1" }, 17 * 3)*/ return false } } var ancestorEle = getTitleFromParent(ele, 0, '//ytd-item-section-renderer|//ytd-playlist-video-renderer|//ytd-grid-video-renderer|//div[@id="dismissible" and @class="style-scope ytd-video-renderer"]|//div[@id="dismissible" and @class="style-scope ytd-rich-grid-media"]|//ytd-compact-video-renderer'); if (!ancestorEle) return false let menuButton = elegeta('//yt-icon[@class="style-scope ytd-menu-renderer"]', ancestorEle); if (menuButton.length == 1) { setTimeout(() => { let queue = elegeta('yt-formatted-string.style-scope.ytd-menu-service-item-renderer')?.find(v => ["キューに追加", "Add to queue"].includes(v.textContent)) // let queue = eleget0('//span[text()="キューに追加"]|//span[text()="Add to queue"]'); //let queue = eleget0('//yt-formatted-string[text()="キューに追加"]|//yt-formatted-string[text()="Add to queue"]'); if (queue) { queue.click(); /*setTimeout(() => { ancestorEle.style.opacity = 0.5 }, 0) setTimeout(() => { ancestorEle.style.opacity = 0.5 }, 17 * 2) setTimeout(() => { ancestorEle.style.opacity = 1 }, 17 * 4)*/ } }, 200) setTimeout(() => { menuButton[0].click() }, 0); if (!USE_INSTANT_PLAYLIST) boxatt([ancestorEle, eleget0('#instantPlaylistButton')]) } return false; } if (key === "y" && !/\/watch/.test(location.href)) { // y::start playing e.preventDefault(); cli('//div[contains(@class,"ytp-miniplayer-play-button-container")]/button|//button[contains(@class,"ytp-play-button-playlist")]') if (!(location.href.match(/\/watch\?v=/))) cli('//div/button[contains(@class,"ytp-miniplayer-expand-watch-page-button")]:visible', 111, "infinity"); setTimeout(() => { let e = eleget0('//video'); if (e) { e.play(); } }, 222); return false; } if (/^Alt\+c$|^Ctrl\+x$/.test(key) && /\/watch/.test(location.href) && USE_INSTANT_PLAYLIST) { // Alt+c:: Ctrl+x:: 視聴中の再生リストをURLにしてコピー e.preventDefault(); makeUrlFromCuelist(1, kaisuu) kaisuu = ++kaisuu % YOUTUBE_WATCH_ALTC_VARIATIONS; } }, false) return; function makeUrlFromCuelist(disp = 1, kaisuu) { // disp:1:表示する 0:urlを作って返すだけ if (/\/watch/.test(location.href) && USE_INSTANT_PLAYLIST) { // Alt+c::視聴中の再生リストをURLにしてコピー //let eles = elegeta('//ytd-playlist-panel-video-renderer[@id="playlist-items"]/a:visible'); let eles = elegeta('//ytd-playlist-panel-video-renderer[@id="playlist-items"]/a:visible').filter(e => e?.closest('ytd-playlist-panel-video-renderer')?.style?.opacity != 0.5); let videoIDa = [...new Set(eles.map(c => c.href.match0(/\?v=([a-zA-Z0-9_\-]{11})/)))].slice(0, 50); // 重複削除 let videoIDaAll = [...new Set(eles.map(c => c.href.match0(/\?v=([a-zA-Z0-9_\-]{11})/)))]; // 重複削除 if (eles.length) { let indexEle = eleget0('//yt-formatted-string[@class="index-message style-scope ytd-playlist-panel-renderer"]/span[1]|//div/div[@id="secondary-inner" and @class="style-scope ytd-watch-flexy"]/ytd-playlist-panel-renderer[@id="playlist" and @class="style-scope ytd-watch-flexy" and @js-panel-height="" and @collapsible="" and @playlist-type="TLPQ"]/div/div[1]/div[@id="header-contents"]/div[@id="header-top-row" and contains(@class,"style-scope ytd-playlist-panel-renderer")]/div[@id="header-description"]/div/div/span:visible'); let indexNo = indexEle && indexEle.textContent ? indexEle.textContent.match0(/(\d+)/mi) - 1 : 0; let indexUrlQP = (PRESERVE_INDEX && indexNo > 0 && indexNo < 50) ? `&index=${indexNo}` : ""; elegeta("#link4bm").forEach(e => e.remove()) if (kaisuu == 0 || kaisuu == 2 || disp == 0) { // プレイリストの動画の合計時間を算出、全部読み込みが終わっていないとしない let playtimesum = gettotal(50) playtimesum = playtimesum ? " " + playtimesum : "" let pl = location.href.match0(/\&list=((?:PL|UU)[a-zA-Z0-9_\-]+)/); //let pl = location.href.match0(/\&list=((?:PL|UU|UL)[a-zA-Z0-9_\-]+)/); var cb = kaisuu == 2 ? `
\n${sani(eleget0('span#video-title.style-scope.ytd-playlist-panel-video-renderer')?.textContent?.replace(/\n/gm," ")?.trim())} (${videoIDa?.length})${playtimesum?" "+playtimesum:""}
\n\n
\n\n` + (pl ? `
\n${sani(eleget0('yt-formatted-string.title.style-scope.ytd-playlist-panel-renderer.complex-string')?.textContent?.replace(/\s+|\n/gm," ")?.trim()||"")}
\n\n
` : "") : //var cb = kaisuu == 2 ? `
\n${sani(eleget0('span#video-title.style-scope.ytd-playlist-panel-video-renderer')?.textContent?.replace(/\n/gm," ")?.trim())} (${videoIDa?.length})${playtimesum?" "+playtimesum:""}
\n\n
\n\n` + (pl ? `
\n${sani(eleget0('yt-formatted-string.title.style-scope.ytd-playlist-panel-renderer.complex-string')?.textContent?.replace(/\s+|\n/gm," ")?.trim()||"")}
\n\n
` : "") : // "https://www.youtube.com/watch_videos?video_ids=" + videoIDa.join(",") + indexUrlQP; // h181px~:hd thumbnail + "&cc_load_policy=1&cc_lang_pref=jpn" `${IPURL}${videoIDa.join(",") + indexUrlQP}`; // h181px~:hd thumbnail + "&cc_load_policy=1&cc_lang_pref=jpn" //var embedHTML = `