F-List log saver

A simple script to add buttons on login that let you save and load logs into your browser storage.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         F-List log saver
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  A simple script to add buttons on login that let you save and load logs into your browser storage.
// @author       DD
// @match        https://www.f-list.net/chat3/
// @grant        none
// ==/UserScript==


(function() {
    const userscript = document.createElement("script");
    userscript.innerHTML = `
const saveLogs=() => {
    //////////////////////////////////////////////////////////////////////////
    // Parse Local Storage
    //////////////////////////////////////////////////////////////////////////
    const keyList = Object.keys(window.localStorage);
    let storageContent = [];
    let completeJSON = {saved_dbs: {}};

    for(let key of keyList){
        storageContent.push(JSON.parse('{ "key":"' + key + '", "value":"" }'))
    }

    for(let key of storageContent){
        key.value = JSON.parse(window.localStorage.getItem(key.key));
    }

    completeJSON.saved_dbs.local_storage = storageContent;

    //////////////////////////////////////////////////////////////////////////
    // Parse IndexedDB
    //////////////////////////////////////////////////////////////////////////
    storageContent = {};
    let databaseLoopIndex = 0;
    indexedDB.databases().then(databaseList =>{
        for(let database of databaseList){
            const dataBaseLoop=(db, index)=>{
                let dbConnection;
                let request = window.indexedDB.open(db.name, db.version);
                request.onerror=(event) =>{
                    console.log('Error on connect to "'+db.name+'" : ' + event.target.errorCode);
                };
                request.onsuccess=(event) =>{
                    dbConnection = event.target.result;
                    console.log('Connection to "'+db.name+'" established!');
                    let databaseObject = {};

                    let storeIndex = 0;
                    for(let storeName of dbConnection.objectStoreNames){

                        const objectStoreLoop=(pStoreName, pStoreIndex, databaseIndex)=>{
                            databaseObject[pStoreName] = [];
                            let transaction = dbConnection.transaction([pStoreName]);

                            transaction.oncomplete=(event) =>{
                                console.log('Transaction finished on "' + pStoreName);
                                if(pStoreIndex === dbConnection.objectStoreNames.length - 1 &&
                                    databaseIndex === databaseList.length - 1){

                                    function downloadObjectAsJson(exportObj, exportName){
                                        var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj));
                                        var downloadAnchorNode = document.createElement('a');
                                        downloadAnchorNode.setAttribute("href", dataStr);
                                        downloadAnchorNode.setAttribute("download", exportName + ".json");
                                        document.body.appendChild(downloadAnchorNode); // required for firefox
                                        downloadAnchorNode.click();
                                        downloadAnchorNode.remove();
                                        console.log("Saved successfully!")
                                    }
                                    console.log(completeJSON);
                                    downloadObjectAsJson(completeJSON, "f-list-log");
                                }
                            };

                            transaction.onerror=(event)=>{
                                console.log('Transaction-Error: ' + event.target.errorCode);
                            };

                            transaction.objectStore(pStoreName).getAll().onsuccess=(event) =>{
                                databaseObject[pStoreName] = event.target.result;
                            }
                        }

                        objectStoreLoop(storeName, storeIndex, index);
                        storeIndex++;
                    };
                    storageContent[db.name] = databaseObject;
                };
            }
            dataBaseLoop(database, databaseLoopIndex);
            databaseLoopIndex++;
        }
    });
    completeJSON.saved_dbs.indexed_db = storageContent;
}

const loadLogs=(e)=>{
    const file = e.target.files[0];
    if (!file) {
        return;
    }
    const reader = new FileReader();
    reader.onload = function(e) {
        const contents = e.target.result;
        const totalJSONObject = JSON.parse(contents);
        console.log(totalJSONObject);

        //////////////////////////////////////////////////////////////////////////
        // load Local Storage
        //////////////////////////////////////////////////////////////////////////
        for(let entry of totalJSONObject.saved_dbs.local_storage){
            window.localStorage.setItem(entry.key, JSON.stringify(entry.value));
        }
        //////////////////////////////////////////////////////////////////////////
        // load IndexedDB
        //////////////////////////////////////////////////////////////////////////
        let databaseLoopIndex = 0;
        const databaseList = Object.keys(totalJSONObject.saved_dbs.indexed_db);
        // Need to parse the datestrigns properly into dates
        for(let databaseName of databaseList){
            for(let entry of totalJSONObject.saved_dbs.indexed_db[databaseName].logs){
                entry.time = new Date(entry.time);
            }
        }

        console.log(totalJSONObject);

        for(let database of databaseList){
            const dataBaseLoop=(dbName)=>{
                let request = window.indexedDB.open(dbName, 1);
                request.onerror=(event) =>{
                    console.log('Error on connect to "'+dbName+'" : ' + event.target.errorCode);
                };
                request.onsuccess=(event) =>{
                    const dbConnection = event.target.result;
                    console.log('Connection to "'+dbName+'" established!');

                    let storeIndex = 0;
                    for(let storeName of dbConnection.objectStoreNames){

                        const objectStoreLoop=(pStoreName)=>{
                            const transaction = dbConnection.transaction(pStoreName, "readwrite");

                            transaction.oncomplete=(event) =>{
                                console.log('Transaction finished on "' + pStoreName);
                            };

                            transaction.onerror=(event)=>{
                                console.log('Transaction-Error: ' + event.target.errorCode);
                            };

                            // transaction.objectStore(pStoreName).getAll().onsuccess=(event) =>{
                            // }
                            const objectStoreArray = totalJSONObject.saved_dbs.indexed_db[dbName][pStoreName];
                            let objectStore = transaction.objectStore(pStoreName);
                            objectStoreArray.forEach(element => {
                                objectStore.put(element).onsuccess=(event) => {}
                            });

                        }
                        objectStoreLoop(storeName);
                        storeIndex++;
                    };
                };
                request.onupgradeneeded=(event) => {
                    const dbConnection = event.target.result;
                    dbConnection.createObjectStore("conversations", {autoIncrement: true, keyPath: "id"});

                    const objectStore = dbConnection.createObjectStore("logs", {autoIncrement: true, keyPath: "id"});
                    objectStore.createIndex("conversation", "conversation", {unique: false});
                    objectStore.createIndex("conversation-day", ["conversation", "day"], {unique: false});
                }
            }
            dataBaseLoop(database);
            databaseLoopIndex++;
        }
    };
    reader.readAsText(file);
}

//////////////////////////////////////////////////////////////////////////
// Insert buttons
//////////////////////////////////////////////////////////////////////////
let cardHeader = document.getElementsByClassName("card-body")[0].childNodes[2];

// Execute the code only when connected
if(cardHeader){
    // Show the buttons on the page for Saving and Loading
    let btn_load = document.createElement("input");
    let btn_save = document.createElement("button");

    btn_save.setAttribute("class", "btn btn-primary");
    btn_save.innerText = "Save Logs";
    btn_save.setAttribute("onclick", "saveLogs()");
    cardHeader.appendChild(btn_save);

    // btn_load.setAttribute("class", "btn btn-primary");
    btn_load.innerText = "Load Logs";
    btn_load.setAttribute("type", "file");
    btn_load.setAttribute("id", "btn_load");
    cardHeader.appendChild(btn_load);

    document.getElementById('btn_load')
    .addEventListener('change', loadLogs, false);
}
`;
    document.getElementsByTagName("html")[0].appendChild(userscript);
})();