ローカルストレージが不本意にリセットされる場合 

ユーザーがブラウザの「閲覧履歴データの削除」を行った際に「Cookieと他のサイトデータ」にチェックが入っていると、「ローカルストレージ」のデータが綺麗に削除されてしまう事があります。

 

下は Chromeの例ですが、下側の「パスワードとその他の…」にチェックが入ってないので問題なしと思い、「Cookieと他のサイトデータ」にチェックを入れて「データを削除」を押すのですが、これでローカルストレージも削除されます。

 

ブラウザの閲覧履歴削除設定画面

 

ただし、この時の削除範囲をテストして調べると、削除時にブラウザが開いているドメインに限って削除をしているのか、ブラウザ(ツール)で使用しているローカルストレージの全てが削除されるのではない様です。

 

これは、「Cookieと他のサイトデータ」の削除の危険を判り難くします。 以前はローカルストレージは無関係だったが、今回は全部消えたという事が起こるので、余計に厄介な仕様と言えます。

 

「Cookie」削除=「ローカルストレージ」削除 と思っておいた方が良いです。

 

 

ローカルストレージが削除されると 

ローカルストレージに機能の設定などを保存するツールの場合は、少しの間は不便ですが使っている間に必要な設定に戻せます。 しかし、長期に渡って集積したデータをローカルストレージに保存するツールの場合は、打撃が大きいです。

 

私が制作したツールに関しては、以下のツールは「Cookie削除」をする前にファイル化が必須です。

 

 ◎「Bad Iine Mute」

 ◎「Bad Comment Mute」

 ◎「Ranking Blocker」

 ◎「RemPage For Chrome」「RemPage For Firefox」

 

各ツールに関しては、以下のページで最新版のページを探せます。

 

 

 

 

「Authentic Reader」のファイル機能 

このツールの「フォロワー履歴」はローカルストレージに保存されていて、ローカルストレージの削除で「フォロワー履歴」が失われます。

 

「フォロワー履歴」が失われるとツールは新規に作り直しますが、「消失したフォロワー」のデータが無くなります。 それが「時限フォロー」の場合は、次の再フォローでの判定ができません。 結果は、以降の何件かのチェックをロストするだけですが。

 

「Authentic Reader」のファイル機能で「フォロワー履歴」のファイル保存と読込みが可能ですが、何ヵ月も昔の「フォロワー履歴」は余り役にたちません。 このツールは、短期間での「フォロー登録 & 削除」をチェックするので、最近に削除されたフォロワーのデータが必要だからです。

 

ただ、「イエロー」指定は履歴に残り続けるので、その履歴の保持にはファイル化が使えます。 以下は、ファイル読込み時の処理仕様です。

 

▪ファイル読込み時に、それまで履歴に無いIDのフォロー情報は履歴に追加。

▪同じIDのフォロー情報は、日付が現在のリストより新しい場合だけ情報を上書き。

▪更新された「フォロワー履歴」は、日付順にソートする。

現在の1年前より旧い情報は、「フォロワー履歴」から削除する。 ただし、「イエロー」指定の情報は、期限に関係なく履歴上に残す。

 

最後の処理ですが、これまで「フォロワー管理」の 1ページ目の最後より旧い情報を期限切れとして削除していました。 しかし、フォロワーの少ないユーザーが、最近の2~3件を残してフォロー削除をすると、これまでの処理方法では、残した2~3件以降は全て履歴が削除されます。 ここは、オウン削除の「グリーン」のデータを残したい所です。

 

この様なフォロワー数が少ない場合を考え、「ページの末尾の日付」より「現在より1年前の日付」を履歴の有効期限にする方法に改めました。 この変更で、当ブログの場合は、1ページの2/3程度まで処理対象のフォロワー行が減りました。

 

アメーバブログ フォロワー管理画面

 

この履歴の有効期限は、ver.0.4 の213行の書換えで変更できます。

 

 

ファイル保存と読込み 

 

Export Import ボタンとファイル保存読込

 

● 「Export」ボタンを「左Click」すると、ダウンロードフォルダーに「フォロワー履歴」がファイル保存されます。

 

▪ファイル名はブログのユーザーIDが付いた以下のファイル名の形になります。

「auth_reader_UserID.json」

 

▪以降の保存時は、自動連番(n)が付いた以下のファイル名の形で保存されます。

「auth_reader_UserID (n).json」

 

下の青枠は、別IDの2個のブログから保存したものです。 アイコンはメモ帳になっていますが、これは私がメモ帳で編集するからで、Win10デフォルトは白紙のアイコンデザインです。

 

Authentic Reader JSONファイルバックアップ

 

 

●「Import」ボタンを「左Click」すると、ファイルから「フォロワー履歴」を読込む事ができます。

 

▪ファイル名が「auth_reader … .json」の太字で始まるファイルであれば、読込む事ができます。 当然、現在ログインしているブログIDのファイルから選択します。

 

 

 

ヘルプ以外は完成しました 

「Authentic Reader」は、ver.0.4 で実用可能になったと思います。 部分的な修正や更新はあるかもしれませんが。

 

制作を開始して 1週ほどしか経っていませんが、既に「2件」の「時限フォロー」らしきフォロワー側の「フォロー削除」と、「1件」の「ブログ閉鎖」による「フォロー削除」がありました。 案外と「時限フォロー」は多いのかも知れません。

 

この後はヘルプを作成します。

 

 

 

「Authentic Reader」を利用するには

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

 

❶「Tampermonkey」を導入します

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

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

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

 

 

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

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

 

Tampermonkey新規スクリプト編集画面

 

 

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

 

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

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

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

 

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

 

 

〔 Authentic Reader 〕 ver. 0.4

 

// ==UserScript==
// @name         Authentic Reader
// @namespace    http://blog.ameba.jp
// @version      0.4
// @description  自動プログラムの時限フォローを判定する
// @author       Ameba Blog User
// @match        https://blog.ameba.jp/ucs/reader/readerlist.do
// @match        https://blog.ameba.jp/ucs/reader/readerlist.do?pageID=1
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ameba.jp
// @grant        none
// ==/UserScript==


let readers=[]; // フォロワー登録データ
let deleted_reader; // フォロワーリスト表示数とフォロワー履歴数の差
let UserID; // アメーバログインID

let amebaId=document.querySelector('.amebaId');
if(amebaId){
    UserID=amebaId.textContent; }

function write_local(){
    let write_json=JSON.stringify(readers);
    if(UserID){
        localStorage.setItem('AR_'+UserID, write_json); } // ローカルストレージ 保存名
    else{
        id_alert(); }}

if(UserID){
    let read_json=localStorage.getItem('AR_'+UserID); // ローカルストレージ 保存名
    readers=JSON.parse(read_json);
    if(readers==null){
        readers=[['name', '1990年time', '0']];
        write_local(); }}
else{
    id_alert(); }

function id_alert(){
    alert(
        '⛔ ======== Authentic Reader ========\n'+
        '  ユーザーIDが取得出来ないため処理を実行できません\n'+
        '  ページのリロードを試し、さらにアメーバのログインに問題\n'+
        '  が無いかを確認してください'); }




check(); // フォロワー管理のトップページを開いた時にデータベースを更新
disp_list(); // フォロワーリストで属性のカラー表示


function disp_list(){
    let table_tr=document.querySelectorAll('.tableList tbody tr');
    for(let k=0; k<table_tr.length; k++){
        let name=table_tr[k].querySelector('.name a').textContent;
        for(let i=0; i<readers.length; i++){
            if(name==readers[i][0]){
                table_tr[k].style.background=set_color(readers[i][2]); }}}}


function deleted_count(){ // フォロワーリスト数と履歴データ数の差をチェック
    let deleted=0; // チェック時にリセット
    for(let i=0; i<readers.length; i++){
        let table_tr=document.querySelectorAll('.tableList tbody tr');
        let live=0;
        for(let k=0; k<table_tr.length; k++){
            let name=table_tr[k].querySelector('.name a').textContent;
            if(readers[i][0]==name){
                live+=1; }}
        if(live==0){
            deleted +=1; }}
    return deleted; }


function disp_deleted_count(){
    let data_disp=document.querySelector('#inner_AR2 .data_disp');
    if(data_disp){
        data_disp.textContent='hidden: '+ deleted_reader; }}



control_panel(); // コントロールパネルを表示


function control_panel(){
    let style=
        '#panel_AR { position: absolute; z-index: 1; top: 55px; left: calc(50% + 57px); '+
        'display: flex; align-items: center; '+
        'font: bold 16px/16px Meiryo; color: #666; background: #e0f0fd; '+
        'width: 330px; height: 30px; padding: 3px 0 1px 15px; '+
        'border: 1px solid #ccc; border-radius: 2px; } '+
        '#inner_AR1, #inner_AR2 { margin-bottom: 3px; } '+
        '.swe, .sec { cursor: pointer; } '+
        '.swe { font: normal 16px Meiryo; padding: 1px 6px 0; height: 28px; '+
        'margin-right: 12px; } '+
        '.file_input { display: none; } '+
        '.data_disp { display: inline-block; width: 115px; height: 28px; text-align: center; '+
        'padding: 6px 6px 0; margin-right: 12px; font: normal 16px/16px Meiryo; '+
        'color: #000; background: #fff; border: 1px solid #ccc; box-sizing: border-box; } '+
        '.swc { font: normal 16px Meiryo; padding: 1px 4px 0; height: 28px; } '+
        '.help_AR { height: 18px; width: 18px; margin: 0 45px -3px 12px; cursor: pointer; } '+
        '.setting_AR { margin: 0 0 -2px 4px; } '+
        '#inner_AR2 { display: none; }';

    let SVG_h=
        '<svg class="help_AR" viewBox="0 0 150 150">'+
        '<path  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>';

    let SVG_g=
        '<svg class="setting_AR" height="16" width="16" viewBox="0 0 256 256">'+
        '<path d="M114 19C110 22 109 30 108 34C106 41 102 46 96 49C88 53 81 52 '+
        '73 48C69 46 63 41 58 42C53 43 49 49 46 52C44 54 41 56 40 59C38 64 44 69 '+
        '46 73C50 82 52 90 47 99C42 107 35 109 27 112C23 113 18 114 16 118C15 124 '+
        '16 132 16 138C16 140 16 143 18 145C20 148 25 149 28 150C36 152 44 155 48 '+
        '164C52 173 50 180 46 188C44 192 38 198 41 203C42 206 45 208 47 210C50 '+
        '213 54 218 58 219C62 220 68 216 71 214C78 210 84 208 92 210C99 213 105 '+
        '218 107 225C109 230 110 239 114 242C117 244 123 243 126 243C130 243 138 '+
        '244 141 241C146 238 146 229 148 224C151 216 159 210 168 209C175 208 182 '+
        '213 188 216C191 218 195 221 199 218C204 216 208 210 212 206C213 204 215 '+
        '202 215 200C215 196 212 193 210 190C206 182 203 175 206 166C210 157 217 '+
        '153 225 150C229 149 237 148 239 143C240 137 239 129 239 123C239 121 239 '+
        '118 237 116C235 113 229 112 226 111C218 108 210 105 207 96C203 86 206 80 '+
        '210 71C212 68 215 65 215 61C215 59 213 57 212 55C208 51 204 45 199 43C195 '+
        '40 191 43 188 45C181 48 174 54 166 52C158 50 151 45 148 37C146 32 146 22 '+
        '141 19C137 17 129 18 125 18C122 18 117 17 114 19z" style="fill:#000"></path>'+
        '<path d="M123 70C116 71 109 72 103 75C82 85 69 106 68 129C66 162 97 195 '+
        '131 191C162 187 185 164 187 132C189 99 157 66 123 70z" style="fill:#fff">'+
        '</path></svg>';

    let panel=
        '<div id="panel_AR">'+
        '<div id="inner_AR1">'+
        'Authentic Reader<span>'+ SVG_h +'</span>'+
        '<button class="mentenance swe" type="submit" >Setting'+ SVG_g +'</button>'+
        '</div>'+
        '<div id="inner_AR2">'+
        '<input class="export swe" type="submit" value="Export">'+
        '<input class="import swe" type="submit" value="Import">'+
        '<input class="file_input" type="file">'+
        '<span class="data_disp"> </span>'+
        '<input class="close swc" type="submit" value="✖"></div>'+
        '<style>'+ style +'</style></div>';

    let panel_AR=document.querySelector('#F_AR');
    if(!panel_AR){
        document.querySelector('body').insertAdjacentHTML('beforeend', panel); }


    let AR1=document.querySelector('#inner_AR1');
    let AR2=document.querySelector('#inner_AR2');
    let mentenance=document.querySelector('.mentenance');
    let close=document.querySelector('.close');

    if(mentenance && AR1 && AR2){
        mentenance.onclick=function(){
            AR1.style.display='none';
            AR2.style.display='block';
            database();
            disp_deleted_count();
            own_delete();
            AR_backup(); }}


    if(close && AR1 && AR2){
        close.onclick=function(){
            AR1.style.display='block';
            AR2.style.display='none';
            database_close();
            disp_list();
            own_delete(); }}

} // control_panel()



function check(){ // データベースの更新
    let table_tr=document.querySelectorAll('.tableList tbody tr');
    for(let k=0; k<table_tr.length; k++){
        let name=table_tr[k].querySelector('.name a').textContent;
        let time=table_tr[k].querySelector('.rdrCmnt span').textContent;

        let count=0;
        for(let i=0; i<readers.length; i++){
            if(name==readers[i][0]){
                count+=1;
                if(time!=readers[i][1]){ // 同じデータは更新しない
                    if(readers[i][2]=='0'){
                        readers[i][2]='1'; // 時限フォロー
                        readers[i][1]=time; // 今回の日付に差換え(更新データ)
                        table_tr[k].style.background=set_color('1'); }
                    else if(readers[i][2]=='1'){
                        readers[i][2]='1'; // 時限フォロー
                        readers[i][1]=time; // 今回の日付に差換え(更新データ)
                        table_tr[k].style.background='red'; }
                    else if(readers[i][2]=='2'){ // こちらでフォロー削除
                        readers[i][1]=time; // 今回の日付に差換え(更新データ)
                        table_tr[k].style.background=set_color('2'); }}}}

        if(count==0){ // 同データが無い新しい登録
            readers.push([name, time, '0']); }}


    readers.sort((a, b)=>{
        return b[1].replace(/[^0-9]/g, '')*1 - a[1].replace(/[^0-9]/g, '')*1 });

    setTimeout(()=>{
        let now=new Date();
        let year=now.getFullYear()-1; // 1年前 🔴🔴「-2」2年前までになります 🔴🔴
        let month=now.getMonth()+1;
        let date=now.getDate();
        let last_time=year*10000 + month*100 + date; // データの有効期限を1年とする
        readers=readers.filter(value=>{
            if(value[1].replace(/[^0-9]/g, '')*1 > last_time || value[2]=='1'){
                return true; }});

        deleted_reader=deleted_count();
        write_local(); }, 500);

} // check()



function own_delete(){
    let table_tr=document.querySelectorAll('.tableList tbody tr');
    for(let k=0; k<table_tr.length; k++){
        let name=table_tr[k].querySelector('.name a').textContent;
        let btnDelete=table_tr[k].querySelector('.btnDelete');

        btnDelete.onmouseup=function(){
            let AppButton=document.querySelector('.minimumApplyButton a:first-child');
            if(AppButton){
                AppButton.addEventListener('mouseup', function(){
                    set_2(name); }); }}}

    function set_2(name_){
        for(let i=0; i<readers.length; i++){
            if(name_==readers[i][0]){
                if(readers[i][2]=='0'){ // フラグ無しフォロワーをユーザー側で削除した場合
                    readers[i][2]='2'; } // オウン削除のフラグを設定
                write_local(); }}}
} // own_delete()



function database(){ // 履歴のみのフォロワーを追加して履歴編集環境にする
    disp_datalist();
    change_color();
    remove_data(); }



function disp_datalist(){
    let thead_AR=
        '<span class="thead_AR">履歴属性'+
        '<style>'+
        '.tableList thead .closeRow { padding: 6px 124px 4px 20px; } '+
        '.tableList .thead_AR { margin-left: 55px; } '+
        '.tableList .rdrCmnt p { width: 400px; } '+
        '.tableList tbody .closeRow { position: relative; width: 140px !important; '+
        ' box-shadow: none !important; } '+
        '.tableList .color.btn { position: absolute; top: 19px; left: 120px; '+
        'width: 24px; height: 24px; cursor: pointer; }'+
        '.btnDelete.AR { width: 90px !important; margin-right: -30px; '+
        'background-color: #bedcf7 !important; } '+
        '</style></span>';

    let thead_closeRow=document.querySelector('.tableList thead .closeRow');
    if(thead_closeRow && !document.querySelector('.thead_AR')){
        thead_closeRow.insertAdjacentHTML('beforeend', thead_AR); }

    let SVG_user=
        '<svg viewBox="0 0 240 240">'+
        '<path d="M0 0L0 240L240 240L240 0L0 0z" style="fill:#fff;"></path>'+
        '<path d="M118 32C111 32 104 33 98 36C79 45 73 67 72 86C71 98 72 113 80 '+
        '123C92 136 114 135 129 134C138 133 149 131 156 124C165 115 166 103 166 '+
        '91C166 63 151 29 118 32M37 224L201 224C194 199 186 177 163 162C128 139 '+
        '81 148 55 180C45 193 40 208 37 224z" style="fill:#d4e7f5;"></path></svg>';



    for(let i=0; i<readers.length; i++){ // リストにデータベースの全フォロワーを追加表示
        insert(i); }

    disp_list(); // 生成したデータベースリストに属性色表示



    function insert(n){
        let table_tr=document.querySelectorAll('.tableList tbody tr');

        if(table_tr.length==0){ // リストにフォロワーが無い場合
            creat_tr3(n); }

        else{ // リストにフォロワーが1人でもある場合
            for(let k=0; k<table_tr.length; k++){
                let name=table_tr[k].querySelector('.name a').textContent;
                let time=table_tr[k].querySelector('.rdrCmnt span').textContent;
                let time_d=time.replace(/[^0-9]/g, '')*1;

                if(readers[n][1].replace(/[^0-9]/g, '')*1 > time_d){
                    creat_tr1(n, table_tr[k]); // 削除されたフォロワー
                    break; }

                else if(readers[n][1].replace(/[^0-9]/g, '')*1 == time_d){
                    if(readers[n][0]==name){ // 登録更新が無い正常フォロワー
                        creat_tr2(n, table_tr[k]);
                        break; }}
                // 登録日時が同じ別フォロワーがある場合は、次行でヒットするか
                // ヒットが無い場合は 次行の上に削除されたフォロワー行が作成される

                else if(readers[n][1].replace(/[^0-9]/g, '')*1 < time_d){
                    if(k==table_tr.length-1){ // 末尾行よりデータが旧い
                        creat_tr3(n); }}}}


        function creat_tr1(m, ta_tr){
            ta_tr.insertAdjacentHTML('beforebegin', tr_org(m)); }

        function creat_tr2(m, ta_tr){
            let c_btn='<input type="button" value="" class="color btn">';
            let btnDelete=ta_tr.querySelector('.btnDelete');
            if(btnDelete){
                btnDelete.insertAdjacentHTML('afterend', c_btn); }}

        function creat_tr3(m){
            let tbody=document.querySelector('.tableList tbody');
            if(tbody){
                tbody.insertAdjacentHTML('beforeend', tr_org(m)); }}


        function tr_org(index){
            let tr_text=
                '<tr class="history">'+
                '<td><p class="profThmb"><a class="thumb">'+ SVG_user +'</a></p></td>'+
                '<td class="rdrCmnt"><p class="name">'+
                '<a target="_blank" href="https://profile.ameba.jp/ameba/'+ readers[index][0] +
                '">'+ readers[index][0] +'</a>さん</p>'+
                '<a class="blogLink"></a><span>'+ readers[index][1] +'</span></td>'+
                '<td class="openRow"></td>'+
                '<td class="closeRow">'+
                '<input type="button" value="履歴削除" class="btnDelete AR">'+
                '<input type="button" value="" class="color btn">'+
                '</td></tr>';

            return tr_text; }

    } // insert(n)
} // disp_datalist()



function database_close(){
    let thead_AR=document.querySelector('.thead_AR');
    if(thead_AR){
        thead_AR.remove(); }

    let table_tr=document.querySelectorAll('.tableList tbody tr');
    for(let k=0; k<table_tr.length; k++){
        if(table_tr[k].classList.contains('history')){
            table_tr[k].remove(); }
        else{
            let c_button=table_tr[k].querySelector('.color.btn');
            if(c_button){
                c_button.remove(); }}}}



function set_color(flag){
    if(flag=='0'){
        return '#fff'; }
    if(flag=='1'){
        return '#fe0'; }
    else{
        return '#d6fed8' }}



function change_color(){
    let table_tr=document.querySelectorAll('.tableList tbody tr');
    for(let k=0; k<table_tr.length; k++){
        let name=table_tr[k].querySelector('.name a').textContent;
        let c_button=table_tr[k].querySelector('.color.btn');

        if(c_button){
            c_button.onclick=function(){
                tr_color(name);
                disp_list(); }}}

    function tr_color(name_){
        for(let i=0; i<readers.length; i++){
            if(name_==readers[i][0]){
                readers[i][2]=((readers[i][2]+1)%3).toString();
                write_local(); }}}
} // change_color()



function remove_data(){
    let table_tr=document.querySelectorAll('.tableList tbody tr');
    for(let k=0; k<table_tr.length; k++){
        let name=table_tr[k].querySelector('.name a').textContent;
        let d_button=table_tr[k].querySelector('.btnDelete.AR');

        if(d_button){
            d_button.onclick=function(){
                off_history(name); }}}

    function off_history(name_){
        for(let i=0; i<readers.length; i++){
            if(name_==readers[i][0]){
                let result=window.confirm(
                    '💢 この行のユーザーは、現在はフォロワーではありません。\n'+
                    '   「履歴削除」を実行すると、このユーザーを追跡する\n'+
                    '   情報は 完全にクリアーされます。\n\n'+
                    '   履歴削除をする場合は「OK」をクリックしてください。');
                if(result){
                    readers.splice(i, 1);
                    write_local();
                    window.location.reload(true); }}}}

} // remove_data()



function AR_backup(){
    let exp=document.querySelector('#inner_AR2 .export');
    let imp=document.querySelector('#inner_AR2 .import');
    let file_input=document.querySelector('#inner_AR2 .file_input');

    if(exp){
        exp.onclick=function(){
            let write_json=JSON.stringify(readers); //「フォロワー履歴」を書出す
            let blob=new Blob([write_json], {type: 'application/json'});

            let a_elem=document.createElement('a');
            a_elem.href=URL.createObjectURL(blob);
            a_elem.download='auth_reader_'+ UserID +'.json'; // 保存ファイル名
            a_elem.click();
            URL.revokeObjectURL(a_elem.href); }}



    if(imp && file_input){
        imp.onclick=function(){
            file_input.click(); }

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

            if(file.name.startsWith('auth_reader')){ // ファイル名の確認
                let file_reader=new FileReader();
                file_reader.readAsText(file);
                file_reader.onload=function(){
                    let data_in=JSON.parse(file_reader.result);
                    add_readers(data_in);//「フォロワー履歴」の統合
                    write_local(); // ローカルストレージに保存
                    database_close();
                    setTimeout(()=>{
                        alert(
                            "✅ フォロワー履歴データを読込みました\n"+
                            "   読込んだファイル名: " + file.name);
                        window.location.reload(true);
                    }, 200); }}
            else{
                alert(
                    "❌ Authentic Reader の Exportファイルではありません\n"+
                    "   Importファイルは「auth_reader ... 」の名前です"); }
        }); }


    function add_readers(data){
        for(let d=0; d<data.length; d++){
            compare(data[d]); }

        function compare(data_){
            let count=0;
            for(let i=0; i<readers.length; i++){
                if(data_[0]==readers[i][0]){
                    count+=1;
                    // 日付が新しい場合のみ上書き
                    if(data_[1].replace(/[^0-9]/g, '')*1>readers[i][1].replace(/[^0-9]/g, '')*1){
                        readers[i][1]=data_[1];
                        readers[i][2]=data_[2]; }}}
            if(count==0){
                readers.push(data_); }}}


} // AR_backup()


 

 

 

「Authentic Reader」最新版について 

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

 

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