プレミアム会員向けに、ニコ動プレーヤーに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});
})();