// ==UserScript== // @namespace https://greasyfork.org/users/294014-useyourname // @name MangaDex mark as read // @description Slide the button down to mark everything below as read // @copyright 2019, UseYourName // @license Beerware // @version 4 // @match https://mangadex.org/title/* // @match https://mangadex.org/manga* // @require https://code.jquery.com/ui/1.12.1/jquery-ui.min.js // @downloadURL https://update.greasyfork.icu/scripts/382117/MangaDex%20mark%20as%20read.user.js // @updateURL https://update.greasyfork.icu/scripts/382117/MangaDex%20mark%20as%20read.meta.js // ==/UserScript== // If previous pages should be marked read const MARK_PAGES = true; // Number of simultaneous requests for marking read const MARK_CONCURRENT = 20; $(document).ready(function() { // Timeout 1ms so it's run after site stuff setTimeout(function() { // Unbind default click handlers for marking (un)read $(".chapter_mark_read_button, .chapter_mark_unread_button").unbind("click"); // One handler for both to make it easy to process repeated toggles $(".chapter_mark_read_button, .chapter_mark_unread_button").click(function(event){ queueChapter($(this).attr('data-id'), ($(this).hasClass("chapter_mark_read_button") ? "read" : "unread")); event.preventDefault(); }); }, 1); }); // Make mark read/unread draggable and disable by default $(".chapter_mark_read_button, .chapter_mark_unread_button").draggable({ helper: function(event) { // Make a thing to drag var targetDiv = $('
"); if(start != -1 && end != -1) { $(data.slice(start, end)).find('.chapter_mark_read_button').each(function(index) { queueChapter($(this).attr('data-id')); }); } }, "html" ); } } } var queueChapter = (function () { var chapterQueue = []; var chapterMarking = 0; var chapterSpinning = false; // Spin eye to indicate requests in progress function spinChapter(toggle=true) { // If chapterDragged isn't set then queued requests are from this page, no need for a visual inidicator if(!chapterDragged) return; if(toggle) { $("#marker_"+chapterDragged).children(".fas").addClass("eyerotate"); } else if (CSS && CSS.supports && CSS.supports('animation: name')) { $("#marker_"+chapterDragged).children(".fas").on('animationiteration', function () { $(this).off('animationiteration').removeClass('eyerotate'); }); } else { $("#marker_"+chapterDragged).children(".fas").on('animationiteration webkitAnimationIteration', function () { $(this).off('animationiteration webkitAnimationIteration').removeClass('eyerotate'); }); } } // Should perhaps requeue on failure, but then I'd need to store retrys and limit them function updateChapter(chapter_id, mark) { $.ajax({ ...(!!mark && {success: function () { if(mark == "unread") { $("#marker_"+chapter_id) .removeClass("chapter_mark_unread_button") .addClass("grey chapter_mark_read_button") .prop("title", "Mark read") .draggable({disabled:false}) .children(".fas").switchClass("fa-eye", "fa-eye-slash"); } else { $("#marker_"+chapter_id) .removeClass("grey chapter_mark_read_button") .addClass("chapter_mark_unread_button") .prop("title", "Mark unread") .draggable({disabled:true}) .children(".fas").switchClass("fa-eye-slash", "fa-eye"); } } }), url: "/ajax/actions.ajax.php", data: { function: (mark === "unread" ? "chapter_mark_unread" : "chapter_mark_read"), id: chapter_id }, complete: function() { if(chapterQueue.length) { updateChapter(...chapterQueue.shift()); } else { chapterMarking--; if(!chapterMarking && chapterSpinning) { chapterSpinning = false; spinChapter(false); } } }, cache: false, contentType: false }); } return function (chapter_id, mark) { if(chapterMarking < MARK_CONCURRENT) { chapterMarking++; updateChapter(chapter_id, mark); } else { chapterQueue.push([chapter_id, mark]); if(!chapterSpinning) { chapterSpinning = true; spinChapter(true); } } } })();