您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
プレミアム会員向けに、ニコ動プレーヤーにx2.0以上の再生速度を追加します。 一般会員向けには公式と同じ速度制限があります。速度を出すには動画右クリックのメニューから「視聴方法の切替」で「http」を選んでおくとhlsより速いとされています。
// ==UserScript== // @name NicoSpeedMaster // @namespace https://toogiri.buhoho.net/ // @version 0.1.0.1 // @description プレミアム会員向けに、ニコ動プレーヤーにx2.0以上の再生速度を追加します。 一般会員向けには公式と同じ速度制限があります。速度を出すには動画右クリックのメニューから「視聴方法の切替」で「http」を選んでおくとhlsより速いとされています。 // @author buhoho // @match https://*.nicovideo.jp/watch/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // スクリプトが管理している再生速度 let customPlaybackRate = parseFloat(localStorage.customPlaybackRate ?? 1.0); // 変更前のvideo要素 let prevVideo, prevVideoSrc; // 多分Premiumじゃないとろくに再生速度出ないので、公式仕様通り制限 let isPremium = JSON.parse(document.querySelector('#CommonHeader').dataset.commonHeader).initConfig.user.isPremium; function createPlaybackRateMenuItem(rate) { const menuItem = document.createElement('div'); menuItem.classList.add('PlaybackRateMenuItem'); menuItem.innerHTML = rate === customPlaybackRate? `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" class="CheckIcon PlaybackRateMenuItem-checkIcon"><path d="M13.7 29.9 2.9 19.1l4.2-4.3 6.6 6.6L28.9 6.2l4.2 4.3-19.4 19.4z"></path></svg><div>x${rate.toFixed(1)}</div>`: `<div class="PlaybackRateMenuItem-iconSpace"></div><div>x${rate.toFixed(1)}</div>`; menuItem.onclick = function () { localStorage.customPlaybackRate = prevVideo.playbackRate = customPlaybackRate = rate; togglePlaybackRateMenu(); }; return menuItem; } function createPlaybackRateMenu() { const menu = document.createElement('div'); menu.classList.add('PlaybackRateMenu'); menu.innerHTML = '<div class="PlaybackRateMenu-title">再生速度</div>'; const menuContents = document.createElement('div'); menuContents.classList.add('PlaybackRateMenu-contents'); menu.appendChild(menuContents); const rates = isPremium ? [0.5, 1.0, 1.5, 1.8, 2.3, 2.7, 3.4, 4.2]: [0.5, 1.0, 1.25]; for (const rate of rates) { const menuItem = createPlaybackRateMenuItem(rate); menuContents.appendChild(menuItem); } return menu; } function togglePlaybackRateMenu(e) { e && e.stopPropagation(); const existingMenu = document.querySelector('.PlaybackRateMenu'); if (existingMenu) { existingMenu.remove(); } else { const menu = createPlaybackRateMenu(); const container = document.querySelector('.VideoOverlayContainer'); if (container) { container.appendChild(menu); } } } function buttonShowRate(rate) { let btn = document.querySelector('.ActionButton.PlaybackRateButton'); const btnItem = document.createElement('div'); //btnItem.style.border = '2px solid white'; btnItem.style.setProperty('border', '2px solid white', 'important'); // btnItem.style.background = '#113'; btnItem.style.padding = '2px'; btnItem.style.borderRadius = '12px'; // btnItem.style.backgroundColor = 'rgb(20, 13, 55)'; btnItem.innerText = `x${rate.toFixed(1)}`; // 文字色を白に設定 btn.style.color = 'white'; // btn.style.backgroundColor = 'rgb(20, 13, 55)'; if (rate > 1.0 && rate <= 2.0) { btnItem.style.backgroundColor = '#002176'; btnItem.style.setProperty('border', '2px solid #aaeeff', 'important'); btnItem.style.setProperty('color', '#aaeeff', 'important'); // btnItem.style.backgroundColor = '#003386'; // 濃い青色 } else if (rate > 2.0) { btnItem.style.backgroundColor = '#660005'; btnItem.style.setProperty('border', '2px solid #ffaacf', 'important'); btnItem.style.setProperty('color', '#ffaacf', 'important'); // btnItem.style.backgroundColor = '#a60012'; // 濃い赤色 } btn.innerHTML = ''; btn.appendChild(btnItem); } function setPlaybackRateEventListener(v) { v.addEventListener('ratechange', () => { // console.log("レートが変更されました。"); let rate = v.playbackRate; if (rate !== customPlaybackRate) { // 再生速度がスクリプトが管理しているものと異なる場合、管理している再生速度に戻す v.playbackRate = customPlaybackRate; return; } buttonShowRate(rate); }); } new MutationObserver(mutations => { const v = document.querySelector('#MainVideoPlayer video'); if (prevVideo === v && prevVideoSrc === v.src) return; // video 要素が変更されたときの処理を記述 setPlaybackRateEventListener(v); // メニュー表示処理を上書き document.querySelector('button.ActionButton.PlaybackRateButton').onclick = togglePlaybackRateMenu; // 速度更新 v.playbackRate = customPlaybackRate; // 現在のvideo要素を保存(変更を検知するため) prevVideo = v; prevVideoSrc = v.src; }).observe(document.querySelector('#js-app'), {childList: true, subtree: true}); })();