「TVチャンネルのサムネイル」を小型化

「ホーム」画面の上部は「TVチャンネルのサムネイル」が30個ほど並びますが、この配置は「display: grid」を使っています。

 

 

そのため、リンク先を表示する「iframe」が生成される時に、横方向にページ全体を圧迫して、「TVチャンネルのサムネイル」部分の高さが大きく変化します。

 

下側にある「動画サムネイル」をクリックすると、そのサムネイルが右下方向に移動します。 右方向の移動は「iframe」の幅ですが、下方への移動は「TVチャンネルのサムネイル」によるものです。 この移動は扱い難さに繋がるので、移動を最小限にするために「TVチャンネルのサムネイル」を小型化しました。「TVチャンネルのサムネイル」は無駄に大きかったので、すっきりしました。

 

 

 

 「iframe」のレイアウトと音声ミュート

「iframe」の導入で、動画サムネイルのリストが大変に扱い易くなりました。

「動画サムネイル」を「Ctrl+左Click」すると、そのリンク先の動画ページを左側に生成した「iframe」の中に表示する仕組みです。

 

欲しい情報は、動画ページにある「配信リスト」だけで、「iframe」はそれのみを表示するアレンジをしています。 ただ「iframe」の中で動画が再生されてしまいます。 アレンジで動画は非表示ですが、音声だけが漏れます。

 

そこで、動画プレーヤーを削除するコードを色々試しましたが、削除すると再びプレーヤーが再生成され、うまく止める事が出来ません。 首尾よくプレーヤーを削除するのは困難と判ったので、音声を止める事にしました。 プレーを停止する事も不可能ではないですが、動画の最初が僅かに再生されるなど不安定です。 動画のロードタイミングが、コンテンツや通信状態で変化し、正確なタイミングの停止が難しいのです。

 

結局、一番確実に動作したのは、音声をミュートする方法でした。

 

先ず「iframe」の生成時に、生成したiframe内の「body」要素に「if_movie」というクラス名を付けます。

 

let notify=document.querySelector('#notify'); 
notify.onload=()=>{ // iframe が生成され次第に以下を実行する
    let if_body=notify.contentWindow.document.body; // body要素取得
    if(if_body){
        if_body.setAttribute('class', 'if_movie'); // 音声抑止のclass名

 

この「iframe」に動画個別ページが呼込まれるので、その動画プレーヤーのミュートボタンを、プレーヤーが生成されるタイミングで押します。 通常は音声再生の場合が多いが、最初からミュートONの場合は押さない工夫が必要です。

 

下は動画個別ページのサンプルです。

 

 

下部のグリーン枠の部分が「配信リスト」で、これだけを「iframe」に表示するアレンジをしているわけです。 その背後で上部の動画プレーヤーが動作します。 その音声の「ミュートボタン」は、赤丸で囲った部分にあります。

 

「ミュートボタン」を押して「ミュート」を実行するコードは以下です。

 

if(document.body.classList.contains('if_movie')){ // 音声抑止のclass名
    mute(player, 0); }
else{
    mute(player, 1); }

function mute(player, n){
    setTimeout(()=>{
        let vol=player.querySelector('.com-playback-Volume__icon-button');
        if(vol){
            if(n==0){
                if(vol.getAttribute('aria-label')=="音声をオフにする"){
                    vol.click(); }}
            else{
                if(vol.getAttribute('aria-label')=="音声をオンにする"){
                    vol.click(); }}}
    }, 400); }

 

動画プレーヤーに対する「AmbTV Comfy」の機能コードに、上記コードを追加しました。 このコードは動画プレーヤー生成時に常に動作するので、「iframe」の中か否かで、ミュートのON・OFFを選択しています。

 

後半は、ミュートを実行する関数です。 ミュートボタンを取得し、その状態が「ミュートON」「ミュートOFF」かによって、動作を分岐しています。

 

最後の行の「400」はタイミングの「0.4sec」を意味します。 これは少し余裕を見ています。 動画プレーヤーの停止や削除をする場合は「0.9sec ~ 1.2sec」などと長くなり、動作も不安定です。 音声ミュートは早く指定可能で結果も安定するのは、動画データのロードタイミングと無関係に設定できる仕様だからかも知れません。

 

 

 

 「iframe」を閉じるボタン

「iframe」は、不必要な場合には出来るだけ自動的に閉じる様に工夫をしています。 しかし、ユーザーの判断で閉じたい場合が出て来るので、「閉じる」のボタンは必要です。 以下の場合は、自動的に「iframe」が閉じます。

 

◎「TVチャンネルのサムネイル」を「Ctrl+左Click」した場合

◎「ジャンル選択のサムネイル」を「Ctrl+左Click」した場合

◎ あらゆるサムネイルを「左Click」した場合(動画ページに遷移)

◎「iframe」内の「配信リスト」を「左Click」した場合(動画ページに遷移)

 

以下は「iframe」上部に設置した、ユーザーが選択できるボタンです。

 

 

●「Abema Home」ボタンを「左Click」すると、ホーム画面に遷移します。

 

▪「iframe」はホーム画面だけでなく「各ジャンル」の画面や「動画ページ」の下部の動画サムネイルからも開くので、「ホーム画面」へのリンクがあると便利です。

 

●「✖」ボタンを「左Click」すると、「iframe」を閉じます。

 

 

 

 「AmbTV Comfy」のマニュアル

「AmbTV Comfy」の操作に関しては、以下のマニュアルを参照ください。

 

 

 

 

「AmbTV Comfy」を利用するには

このツールは Chrome / Edge / Firefox版の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。

 

❶「Tampermonkey」を導入します

◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。

既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。 

拡張機能の導入については、以下のページに簡単な説明があるので参照ください。

 

 

❷「Tampermonkey」にスクリプトを登録します

◎「Tampermonkey」の「」マークの「新規スクリプト」タブを開きます。

 

 

 

◎「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。

 

〔コピー方法〕 軽量シンプルなツール「PreBox Button   」を使うと

  コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」

  の操作で、掲載コードのコピーが可能になります。

 

◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。

 

 

〔 AmbTV Comfy 〕 ver. 1.1

 

// ==UserScript==
// @name         AmbTV Comfy
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  AbemaTV ユーティリティ
// @author       Ameba User
// @match        https://abema.tv/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=abema.tv
// @grant        none
// ==/UserScript==


main();

let target=document.querySelector('head > title');
let monitor=new MutationObserver(main);
monitor.observe(target, { childList: true });


function main(){

    let retry=0;
    let interval=setInterval(wait_target, 20);
    function wait_target(){
        retry++;
        if(retry>100){ // リトライ制限 100回 2secまで
            clearInterval(interval); }
        let player=document.querySelector(
            '.com-vod-VODRecommendedContentsContainerView__player');
        if(player){
            clearInterval(interval);
            set_player(player); }}


    function set_player(player){
        if(document.body.classList.contains('if_movie')){ // 音声抑止の指定class
            mute(player, 0); }
        else{
            mute(player, 1);

            let style=
                '<style class="atv_style">'+
                '.c-common-HeaderContainer-header, '+
                '.c-application-SideNavigation, '+
                '.c-application-SideNavigation--collapsed, '+
                '.com-vod-VODRecommendedContentsContainerView__player-aside-recommended '+
                '{ display: none !important; } '+
                '.c-video-EpisodeContainerView-breadcrumb, '+
                '.com-vod-VODRecommendedContentsContainerView__details, '+
                '.com-vod-VODRecommendedContentsContainerView__episode-list, '+
                '.com-feature-area-FeatureRecommendedArea__section, '+
                '.c-video-EpisodeContainerView__page-bottom, '+
                '.c-application-FooterContainer '+
                '{ display: none; } '+
                '.c-application-DesktopAppContainer__content-container { '+
                'align-items: center; height: 100vh; } '+
                '.c-application-DesktopAppContainer__content { '+
                'min-width: 400px !important; } '+
                '.com-vod-VODResponsiveMainContent { '+
                'margin: 0 !important; padding: 0 !important; '+
                ' --com-vod-VODResponsiveMainContent--content-min-width: 500 !important; }'+
                '.com-vod-VODRecommendedContentsContainerView__player-and-details '+
                '{ margin-right: 0 !important; } '+
                '.com-vod-VODRecommendedContentsContainerView__player '+
                '{ margin: 0 6px !important; } '+
                '.com-vod-VODMiniPlayerWrapper:before { display: none !important; } '+
                '.com-vod-VODMiniPlayerWrapper__player--bg { display: none !important; } '+
                '.com-vod-VODMiniPlayerWrapper__player { position: relative !important; } '+
                '.c-vod-EpisodePlayerContainer-inlined:before { display: none !important; } '+
                '.c-vod-EpisodePlayerContainer-wrapper { '+
                'position: relative !important; height: calc(100vh - 12px) !important; } '+
                '.com-vod-VODMiniPlayerWrapper__player--mini { height: 0 !important; } '+
                '.com-vod-FullscreenInBrowserButton__screen-controller { '+
                'display: none !important; } '+
                '</style>'+
                '<style class="atv_style_ex">'+
                '.com-vod-VODScreen__player { '+
                'height: 99% !important; width: 132% !important; margin-left: -16%; }'+
                '</style>'+
                '<style class="atv_style_basic">'+
                '.com-vod-VODScreen-container { background: #000 !important; }'+
                '.com-playback-SeekBar__highlighter, .com-playback-SeekBar__marker, '+
                '.com-a-Slider__highlighter { background-color: #2196f3 !important; }'+
                '</style>';

            if(!player.querySelector('.atv_style')){
                player.insertAdjacentHTML('beforeend', style);

                let atv_style=player.querySelector('.atv_style');
                if(atv_style){
                    atv_style.disabled=true; }

                let atv_style_ex=player.querySelector('.atv_style_ex');
                if(atv_style_ex){
                    atv_style_ex.disabled=true; }}


            let wrap=player.querySelector('.c-vod-EpisodePlayerContainer-wrapper');
            if(wrap){
                let monitor1=new MutationObserver(play);
                monitor1.observe(wrap, { childList: true }); }

            setTimeout(()=>{
                let wrap_tv=player.querySelector('.c-tv-TimeshiftPlayerContainerView');
                if(wrap_tv){
                    let monitor2=new MutationObserver(play);
                    monitor2.observe(wrap_tv, { childList: true }); }
            }, 1000);


            setTimeout(()=>{
                let ec_thumbnail=
                    document.querySelector('.c-vod-EpisodePlayerContainer-thumbnail');
                if(ec_thumbnail){
                    reset_subw(); } // プレミアムAD表示時に「サブウインドウ表示」をリセット
            }, 200);
        }


        function mute(player, n){
            setTimeout(()=>{
                let vol=player.querySelector('.com-playback-Volume__icon-button');
                if(vol){
                    if(n==0){
                        if(vol.getAttribute('aria-label')=="音声をオフにする"){
                            vol.click(); }}
                    else{
                        if(vol.getAttribute('aria-label')=="音声をオンにする"){
                            vol.click(); }}}
            }, 400); }

    } // set_player()



    function play(){
        let nav_b=document.querySelector(
            '.com-vod-VideoControlBar__playback-rate');

        if(nav_b){
            let help=
                '<svg class="atv_help" viewBox="0 0 150 150">'+
                '<path  fill="#fff" d="M66 13C56 15 47 18 39 24C-12 60 18 146 82 137C92 '+
                '135 102 131 110 126C162 90 128 4 66 13M68 25C131 17 145 117 81 '+
                '125C16 133 3 34 68 25M69 40C61 41 39 58 58 61C66 63 73 47 82 57C84 '+
                '60 83 62 81 65C77 70 52 90 76 89C82 89 82 84 86 81C92 76 98 74 100 66'+
                'C105 48 84 37 69 40M70 94C58 99 66 118 78 112C90 107 82 89 70 94z">'+
                '</path></svg>'+
                '<style>.atv_help { width: 20px; margin: 0px 16px 0; cursor: pointer; '+
                'display: none; }</style>';

            if(!document.querySelector('.atv_help')){
                nav_b.insertAdjacentHTML('beforebegin', help); }

            let atv_help=document.querySelector('.atv_help');
            if(atv_help){
                atv_help.onclick=(event)=>{
                    event.stopImmediatePropagation();
                    let url='https://ameblo.jp/personwritep/entry-12800867556.html'
                    window.open( url, null, '_blank'); }}

            let sw=
                '<button type="button" class="atv_sw com-vod-FullscreenButton">'+
                '<div class="com-vod-FullscreenButton__tooltip">'+
                '<div class="atv_tp com-a-Tooltip com-a-Tooltip--arrow-position-center">'+
                '</div></div>'+
                '<span class="atv_icon">🔳</span></button>'+
                '<style>.atv_icon { padding: 0 0 2px; filter: drop-shadow(2px 2px 0 #fff); } '+
                ':fullscreen .atv_sw { display: none; }</style>';

            if(!document.querySelector('.atv_sw')){
                nav_b.insertAdjacentHTML('afterend', sw); }

            let atv_sw=document.querySelector('.atv_sw');
            let atv_style=document.querySelector('.atv_style');
            let atv_tp=document.querySelector('.atv_tp');
            if(atv_sw && atv_style && atv_tp && atv_help){
                if(atv_style.disabled==false){
                    atv_tp.textContent='デフォルト表示';
                    atv_help.style.display='block'; }
                else{
                    atv_tp.textContent='サブウインドウ表示';
                    atv_help.style.display='none'; }

                atv_sw.onclick=function(e){
                    e.preventDefault();
                    if(atv_style.disabled==false){
                        atv_style.disabled=true;
                        atv_tp.textContent='サブウインドウ表示';
                        atv_help.style.display='none'; }
                    else{
                        atv_style.disabled=false;
                        atv_tp.textContent='デフォルト表示';
                        atv_help.style.display='block'; }}
            }}

        ex_view();

    } // play()



    function reset_subw(){
        let atv_style=document.querySelector('.atv_style');
        if(atv_style){
            if(atv_style.disabled==false){
                atv_style.disabled=true; }}}


    function ex_view(){
        let full=document.querySelector('.com-vod-FullscreenButton__icon');
        let atv_style_ex=document.querySelector('.atv_style_ex');
        if(full && atv_style_ex){
            full.onclick=(event)=>{
                if(event.ctrlKey){
                    event.preventDefault();
                    event.stopImmediatePropagation();
                    if(atv_style_ex.disabled==true){
                        atv_style_ex.disabled=false;
                        full.style.color='red'; }
                    else{
                        atv_style_ex.disabled=true;
                        full.style.color='#fff';}
                }}}}

} // main()




catch_click();

function catch_click(){ // 動画のサムネイルの暗転拡大表示
    let html_=document.documentElement;

    box_env();

    document.addEventListener('contextmenu', function(event){
        if(!event.shiftKey && !event.ctrlKey){
            event.preventDefault();
            let elem=document.elementFromPoint(event.clientX, event.clientY);
            let link_elem=elem.closest('a');

            if(link_elem){
                set_link(link_elem);
                set_img(link_elem);
                close(); }}});


    document.addEventListener('click', function(event){
        if(event.ctrlKey){
            event.preventDefault();
            let elem=document.elementFromPoint(event.clientX, event.clientY);
            let link_elem=elem.closest('a');
            if(link_elem){
                set_if(link_elem); }}
        else{
            setTimeout(()=>{
                if_close(); }, 1000); }});


    function box_env(){
        let lightbox=
            '<div id="lightbox">'+
            '<div id="photo_sw"><a id="photo_link">🎦 Movie Page</a></div>'+
            '<img id="box_img">'+
            '<style>'+
            '@keyframes fadeIn { 0% {opacity: 0} 100% {opacity: 1}} '+
            '.fin { animation: fadeIn .5s ease 0s 1 normal; animation-fill-mode: both; } '+
            '@keyframes fadeOut { 0% {opacity: 1} 100% {opacity: 0}} '+
            '.fout { animation: fadeOut .2s ease 0s 1 normal; animation-fill-mode: both; } '+
            '#lightbox { position: fixed; top: 0; left: 0; z-index: 3000; visibility: hidden; '+
            'background: black; width: 100vw; height: 100vh; text-align: center; } '+
            '#photo_sw { position: absolute; width: 100%; height: 15%; } '+
            '#photo_sw:hover #photo_link { opacity: 1; } '+
            '#photo_link { font: bold 21px Meiryo; position: absolute; top: 20px; left: 30px; '+
            'padding: 4px 12px 2px 10px; color: #000; background: #fff; cursor: pointer; '+
            'border: 2px solid #000; border-radius: 6px; text-decoration: none; opacity: 0; } '+
            '#box_img { width: 100vw; height: 100vh; padding: 2vh 2vw; '+
            'object-fit: contain; } '+
            '.com-home-ChannelCardLinksPanel { '+
            'grid-template-columns: repeat(auto-fill,minmax(120px,1fr)); } '+
            '.com-home-ChannelCardLink__play, '+
            '.com-home-ChannelListReorderButton { font-size: 20px; } '+
            '</style></div>';

        if(!document.querySelector('#lightbox')){
            document.body.insertAdjacentHTML('beforeend', lightbox); }}


    function set_link(target){
        let photo_link=document.querySelector('#photo_link');
        if(photo_link){
            let url=target.getAttribute('href');
            if(url){
                photo_link.setAttribute('href', url); }

            photo_link.onclick=function(event){
                event.stopImmediatePropagation(); }}}


    function set_img(target){
        let lightbox=document.querySelector('#lightbox');
        let box_img=lightbox.querySelector('#box_img');
        let img=target.querySelector('img');
        if(lightbox && box_img && img){
            let img_url=img.getAttribute('src').replace(/%3Fversion%.*$/,"");
            if(img_url){
                box_img.src=img_url;
                html_.style.overflow='hidden';
                lightbox.style.visibility='visible';
                lightbox.classList.remove('fout');
                lightbox.classList.add('fin'); }}}


    function close(){
        let html_=document.querySelector('html');
        let lightbox=document.querySelector('#lightbox');
        let box_img=lightbox.querySelector('#box_img');
        if(lightbox){
            lightbox.onclick=function(event){
                event.preventDefault();
                html_.style.overflow='inherit';
                lightbox.classList.remove('fin');
                lightbox.classList.add('fout');
                setTimeout(()=>{
                    lightbox.style.visibility='hidden';
                    box_img.src='';
                }, 200); }}}




    function set_if(target){
        outline_off();
        let Card=target.closest('.com-feature-area-CardItem');
        if(Card){
            if(!Card.closest('.c-home-HomeContainerView-TvAreaContainer')){
                Card.style.outline='2px solid #fff'; }}

        let Ranking=target.closest('.com-feature-area-FeatureRankingItem');
        if(Ranking){
            Ranking.style.outline='2px solid #fff'; }



        let url=target.getAttribute('href');

        if(!url.includes('video/genre/') && !url.includes('now-on-air/')){
            let if_elem=
                '<div id="if_wrap">'+
                '<div id="if_cont">'+
                '<a href="https://abema.tv/" style="text-decoration: none">'+
                '<span class="if_link if" >'+
                '<svg width="32" height="32" style="vertical-align: -7px">'+
                '<use xlink:href="/assets/images/icons/feature/home.svg?v'+
                '=3451d87a53b7f6c71bed#svg-body"></use></svg>'+
                '<span class="t"> Abema Home</span></span></a>'+
                '<span class="if_close if">✖</span>'+
                '</div>'+
                '<iframe id="notify" scrolling="no" src="'+ url +'">'+
                '</iframe>'+
                '<style>#if_wrap { position: fixed; z-index: 20; top: 0; left: 0; width: 480px; '+
                'height: calc(100% - 22px); border: 2px solid #fff; background: #000; } '+
                '#if_cont { display: flex; justify-content: space-between; align-items: center; '+
                'color: #fff; height: 40px; padding: 0 40px; background: #a7b8c4; } '+
                '.if { cursor: pointer; } '+
                '.t { font: 20px Meiryo; } '+
                '.if_close { font-size: 16px; padding: 2px 6px 0; } '+
                '#notify { padding: 0; width: 100%; height: calc(100% - 40px); } '+
                '.c-application-SideNavigation { width: 480px; }'+
                '</style></div>';

            if(document.querySelector('#if_wrap')){
                document.querySelector('#if_wrap').remove(); }
            document.body.insertAdjacentHTML('beforeend', if_elem);


            let notify=document.querySelector('#notify');
            notify.onload=()=>{
                let if_body=notify.contentWindow.document.body; // 監視 target
                if(if_body){
                    if_body.setAttribute('class', 'if_movie'); // 動画再生抑止のclassとする
                    let in_style=
                        '<style class="in_style">'+
                        '.com-content-list-ContentList, '+
                        '.com-vod-VODRecommendedContentsContainerView__player-and-details { '+
                        'position: fixed; top: 0; left: 0; z-index: 20; width: 476px; '+
                        'height: 100%; overflow-y: scroll; overflow-x: hidden; background: #000; } '+
                        '.com-vod-VODRecommendedContentsContainerView__player-and-details { '+
                        'top: 15px; margin-left: 8px; } '+
                        '.com-content-list-ContentListEpisodeItem { overflow: hidden; padding: 8px; } '+
                        '.com-vod-VODLabel__text--free { box-shadow: 0 0 0 6000px #144f7a; } '+
                        '.com-content-list-ContentListEpisodeItem-ContentListEpisodeItemOverview'+
                        '__supplement, .com-content-list-ContentListEpisodeItem__description { '+
                        'color: #ddd; position: relative; } '+
                        '.com-vod-VodExpiredDateText-ExpiredDateText__text--info { color: #fff; }'+
                        '.com-content-list-ContentListEpisodeItem__my-list-button { '+
                        'margin-left: 0; width: 24px; } '+
                        '.com-m-NotificationManager { width: 290px; } '+
                        '.com-application-NotificationToast { '+
                        'gap: 0; height: 50px; padding: 0 10px 0 25px; } '+
                        '.com-application-NotificationToast__button-wrapper { display: none; } '+
                        '</style>';

                    if_body.insertAdjacentHTML('beforeend', in_style);

                    let links=if_body.querySelectorAll('.com-content-list-ContentListItem a');
                    for(let k=0; k<links.length; k++){
                        links[k].onmousedown=()=>{
                            let url=links[k].getAttribute('href');
                            if(url){
                                location.href=url; }}}

                }}}

        else if(url.includes('video/genre/') || url.includes('now-on-air/')){
            if_close(); }


        let close_button=document.querySelector('.if_close');
        if(close_button){
            close_button.onclick=()=>{
                outline_off();
                if_close(); }}

    } //set_if()



    function outline_off(){
        let cards=document.querySelectorAll('.com-feature-area-CardItem');
        for(let k=0; k<cards.length; k++){
            let style=window.getComputedStyle(cards[k]);
            let out=style.getPropertyValue('outline-width');
            if(out='2px'){
                cards[k].style.outline=''; }}

        let rankings=document.querySelectorAll('.com-feature-area-FeatureRankingItem');
        for(let k=0; k<rankings.length; k++){
            let style=window.getComputedStyle(rankings[k]);
            let out=style.getPropertyValue('outline-width');
            if(out='2px'){
                rankings[k].style.outline=''; }}}


    function if_close(){
        if(document.querySelector('#if_wrap')){
            document.querySelector('#if_wrap').remove(); }}


} // catch_click()




 

 

 

「AmbTV Comfy」最新版について 

旧いバージョンの JavaScriptツールは、Abemaサイトのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。

 

●「AmbTV Comfy」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。