機能の整理

「HOME」画面で動作するツールとして「Follow Feed Checker」「Aid AmbH」を制作して来ましたが、両方の機能がクロスするので整理する事にしました。 これは、今後のメンテナンスや更新上で、コードの無駄な複雑化を防ぐ意味があります。 整理の基本方針は以下です。

 

▪「Follow Feed Checker」は「Follow Feed」の機能拡張ツール
▪「Aid AmbH」は「HOME」全体のリンク機能の管理ツール

 

この方針から、「Follow Feed Checker」の「お知らせ」表示をシンプル化するコードと、「いいね!」のお知らせから「管理トップ」を開くコードを、「Aid AmbH」に移設する事にしました。

 

 

今回、「Follow Feed Checker ver. 1.5」に更新すると、上記のアレンジ機能は動作しなくなります。「Aid AmbH」の更新版「Aid AmbH ver. 1.5」をインストールすることで、上記の機能が復活します。 

 

「Aid AmbH」ver. 1.5 は次ページの掲載予定です。 よろしくお願いします。◞(..)◟

 

 

 

「Follow Feed Checker」の機能 

「Follow Feed Checker」は、「HOME」画面で動作するツールです。 機能の詳細については、以下のリンク先の開発ページを参照ください。

 

 

 

 

 

「Follow Feed Checker」を使うには

このツールは Chrome / Edge / Firefox 版の拡張機能「Tampermonkey」上で動作します。 ツールの導入は以下の手順で行います。

 

❶ 拡張機能「Tampermonkey」の導入

「Tampermonkey」は、使用しているブラウザに適した版を導入する必要があります。 既にこの拡張機能を導入している場合は、❶の手順は不要です。

 

 

❷「Follow Feed Checker」のインストール 

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

 

 

 

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

 

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

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

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

 

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

 

● 旧バージョンをご利用の場合は、それをOFFにするか登録を削除して、新旧の同時ONは避けてください。

 

 

〔 Follow Feed Checker 〕ver. 1.5

 

// ==UserScript==
// @name         Follow Feed Checker
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  「フォローフィード」の管理補助ツール
// @author       Ameba Blog User
// @match        https://www.ameba.jp/home
// @match        https://blog.ameba.jp/ucs/blgfavorite/*
// @match        https://blog.ameba.jp/reader.do?bnm*
// @match        https://blog.ameba.jp/readerend.do*
// @grant        none
// ==/UserScript==



if(document.querySelector('#AppShellDesktop')){ // HOMEページで有効
    let mode=0;
    let lock=0;
    let user_id;

    let redo; // インターバル変数
    let setting=[]; // 動作設定の記録配列
    // setting[0] スクリプト名
    // setting[1] フィード初期リスト数
    // setting[2] フィードタイマー更新 ON/OFF
    // setting[3] タイマー更新の繰返し時間
    // setting[4] ブラウザフォーカス ON/OFF
    // setting[5] リスト更新直前の最下のリスト番号
    // setting[6] リスト更新直前のページスクロール量


    let read_json=localStorage.getItem('followfeed_set'); // ローカルストレージ保存名
    setting=JSON.parse(read_json);
    if(setting==null || setting.length<7){
        setting=['FollowFeedSet',20,1,10,0,0,0]; }
    let write_json=JSON.stringify(setting);
    localStorage.setItem('followfeed_set', write_json); // ローカルストレージ保存



    ff_panel();
    ff_setting();
    auto_feed();



    function slow_more(){
        let more_button=
            document.querySelector('.HomeChecklist .Collection_ReadMore_Button');
        if(more_button){
            let rect=more_button.getBoundingClientRect();
            let item=document.querySelectorAll('.HomeChecklist_Collection_Item');
            if(rect.top<window.innerHeight && item.length<setting[1]){ // 指定記事数まで 🔴
                last_item();
                more_button.click(); }}}


    function last_item(){
        let item=document.querySelectorAll('.HomeChecklist_Collection_Item');
        for(let k=item.length-1; k>=0; k--){
            let rect=item[k].getBoundingClientRect();
            if(rect.top<window.innerHeight){
                setting[5]=k; // 🔵 リストの表示上の末尾を取得
                setting[6]=parseInt(window.pageYOffset);
                break; }}
        let write_json=JSON.stringify(setting);
        localStorage.setItem('followfeed_set', write_json); } // ローカルストレージ保存


    function fix_last(){
        let item=document.querySelectorAll('.HomeChecklist_Collection_Item');
        let more_button=
            document.querySelector('.HomeChecklist .Collection_ReadMore_Button');
        if(more_button){
            if(item.length<setting[5]){ // 指定記事までリストを開く 🔵
                more_button.click(); }}
        document.documentElement.scrollTop=setting[6]; }


    function top_env(){ // ページ最上部に 戻るボタン・スクロールバー で戻った場合
        if(document.documentElement.scrollTop<100){
            setting[5]=8;
            setting[6]=0;
            let write_json=JSON.stringify(setting);
            localStorage.setItem('followfeed_set', write_json); }} // ローカルストレージ保存



    function auto_feed(){
        redo=setInterval(()=>{
            feed(setting[2]); }, setting[3]*60000); } // 自動タイマー設定と開始 🔴

    let focus_fake=1; // 不感コントロール変数
    window.addEventListener('focus', function(){
        if(setting[4]==1){ // フォーカスで自動タイマーリセット 🔴
            if(focus_fake==1){
                focus_fake=0;
                clearInterval(redo);
                auto_feed();
                setTimeout(()=>{
                    focus_fake=1; }, setting[3]*30000); }}}); // フォーカス不感時間 🔴

    function feed(sw){
        let control_b=document.querySelector('.PcModuleHeader_Control button');
        if(control_b && sw==1){
            last_item(); // 🔵 リストスクロール位置取得
            control_b.click();
            fix_last(); }} // 指定記事までリストを開く 🔵



    function ff_panel(){
        let panel=document.createElement('div');
        panel.innerHTML=
            '<input id="ff_close" type="submit" value="✖">'+
            '<span> フィードの初期リスト数 </span>'+
            '<input id="list_open" type="number" value="20" min="10" step="10">  '+
            '<label><input id="ff_timer" type="checkbox"> タイマー更新</label>'+
            '<div id="ref_set"><span> 更新間隔 </span>'+
            '<input id="ref_setter" type="number" value="10" min="1" max="30" step="1">'+
            '<span> 分  </span></div>'+
            '<label><input id="ff_focus" type="checkbox"> フォーカス検知</label>'+
            '<style>#ff_panel { position: fixed; top: 8px; left: calc(50% - 532px); '+
            'font: bold 16px/24px Meiryo; color: #666; background: #fff; display: none; '+
            'width: auto; height: 30px; padding: 7px 20px 3px; border: 1px solid #20d6c5; '+
            'box-shadow: 4px 6px 8px rgb(0, 0, 0, .1); z-index: 10; } '+
            '@media screen and (max-width: 1140px){ #ff_panel { left: 28px; }} '+
            '#ff_close { padding: 3px 2px 1px; } '+
            '#list_open, #ref_setter { width: 50px; padding: 4px 2px 1px; text-align: center; } '+
            '#ref_set { display: inline-block; } '+
            '.PcHeader_Logo_Image { outline: 1px solid #20d6c5; outline-offset: 3px; } '+
            '</style>';
        panel.setAttribute('id', 'ff_panel');
        if(!document.querySelector('#ff_panel')){
            document.querySelector('body').appendChild(panel); }}


    function ff_setting(){
        let pc_logo=document.querySelector('h1.PcHeader_Logo');
        let ff_panel=document.querySelector('#ff_panel');
        if(pc_logo && ff_panel){
            pc_logo.onclick=function(event){
                event.preventDefault();
                ff_panel.style.display='block';

                let ff_close=document.querySelector('#ff_close');
                ff_close.onclick=function(event){
                    event.stopImmediatePropagation();
                    window.location.reload(); }

                let list_open=document.querySelector('#list_open');
                list_open.value=setting[1];
                list_open.onchange=function(){
                    setting[1]=parseFloat(list_open.value);
                    let write_json=JSON.stringify(setting);
                    localStorage.setItem('followfeed_set', write_json); } // ストレージ保存

                let ff_timer=document.querySelector('#ff_timer');
                let ref_set=document.querySelector('#ref_set');
                let ref_setter=document.querySelector('#ref_setter');
                if(setting[2]==1){
                    ff_timer.checked=true;
                    ref_set.style.opacity=1;
                    ref_setter.disabled=false; }
                else{
                    ff_timer.checked=false;
                    ref_set.style.opacity=0.5;
                    ref_setter.disabled=true; }
                ff_timer.onchange=function(){
                    if(ff_timer.checked){
                        setting[2]=1;
                        ref_set.style.opacity=1;
                        ref_setter.disabled=false; }
                    else{
                        setting[2]=0;
                        ref_set.style.opacity=0.5;
                        ref_setter.disabled=true; }
                    let write_json=JSON.stringify(setting);
                    localStorage.setItem('followfeed_set', write_json); } // ストレージ保存

                ref_setter=document.querySelector('#ref_setter');
                ref_setter.value=setting[3];
                ref_setter.onchange=function(){
                    if(parseFloat(ref_setter.value)>=0.1){
                        setting[3]=parseFloat(ref_setter.value); }
                    else{
                        setting[3]=1; }
                    let write_json=JSON.stringify(setting);
                    localStorage.setItem('followfeed_set', write_json); } // ストレージ保存

                let ff_focus=document.querySelector('#ff_focus');
                if(setting[4]==1){
                    ff_focus.checked=true; }
                else{
                    ff_focus.checked=false; }
                ff_focus.onchange=function(){
                    if(ff_focus.checked){
                        setting[4]=1; }
                    else{
                        setting[4]=0; }
                    let write_json=JSON.stringify(setting);
                    localStorage.setItem('followfeed_set', write_json); } // ストレージ保存
            }}} // ff_setting()



    let target=document.querySelector('.HomeChecklist'); // 監視 target
    let monitor=new MutationObserver(main);
    monitor.observe(target, {childList: true, subtree: true}); // 監視開始

    function main(){

        fix_last(); // ホームを開いた時の初期リスト表示 🔴

        window.addEventListener('wheel', function(){
            slow_more(); });

        window.addEventListener("scroll", function() {
            top_env(); });

        window.addEventListener("beforeunload", function(){
            setting[5]=8;
            setting[6]=0;
            let write_json=JSON.stringify(setting);
            localStorage.setItem('followfeed_set', write_json); }); // ローカルストレージ保存

        let more_button=
            document.querySelector('.HomeChecklist .Collection_ReadMore_Button');
        if(more_button){
            more_button.addEventListener('mousedown', function(event){
                last_item(); }); }


        mode_select();
        checker();


        function mode_select(){
            let control_a=document.querySelector('.PcModuleHeader_Control a');
            control_a.onclick=function(e){
                lock=1; } //「設定」で mode_selectを抑止

            let control_b=document.querySelector('.PcModuleHeader_Control button');
            control_b.onclick=function(e){
                lock=1;
                setTimeout( function(){
                    lock=0; }, 100); } //「フィードを更新」で mode_selectを抑止

            let checklist=document.querySelector('.HomeChecklist');
            let title=document.querySelector('.HomeChecklist .PcModuleHeader');
            let title_label=document.querySelector('.HomeChecklist .PcModuleHeader_Title');
            let title_con=document.querySelectorAll('.PcModuleHeader_Control_Link');

            title.style.cursor='pointer';

            title.onclick=function(){
                if(mode==0 && lock==0){
                    mode=1;
                    checklist.style.boxShadow='0 0 0 15px #6292ab inset';
                    title.style.boxShadow='0 -4px 0 10px #6292ab, 0 0 0 20px #6292ab inset';
                    title_label.style.color='#fff';
                    title_con[0].style.background='#fff';
                    title_con[1].style.background='#fff';
                    wide_style();
                    checker();}
                else if(mode==1 && lock==0){
                    mode=0;
                    checklist.style.boxShadow='';
                    title.style.boxShadow='';
                    title_label.style.color='#298538';
                    title_con[0].style.background='';
                    title_con[1].style.background='';
                    wide_style_off();
                    checker(); }}

            let k;
            let r_column=document.querySelector('.PcLayout_RightColumn');
            let c_style=window.getComputedStyle(r_column);
            let c_width=c_style.getPropertyValue('width');
            let c_item=document.querySelectorAll('.HomeChecklist_Collection_Item:nth-child(odd)');
            function wide_style(){
                if(c_width=='740px'){
                    checklist.style.padding='20px';
                    for(k=0; k<c_item.length; k++){
                        c_item[k].style.marginRight='24px'; }}}

            function wide_style_off(){
                if(c_width=='740px'){
                    checklist.style.padding='';
                    for(k=0; k<c_item.length; k++){
                        c_item[k].style.marginRight='64px'; }}}}


        function checker(){
            let k;
            let user_href;

            let item=document.querySelectorAll('.HomeChecklist_Collection_Item');
            for(k=0; k<item.length; k++){
                select_item(k); }

            function select_item(n){
                if(mode==1){
                    item[n].onclick=function(e){
                        e.preventDefault();
                        user_href=item[n].querySelector('.HomeChecklist_Article_Link').getAttribute('href');
                        user_id=user_href.replace('https://ameblo.jp/', '');
                        let index=user_id.indexOf('/entry');
                        user_id=user_id.substring(0, index);
                        item[n].style.outline='2px solid red';
                        setTimeout( conf, 800);

                        function conf(){
                            item[n].style.outline='';
                            let url_str='https://blog.ameba.jp/ucs/blgfavorite/favoritelist.do?' + user_id;
                            window.open( url_str, '_blank'); }}} // ページ移動
                else if(mode==0){
                    item[n].onclick=function(e){ ; }}}}

    } // main()

} // HOMEページで有効



if(document.querySelector('#readerList')){ // フォロー管理ページで有効
    let user_id;
    let win_url;

    let target=document.querySelector('body'); // 監視 target
    let monitor=new MutationObserver(table_view);
    monitor.observe(target, {childList: true, subtree: true}); // 監視開始

    function table_view(){ // HOMEから遷移して来た最初の管理画面でのみ動作する
        let k;
        let tr_href=[];
        let find=0;

        win_url=window.location.search.substring(1,window.location.search.length);

        if(win_url !='' && win_url.indexOf('pageID') ==-1){ // URLにuser_idが有る場合
            user_id=win_url;
            let write_json=JSON.stringify(user_id);
            sessionStorage.setItem('followfeedcheck_id', write_json); // セッションストレージ名

            let table_tr=document.querySelectorAll('.tableList tbody tr');
            for(k=0; k<table_tr.length; k++){
                tr_href[k]=table_tr[k].querySelector('td.title a').getAttribute('href');
                if(tr_href[k].indexOf(user_id) !=-1){
                    find=1;
                    table_tr[k].style.outline='2px solid red';
                    table_tr[k].scrollIntoView({block: 'center'});
                    status();
                    return; }} // 検索処理を終了

            if(find==0){ // user_idが見つからないと2ページへ移動
                let pager=document.querySelector('.pagingArea');
                let end=document.querySelector('.pagingArea .disabled.next');
                if(!end && pager){ // ページング末尾で無ければ2ページへ
                    let url_str='https://blog.ameba.jp/ucs/blgfavorite/favoritelist.do?pageID=2&More';
                    window.open( url_str, '_self'); }}} // URLにuser_idが有る場合

        else if(win_url.indexOf('&More') !=-1){ // URLに&Moreが有る場合のみ
            let read_json=sessionStorage.getItem('followfeedcheck_id'); // &Moreページで再読込み
            if(JSON.parse(read_json)){
                user_id=JSON.parse(read_json); }

            let table_tr=document.querySelectorAll('.tableList tbody tr');
            for(k=0; k<table_tr.length; k++){
                tr_href[k]=table_tr[k].querySelector('td.title a').getAttribute('href');
                if(tr_href[k].indexOf(user_id) !=-1){
                    find=1;
                    table_tr[k].style.outline='2px solid red';
                    table_tr[k].scrollIntoView({block: 'center'});
                    status(); // 非公開への自動変更機能の待機
                    return; }} // 検索処理を終了

            if(find==0){ // user_idが見つからないと次ページへ移動
                let end=document.querySelector('.pagingArea .disabled.next');
                if(!end){ // ページング末尾で無ければ次ページへ
                    let page_n=win_url.replace(/[^0-9]/g, '');
                    page_n=parseInt(page_n, 10) +1;
                    let url_str=['https://blog.ameba.jp/ucs/blgfavorite/favoritelist.do?pageID=',
                                 + page_n + '&More'].join('');
                    window.open( url_str, '_self'); }}}

        else{ //  HOMEからの遷移ではなく、単独でフォロー管理を開いた場合
            status(); }

    } // table_view()


    function status(){ //「公開フォロー」を「非公開」に変更
        let k;
        let blog_id=[];
        let status_span=[];
        let del_button=[];
        let blog_name=document.querySelectorAll('input[name="blog_name"]');
        let table_tr=document.querySelectorAll('.tableList tbody tr');

        let info=document.createElement('div');
        info.textContent="「承認済み」ボタンをクリックすると"+
            "「公開フォロー」を「非公開フォロー」に自動的に変更します";
        info.style.margin='6px 0 -12px';
        info.style.padding='2px 6px 1px';
        info.style.color='#fff';
        info.style.background='#2196f3';
        let box=document.querySelector('#ucsMainLeft #notes');
        if(!box.querySelector('div')){
            box.appendChild(info); }

        for(k=0; k<table_tr.length; k++){
            blog_id[k]=blog_name[k].getAttribute('value');
            del_button[k]=table_tr[k].querySelector('.btnDelete');
            status_span[k]=table_tr[k].querySelector('.status span');
            if(status_span[k].classList.contains('open')==true){
                status_span[k].style.borderRadius='3px';
                status_span[k].style.boxShadow='0 0 0 2px #2196f3';
                status_span[k].style.cursor='pointer';
                win_open(status_span[k], blog_id[k], del_button[k]); }}


        function win_open(span, id, del){ // 公開→非公開の自動変更
            span.onclick=function(){
                del.click();
                setTimeout(()=>{ // 対象ブログの削除ボタンを押す
                    let ok=document.querySelector('.minimumApplyButton a:first-child');
                    ok.click();
                }, 20);
                setTimeout(()=>{ // 対象ブログを非公開フォローする
                    let follow_url='https://blog.ameba.jp/reader.do?bnm=' + id + '&status=close';
                    window.open( follow_url, '_blank', 'top=0, left=0, width=480, height=360');
                }, 500); }}} // 処理を待ってから次のステップを実行

} // フォロー管理ページで有効



if(document.querySelector('#header.rd-header')){ // フォロー登録画面で有効
    let css=[
        'body { font-family: Meiryo; background: #cfd8dc; }',
        '#ambHeader { min-width: 400px !important; }',
        '#header.rd-header { display: flex; justify-content: center; width: auto; ',
        'padding: 20px 0 14px !important; }',
        '#contentsArea.rd-contentsArea { width: 400px !important; margin: 0 auto; }',
        '#mainCol.rd-mainCol { padding-top: 40px; }',
        '#contentsArea.rd-contentsArea._end { width: 400px; margin: 0 auto; }',
        '.rd-contentsArea._end #mainCol.rd-mainCol { padding: 20px 0 0; }',
        '.rd-checkList { margin: 15px 0; } .rd-error .error { font-size: 18px; font-weight: bold; }',
        '.rd-selectArea { width: 394px; } .rd-regist { padding: 15px; }',
        '.rd-radioArea { margin: 0; } .rd-radioLabel { font-size: 16px; }',
        '.rd-radioLabel:before { left: -23px; width: 14px; height: 14px; margin-top: -8px; }',
        '.rd-radioLabel:after { left: -24px; width: 14px; height: 14px; margin-top: -9px; ',
        'border: 1px solid #88bae6; }',
        '#ambHeaderRight, #ambFooter { display: none; }',
        '.rd-explanationSmall, .rd-amemberArea, .rd-browserPushArea, .rd-monsterBnr, ',
        '.rd-explanation, .rd-explanationSub, .rd-radioExplanation, .rd-infoMail, ',
        '.rd-followManagementLink { display: none; }' ].join(' ');

    let style=document.createElement('style');
    style.insertAdjacentHTML('afterbegin', css);
    let head=document.getElementsByTagName('head')[0];
    head.appendChild(style);

    let target=document.querySelector('body'); // 監視 target
    let monitor=new MutationObserver(ffcheker_do);
    monitor.observe(target, {childList: true, subtree: true}); // 監視開始

    function ffcheker_do(){
        let win_url=window.location.search.substring(1,window.location.search.length);
        if(win_url.indexOf('status=close')!=-1){
            if(!document.querySelector('.rd-error._whole .error')){ // 既にフォローしていない事が条件
                setTimeout(()=>{ // 非公開でフォローするにチェックを入れる
                    document.querySelector('#secInValidateNumber_01').checked=true;
                }, 20);
                setTimeout(()=>{ //「フォロー」決定ボタンを押す
                    document.querySelector('.rd-btnSubmit').click();
                }, 40);
                setTimeout(()=>{ // フォロー管理のトップを開く
                    let top_href='https://blog.ameba.jp/ucs/blgfavorite/favoritelist.do';
                    window.opener.location.href=top_href;
                }, 500); }}} // 処理の結果をフォロー管理画面に反映

} // フォロー登録画面で有効

 

 

 

「Ameblo Management」の利用をお勧めします 

「Follow Feed Checker」は「Ameblo Management」でアレンジした「HOME」画面や「フォロー管理」画面のデザインを前提に制作しています。 このアレンジが無くてもツールは動作しますが、なにかと扱い難いと思います。

 

特に「フォローフィード」に関しては、「Ameblo Management」のスタイルを適用すると、圧倒的に使い易いと感じるでしょう。

 

▪「フォローフィード」は「ホーム」画面の最上部に配置されます。

▪ デフォルトの2列の千鳥配列は、1列で縦並びのリストになります。

▪「新着 」「未読 」のマークと「記事タイトル文字色」で、未読 / 既読が明瞭に判断出来ます。 デフォルトの新着マークが消えた後でも、未読が判断できます。 

 

「Ameblo Management」は、「ホーム」画面以外にも、アメブロの多くの画面のデザインをユーザーライクにアレンジします。 このスタイルを利用するには、以下のリンク先の導入手順を参照ください。

 

 

 

 

「Follow Feed Checker」最新版について 

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

 

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