検出した画像をページ上で示す
「Edit Yahoo Img」を使うと、対象画像が検出されたページに直接に移動できます。 開いたブログページで問題の画像を探すと、それがすぐに判る場合もありますが、中にはどこに問題の画像があるか判らない事があります。
DevTools を使ってHTMLを調べると、検出された画像が漸く見つかるのですが、これでは不便です。 ページ上に多数の画像があり、その一部だけが対象画像の場合もあります。 スタッフブログの告知の通り、クリックでYahooのエラー画面が出る場合と、告知とは違ってYahooのリンクが設定されていない場合もあります。 その場合は、クリックでエラー画面は表示されません。 しかし DevToolsで調べると(あるいは再編集画面のHTML表示で調べると)やはり「Search Yahoo Img」が検出した通りの要対策画像だったりします。
問題をできるだけ早く解決するには、問題の画像を明確に示す必要があります。 また、画像が表示されない場合も、どこに調べるべきSRCコードがあるか、ユーザーに明瞭に教える必要があります。
「Edit Yahoo Img」に、この問題箇所を示す機能を実装しました。 対象のページを開くと、デフォルトで問題の画像に「赤点滅」のマークが表示されます。 パネル中央の「記事のデータ表示枠」 には、ページで検出された画像数が表示されますから、ページ本文を見て、対象画像の数のマークの場所を先ず確認すべきでしょう。
対象の画像を示すマーク
以下は、調査で検出した画像の場所を示すマークの様子です。
画像が表示されないケースでは、ブラウザが用意した「画像欠損」を示すアイコンが代わりに表示される場合が多く、下の様な状態になります。「▲」のマークが、検出した場所を示して点滅しています。
画像が表示されるケースでは、一般に画像の隅にこのマークが表示されます。
ただし、画像が中央配置になっている場合は、マークが本文枠の左端に離れますが、対象の画像は判断できるでしょう。
このマークは、ページを開いた時から点滅して場所を示します。
「Edit Yahoo Img」を使用するには
「Edit Yahoo Img」は Chrome/Edge/Firefox の拡張機能「Tampermonkey」上で動作するスクリプトツールです。 上記のブラウザで動作を確認していますが、他のブラウザでの動作は未確認です。
❶「Tampermonkey」を導入します
◎ 使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。
既に「Tampermonkey」を導入している場合は、この手順 ❶ は不要です。
拡張機能の導入については、以下のページに簡単な説明があるので参照ください。
❷「Tampermonkey」にスクリプトを登録します
◎「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
◎「新規スクリプト」には、最初から「新規のテンプレート」が記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
◎ 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
〔 Edit Yahoo Img 〕 ver. 0.3
// ==UserScript== // @name Edit Yahoo Img // @namespace https://ameblo.jp/ // @version 0.3 // @description Yahoo由来の画像検索と編集 // @author Ameblo User // @match https://ameblo.jp/* // @grant none // ==/UserScript== let ua=0; // Chromeの場合のフラグ let agent=window.navigator.userAgent.toLowerCase(); if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラグ let target=document.querySelector('head'); // 監視 target let monitor=new MutationObserver(do_task); monitor.observe(target, { childList: true }); // 監視開始 do_task(); function do_task(){ let entry_id=0; let entryWrapper=document.querySelector('.js-entryWrapper'); if(entryWrapper){ entry_id=entryWrapper.getAttribute('data-unique-entry-id'); } // 現在のページID let pageDB; // 主データ配列 [entry-ID, 対象数, 処理フラグ, 投稿日付, 起動コントロール] let idDB=[]; // 記事idの配列 let read_json=localStorage.getItem('CKIMG_DB'); // ローカルストレージ 保存名 pageDB=JSON.parse(read_json); for(let k=0; k<pageDB.length; k++){ idDB.push(pageDB[k][0]); } // 記事id検索用の配列を作る envi_0(); envi_1(); now_entry(); pointer(); function now_entry(){ let done=document.querySelector('#done'); let page_edit=document.querySelector('#page_edit'); let entry_date; let time=document.querySelector('time'); if(!time){ entry_date=' '; } else{ entry_date=time.getAttribute('datetime'); } if(entry_id!=0){ let index=idDB.indexOf(entry_id); if(index!=-1){ if(pageDB[index][2]==0){ done.style.boxShadow='inset 0 0 30px red'; // 未処理 if(pageDB[index][1]>1){ page_edit.value=pageDB[index][1] +'*'+ entry_id +' date: '+ entry_date; } else{ page_edit.value=' '+ entry_id +' date: '+ entry_date; }} else{ done.style.boxShadow='inset 0 0 30px #00e2ff'; // 処理済 if(pageDB[index][1]>1){ page_edit.value=pageDB[index][1] +'*'+ entry_id +' date: '+ entry_date; } else{ page_edit.value=' '+ entry_id +' date: '+ entry_date; }}} else{ done.style.boxShadow='none'; page_edit.value=' '+ entry_id +' date: '+ entry_date; }} // 対象外 else{ page_edit.value=' '; }} let done=document.querySelector('#done'); done.onclick=function(event){ // マニュアルでマークを変更 event.preventDefault(); let index=idDB.indexOf(entry_id); if(index!=-1){ if(pageDB[index][2]==0){ pageDB[index][2]=1; // 処理済に変更 done.style.boxShadow='inset 0 0 30px #00e2ff'; } else{ pageDB[index][2]=0; // 未処理に変更 done.style.boxShadow='inset 0 0 30px red'; } panel_color(index); } // リストパネルの配色を変更 let write_json=JSON.stringify(pageDB); localStorage.setItem('CKIMG_DB', write_json); } // ローカルストレージ 保存 function get_date_n(){ let time=document.querySelector('time'); if(time){ let n_time=time.getAttribute('datetime'); if(n_time){ let m_time=n_time.replace(/-/g, ''); return parseInt(m_time, 10); }} else return 0; } let go_next=document.querySelector('#go_next'); go_next.onclick=function(){ let active_arr=[]; for(let k=1; k<pageDB.length; k++){ if(pageDB[k][2]==0){ // 未処理の [記事ID,日付] 配列を作る active_arr.push([pageDB[k][0], pageDB[k][3]]); }} if(entry_id!=0){ // 記事一覧を開いている場合などを除外 let now_index=active_arr.findIndex(item=> item[0]==entry_id); if(now_index!=-1){ // 現在 リスト中の記事ID if(now_index==active_arr.length-1){ alert("これより最近の未処理ページはありません"); } else{ goto(active_arr[now_index+1][0]); }} else{ // 現在 リスト外の記事ID 日付から次の記事を探す let entry_date=get_date_n(); let next_index=active_arr.findIndex( item=> item[1] >= entry_date ); if(next_index==-1){ alert("これより最近の未処理ページはありません"); } else{ goto(active_arr[next_index][0]); }}}} let go_back=document.querySelector('#go_back'); go_back.onclick=function(){ let active_arr=[]; for(let k=pageDB.length-1; k>=1; k--){ if(pageDB[k][2]==0){ // 未処理の [ページID,日付] 配列を作る(降順) active_arr.push([pageDB[k][0], pageDB[k][3]]); }} if(entry_id!=0){ // 記事一覧を開いている場合などを除外 let now_index=active_arr.findIndex(item=> item[0]==entry_id); if(now_index!=-1){ // 現在 リスト中の記事ID if(now_index==active_arr.length-1){ alert("これより以前の未処理ページはありません"); } else{ goto(active_arr[now_index+1][0]); }} else{ // 現在 リスト外の記事ID 日付から次の記事を探す let entry_date=get_date_n(); let back_index=active_arr.findIndex( item=> item[1] <= entry_date ); if(back_index==-1){ alert("これより以前の未処理ページはありません"); } else{ goto(active_arr[back_index][0]); }}}} let page_edit=document.querySelector('#page_edit'); page_edit.onclick=function(event){ let article=document.querySelector('.js-entryWrapper'); let path= 'https://blog.ameba.jp/ucs/entry/srventryupdateinput.do?id='+entry_id; if(event.shiftKey){ window.open(path, 0,'top=100, left=200, width=1020, height=900'); } else if(event.ctrlKey){ window.location.href=path; } else{ window.open(path, "_blank"); }} page_edit.onchange=panel_act(); // 記事一覧による移動に対応する let trial=document.querySelector('#trial'); // SRCの書換えで画像表示を試す trial.onclick=function(){ let entryBody=document.querySelector('#entryBody'); let imgs=entryBody.querySelectorAll('img'); for(let k=0; k<imgs.length; k++){ if(search_img(imgs[k])==1){ trial_do(imgs[k]); }} function trial_do(target_img){ let img_src=target_img.getAttribute('src'); let new_src=img_src.replace('://other-', '://'); target_img.setAttribute('src', new_src); }} function pointer(){ let entryBody=document.querySelector('#entryBody'); let imgs=entryBody.querySelectorAll('img'); for(let k=0; k<imgs.length; k++){ if(search_img(imgs[k])==1){ point(imgs[k]); }} let links=entryBody.querySelectorAll('a'); for(let k=0; k<links.length; k++){ if(search_a(links[k])==1){ point(links[k]); }}} function search_img(target_img){ let pattern=[ 'yahoo.co.jp/IMG/ybi', 'c.yimg.jp/res/blog', 'west.edge.storage-yahoo.jp'].join('|'); let url_regex=RegExp(pattern); let img_src=target_img.getAttribute('src'); if(url_regex.test(img_src)==true){ return 1; }} function search_a(target_link){ let pattern=[ 'yahoo.co.jp/IMG/ybi', 'c.yimg.jp/res/blog', 'west.edge.storage-yahoo.jp'].join('|'); let url_regex=RegExp(pattern); let link_href=target_link.getAttribute('href'); if(url_regex.test(link_href)==true){ return 1; }} function point(target_img){ let insert_div; insert_div=document.createElement('div'); insert_div.setAttribute('class', 'mark'); insert_div.innerHTML="▲"; let parent=target_img.parentNode; parent.style.position='relative'; if(!parent.querySelector('.mark')){ parent.insertBefore(insert_div, target_img); }} function envi_0(){ let css= '#disp_yimg0 { position: absolute; top: 0; left: 0; font: 16px Meiryo; z-index: 1; '+ 'padding: 8px 0 6px; color: #000; background: aliceblue; width: 100%; } '+ '#disp_yimg0 span { font: 16px Meiryo; color: #000; } '+ '#num1, #num2 { width: 40px; margin-left: 4px; font: 16px Meiryo; '+ 'height: 18px; padding: 3px 8px 0; } '+ '#go_next, #go_back { height: 26px; font-size: 16px; width: 60px; '+ 'box-shadow: inset 0 0 40px #87caff; } '+ '#go_next { margin-left: 40px; } '+ '#done { font: 16px Meiryo; width: 15px; margin-left: 15px; height: 26px; } '+ '#page_edit { font: 16px Meiryo; height: 26px; width: 310px; text-align: left; '+ ' padding-left: 6px; margin: 0 15px 0 2px; box-shadow: inset 0 0 30px #fff; } '+ '#list_panel { margin-left: 30px; box-shadow: inset 0 0 40px #87caff; } '+ '#trial { margin-left: 50px; box-shadow: inset 0 0 50px #5fd1c1; } '+ '#page_sort { margin-left: 8px; box-shadow: inset 0 0 40px #5fd1c1; } '+ '#storage { margin-left: 8px; padding: 0; line-height: 25px; vertical-align: 1px;'+ 'box-shadow: inset 0 0 20px #5fd1c1; } '+ '.exe { font: 16px Meiryo; height: 26px; font-size: 16px; } '+ '#i_panel { position: fixed; top: 50px; right: 10px; width: 300px; outline: 1px solid; '+ 'font: 16px Meiryo; color: #000; background: #fff; z-index: 4000; } '+ '#items_ul { max-height: 60vh; overflow-y: scroll; list-style: none; '+ 'padding: 0px 0 0 22px; } '+ '.item_li { margin: 6px 0; padding: 4px 0 1px 6px; line-height: 14px; cursor: pointer; } '+ '.raw { box-shadow: -12px 0 0 red; } .dev { box-shadow: -12px 0 0 #00e2ff; } '+ '.item_li:hover { background: #eee; } '+ '.mark { position: absolute; color: red; font: 20px Meiryo; top: 6px; left: 0; '+ ' animation: blinkAn .3s infinite alternate; -webkit-text-stroke: 1px #FFF; } '+ '@keyframes blinkAn{ 0% { color: #fff; } 100%{ color: red; }} '; if(ua==1){ css+='input[type="submit"] { background: unset; }'; } let style=document.createElement('style'); style.setAttribute('id', 'style_yimg0'); style.insertAdjacentHTML('afterbegin', css); if(!document.querySelector('#style_yimg0')){ document.body.appendChild(style); } // CSSのセット let insert_div0; insert_div0=document.createElement('div'); insert_div0.setAttribute('id', 'disp_yimg0'); let ambHeader=document.querySelector('#ambHeader'); if(!ambHeader.querySelector('#disp_yimg0')){ ambHeader.appendChild(insert_div0); } insert_div0.innerHTML= '<span> 処理済</span>'+ '<input id="num1" type="text" readonly>'+ '<span> リスト</span>'+ '<input id="num2" type="text" readonly>'+ '<input id="go_next" type="submit" value="◀">'+ '<input id="done" type="submit" value=" ">'+ '<input id="page_edit" type="submit" value=" ">'+ '<input id="go_back" type="submit" value="▶">'+ '<input id="list_panel" class="exe" type="submit" value="▽ List">'+ '<input id="trial" class="exe" type="submit" value="❖ Trial">'+ '<input id="page_sort" class="exe" type="submit" value="♻ Sort">'+ '<input id="storage" class="exe" type="submit" value="🔅">'; } // envi_0() function envi_1(){ // 処理済・リスト数を表示 let num1=document.querySelector('#num1'); let num2=document.querySelector('#num2'); let undone=0; for(let k=0; k<pageDB.length; k++){ if(pageDB[k][2]==1){ undone+=1; }} num1.value=undone; num2.value=pageDB.length -1; } let page_sort=document.querySelector('#page_sort'); page_sort.onclick=function(){ // 主配列を末尾の entry-date でソートする let conf_str=' 🟢 Yahoo画像の調査ツール「Search Yahoo Img」で\n'+ ' 調査や追加の調査を行った後は、データのソートを\n'+ ' 行ってください。\n'+ ' ソートにより「Edit Yahoo Img」のページ送り順が\n'+ ' ブログのページ順と同じになります。\n\n'+ ' ソートする場合は「OK」を押してください'; let ok=confirm(conf_str); if(ok){ pageDB.sort((a, b)=>{ // 日付が若い順にソート if(a[3] > b[3]) return 1; if(a[3] < b[3]) return -1; return 0; }); let write_json=JSON.stringify(pageDB); localStorage.setItem('CKIMG_DB', write_json); // ローカルストレージ 保存 window.location.reload(); }} let list_panel=document.querySelector('#list_panel'); list_panel.onclick=function(){ let i_panel=document.querySelector('#i_panel'); if(!i_panel || i_panel.style.display=='none'){ disp_itemes(1); } else{ disp_itemes(0); }} function disp_itemes(n){ if(n==1){ let i_panel=document.querySelector('#i_panel'); if(!i_panel){ // リスト未作成 let panel=document.createElement('div'); panel.innerHTML= '<ul id="items_ul"></ul>'; panel.setAttribute('id', 'i_panel'); document.querySelector('body').appendChild(panel); let items_ul=document.querySelector('#items_ul'); if(items_ul){ items_ul.innerHTML=''; for(let k=1; k<pageDB.length; k++){ let item_li=document.createElement('li'); item_li.setAttribute('class', 'item_li'); if(pageDB[k][2]==0){ item_li.classList.add('raw'); } else if(pageDB[k][2]==1){ item_li.classList.add('dev'); } if(pageDB[k][1]>1){ item_li.innerHTML=pageDB[k][1] +'*'+ pageDB[k][0] + m(pageDB[k][3]); } else{ item_li.innerHTML='  '+ pageDB[k][0] + m(pageDB[k][3]); } items_ul.appendChild(item_li); }}} else{ // リスト作成済 i_panel.style.display='block'; } panel_act(); panel_get(); } else{ let i_panel=document.querySelector('#i_panel'); if(i_panel){ i_panel.style.display='none'; }} function m(da){ let d=da.toString(); return ' '+ d.slice(0, 4) +'-'+ d.slice(4, 6) +'-'+ d.slice(6, 8); } } // disp_itemes() function panel_act(){ // 日付の近いリスト行を表示 let entry_date=get_date_n(); if(entry_date!=0){ let next_index=pageDB.findIndex( item=> item[3] >= entry_date ); if(next_index==-1){ next_index=pageDB.length-1; } let list_items=document.querySelectorAll('.item_li'); if(list_items.length>0){ list_items[next_index-1].scrollIntoView({block: "center"}); }}} function panel_get(){ let list_items=document.querySelectorAll('.item_li'); for(let k=0; k<list_items.length; k++){ list_items[k].onclick=function(){ goto_(k); }} function goto_(k){ goto(pageDB[k+1][0]); }} function goto(entry){ let path=location.pathname; // 現在のパス名 let user_id=path.split('/')[1]; let goto_url= 'https://ameblo.jp/'+ user_id +'/entry-'+ entry +'.html'; window.location.href=goto_url; } function panel_color(index){ let list_items=document.querySelectorAll('.item_li'); if(list_items[index-1]){ list_items[index-1].classList.toggle('raw'); list_items[index-1].classList.toggle('dev'); }} let storage=document.querySelector('#storage'); storage.onclick=function(){ let conf_str= ' 🔴 全ての調査データを削除します\n\n'+ ' 調査データは 70kB/1000件で、ローカルストレージ\n'+ ' の容量を心配する必要はありません。\n'+ ' 再調査の目的でデータをリセットする場合を除いて\n'+ ' 調査データを削除せずにしておく事をお勧めします。\n\n'+ ' データを全削除する場合は「OK」を押してください'; let ok=confirm(conf_str); if(ok){ pageDB=[['', 0, 0, 0, 1]]; let write_json=JSON.stringify(pageDB); localStorage.setItem('CKIMG_DB', write_json); // ローカルストレージ 保存 window.location.reload(); }} } // do_task()
〔追記〕2023.04
「secret.ameba.jp」のサブドメイン廃止に伴い、上記コードを修正しました。
ver.0.2 ➔ ver.0.3 に更新しています。