dA_Sidebar2

Track /watch count on all sites. See /watch counts in /watch menu and button

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         dA_Sidebar2
// @namespace    phi.pf-control.de/userscripts/dA_Sidebar2
// @version      1.1
// @description  Track /watch count on all sites. See /watch counts in /watch menu and button
// @author       Dediggefedde
// @include      *
// @grant        GM.xmlHttpRequest
// @grant        GM.setValue
// @grant        GM.getValue
// @grant        GM.addStyle
// ==/UserScript==

//TODO
//GUI settings (CD time), 2 places: dA settings, dialog
//option visible: sidebar, watchcnt, watchbut, actcnt

(function() {
    'use strict';
    // @match        https://www.deviantart.com/notifications/watch*
    let lastReqTime = 0;
    let settings = {
        reqCoolDown: 1 * 60, //min time between requests, seconds, default 1min
        showWatchCnt: true,
        showWatchBtn: true,
        showActivityCnt: true,
        showSidebar: true
    };
    let dAObjects = {
        "all": { url: "", urlCat: "watch", button: "all", sidebar: "🔔 Activity", folder: "root", link: "#all" },
        "deviations": { url: "deviations", urlCat: "watch", button: "^deviations$", sidebar: "🎨 Deviations", folder: "all", link: "/deviations" },
        "journals": { url: "journals", urlCat: "watch", button: "(journals|posts)", sidebar: "🧾 Journals", folder: "all", link: "/journals" },
        "groupDeviations": { url: "groupDeviations", urlCat: "watch", button: "group deviations", sidebar: "🗫 Group", folder: "all", link: "/groupdeviations" },
        "polls": { url: "polls", urlCat: "watch", button: "(polls|posts)", sidebar: "📊 Polls", folder: "all", link: "/polls" },
        "forums": { url: "forums", urlCat: "watch", button: "forums", sidebar: "💬 Forums", folder: "all", link: "/forums" },
        "commissions": { url: "commissions", urlCat: "watch", button: "commissions", sidebar: "🛒 Commissions", folder: "all", link: "/commissions" },
        "status": { url: "status", urlCat: "watch", button: "(status updates|posts)", sidebar: "⏰ Status", folder: "all", link: "/status" },
        "misc": { url: "misc", urlCat: "watch", button: "misc.", sidebar: "🧸 Misc.", folder: "all", link: "/miscellaneous" },
        "feedback": { url: "", urlCat: "feedback", button: "all", sidebar: "📬 Feedback", folder: "root", link: "#feed" },
        "comments": { url: "comments", urlCat: "feedback", button: "comments", sidebar: "📝 Comments", folder: "feedback", link: "/comments" },
        "replies": { url: "replies", urlCat: "feedback", button: "replies", sidebar: "🗐 Replies", folder: "feedback", link: "/replies" },
        "mentions": { url: "mentions", urlCat: "feedback", button: "mentions", sidebar: "📣 Mentions", folder: "feedback", link: "/mentions" },
        "activity": { url: "activity", urlCat: "feedback", button: "activity", sidebar: "🚀 Activity", folder: "feedback", link: "/activity" },
        "correspondence": { url: "correspondence", urlCat: "feedback", button: "correspondence", sidebar: "📚 Correspondence", folder: "feedback", link: "/correspondence" },
    };

    let tmpCounter = {};
    let counter = {}; //website button text : counter
    Object.keys(dAObjects).forEach(function(key, index) { //reset counter
        tmpCounter[key] = 0;
        counter[key] = 0;
    });

    let watchDropDown;
    let footer;
    let settingDiag;

    //deviatnart API request, recursive for offset, type one of types-keys.
    //Promise and updates counter and lastReqTime
    function updateMessages(objKey, offset = 0) {
        let murl = "https://www.deviantart.com/_napi/da-messagecentre/api/" + dAObjects[objKey].urlCat + "?limit=24&messagetype=" + dAObjects[objKey].url + "&offset=" + offset; //
        return new Promise(function(resolve, reject) {
            lastReqTime = (new Date()).getTime() / 1e3;
            GM.setValue("lastReqTime", lastReqTime);
            if (dAObjects[objKey].url == "") {
                return resolve();
            }
            GM.xmlHttpRequest({
                method: "GET",
                url: murl,
                onerror: function(response) {
                    return reject(response);
                },
                onload: function(response) {
                    try {
                        if (response.status == 200) {
                            let l = JSON.parse(response.responseText)
                            let total = 0;

                            if (!l.settings.stacked) {
                                total = parseInt(l.counts.total);
                                tmpCounter[objKey] += total;
                                if (dAObjects[objKey].folder != "root") {
                                    tmpCounter[dAObjects[objKey].folder] += total;
                                }
                                return resolve();
                            } else {
                                l.results.forEach(el => {
                                    if (el.hasOwnProperty("stackCount")) {
                                        total += parseInt(el.stackCount);
                                    } else {
                                        ++total;
                                    }
                                });

                                tmpCounter[objKey] += total;

                                if (dAObjects[objKey].folder != "root") {
                                    tmpCounter[dAObjects[objKey].folder] += total;
                                }

                                if (l.hasMore == true) {
                                    updateMessages(objKey, offset + 24).then(() => { return resolve() });
                                    return;
                                }
                                return resolve();
                            }
                            return;
                        }
                        return reject(response);
                    } catch (ex) {
                        console.log(ex);
                        return reject(response);
                    }
                }
            });
        });
    }
    //helper: get DOM matching selector and textContent
    function getElementsByText(selector, tex) {
        let rex = new RegExp("^" + tex + "$", "i");
        return Array.prototype.slice.call(document.querySelectorAll(selector)).filter(function(el) {
            return rex.test(el.innerHTML);
            //return el.textContent.toLowerCase() ===tex;
        })
    }
    //helper: only overwrites present object members
    function updateObject(oldObj, newObj) {
        Object.keys(oldObj).forEach((key, ind) => { //backward compatibility in case settings change
            if (newObj.hasOwnProperty(key)) {
                oldObj[key] = newObj[key];
            }
        });
        return oldObj;
    }

    //cls: style. string for classname, object for copy computated font properties.
    function createCntEl(id, cnt, cls) {
        let newel = document.createElement("span"); //add span with count
        if (typeof cls == "string") {
            newel.className = cls;
        } else {
            let sty = window.getComputedStyle(cls, null);
            Object.values(sty).filter(re => { return re.includes("font") }).forEach(key => {
                newel.style[key] = sty[key];
            });
            newel.style.color = sty.getPropertyValue("color");
        }
        newel.classList.add("dASidebar2_cnt");
        newel.setAttribute("dASidebar2_span", id);
        newel.setAttribute("cnt", cnt); //dAObjects shares key with counter
        newel.innerHTML = "(" + cnt + ")";
        return newel;
    }

    function updateCntEl(cntEl, cnt) {
        if (parseInt(cntEl.getAttribute("cnt")) != cnt) {
            cntEl.innerHTML = " (" + cnt + ")";
            cntEl.setAttribute("cnt", cnt);
            cntEl.classList.add("dASidebar2_updated");
            updateSidebar();
        }
    }

    function updateSidebar() {
        if (!footer) return;
        footer.classList.add("dASidebar2_alarm");
    }
    //update dA DOM buttons to show the numbers
    //expects counter[] to be filled correctly
    function updateDOM() {
        if (settings.showWatchCnt && /https:\/\/www\.deviantart\.com.*/.test(location.href)) {
            newWatchButton();
        }
        if (settings.showWatchBtn && /https:\/\/www\.deviantart\.com\/notifications\/watch.*/.test(location.href)) {
            newWatchMenu();
        }
        if (settings.showActivityCnt && /https:\/\/www\.deviantart\.com\/notifications\/feedback.*/.test(location.href)) {
            newFeedbackMenu()
        }
        if (settings.showSidebar && !/https:\/\/www\.deviantart\.com.*/.test(location.href) && window.top == window.self) {
            newSideBar();
        }
    }

    function newWatchButton() {
        let tarbut = getElementsByText("header a", "watch");
        if (tarbut.length == 0) return;
        tarbut = tarbut[0];
        if (tarbut.getAttribute("dASidebar2_button")) {
            updateCntEl(tarbut.parentNode.querySelector("span.dASidebar2_cnt"), counter.all);
        } else {
            tarbut.setAttribute("dASidebar2_button", 1);
            tarbut.parentNode.insertBefore(createCntEl("all", counter.all, tarbut), tarbut.nextSibling);
            tarbut.parentNode.style["white-space"] = "nowrap";

            watchDropDown = document.createElement("div");
            watchDropDown.id = "dASidebar2_DDWrap";
            Object.keys(dAObjects).filter(key => { return dAObjects[key].urlCat == "watch" }).forEach(key => {
                let newel = document.createElement("div");
                newel.innerHTML = dAObjects[key].sidebar + " ";
                newel.setAttribute("dASidebar2_div", key);
                newel.appendChild(createCntEl(key, counter[key], ""));
                watchDropDown.appendChild(newel);
            });
            watchDropDown.style.display = "none";
            tarbut.parentNode.insertBefore(watchDropDown, tarbut.nextSibling);
        }
        watchDropDown.addEventListener("mouseenter", evt => {
            watchDropDown.style.display = "block";
        });
        watchDropDown.addEventListener("mouseleave", evt => {
            watchDropDown.style.display = "none";
        });
        watchDropDown.addEventListener("click", evt => { //delegation
            let key = evt.target.getAttribute("dASidebar2_div");
            if (!key || !Object.keys(dAObjects).includes(key)) return;
            window.location.href = "https://www.deviantart.com/notifications/watch" + dAObjects[key].link;
        });
        tarbut.addEventListener("mouseenter", evt => {
            watchDropDown.style.display = "block";
        });
        tarbut.parentNode.addEventListener("mouseleave", evt => {
            watchDropDown.style.display = "none";
        });
    }

    function newWatchMenu() {
        if (getElementsByText("button", "deviations").length == 0) {
            return;
        }
        Object.keys(dAObjects).reverse().filter(key => { return dAObjects[key].urlCat == "watch" }).forEach(key => {
            let tbuts = getElementsByText("button,span", dAObjects[key].button); //terrible deviantart Dom structure
            tbuts.forEach(tarbut => {
                if (tarbut.getAttribute("dASidebar2_button")) return;
                tarbut.setAttribute("dASidebar2_button", 1);
                tarbut.parentNode.insertBefore(createCntEl(key, counter[key], tarbut.className), tarbut.nextSibling);
                tarbut.parentNode.style["white-space"] = "nowrap";
            });
            document.querySelectorAll("[dASidebar2_span='" + key + "']").forEach(newel => {
                updateCntEl(newel, counter[key]);
            });
        });
    }

    function newFeedbackMenu() {
        if (getElementsByText("button", "comments").length == 0) {
            return;
        }
        //console.log(counter);
        Object.keys(dAObjects).reverse().filter(key => { return dAObjects[key].urlCat == "feedback" }).forEach(key => {
            let tbuts = getElementsByText("button,span", dAObjects[key].button); //terrible deviantart Dom structure
            tbuts.forEach(tarbut => {
                if (tarbut.getAttribute("dASidebar2_button")) return;
                tarbut.setAttribute("dASidebar2_button", 1);
                tarbut.parentNode.insertBefore(createCntEl(key, counter[key], tarbut.className), tarbut.nextSibling);
                tarbut.parentNode.style["white-space"] = "nowrap";
            });
            document.querySelectorAll("[dASidebar2_span='" + key + "']").forEach(newel => {
                updateCntEl(newel, counter[key]);
            });
        });
    }

    function newSideBar() {
        let but, subbut, subel;
        if (!footer) {
            footer = document.createElement("div");
            footer.id = "dA_sidebar2_footer";
            Object.keys(dAObjects).filter(key => { return dAObjects[key].folder == "root"; }).forEach(key => {
                but = document.createElement("div");
                but.innerHTML = dAObjects[key].sidebar;
                but.className = "dA_sidebar2_rootmenu";
                but.appendChild(createCntEl(key, counter[key], ""));
                subbut = document.createElement("div");
                subbut.className = "dA_sidebar2_submenu";
                subbut.style.display = "none";
                subbut.setAttribute("folder", key);
                Object.keys(dAObjects).filter(skey => { return dAObjects[skey].folder == key; }).forEach(skey => {
                    subel = document.createElement("a");
                    subel.href = "https://www.deviantart.com/notifications/" + dAObjects[skey].urlCat + dAObjects[skey].link;
                    subel.title = dAObjects[skey].url;
                    subel.innerHTML = dAObjects[skey].sidebar;
                    subel.appendChild(createCntEl(skey, counter[skey], ""));
                    subbut.appendChild(subel);
                });
                but.appendChild(subbut);
                footer.appendChild(but);
                but.addEventListener("mouseenter", evt => {
                    evt.target.querySelector("div.dA_sidebar2_submenu").style.display = "block";
                });
                but.addEventListener("mouseleave", evt => {
                    evt.target.querySelector("div.dA_sidebar2_submenu").style.display = "none";
                });
            });
            but = document.createElement("div");
            but.innerHTML = "🔧";
            but.title = "Settings";
            but.className = "dA_sidebar2_rootmenu";
            but.style = "cursor:pointer";
            but.addEventListener("click", ev => {
                if (settingDiag) {
                    settingDiag.style.display = "";
                }
            });
            footer.appendChild(but);
            document.body.appendChild(footer);

            settingDiag = document.createElement("div");
            settingDiag.innerHTML = `
			<div>Setting</div>
			<label for="dASidebar2_ReqCD">Request Cooldown (minutes)</label>
			<input type="text" id="dASidebar2_ReqCD" value="${settings.reqCoolDown/60}" />
			<label for="dASidebar2_WatchBtn">Show counter next to Watch-button</label>
			<input type="checkbox" id="dASidebar2_WatchBtn" ${settings.showWatchBtn?"checked":""} />
			<label for="dASidebar2_WatchCnt">Show counters in Watch-menu</label>
			<input type="checkbox" id="dASidebar2_WatchCnt" ${settings.showWatchCnt?"checked":""} />
			<label for="dASidebar2_ActCnt">Show counters in Feedback-menu</label>
			<input type="checkbox" id="dASidebar2_ActCnt" ${settings.showActivityCnt?"checked":""} />
			<label for="dASidebar2_ShowSide">Show Sidebar</label>
			<input type="checkbox" id="dASidebar2_ShowSide" ${settings.showSidebar?"checked":""} />
			<button type="button" id="dASidebar2_SaveSet">Save</button>
			`;
            settingDiag.className = "dASidebar2_settings";
            settingDiag.style.display = "none";
            document.body.appendChild(settingDiag);
            document.getElementById("dASidebar2_SaveSet").addEventListener("click", evt => {
                evt.preventDefault();
                evt.stopPropagation();
                settingDiag.style.display = "none";

                settings.reqCoolDown = parseInt(document.getElementById("dASidebar2_ReqCD").value) * 60;
                settings.showWatchBtn = document.getElementById("dASidebar2_WatchBtn").checked;
                settings.showWatchCnt = document.getElementById("dASidebar2_WatchCnt").checked;
                settings.showActivityCnt = document.getElementById("dASidebar2_ActCnt").checked;
                settings.showSidebar = document.getElementById("dASidebar2_ShowSide").checked;
                GM.setValue("settings", JSON.stringify(settings));
            });

        } else {
            Object.keys(counter).forEach(key => {
                footer.querySelectorAll("[dASidebar2_span='" + key + "']").forEach(newel => {
                    updateCntEl(newel, counter[key]);
                });
            });
        }

    }


    //requests API for /watch numbers
    function updateAllNumbers() {
        let reqChain = []; //promise array
        tmpCounter = {};
        Object.keys(dAObjects).forEach(function(key, index) {
            reqChain.push(updateMessages(key)); //new promises for request
            tmpCounter[key] = 0; //reset counter
        });

        Promise.all(reqChain).then(ev => { //execute requests
            GM.setValue("counter", JSON.stringify(tmpCounter)); //save result
            counter = tmpCounter; //overwrite local counter
            updateDOM(); //update display
        }).catch(ex => { console.log(ex); });

    }

    function insertSettingMenu() {
        let setMenuCont = document.getElementById("settings_public").parentNode; //li element
        let newMen = document.createElement("li");
        newMen.innerHTML = "<a>dA_Sidebar2</a>";
        newMen.style = "cursor:pointer";
        newMen.addEventListener("click", evt => {
            evt.stopPropagation();
            evt.preventDefault();
            document.querySelectorAll("ul.menu_holder a.active").forEach(el => { el.classList.remove("active"); });
            evt.target.classList.add("active");
            document.querySelector("div.settings_form").innerHTML = `
					<div class="fooview ch dA_Sidebar2_dAsettings">
						<div class="fooview-inner">
							<h3>dA_Sidebar2 Settings</h3>
							<div class="altaltview altaltview-wider">
								<div class="row">
									<div class="browse-sitback row">
										<input type="text" id="dASidebar2_ReqCD" value="${settings.reqCoolDown/60}" />
										<label for="dASidebar2_ReqCD" class="l">Cooldown</label><br/>
										 <small>Request Cooldown (in minutes)</small>
									</div>
									<div class="browse-sitback row">
										<input type="checkbox" id="dASidebar2_WatchBtn" ${settings.showWatchBtn?"checked":""} />
										<label for="dASidebar2_WatchBtn" class="l">watch button</label><br/>
										<small>Show counter next to Watch-button</small>
									</div>
									<div class="browse-sitback row">
										<input type="checkbox" id="dASidebar2_WatchCnt" ${settings.showWatchCnt?"checked":""} />
										<label for="dASidebar2_WatchCnt" class="l">Watch counters</label><br/>
										<small>Show counters in Watch-menu</small>
									</div>
									<div class="browse-sitback row">
										<input type="checkbox" id="dASidebar2_ActCnt" ${settings.showActivityCnt?"checked":""} />
										<label for="dASidebar2_ActCnt" class="l">Feedback Counters</label><br/>
										<small>Show counters in Feedback-menu</small>
									</div>
									<div class="browse-sitback row">
										<input type="checkbox" id="dASidebar2_ShowSide" ${settings.showSidebar?"checked":""} />
										<label for="dASidebar2_ShowSide" class="l">Sidebar</label><br/>
										<small>Show sidebar on other websites</small>
									</div>
									<div class="browse-sitback row">
										<div class=" buttons ch hh " id="submit">
											<div style="text-align:right" class="rr">
												<a class="smbutton smbutton-green" href="javascript:void(0)">
													<span id="dASidebar2_savesettings">Save</span>
												</a>
											</div>
										</div>
									</div>
								</div>
							</div>
						</div>
					</div>`.replace(/\s\s+/, "");
            document.getElementById("dASidebar2_savesettings").addEventListener("click", evt => {
                evt.preventDefault();
                evt.stopPropagation();

                settings.reqCoolDown = parseInt(document.getElementById("dASidebar2_ReqCD").value) * 60;
                settings.showWatchBtn = document.getElementById("dASidebar2_WatchBtn").checked;
                settings.showWatchCnt = document.getElementById("dASidebar2_WatchCnt").checked;
                settings.showActivityCnt = document.getElementById("dASidebar2_ActCnt").checked;
                settings.showSidebar = document.getElementById("dASidebar2_ShowSide").checked;
                GM.setValue("settings", JSON.stringify(settings));

                alert("dA_Sidebar2 settings saved!");
            })
        });
        setMenuCont.parentNode.insertBefore(newMen, setMenuCont.nextSibling);
    }

    //changing dA DOM using js requires periodic check of DOM
    //watchdog checks once a second
    function watchdog() {
        GM.getValue("lastReqTime", 0).then(t => {
            lastReqTime = t;
            if (t == 0 || (new Date()).getTime() / 1e3 - lastReqTime > settings.reqCoolDown) { //Check request cooldown
                updateAllNumbers();
            } else { //update dom without request (js navigation, update in different tab)
                GM.getValue("counter", "{}").then(cnt => { //use counter from last request
                    let newCnt = JSON.parse(cnt);
                    counter = updateObject(counter, newCnt);
                    updateDOM();
                });
            }
        });
    }

    //script start
    GM.addStyle(`
    #dA_sidebar2_footer{
		position:fixed;
		bottom:0;
		margin:0;
		left:2px;
        height:25px;
		background-color:#ffd;
		border-radius:5px;
		border: 1px solid black;
        z-index:7777777;
		transform:translateY(90%);
		transition: 0.5s ease-in-out;
        color:#002;
		font-family: Verdana, serif;
		font-size:10pt;
		user-select:none;
    }
    #dA_sidebar2_footer *{
        font-style :normal;
        font-variant: normal;
        font-weight:normal;
        line-height:1em;
        letter-spacing:normal;
    }
    #dA_sidebar2_footer:hover{
		transform:translateY(0%);
		transition: 0.2s ease-in-out;
	}
    #dA_sidebar2_footer div.dA_sidebar2_rootmenu {
		padding: 4px;
		margin: 0;
		display:inline-block;
		position:relative;
	}
    #dA_sidebar2_footer div.dA_sidebar2_submenu {
		position: absolute;
		bottom: 22px;
		left: 0;
		background-color: wheat;
		border: 1px solid black;
		box-shadow: 1px 1px 2px black;
		border-radius: 10px;
		white-space: nowrap;
	}
    #dA_sidebar2_footer div.dA_sidebar2_submenu a{
		text-decoration:none;
		color:black;
		display:block;
		padding: 5px;
	}
    #dA_sidebar2_footer div.dA_sidebar2_submenu a:hover{
		color:grey;
	}
    .dASidebar2_updated{
		color:red;
	}
    .dASidebar2_cnt{
		margin-left:5px;
	}
	#dASidebar2_DDWrap{
		top:52px;
		background-color:white;
		position:absolute;
		box-shadow: 1px 1px 5px rgba(0,0,0,0.6);
		border: 1px solid black;
		border-radius: 10px;
		white-space: nowrap;
        color:rgb(6, 7, 13);
	}
    #dASidebar2_DDWrap>div{
		padding:7px;
		display:block;
		cursor:pointer;
    }
    #dASidebar2_DDWrap>div:hover{
		color:#050;
        text-decoration:underline;
    }
	#dASidebar2_DDWrap span{
		color:black
	}
    div.dASidebar2_alarm{
   		animation: blink 1s ease-in-out alternate infinite;
    }
    @keyframes blink {
    	0% {
			box-shadow: 0 0 15px 5px rgba(255,0,0,0);
  		}
   		100% {
    		box-shadow: 0 0 15px 5px rgba(255,0,0,1);
  		}
    }
	div.dASidebar2_settings {
		position: fixed;
		z-index: 777777;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		background-color: #fffddd;
		border: 1px solid black;
		border-radius: 5px;
		padding: 5px;
		display: grid;
		grid-template-columns: auto auto;
		grid-gap: 10px;
		justify-items: stretch;
		align-items: center;
        box-shadow: 1px 1px 5px rgba(0,0,0,0.5);
	}
    div.dASidebar2_settings *{
		color:#002;
		font-family: Verdana, serif;
		font-size:10pt;
        font-style :normal;
        font-variant: normal;
        font-weight:normal;
        line-height:1em;
        letter-spacing:normal;
    }
	div.dASidebar2_settings input{
		justify-self:center;
    }
	div.dASidebar2_settings input,div.dASidebar2_settings label, div.dASidebar2_settings button {
		cursor:pointer;
	}
	div.dASidebar2_settings * {
		margin: 0;
		padding: 0;
	}
	#dASidebar2_ReqCD{
		width:40px;
        height:1.5em;
		text-align:center;
		cursor:text;
	}
	div.dASidebar2_settings div{
		grid-column:span 2;
		font-size:14pt;
		text-align: center;
	}
	div.dASidebar2_settings button{
		grid-column:span 2;
        background-color: #adffad;
        border-radius: 10px;
        width: 80%;
        margin: auto;
        padding: 5px;
	}
	div.dASidebar2_settings button:hover{
        background-color: #2edb75;
	}
	div.dA_Sidebar2_dAsettings intput, div.dA_Sidebar2_dAsettings labels{
		cursor:pointer;
	}
	`)
    GM.getValue("settings", "{}").then(set => { //load settings, then do stuff
        let newSet = JSON.parse(set);
        settings = updateObject(settings, newSet); //backward compatibility in case settings change

        if (!settings.showSidebar && !/deviantart.com/.test(location.href)) {
            return;
        }
        if (/deviantart.com\/settings/.test(location.href)) {
            insertSettingMenu();
        }
        setInterval(watchdog, 1000); //start watchdog

        let forceNavi = location.href.match(/https:\/\/www\.deviantart\.com\/notifications\/watch.*#(.*)/i);
        if (forceNavi != null) {
            if (forceNavi[1] == "all") getElementsByText("button", "all")[0].click()
        }
    });

})();