〔追記〕2022.10.30
「Bad Comment Delete」のコードは、システム側の更新で動作不能になり、修復を断念しましたが、このツールの全ての目的を達成する「コメント管理 / コメントブロック機能」が、アメーバから提供されています。

従って、「Bad Comment Delete」のツールとしての存在価値はなくなりましたが、部分的なコードを参考にする場合を考慮して、記事を残しています。

 

 

 

ブロックIDのデータ管理機能を実装しました 

これまではブロックするアメーバID(ログアウト・外部ユーザーの場合はコメントユーザー名を代用)を登録する機能しかありませんでした。 しかし、間違って無関係のIDを登録したり、削除の必要がなくなったりした場合に、ブロックの解除を行えないと困ります。 ユーザースクリプトツールは、ツールをOFFにすればブロック機能が働かなくなりますが、複数のブロックの一部を解除する操作が出来ないと不便です。

 

そのため、登録したブロックIDを一覧出来て、その中から不要なID登録を削除する(ブロックを解除する)機能を実装しました。

 

 

 

管理機能の中心はセレクトボックス 

下はページタイトル上に配置したブロックIDデータの管理機能です。 データをファイルに保存する「Export」ボタン、反対にそれを読込む「Import」ボタン、ブロックIDを解除する「セレクトボックス」を並べています。 タイトル部をクリックして「設定モード」にすると、これらが表示される仕様です。

 

 

セレクトボックスをクリックすると、ブロック指定したIDがプルダウンリストで表示されます。

 

 

このリストで、ブロックを解除するIDをクリックすると、下の様な確認のダイアログが表示されます。

 

 

「OK」を押すと、指定したブロックIDが登録リストから削除され、そのIDに関するブロックが解除されます。「キャンセル」を押すと処理を中止します。

 

 

 

ファイル保存と読込み 

登録したブロックIDはツール上で配列として扱われます。 JavaScriptは配列データを「.json」形式のファイルに保存します。 これはメモ帳等のテキストエディタで扱え、配列の一部をコピーしたり、書き換えが可能です。

 

 

「Export」 保存 

「Export」ボタンを押すと、ツールに登録された配列がダウンロードフォルダーに保存されます。 Chromeや新Edgeではウインドウ下部に、そのファイルへのアクセスが表示されます。

 

 

下部の「ファイルを開く」を押すと、「.json」ファイルをメモ帳に関連付けている場合は、下の様に配列の内容がそのまま表示されます。

 〔参考〕メモ帳に関連付けを行う操作は 次ページ を参照ください。

 

 

配列の [ ] の中はカンマで区切られた簡単な構造で、最初の3個はツールの機能のために使っていて、それ以降にブロックIDが書き込まれます。 なお、ver.0.2まで 最初の2個を機能用に使っていましたが、今回から予備を加えて3個にしました。 また、ブロックIDの検索対象に機能用の要素も含めていたのを、完全に後の登録IDのみを調べる様にしました。 これで「stop」「0」もヒットする事はなくなりました。

 

 

「Import」 読込み 

「Import」ボタンを押すと、読込むファイルを指定するダイアログが表示されます。 Windows10の場合は「ダウンロード」フォルダの中に、それまでに保存したファイルがあります。

 

 

「Bad Comment Delete」の「Export」したファイルは「Bad_Comment_Delete」で始まるファイル名(連番付き)です。 これをクリックで指定し「開く」を押すとツールに読込まれます。

 

正しいファイルを読込んだ場合は、下の様なアラートが表示されます。

 

 

ツール上の配列はファイルから読込んだデータに、既に書換えられています。 プルダウンメニューを開くと、読込んだ新しいデータを確認する事が出来ます。

 

なお安全のために、読込んだ配列データに、このページ上のコメントを削除するIDが含まれていても、すぐには削除動作は行われません。 しかし、ページをリロードした直後から、削除動作が行われます。

 

 

ファイルバックアップの利用について 

ファイル保存・読込みの機能は、基本的にブロックIDのデータをバックアップする事に使います。 通常は、PC内の記録スペース(ローカルストレージ)にデータが保存され、困る事はありません。 しかし、ブラウザのリセットや「サイトデータの削除」などの操作で、ローカルストレージのデータが削除される事があります。 Cookie削除などと一緒に誤って削除してしまう事があり、そういう場合にバックアップがあると助かります。 重要なブロックIDの登録後にだけ「Export」を押せば良いでしょう。

 

 

 

「Bad Comment Delete」ver. 0.3 

このツールは Chrpme・新Edge / Firefox で動作を確認しています。 今回のver. 0.3 で、ほぼ実際に利用できるツールになりましたが、今後も改善を加えて行きます。

 

以下のコードを「Tampermonkey」の新規スクリプトの編集画面にコピー&ペーストして「保存」する事で、ツールが利用できる様になります。 ペーストの際、編集画面の初期テンプレートを完全に空白にしてから、ペーストをしてください。

 

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

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

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

 

 

〔 Bad Comment Delete 〕ver. 0.3

 

// ==UserScript==
// @name         Bad Comment Delete
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  コメント管理画面におけるコメント自動削除機能
// @author       Ameba Blog User
// @match        https://blog.ameba.jp/ucs/comment/comment*
// @noframes
// @run-at        document-start
// @grant        none
// ==/UserScript==


let ua=0;
let agent=window.navigator.userAgent.toLowerCase();
if(agent.indexOf('firefox') > -1){ ua=1; } // Firefoxの場合のフラッグ


window.addEventListener('DOMContentLoaded', function(){
    let comm_block_data=[]; // 総合ブロックデータ
    let block_filter_id;
    let block_regex_id;

    let edit_mode=0;
    disp_environ();


    let read_json=localStorage.getItem('comm_id_back'); // ローカルストレージ 保存名
    comm_block_data=JSON.parse(read_json);
    if(comm_block_data==null){
        comm_block_data=['BadCommDelete','stop','0'];
        let write_json=JSON.stringify(comm_block_data);
        localStorage.setItem('comm_id_back', write_json); } // ローカルストレージ 保存



    reg_set();

    function reg_set(){
        let comm_block_data_copy=[];
        comm_block_data_copy=comm_block_data.slice();
        comm_block_data_copy.splice(0, 3);
        block_filter_id='^('+comm_block_data_copy.join('|')+')$';
        block_regex_id=new RegExp(block_filter_id);
        list_set(); }

    function list_set(){
        let list_select=document.querySelector('#list_select');
        if(list_select){
            list_select.innerHTML=''; // リセット

            let option0=document.createElement("option");
            option0.setAttribute('hidden', '');
            option0.text='ブロック指定ID 登録解除';
            option0.value=0;
            list_select.appendChild(option0);

            for(let k=3; k<comm_block_data.length; k++){
                let option=document.createElement("option");
                option.text=comm_block_data[k];
                option.value=k;
                list_select.appendChild(option); }}}



    function disp_environ(){
        let b_panel=document.createElement('li');
        b_panel.setAttribute('id', 'b_panel');

        let comm_set=document.querySelector('ul.commentSetting');
        if(comm_set){
            comm_set.appendChild(b_panel);
            b_panel.innerHTML=
                '<input id="export" type="submit" value="Export">'+
                '<input id="import" type="submit" value="Import">'+
                '<input id="reader" type="file" value="">'+
                '<select id="list_select">'+
                '</select>'; }

        let css=
            '#ucsMainLeft { position: relative; } '+
            '#b_panel { position: absolute; top: 8px; right: 15px; display: none; } '+
            '#list_select { width: 230px; height: 26px; padding: 1px 15px 0; '+
            'font-size: 15px !important; background: #fff; } '+
            '#list_select option { font-size: 16px; } '+
            '#export { font-size: 17px; padding: 2px 8px 0; margin-right: 10px; '+
            'height: 26px; vertical-align: -3px; } '+
            '#import { font-size: 17px; padding: 2px 8px 0; margin-right: 15px; '+
            'height: 26px; vertical-align: -3px; } '+
            '#reader{ display: none; }';

        if(ua==1){
            css+='#export, #import { padding: 0 8px 0; height: 27px; }'; }

        let style=document.createElement('style');
        style.setAttribute('id', 's_list');
        style.innerHTML=css;

        let target=document.querySelector('body');
        if(!target.querySelector('#s_list')){
            target.appendChild(style); }

        file_write_read();
        permit(); }



    function file_write_read(){
        let ex_file=document.querySelector('#export');
        ex_file.onclick=function(){
            let write_json=JSON.stringify(comm_block_data);
            let blob=new Blob([write_json], {type: 'application/json'});
            let a_elem=document.createElement('a');
            a_elem.href=URL.createObjectURL(blob);
            a_elem.download='Bad_Comment_Delete.json'; // 保存ファイル名
            if(ua==1){
                a_elem.target = '_blank';
                document.body.appendChild(a_elem); }
            a_elem.click();
            if(ua==1){
                document.body.removeChild(a_elem); }
            URL.revokeObjectURL(a_elem.href); }


        let im_file=document.querySelector('#import');
        im_file.onclick=function(){
            file_read.click(); }

        let file_read=document.querySelector('#reader');
        file_read.addEventListener("change" , function(){
            if(!(file_read.value)) return; // ファイルが選択されない場合
            let file_list=file_read.files;
            if(!file_list) return; // ファイルリストが選択されない場合
            let file=file_list[0];
            if(!file) return; // ファイルが無い場合

            let file_reader=new FileReader();
            file_reader.readAsText(file);
            file_reader.onload=function(){
                if(file_reader.result.slice(0, 16)=='["BadCommDelete"'){ // ファイルデータの確認
                    comm_block_data=JSON.parse(file_reader.result); // 読出して配列を上書きする
                    let write_json=JSON.stringify(comm_block_data);
                    localStorage.setItem('comm_id_back', write_json); // ローカルストレージ 保存

                    reg_set();
                    alert("✅ ブロック指定IDのデータを読込みました\n"+
                          "   読込んだファイル名: " + file.name); }
                else{
                    alert("❌ Bad Comment Delete の Exportファイルではありません\n"+
                          "   Importファイル名は「Bad_Comment_Delete ... 」で始まります"); }}});
    } // file_write_read()



    function permit(){
        let list_select=document.querySelector('#list_select');
        list_select.addEventListener('change', (event)=>{
            let sel_id=list_select.options[list_select.selectedIndex].text;
            let sel_index=list_select.selectedIndex+2;

            let ok=confirm(" ⛔ "+ sel_id +" のブロックID設定を解除しますか?");
            if(ok){
                comm_block_data.splice(sel_index, 1);
                reg_set();
                let write_json=JSON.stringify(comm_block_data);
                localStorage.setItem('comm_id_back', write_json); } // ローカルストレージ 保存
            else{
                list_set(); }});
    } // permit()



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

    function main(){
        comm_blocker();
        checker();

        let b_panel=document.querySelector('#b_panel');

        let commHeader=document.querySelector('#ucsMainLeft h1');
        if(commHeader){
            commHeader.textContent='💛 コメント管理';
            commHeader.style.paddingLeft='5px';

            commHeader.onclick=function(){
                if(edit_mode==0){
                    edit_mode=1;
                    commHeader.style.color='#fff';
                    commHeader.style.background='red';
                    b_panel.style.display='block';
                    list_set();
                    link_prevent();
                    comm_blocker(); }
                else{
                    edit_mode=0;
                    commHeader.style.color='#444';
                    commHeader.style.background='none';
                    b_panel.style.display='none';
                    link_prevent();
                    comm_blocker(); }}}
    } // main()



    function link_prevent(){
        let comm_li=document.querySelectorAll('#comments li');
        if(comm_li.length!=0){
            for(let k=0; k<comm_li.length; k++){
                if(edit_mode==1){
                    comm_li[k].querySelector('#comments .left h3').style.pointerEvents='none';
                    comm_li[k].querySelector('#comments .left h4').style.pointerEvents='none';
                    comm_li[k].querySelector('#comments .right').style.pointerEvents='none';
                    comm_li[k].querySelectorAll('#comments .right a')[0].style.pointerEvents='none';
                    comm_li[k].querySelectorAll('#comments .right a')[1].style.pointerEvents='none';
                    let public_a=comm_li[k].querySelector('#comments .right publicconfirm a');
                    if(public_a){
                        public_a.style.pointerEvents='none'; }
                    let cmtTxt_a=comm_li[k].querySelector('#comments .cmtTxt a');
                    if(cmtTxt_a){
                        cmtTxt_a.style.pointerEvents='none'; }}
                if(edit_mode==0){
                    comm_li[k].querySelector('#comments .left h3').style.pointerEvents='auto';
                    comm_li[k].querySelector('#comments .left h4').style.pointerEvents='auto';
                    comm_li[k].querySelector('#comments .right').style.pointerEvents='auto';
                    comm_li[k].querySelectorAll('#comments .right a')[0].style.pointerEvents='auto';
                    comm_li[k].querySelectorAll('#comments .right a')[1].style.pointerEvents='auto';
                    let public_a=comm_li[k].querySelector('#comments .right publicconfirm a');
                    if(public_a){
                        public_a.style.pointerEvents='auto'; }
                    let cmtTxt_a=comm_li[k].querySelector('#comments .cmtTxt a');
                    if(cmtTxt_a){
                        cmtTxt_a.style.pointerEvents='auto'; }}}}}



    function comm_blocker(){
        let comm_name=[];
        let count=0;

        let comm_li=document.querySelectorAll('#comments li');
        if(comm_li.length!=0){
            for(let k=0; k<comm_li.length; k++){
                if(comm_li[k].querySelector('input[name="comment_name"]')){
                    comm_name[k]=
                        comm_li[k].querySelector('input[name="comment_name"]').value;
                    if(block_regex_id.test(comm_name[k])==true){
                        count+=1;
                        comm_li[k].querySelector('input[name="del_index"]').checked=true; }}}}

        if(count!=0){
            comm_block_data[1]='delete'; // 削除フラグを設定
            let write_json=JSON.stringify(comm_block_data);
            localStorage.setItem('comm_id_back', write_json); // ローカルストレージ 保存

            let btn_del=document.querySelector('.actionControl .btnDelete');
            if(btn_del){
                btn_del.click();
                //    alert(count);
            }}
    } // comm_blocker()



    function checker(){
        let comm_name=[];

        let comm_li=document.querySelectorAll('#comments li');
        if(comm_li.length!=0){
            for(let k=0; k<comm_li.length; k++){
                if(comm_li[k].querySelector('input[name="comment_name"]')){
                    comm_name[k]=
                        comm_li[k].querySelector('input[name="comment_name"]').value;
                    comm_li[k].onclick=function(event){ // リストのクリックで設定
                        set_guard(k); }}}

            function set_guard(n){
                if(edit_mode==1){
                    if(block_regex_id.test(comm_name[n])!=true){
                        comm_li[n].style.outline='solid 2px red';
                        comm_li[n].style.outlineOffset='-2px';

                        setTimeout(()=>{
                            let ok=
                                confirm(" ⛔ "+ comm_name[n] +" をブロックIDに設定しますか?");
                            if(ok){
                                comm_block_data.push(comm_name[n]);
                                reg_set();
                                let write_json=JSON.stringify(comm_block_data);
                                localStorage.setItem('comm_id_back', write_json); // ストレージ 保存
                                comm_blocker(); } // 排除リストに従って削除を実行
                            else{
                                comm_li[n].style.outline='none'; }
                        }, 20); }}}
        }} // checker()
})



window.addEventListener('DOMContentLoaded', function(){
    let path=document.location.pathname;
    if(path=='/ucs/comment/commentconfirm.do'){ // 削除確認画面の場合

        let comm_block_data=[]; // 総合ブロックデータ

        let read_json=localStorage.getItem('comm_id_back'); // ローカルストレージ 保存名
        comm_block_data=JSON.parse(read_json);
        if(comm_block_data!=null){
            if(comm_block_data[1]=='delete'){ // 削除実行フラグがある場合
                comm_block_data[1]='stop'; // フラグを戻す
                let write_json=JSON.stringify(comm_block_data);
                localStorage.setItem('comm_id_back', write_json); // ローカルストレージ 保存

                setTimeout(()=>{
                    let btn_del=document.querySelector(
                        '.actionControl .btnPrimary[value="削除"]');
                    if(btn_del){

                        btn_del.click(); }}, 50)}}}
});



window.addEventListener('DOMContentLoaded', function(){
    let path=document.location.pathname;
    if(path=='/ucs/comment/commentend.do'){ // 削除完了画面の場合
        window.location.href=
            'https://blog.ameba.jp/ucs/comment/commentlist.do?public_comment_flg=false'; }
});