NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Feedly Switch Theme // @namespace https://openuserjs.org/users/burn // @version 0.2.7 // @description Changes the theme based on times you set // @author Burn // @copyright 2021, burn (https://openuserjs.org/users/burn) // @license LGPL-3.0-or-later // @updateURL https://openuserjs.org/meta/burn/Feedly_Switch_Theme.meta.js // @downloadURL https://openuserjs.org/install/burn/Feedly_Switch_Theme.user.js // @match https://feedly.com/* // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js // @grant GM_getValue // @grant GM_setValue // @grant GM_deleteValue // @grant GM.getValue // @grant GM.setValue // @grant GM.deleteValue // ==/UserScript== /*jshint esversion: 8 */ (async function() { 'use strict'; let DBG = false, timeNow = new Date(), storeName = "FeedlySwitchTheme", lightTheme = { timeStart : new Date(timeNow.getFullYear(), timeNow.getMonth(), timeNow.getDate(), 8, // hours 0, // minutes 0), //seconds timeEnd : new Date(timeNow.getFullYear(), timeNow.getMonth(), timeNow.getDate(), 18, 0, 0), cssClass: 'theme--light' }, darkTheme = { timeStart : new Date(timeNow.getFullYear(), timeNow.getMonth(), timeNow.getDate(), 18, 0, 0), timeEnd : new Date(timeNow.getFullYear(), timeNow.getMonth(), timeNow.getDate() + 1, 8, 0, 0), cssClass: 'theme--dark' }, buttonSwitch = '[aria-label="Switch Between Themes"]', observerConfig = { attributes: false, childList: true, subtree: true }, spy = 0; // helpers functions let log = s => { return (DBG && console.log('|burn| ' + s)); }, qSel = (q, c) => { let d = (typeof c === 'object') ? c : document; return d.querySelector(q) || false; }, qSelAll = (q, c) => { let d = (typeof c === 'object') ? c : document; return d.querySelectorAll(q) || false; }, serialize = (name, val) => { GM.setValue(name, JSON.stringify(val)); }, deserialize = async (name, def) => { log('in serialize'); def = def || '{}'; let tmpOut = await GM.getValue(name, def); log("deserialize: " + tmpOut); return JSON.parse(tmpOut); }, delayClick = (targetEl) => { setTimeout(() => { log('in delayClick'); targetEl.click(); }, 500); }; function callback(mutationsList, observer) { mutationsList.forEach(mutation => { let entry = { mutation: mutation, el: mutation.target, value: mutation.target.textContent, oldValue: mutation.oldValue }; //log(entry.el); if (false !== qSel(buttonSwitch, entry.el) && spy === 0) { log('found button element'); if (timeNow >= lightTheme.timeStart && timeNow < lightTheme.timeEnd) { log('times OK, checking current theme'); if (document.body.classList.contains(darkTheme.cssClass)) { log('setting light theme'); spy = 1; delayClick(qSel(buttonSwitch, entry.el)); observer.disconnect(); } } else { if (document.body.classList.contains(lightTheme.cssClass)) { log('setting dark theme'); spy = 1; delayClick(qSel(buttonSwitch, entry.el)); observer.disconnect(); } else { log('dark theme found, exiting'); } } } }); // end foreach } // end callback let observer = new MutationObserver(callback); observer.observe(document.body, observerConfig); })();