プロフィール

髭山髭人(ひげひと)

自分の書いた記事が、一人でも誰かの役に立てば...
活動信条の一つとして「貴方のメモは、誰かのヒント」というのがあります。

このサイトについて

本家HP packetroom.net から切り離した いわゆる技術メモ用のブログで、無料レンタルサーバーにて運用しています。広告表示はその義務なのでご容赦。
XREA さんには長年お世話になっています

アーカイブ視聴ページにメニューチャプターを付与。リピート再生対応

概要

ほぼタイトル通り。 デレライブ東京公演アーカイブ視聴ページにチャプターなどを付けたかったので。
岩手公演の時に作っておけばよかった

注意

作成時の東京公演と違って、石川公演はきちんと定義していません。
自分でチャプターの正確な時間(秒数)を定義し直してください。

というか、東京の時と環境が変わって使えなかったらごめんなさい ( 未確認なので… )

SNSの情報をもとに、セトリ並びだけは定義済みです。
秒数は (分 × 60) + あまり秒 で出せます
例 → 15:34 表記なら… ( 15 × 60 ) + 34 = 934

適用画面

  • 視聴ページ左側に、定義を元にしたチャプターメニューが作られる
  • 項目クリックで、その時間へ飛ぶ
  • 下のリピートチェックを有効にすれば、再生中チャプターが自動でリピートされる(自動早戻し)

コード / スクリプト

  • 分かる方向け
    アーカイブ視聴ページにて、DevTools の Console にペタっと。

  • 「これをどうすんの?」って方向け
    実行手順を次項で解説しているのでご覧ください

↓ の領域にカーソルを載せ、右上に出てくる Copy ボタンからクリップボードへコピーできるのでオススメ


{
    // 石川昼 チャプター : 秒数 のペア定義
    // セトリ表記に倣って、昼夜の正しい秒数をご自身で定義してください
    // 秒数は (分 * 60) + あまり秒 = で出せます
    let _tSheet = [ 
        ["前説", 0],
        ["Opening", 602],
        ["Vast world", 720],
        ["MC 1", 982],
        ["Shinobi 4.0 忍者のすゝめ", 1126],
        ["花簪 HANAKANZASHI", 1376],
        ["祈りの花", 1643],
        ["美に入り彩を穿つ", 1900],
        ["MC 2", 2147],
        ["義勇忍侠花吹雪", 2626],
        ["青の一番星", 2875],
        ["小さな恋の密室事件", 3170],
        ["桜の頃", 3548],
        ["MC 3", 3815],
        ["廻談詣り", 4354],
        ["満願成就♪巫女の神頼み!", 4621],
        ["碧空ノ一路", 4888],
        ["情熱ファンファンファーレ", 5171],
        ["Enishi", 5487],
        ["夕映えプレゼント", 5587],
        ["MC / お知らせ", 5768],
        ["MC / 感想", 6083],
        ["Come to you", 6547],
        ["写真撮影", 6800],
        ["締め & 退場", 6882],
        ["後説", 6972],
    ];
    // URL判定で夜公演に切り替え
    if(location.href.indexOf("/archive/night") != -1){
        _tSheet = [ 
            ["前説", 0],
            ["Opening", 602],
            ["Vast world", 720],
            ["MC 1", 982],
            ["Shinobi 4.0 忍者のすゝめ", 1126],
            ["薄紅", 1376],
            ["日々あどべんちゃーなのでしてー", 1643],
            ["美に入り彩を穿つ", 1900],
            ["MC 2", 2147],
            ["義勇忍侠花吹雪", 2626],
            ["Private Sign", 2875],
            ["Merry Warm Bodies", 3170],
            ["桜の頃", 3548],
            ["MC 3", 3815],
            ["廻談詣り", 4354],
            ["満願成就♪巫女の神頼み!", 4621],
            ["碧空ノ一路", 4888],
            ["Enishi", 5171],
            ["夕映えプレゼント", 5487],
            ["MC / お知らせ", 5768],
            ["MC / 感想", 6083],
            ["Come to you", 6547],
            ["写真撮影", 6800],
            ["締め & 退場", 6882],
            ["後説", 6972],
        ]
    }

    const _cfName = "gTimeUpdate";
    const _checkNode=(()=>{
        const _n = document.createElement("input");
        _n.type = "checkbox"; _n.style.appearance = "auto"; return _n;
    })();
    const _repeatTxtNode = (()=>{
        const _n = document.createElement("label");
        _n.textContent  = "リピートなし"; _n.style.color = "#A05050"; return _n;
    })();
    const _v = document.querySelector("video");
    if(!window[_cfName]){
        window[_cfName] = function gTimeUpdate(_e){
            const _t =  _e.target.currentTime;
            if(!_checkNode.checked){ return; }
            const _mArr = window["RepeatMarker"];
            if(_mArr && _mArr.length == 3){
                if(_mArr[2] <= _t){
                    console.log(_mArr[2] , "<="  ,_t , "早戻し:" , _mArr[1]);
                    _v.currentTime = _mArr[1];
                }
            }
        };
    }
    // リピートマーカー生成
    function setRepeatMarker(_time){
        if(!_checkNode.checked){
            _repeatTxtNode.textContent = "リピートなし";
            delete window["RepeatMarker"]; return;
        }
        const _t = _time;
        const _arrs = _tSheet;
        let _markerArr = [];
        for(let _n=0; _n<_arrs.length; _n++){
            const _a1 = _arrs[_n];
            if(_arrs.length <= (_n+1)){
                // 該当なしの場合、末尾要素 & 再生時間から -0.1 指定
                _markerArr[0] = _a1[0];
                _markerArr[1] = _a1[1];
                _markerArr[2] = (_v.duration - 0.1);
            }else{
                const _a2 = _arrs[(_n+1)];
                if(_a1[1] <= _t && _t < _a2[1]){
                    _markerArr[0] = _a1[0]; _markerArr[1] = _a1[1]; _markerArr[2] = _a2[1];
                    break;
                }
            }
        }
        _repeatTxtNode.textContent = `${_markerArr[0]} 🔂`;
        console.log( "再生時間" , _t , "をもとにリピートマーカーセット",  _markerArr );
        window["RepeatMarker"] = _markerArr;
    }
    (()=>{
        const _area=document.querySelector(`[class^="VideoPlayer_inner__"]`);
        let _menu = $("#orig_jump_menu");
        if(_menu){
            _menu.parentNode.removeChild(_menu);
        }
        function secToTime(_val){
            let _h, _m, _s;
            _h = Math.floor(_val / 3600); _s = _val % 3600;
            _m = Math.floor(_s / 60); _s = _s % 60;
            return `${String(_h).padStart(2, "0")}:${String(_m).padStart(2, "0")}:${String(_s).padStart(2, "0")}`
        }
        _menu=((_def)=>{
            const _n = document.createElement("div");
            _def.forEach(_e=>{
                const _n2 = document.createElement("div");
                _n2.style.color = "gray"; _n2.style.cursor = "pointer"; _n2.style.fontSize = "0.8em";
                const _sec = _e[1]; const _title = _e[0];
                _n2.textContent = `${secToTime(_sec)}  ${_title}`;
                _n2.onclick = ((_e)=>{
                    // 先にリピートマーカー更新
                    setRepeatMarker( _sec );
                    _v.currentTime = _sec;
                    console.log(_sec , _title , "へ移動");
                });
                _n.appendChild(_n2);
            });
            _n.id = "orig_jump_menu"; _n.style.width = "250px";
            _n.style.height = "100%"; _n.style.marginLeft = "5px";
            return _n;
        })(_tSheet);
        // リピートマーカー生成
        _checkNode.addEventListener("click" , ((_e)=>{
            setRepeatMarker( _v.currentTime );
        }) );
        _v.removeEventListener("timeupdate" , window[_cfName] );
        _v.addEventListener("timeupdate" , window[_cfName] );
        _menu.appendChild(_checkNode);
        _menu.appendChild(_repeatTxtNode);
        _area.parentNode.insertBefore( _menu ,_area);
    })();
}

初心者向け / コードの実行手順を解説

ブラウザに内蔵されている DevTools と呼ばれるものを使います
GoogleChrome 環境前提の解説です

DevTools を開き、 Console 入力欄を見つける

  1. まず、最初に視聴ページを開いておき、 そのページ上で F12 キー を押して DevTools を表示します
  2. 初期設定だと DevTools はブラウザウィンドウに埋め込まれたままなので、別ウィンドウへ分離させておきます。
  3. 上のメニューから コンソール ( 英言語 : Console 表記 ) を選択します
  4. 青い > 記号 が 行頭にある部分を見つけたら準備OKです
    ここは命令文などを入力実行できる場所となっています。
    以降 入力欄 等と表記します

ペースト実行を試す ( 必要に応じてペースト許可を行う )

入力欄を見つけたら、試しに以下の文章を一度コピペで打ち込んでみてください

console.log(1+1);

これを入力欄へコピペで貼り付けして、Enter キーを押します。
2 と表記されたら成功です。

逆に、以下のような黄色いエラーっぽいメッセージが出た場合は、
コードのコピペ実行が許可されていない 🚫 ので、許可する必要が出てきます 👌

  • エラーメッセージ ( 大体こんな内容 )

    Warning: Don’t paste code into the DevTools Console that you don’t understand or haven’t reviewed   yourself.
    This could allow attackers to steal your identity or take control of your computer.
    Please type ‘allow pasting’ below to allow pasting.
  • コピペ実行の許可方法
    先程同様入力欄へ allow pasting と打ち込んで、
    再び Enter を押せば コピペ実行の許可が通るようになるはずです。

実際にコードを実行

コピペ実行が無事通ったら、上記で紹介されているメニュー構築用のソースコードをまるまるコピペして、
先程の入力欄 へ貼り付け & 実行しましょう。

実行のち、視聴ページにチャプターメニューなどが表示されれば成功です ✨

  • 注意
    一度に何回も実行すると誤作動の原因になるかもしれません。
    ページをリロードさえすれば実行処理内容はリセットされるので、
    「間違って二回入力実行しちゃった!」とかあれば、ページ更新 → 再び1回だけ実行 などすればOKです

オマケ / 再入力テクニック

コンソール の > 部分でカーソル入力状態になっているときに、
キーボードの キーを押すと、一つ前にコピペ実行したコードが 再入力状態になります。

これを使えば、一々コピペを繰り返さずとも「↑キー のち Enter」で素早く同じコードを実行できてオススメ ✨

改造メモ?

コード中 _tSheet の定義代入部分を置き換えれば、独自チャプターも作れると思います。
["タイトル" , 秒数] の配列を順に放り込んだ多次元配列形式。
昼夜別でスクリプト変えるの面倒だったので、
1処理内に デフォルト昼 → URLで夜判定切替 を組み込んでいます。

石川昼 (仮 / 秒数不明)

アーカイブ視聴権限はないので、昼夜共にセトリ分だけ記載して、時間は適当にしています。
秒数の部分はご自身で正しく書き換えてください
(再生時間の分表記 × 60) + 秒数 = で出せます

[   
    ["前説", 0],
    ["Opening", 602],
    ["Vast world", 720],
    ["MC 1", 982],
    ["Shinobi 4.0 忍者のすゝめ", 1126],
    ["花簪 HANAKANZASHI", 1376],
    ["祈りの花", 1643],
    ["美に入り彩を穿つ", 1900],
    ["MC 2", 2147],
    ["義勇忍侠花吹雪", 2626],
    ["青の一番星", 2875],
    ["小さな恋の密室事件", 3170],
    ["桜の頃", 3548],
    ["MC 3", 3815],
    ["廻談詣り", 4354],
    ["満願成就♪巫女の神頼み!", 4621],
    ["碧空ノ一路", 4888],
    ["情熱ファンファンファーレ", 5171],
    ["Enishi", 5487],
    ["夕映えプレゼント", 5587],
    ["MC / お知らせ", 5768],
    ["MC / 感想", 6083],
    ["Come to you", 6547],
    ["写真撮影", 6800],
    ["締め & 退場", 6882],
    ["後説", 6972],
]

石川夜 (仮 / 秒数不明)

秒数ややガバいですが、ご容赦

[   
    ["前説", 0],
    ["Opening", 602],
    ["Vast world", 720],
    ["MC 1", 982],
    ["Shinobi 4.0 忍者のすゝめ", 1126],
    ["薄紅", 1376],
    ["日々あどべんちゃーなのでしてー", 1643],
    ["美に入り彩を穿つ", 1900],
    ["MC 2", 2147],
    ["義勇忍侠花吹雪", 2626],
    ["Private Sign", 2875],
    ["Merry Warm Bodies", 3170],
    ["桜の頃", 3548],
    ["MC 3", 3815],
    ["廻談詣り", 4354],
    ["満願成就♪巫女の神頼み!", 4621],
    ["碧空ノ一路", 4888],
    ["Enishi", 5171],
    ["夕映えプレゼント", 5487],
    ["MC / お知らせ", 5768],
    ["MC / 感想", 6083],
    ["Come to you", 6547],
    ["写真撮影", 6800],
    ["締め & 退場", 6882],
    ["後説", 6972],
]

東京夜

[   
    ["前説 #UNICUS", 0],
    ["Opening", 625],
    ["Come to you", 742],
    ["Talk Part / 挨拶", 1004],
    ["OTAHEN アンセム", 1134],
    ["熱血乙女A", 1383],
    ["トキメキは赤くて甘い", 1616],
    ["スパイスパラダイス", 1872],
    ["Talk Part", 2118],
    ["初夢をあなたと", 2553],
    ["お散歩カメラ", 2794],
    ["銀河図書館", 3033],
    ["ダンス・ダンス・ダンス", 3411 ],
    ["Talk Part", 3678],
    ["ミツボシ☆☆★", 4267],
    ["#HE4DSHOT", 4485],
    ["流星浪漫", 4751],
    ["情熱ファンファンファーレ", 5034],
    ["UNIQU3 VOICES!!!", 5350],
    ["Talk Part / お知らせ", 5633],
    ["Talk Part / 感想", 6057],
    ["お願い!シンデレラ", 6590],
    ["写真撮影", 6838],
    ["締め & 退場", 6953],
    ["後説 / 星纏天女", 7056],
]