ニコニコ生放送 360°再生

Equirectangular形式の360°配信を見回せるようにします。ユーザースクリプトコマンドから「360°」を選択すると有効化されます。

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name        ニコニコ生放送 360°再生
// @description Equirectangular形式の360°配信を見回せるようにします。ユーザースクリプトコマンドから「360°」を選択すると有効化されます。
// @namespace   https://greasyfork.org/users/137
// @version     0.1.0
// @match       https://live.nicovideo.jp/watch/lv*
// @license     MPL-2.0
// @contributionURL https://www.amazon.co.jp/registry/wishlist/E7PJ5C3K7AM2
// @compatible  Edge
// @compatible  Firefox 推奨
// @compatible  Opera
// @compatible  Chrome
// @grant       GM.registerMenuCommand
// @grant       GM_registerMenuCommand
// @require     https://cdn.jsdelivr.net/gh/greasemonkey/gm4-polyfill@a834d46afcc7d6f6297829876423f58bb14a0d97/gm4-polyfill.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/build/three.js
// @require     https://cdn.jsdelivr.net/npm/[email protected]/build/panolens.js
// @noframes
// @icon        https://nicolive.cdn.nimg.jp/relive/party1-static/images/common/favicon.3cf1c.ico
// @author      100の人
// @homepageURL https://greasyfork.org/users/137
// ==/UserScript==

'use strict';

const FPS = 30;

GM.registerMenuCommand('360°', function () {
	const video = document.querySelector('[class^="___video-layer"] video');
	const canvas = document.createElement('canvas');
	canvas.hidden = true;
	canvas.width = video.videoWidth;
	canvas.height = video.videoHeight;
	document.body.append(canvas);
	const image = document.createElement('img');
	image.hidden = true;
	document.body.append(image);
	document.querySelector('[class*="player-display-screen"]').insertAdjacentHTML(
		'beforeend',
		'<div class="viewer-360" style="position: absolute; top: 0; right: 0; bottom: 0;left: 0;"></div>'
	);
	const viewer = new PANOLENS.Viewer({ container: document.getElementsByClassName('viewer-360')[0] });
	const panorama = new PANOLENS.ImagePanorama(image);
	viewer.add(panorama);
	image.addEventListener('load', function () {
		panorama.load(image);
	});

	let nextTimestamp = Date.now();
	requestAnimationFrame(function render() {
		if (Date.now() < nextTimestamp) {
			requestAnimationFrame(render);
			return;
		}

		nextTimestamp = Date.now() + 1000 / FPS;

		canvas.getContext('2d').drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
		canvas.toBlob(function (blob) {
			if (image.src) {
				URL.revokeObjectURL(image.src);
			}
			image.src = URL.createObjectURL(blob);
			requestAnimationFrame(render);
		});
	});
});