// ==UserScript== // @name AO3: Fic's Style, Blacklist, Bookmarks // @namespace https://github.com/Schegge // @version 3.0 // @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 // @require https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js // @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($) { /*function debugging(varName, variable) { var message = 'FS\t[' + varName + ']'; if (variable) { message += '\t(' + typeof variable + ') ' + JSON.stringify(variable); } console.log(message); }*/ // BOOKMARKS var Bookmarks = { getBooks: function() { var bookmarks = localStorage.getItem('ficstyle_bookmarks'); if (!bookmarks || bookmarks.charAt(0) !== '[') { bookmarks = '[]'; localStorage.setItem('ficstyle_bookmarks', bookmarks); } //debugging('getBooks', JSON.parse(bookmarks)); return JSON.parse(bookmarks.trim()); }, getUrl: window.location.pathname.split('/works/')[1], // work id getTitle: function() { var title = $('#workskin .preface.group h2.title.heading').text().trim(); //debugging('getTitle heading', title); title = title.substring(0, 28); // to cut long titles if (/chapters/.test(window.location.pathname)) { // if chapter by chapter, also storaging the number of the chapter var chapter = $('#chapters > .chapter > div.chapter.preface.group > h3 > a').text(); chapter = chapter.replace('Chapter ', 'ch'); title += ' (' + chapter + ')'; //debugging('getTitle chapter', chapter); } //debugging('getTitle final', title); return title; }, getNewBook: function() { var newbook = $(document).scrollTop(); // current position of the scroll bar //debugging('getNewBook px', newbook); var chs = $('dl.stats dd.chapters').text(); // # chapters //debugging('getNewBook chapters', chs); if (/(\d+)\/\1/.test(chs) || /chapters/.test(window.location.pathname)) { // if work completed (if number/number is the same) or chapter by chapter view newbook = (newbook / $(document).height()).toFixed(4) + '%'; // calculate in percent //debugging('getNewBook %', newbook); } //debugging('getNewBook final', newbook); return newbook; }, checkIfExist: function(a, b) { var books = this.getBooks(); var url = b || this.getUrl; for (var i = 0; i < books.length; i++) { // if a bookmark already existed for the current chapter if (books[i][0] === url) { //debugging('same chapter'); if (a === 'book') { // retrieve the bookmark var book = books[i][2]; if (book.toString().indexOf('%') !== -1) { book = book.replace('%', ''); book = parseFloat(book); book = book * $(document).height(); } //debugging('checkIfExist(book)', book); return book; } else if (a === 'cancel') { // delete the old bookmark //debugging('checkIfExist(cancel)', i); //debugging('checkIfExist(cancel)', books[i]); return i; } else { //debugging('checkIfExist()', true); return true; } // if a bookmark already existed for the current fic } else if (a === 'cancel' && books[i][0].split('/chapters/')[0] === url.split('/chapters/')[0]) { // delete the old bookmark //debugging('same fic'); //debugging('checkIfExist(cancel)', i); //debugging('checkIfExist(cancel)', books[i]); return i; } } //debugging('checkIfExist', false); return false; }, cancel: function(b) { var newBookmarks = this.getBooks(); var cancel = this.checkIfExist('cancel', b); //debugging('cancel', cancel); if (cancel || cancel === 0) { newBookmarks.splice(cancel, 1); } return newBookmarks; }, getNew: function() { var newBookmarks = this.cancel(); // if the the fic was already bookmarked, delete the old bookmark newBookmarks.push([this.getUrl, this.getTitle(), this.getNewBook()]); // add new bookmark //debugging('getNew', newBookmarks); localStorage.setItem('ficstyle_bookmarks', JSON.stringify(newBookmarks)); } }; // create 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; } ' ); $('#header > ul').append('