// ==UserScript== // @name AO3: Fic's Style, Blacklist, Bookmarks // @namespace https://github.com/Schegge // @version 3.2.1 // @description Change font, size, width, background... of a work + number of words for each chapter and estimated reading time + blacklist/savior: hide works that contain certains tags + fullscreen reading mode + bookmarks: save the position you stopped reading a fic // @author Schegge // @include http*://archiveofourown.org/* // @grant none // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjc0REE4QjE3Qjk1ODExRTY4MEZCQTc3RERGMTNGQ0Y0IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjc0REE4QjE4Qjk1ODExRTY4MEZCQTc3RERGMTNGQ0Y0Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NzREQThCMTVCOTU4MTFFNjgwRkJBNzdEREYxM0ZDRjQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NzREQThCMTZCOTU4MTFFNjgwRkJBNzdEREYxM0ZDRjQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz78uZUsAAACeUlEQVR42uxZvW7bMBCWDaFLuih9A3bJrqJLVhVdigwFZGQPIHdpO9aPYC+dGz1CNXXpEiFzFq0NMtjIE0QvYNQ9Bh+BA6Mf0rKkBuABHyxQJPHxdPfdSZ7sdjvvOdrUe6bmiDvijrgj7og/mn/oDX/4T7YMCAkhxLW0nJARNnzip+32v/H4N8KaEIHsipASBMYv2WHG9TizS3haEp1r96S3C8yRT+IdobTZfNLUq1Q89iYLQEJ6Nib8RCi8NjicfBKLsUJFhsUViCwxlrasSdlaMZaqJPi9YCSKljX8fjwG8YQl2Vs2nhusVXPCMYjHB9gjGJq4gNyV3oA2PVCYyFhd1BzK5OAm+dAL8RTarHs9NAiPUYirpFSkM+3+R8Pc2FSs7ZV4BG+XNbp93uD1gOn9fMgYF/BYpukyb5z+oihF2tozwh/CS8KtasBsKnUX4jFI5jXVUO3/G+V/jUPcE37hkCeEL6zqBkMQT2pKuj72gnBMmKEneYXQ+sAOnsLrcd/EY4RKFfFSG1dzC5C80/twliPGHvc7EC8aEm9TMX+F6zcNWp6bEtinrVUvATbW1N5GiG+pLKlpa+t3SMo2CQuZ3An2FsTbYHV/ZePtfT2+RgyvDKrig5a08wY9l8k+I49nfSSnSjSTzfUkTWqSr2ROWPalKklFkTHptZV9RYgENcks+lAVFacLizXqE4Qi9Bma7mmhJmrUqLPHA1S/fYyH1bGm2zxRPRun+AbKECFEBItDVVCKmnZUYG3I3kW5fUfneEM4xfyZTYfYRnxZ0SDxF+Mc30Sqkrgp0Y4I7wnXUJqN7WOcuP+AHHFH3BF3xB1xR9zC/gkwALX7mp/233xAAAAAAElFTkSuQmCC // @downloadURL none // ==/UserScript== (function() { // CSS changes function addCSS(id, css) { if (!document.querySelector('style#' + id)) { let style = document.createElement('style'); style.id = id; style.textContent = css; document.getElementsByTagName('head')[0].appendChild(style); } else { document.querySelector('style#' + id).textContent = css; } } // estimate reading time: 200 wpm function countTime(num) { let time = (parseInt(num, 10) / 200 / 60).toFixed(2).toString().split('.'); return (time[0] !== '0' ? time[0] + 'hr ' : '') + Math.round(parseInt(time[1], 10) / 100 * 60) + 'min'; } function getScroll() { return Math.max(document.documentElement.scrollTop, window.scrollY); } function setScroll(s) { window.scroll(0, s ? s : 0); } function getDocHeight() { return Math.max(document.documentElement.scrollHeight, document.documentElement.offsetHeight, document.body.scrollHeight, document.body.offsetHeight); } // BOOKMARKS var BM = []; var Bookmarks = { get: function() { if (localStorage.getItem('ficstyle_bookmarks')) BM = JSON.parse(localStorage.getItem('ficstyle_bookmarks')); }, set: function() { localStorage.setItem('ficstyle_bookmarks', JSON.stringify(BM)); }, getUrl: window.location.pathname.split('/works/')[1], getTitle: function() { let title = document.querySelector('#workskin .preface.group h2.title.heading').textContent; // cut long titles title = title.trim().substring(0, 28); // if chapter by chapter, get the number of the chapter if (this.getUrl.indexOf('chapters') !== -1) { let chapter = document.querySelector('#chapters > .chapter > .chapter.preface.group > h3 > a').textContent; chapter = chapter.replace('Chapter ', 'ch'); title += ' (' + chapter + ')'; } return title; }, getNewBook: function() { let newbook = getScroll(); // if chapter by chapter view or work completed (number/number is the same), calculate as a percent if (window.location.pathname.indexOf('chapters') !== -1 || /(\d+)\/\1/.test(document.querySelector('dl.stats dd.chapters').textContent)) { newbook = (newbook / getDocHeight()).toFixed(4) + '%'; } return newbook; }, checkIfExist: function(a, b) { let url = b || this.getUrl; for (let i = 0; i < BM.length; i++) { // if the same fic if (BM[i][0].split('/chapters/')[0] === url.split('/chapters/')[0]) { if (a === 'cancel') { return i; // if the same chapter } else if (BM[i][0] === url) { if (a === 'book') { let book = BM[i][2]; if (book.toString().indexOf('%') !== -1) { book = parseFloat(book.replace('%', '')); book *= getDocHeight(); } return book; } return true; } } } return false; }, cancel: function(url) { let found = this.checkIfExist('cancel', url); if (found !== false) BM.splice(found, 1); }, getNew: function() { this.cancel(); BM.push([this.getUrl, this.getTitle(), this.getNewBook()]); this.set(); } }; Bookmarks.get(); // Bookmarks' menu addCSS( 'ficstyle-menu', '#menu-bookmarks ul li { display: flex!important; align-items: center; justify-content: space-between; } ' + '#menu-bookmarks ul li a:first-child { flex-grow: 1; font-size: .9em; } ' + 'a.delete-book-menu { color: #900!important; } ' ); var bmMenu = document.createElement('li'); var bmMenuDrop = document.createElement('ul'); bmMenu.id = 'menu-bookmarks'; bmMenu.className = 'dropdown'; bmMenu.innerHTML = 'Bookmarks'; bmMenuDrop.className = 'menu dropdown-menu'; bmMenu.appendChild(bmMenuDrop); document.querySelector('#header > ul').appendChild(bmMenu); if (BM.length) { let clickDelete = function() { Bookmarks.cancel(this.getAttribute('data-url')); Bookmarks.set(); this.style.display = 'none'; this.previousSibling.style.opacity = '.4'; }; for (let z = 0; z < BM.length; z++) { let bmLi = document.createElement('li'); bmLi.innerHTML = '' + BM[z][1] + ''; let deleteBookMenu = document.createElement('a'); deleteBookMenu.className = 'delete-book-menu'; deleteBookMenu.title = 'delete bookmark'; deleteBookMenu.setAttribute('data-url', BM[z][0]); deleteBookMenu.textContent = 'x'; deleteBookMenu.addEventListener('click', clickDelete); bmLi.appendChild(deleteBookMenu); bmMenuDrop.appendChild(bmLi); } } else { bmMenuDrop.innerHTML = '