増件したフィードの初期表示のコントロール
フォローフィードの初期表示の仕様は、以下の2通りになります。
❶ 初期表示のデフォルトは「スクロール検知」によるリスト読込みが適している
❷ 増件部分を閲覧時は、オーソドックスな「全件読込み」が適している
ユーザーが「フォローフィードをもっと見る」を押して(実際は自動で)追加表示されたフィードを閲覧している場合は、ツールによる自動更新や、ページのリロード後は、➋ の「全件読込み」をしたフィードを再表示する方が良く、たとえ追加表示をした後であっても、フィードの先頭部分を閲覧している状態の場合は、❶ の先頭の 10件のみ再表示する方が良いと思われます。
これを判断するには、追加表示で最初に読み込まれる「11番目」のリストが、ウインドウ表示域の下方かどうかで判定すると良さそうです。
上のグリーン枠は、ブラウザウインドウの上下端を模式的に示したもので、リストは青枠の列です。 左側はリストをスクロールをしていないか、わずかしかスクロールしていない場合で、この場合は ❶ の初期表示をします。 右側は、「11番目」のリストが表示されていて、これを境にもっと下方のリストを参照している場合を含め、❷ の全件の読込みを初期表示とします。
判定コードは以下です。
setting[5]は、判定結果のストレージ登録用の値で、「0」は ❶ の初期表示、「1」は❷ の初期表示を指定する値です。 これを実際に実行するのは、以下のコードです。
以上のコードによって、「リロード」や「フィード更新」の際に、リストの表示状態の再現性が良くなりました。 フィード更新時の表示位置は完全ではありませんが、リロードの方は数秒かかるものの、元通りのリスト位置がほぼ完全に再現されます。
「フォーカス 検知」に不感時間を設けました
「フォーカス検知」は、フィードを見る時には更新してから見るという発想で作った機能ですが、頻繁に「HOME」画面と「ブログ記事」とを往復する様な場合に、更新頻度が多過ぎるという気がします。 そこで、一度「フォーカス検知」で更新が行われたら、一定時間は機能を抑止する「不感時間」を設けました。
この時間は、「タイマー更新の更新間隔」の1/2にしました。 イコールでは「タイマー更新」と同じ結果になり意味が無くなるので、この1/2という値にしています。
「Follow Feed Checker」ver. 1.0
このツールは Chrome・新Edge / Firefox 版の拡張機能「Tampermonkey」上で動作します。 ツールの導入は以下の手順で行います。
❶ 拡張機能「Tampermonkey」の導入
「Tampermonkey」の導入手順は、以下のページを参照ください。
「Tampermonkey」は、使用しているブラウザに適した版を導入する必要があります。 既にこの拡張機能を導入している場合は、❶の手順は不要です。
❷「Follow Feed Checker」ver. 1.0 のインストール
●「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
●「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
● 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
● 旧バージョンはOFFにするか登録を削除して、新旧の同時ONは避けてください。
〔 Follow Feed Checker 〕ver. 1.0
// ==UserScript==
// @name Follow Feed Checker
// @namespace http://tampermonkey.net/
// @version 1.0
// @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[1] フィード初期リスト数
// setting[2] フィードタイマー更新 ON/OFF
// setting[3] タイマー更新の繰返し時間
// setting[4] ブラウザフォーカス ON/OFF
// setting[5] リロード時表示されていた最上部のリスト
let read_json=localStorage.getItem('followfeed_set'); // ローカルストレージ保存名
setting=JSON.parse(read_json);
if(setting==null || setting.length<6){
setting=['FollowFeedSet',20,1,10,0,0]; }
let write_json=JSON.stringify(setting);
localStorage.setItem('followfeed_set', write_json); // ローカルストレージ保存
ff_panel();
ff_setting();
auto_feed();
function auto_feed(){
feed(1, setting[5]);
redo=setInterval(()=>{
more_mode();
feed(setting[2], setting[5]); }, 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, n){
let control_b=document.querySelector('.PcModuleHeader_Control button');
if(control_b && sw==1){
control_b.click();
more_action(n); }}
function more_action(n){
let more_button=
document.querySelector('.HomeChecklist .Collection_ReadMore_Button');
if(more_button){
let item=document.querySelectorAll('.HomeChecklist_Collection_Item');
if(item.length<setting[1]){ // 指定記事リスト数までクリックする 🔴
if(n==1){ // リロード時の位置コントロール
more_button.click(); }}}}
function more_mode(){
let item=document.querySelectorAll('.HomeChecklist_Collection_Item');
if(item.length<=10){
setting[5]=0; }
if(item.length>10){
let rect=item[10].getBoundingClientRect();
if(rect.top>window.innerHeight){
setting[5]=0; }
else{
setting[5]=1; }}
let write_json=JSON.stringify(setting);
localStorage.setItem('followfeed_set', write_json); }
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; z-index: 10; top: 6px; left: calc(50% - 480px); '+
'font: bold 16px/24px Meiryo; color: #666; background: #fff; display: none; '+
'width: auto; height: 30px; border: 1px solid #aaa; border-radius: 6px; '+
'padding: 12px 20px 6px; box-shadow: 0 20px 30px rgb(0, 0, 0, .2); } '+
'#ff_close { padding: 3px 2px 1px; } '+
'#list_open, #ref_setter { width: 50px; padding: 4px 2px 1px; text-align: center; } '+
'#ref_set { display: inline-block; } '+
'</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(){
window.addEventListener('scroll', ()=>{
more_action(1); }); // ホームを開いた時の初期リスト表示❶ 🔴
more_action(setting[5]); // ホームを開いた時の初期リスト表示❷ 🔴
window.addEventListener("beforeunload", function(){
more_mode(); }); // ローカルストレージ保存
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);
localStorage.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=localStorage.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」のスタイルを適用すると、圧倒的に使い易いと感じるでしょう。
▪「フォローフィード」は「ホーム」画面の最上部に配置されます。
▪ デフォルトの2列の千鳥配列は、1列で縦並びのリストになります。
▪「新着 ●」「未読 ●」のマークと記事タイトル文字色で、未読 / 既読が明瞭に判断出来ます。 このため、新着マークが消えた後でも、未読が判断できます。
「Ameblo Management」は、「ホーム」画面以外にも、アメブロの多くの画面のデザインをユーザーライクにアレンジします。 このスタイルを利用するには、以下のページの後半の導入手順を参照ください。
「Follow Feed Checker」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Follow Feed Checker」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。




