Skip to content

Instantly share code, notes, and snippets.

@Yanrishatum
Last active April 17, 2019 11:32
Show Gist options
  • Save Yanrishatum/5e50111eee74d2c22f401012c8799346 to your computer and use it in GitHub Desktop.
Save Yanrishatum/5e50111eee74d2c22f401012c8799346 to your computer and use it in GitHub Desktop.
Mangastr: A mangadex QOL stuff
// ==UserScript==
// @name Mangastr
// @namespace https://yanrishatum.ru/
// @version 1.0
// @description QOL For Mangadex
// @author Yanrishatum
// @match https://mangadex.org/follows
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
function style(css)
{
let s = document.head.querySelector("#panel-style");
if (!s)
{
s = document.createElement("style");
s.id = "panel-style";
document.head.appendChild(s);
}
s.textContent = css;
}
style(`
.panel-follows #chapters>.chapter-container
{
display: flex;
max-width: 1380px;
flex-wrap: wrap;
}
.panel-follows #chapters>.chapter-container>div:first-child
{
display: none!important;
}
.panel-follows #chapters>.chapter-container>.row.no-gutters
{
display: flex;
flex-direction: column;
flex-wrap: nowrap;
width: 276px;
}
.panel-follows #chapters .row.no-gutters>.col.col-md-3
{
flex-direction: column;
max-width: 100%;
align-items: initial!important;
flex-basis: initial;
}
.panel-follows #chapters .row.no-gutters>.col.col-md-3 .text-truncate
{
text-align: center;
}
.panel-follows div.thumb-image
{
display: flex;
justify-content: center;
align-items: center;
height: 160px;
}
.panel-follows div.thumb-image img
{
max-height: 160px;
}
.panel-follows .chapter-container>.row.no-gutters>.col-md-9
{
max-width: initial!important;
}
.panel-follows .chapter-row>*
{
flex-grow: initial;
flex-basis: auto;
flex-shrink: initial;
}
.panel-follows .chapter-row .order-lg-3 { min-width: 35px; }
.panel-follows .chapter-row .order-lg-1,
.panel-follows .chapter-row .order-lg-3,
.panel-follows .chapter-row .order-lg-4
{
flex-basis: 10%;
}
.panel-follows .chapter-row .order-lg-2
{
flex-basis: 70%;
min-width: 76%;
flex-grow: 1;
}
.panel-follows .chapter-row .order-lg-5
{
flex-grow: 1;
flex-basis: 50%;
}
.panel-follows .chapter-row .order-lg-8
{
order: 6;
flex-basis: 30%;
flex-grow: 1;
max-width: initial;
}
.panel-follows .chapter-row .order-lg-6
{
flex-grow: 1;
flex-basis: 50%;
max-width: initial;
text-align: left!important;
}
.panel-follows .chapter-row .order-lg-7
{
flex-basis: 30%;
max-width: initial;
}
.unread-chapter
{
background: #131313;
}
.filter-read div.read-chapter
{
display: none!important;
}
.title-image-preview
{
position: fixed;
pointer-events: none;
right: 0;
bottom: 0;
transition: all 0.4s ease;
transform: translateX(100%);
}
.title-image-preview>img
{
max-height: 80vh;
max-width: 60vw;
border-radius: 5px!important;
}
.title-image-preview.preview-show
{
transform: translateX(0%);
}
body:not(.panel-follows) div.thumb-image,body:not(.panel-follows) .panel-header-copy
{
display: none;
}
`);
const OPT_MODE = "mode-panels";
const OPT_FILTER = "filter-seen";
const MODE_PANELS = "panels";
const MODE_LIST = "list";
let displayMode = GM_getValue(OPT_MODE, MODE_PANELS);
let filterSeen = GM_getValue(OPT_FILTER, false);
let listViewPreview = false;
for (let chapter of document.querySelectorAll("div[data-manga-id]"))
{
for (let child of chapter.children) child.removeAttribute("style");
let base = chapter.parentElement.parentElement;
let img = new Image();
img.src = "https://mangadex.org/images/manga/" + chapter.getAttribute("data-manga-id") + ".thumb.jpg";
/** @type {HTMLDivElement} */
let header = base.firstElementChild;
if (header.childElementCount == 0)
{
// chained chapter release
let headerCopy = header.parentElement.previousElementSibling.firstElementChild.firstElementChild.cloneNode(true);
headerCopy.classList.add("panel-header-copy");
header.appendChild(headerCopy);
}
header.setAttribute("data-manga-id", chapter.getAttribute("data-manga-id"));
header.addEventListener("mouseenter", showPreview);
header.addEventListener("mouseleave", hidePreview);
let chapterLink = chapter.querySelector(".order-lg-2>a");
let a = document.createElement("a");
a.title = header.firstElementChild.title + " \n" + chapterLink.textContent;
a.href = chapterLink.href;
a.appendChild(img);
let cont = document.createElement("div");
cont.classList.add("thumb-image");
cont.appendChild(a);
chapter.parentElement.parentElement.firstElementChild.appendChild(cont);
let isUnread = chapter.querySelector(".chapter_mark_read_button");
if (isUnread)
{
chapter.classList.add("unread-chapter");
function readClick(e)
{
let chapterBase = e.currentTarget;
while (chapterBase.parentElement) {
if (chapterBase.classList.contains("row") && !chapterBase.classList.contains("col") && !chapterBase.classList.contains("chapter-row")) break;
chapterBase = chapterBase.parentElement;
}
chapterBase.classList.add("read-chapter");
chapterBase.querySelector(".unread-chapter").classList.remove("unread-chapter");
}
isUnread.addEventListener("click", readClick);
chapterLink.addEventListener("auxclick", readClick);
a.addEventListener("auxclick", readClick);
}
else
{
base.classList.add("read-chapter");
}
}
function makeNavButton(action, name, onIcon, offIcon, state = true, triggerActionOnInit = false)
{
let icon = document.createElement("span");
icon.classList.add("fas", state ? onIcon : offIcon, "fa-fw");
let text = document.createElement("span");
text.classList.add("d-none", "d-md-inline");
text.textContent = name;
let filterLink = document.createElement("div");
filterLink.classList.add("nav-link");
filterLink.appendChild(icon);
filterLink.appendChild(text);
let filter = document.createElement("div");
filter.classList.add("nav-item");
filter.style.cursor = "pointer";
filter.style.userSelect = "none";
filter.appendChild(filterLink);
let tabs = document.querySelector(".nav.nav-tabs");
tabs.insertBefore(filter, tabs.lastElementChild);
filter.addEventListener("click", function ()
{
let result = action(!state);
if (offIcon && result !== false)
{
state = !state;
icon.classList.toggle(offIcon);
icon.classList.toggle(onIcon);
}
});
if (state && triggerActionOnInit) action(state);
}
makeNavButton(function (enabled)
{
document.body.classList.toggle("filter-read");
filterSeen = enabled;
GM_setValue(OPT_FILTER, filterSeen);
}, "Show seen", "fa-eye-slash", "fa-eye", filterSeen, true);
makeNavButton(function (enabled)
{
document.body.classList.toggle("panel-follows");
displayMode = enabled ? MODE_PANELS : MODE_LIST;
GM_setValue(OPT_MODE, displayMode);
}, "Panel view", "fa-columns", "fa-align-justify", displayMode == MODE_PANELS, true);
if (listViewPreview) {
let previewImage = new Image();
previewImage.addEventListener("error", function ()
{
let orig = previewImage.src;
if (orig.indexOf(".jpg") != -1) previewImage.src = orig.replace(".jpg", ".png");
else if (orig.indexOf(".png") != -1) previewImage.src = orig.replace(".png", ".jpeg");
else if (orig.indexOf(".jpeg") != -1) previewImage.src = orig.replace(".jpeg", ".gif");
else if (orig.indexOf(".gif") != -1) previewImage.src = orig.replace(".gif", ".webp");
previewImage.current.ext = previewImage.src.substr(previewImage.src.lastIndexOf("."));
});
let previewPanel = document.createElement("div");
previewPanel.classList.add("title-image-preview");
previewPanel.appendChild(previewImage);
document.body.appendChild(previewPanel);
}
function isPanelMode() { return displayMode == MODE_PANELS; }
function showPreview(e)
{
if (!isPanelMode() && listViewPreview)
{
previewPanel.classList.add("preview-show");
let a = e.currentTarget
previewImage.current = a;
let ext = a.ext || ".jpg";
previewImage.src = "https://mangadex.org/images/manga/" + e.currentTarget.getAttribute("data-manga-id") + ext;
}
}
function hidePreview(e)
{
if (!isPanelMode() && listViewPreview)
{
previewPanel.classList.remove("preview-show");
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment