Greasy Fork is available in English.

ニコニコ動画 コメントウィンドウ表示

コメント一覧をポップアップウィンドウで表示します。

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         ニコニコ動画 コメントウィンドウ表示
// @namespace    https://yyya-nico.co/
// @version      1.0.3
// @description  コメント一覧をポップアップウィンドウで表示します。
// @author       yyya_nico
// @license      MIT License
// @match        https://www.nicovideo.jp/watch/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=nicovideo.jp
// @grant        none
// ==/UserScript==

(() => {
    'use strict';

    const played = document.querySelector('.SeekBar-played');
    const nicoApiDataElem = document.getElementById('js-initial-watch-data');
    const origin = 'https://yyya-nico.co';
    const launchIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#B2BAC2"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/></svg>`;
    /*let*/const nicoApiData = JSON.parse(nicoApiDataElem.dataset.apiData);
    // const updateNicoApiData = () => (nicoApiData = JSON.parse(nicoApiDataElem.dataset.apiData));
    let popup = null;

    const observerWrap = (findTargetToken, sendTargetSelector, callback) => {
        return new MutationObserver(records => {
            records.forEach(record => {
                record[sendTargetSelector ? 'addedNodes' : 'removedNodes'].forEach(node => {
                    if (node.nodeType == 1/*ELEMENT*/ && node.classList.contains(findTargetToken)) {
                        callback(
                            sendTargetSelector ? node.querySelector(sendTargetSelector)
                                               : record.target
                        );
                    }
                });
            });
        });
    }

    const createTask = target => {
        target.insertAdjacentHTML('afterbegin', `<button data-title="コメント一覧をウィンドウで表示" type="button" class="ActionButton OpenCommentsListWindow">${launchIcon}</button>`);
        const openBtn = target.querySelector('.OpenCommentsListWindow');
        openBtn.addEventListener('click', () => {
            const w = 480;
            const h = screen.height * .8;
            const lef = (screen.width - w) * .9;
            const top = (screen.height - h) * .25;
            popup = window.open(`${origin}/nv_comment_viewer/`, 'comment-list', 'width='+ w +',height='+ h +',left='+ lef +',top='+ top);
        });
    }

    const waitCreatePlayerPanelContainerObserver = observerWrap('PlayerPanelContainer', '.PlayerPanelContainer-content', target => {
        waitCreatePlayerPanelContainerObserver.disconnect();
        const commentMenu = target.querySelector('.CommentPanelMenuContainer-mainMenuArea:last-child');
        if (commentMenu) {
            createTask(commentMenu);
            removeCommentPanelObserver.observe(target, {childList: true, subtree: true});
        } else {
            createCommentPanelObserver.observe(target, {childList: true, subtree: true});
        }
    });

    const createCommentPanelObserver = observerWrap('CommentPanelContainer', '.CommentPanelMenuContainer-mainMenuArea:last-child', target => {
        // console.log('added');
        createCommentPanelObserver.disconnect();
        createTask(target);
        removeCommentPanelObserver.observe(target.closest('.PlayerPanelContainer-content'), {childList: true, subtree: true});
    });

    const removeCommentPanelObserver = observerWrap('CommentPanelContainer', null, container => {
        // console.log('removed');
        removeCommentPanelObserver.disconnect();
        createCommentPanelObserver.observe(container, {childList: true, subtree: true});
    });

    const timeObserver = new MutationObserver(records => {
        records.forEach(record => {
            if (!popup.closed) {
                const progressPercentage = Number(record.target.style.transform.slice(7, -1)); // scaleX(****)
                popup.postMessage({
                    eventName: 'playerMetadataChange',
                    data: {
                        progressPercentage: progressPercentage
                    }
                }, origin);
            } else {
                timeObserver.disconnect();
            }
        });
    });

    window.addEventListener('message', e => {
        if (e.origin === origin) {
            switch (e.data.eventName) {
                case 'ready':
                    // console.log('ready');
                    // updateNicoApiData();
                    popup.postMessage({
                        eventName: 'sendData',
                        data: nicoApiData
                    }, origin);
                case 'returned':
                    // console.log('returned');
                    timeObserver.observe(played, {attributes: true});
                    break;

                case 'bye':
                    // console.log('bye');
                    timeObserver.disconnect();
                    break;

                case 'keyDown':
                    // console.log('keyDown');
                    ['ArrowUp', 'ArrowRight', 'ArrowDown', 'ArrowLeft', ' '];
                    switch (e.data.data) {
                        case 'ArrowUp':
                            
                            break;
                        case 'ArrowRight':
                            document.querySelector('.PlayerSeekForwardButton')?.click();                            
                            break;
                        case 'ArrowDown':
                            
                            break;
                        case 'ArrowLeft':
                            document.querySelector('.PlayerSeekBackwardButton')?.click();
                            break;
                        case ' ':
                            document.querySelector('.PlayerPauseButton, .PlayerPlayButton')?.click();
                            break;
                    }
                    break;
            }
        }
    });

    waitCreatePlayerPanelContainerObserver.observe(document.body, {childList: true, subtree: true});
})();