Skip to content

Instantly share code, notes, and snippets.

@a-gu
Last active December 23, 2020 18:36
Show Gist options
  • Save a-gu/8313d8523f5e8a08e80b54beb1d7b241 to your computer and use it in GitHub Desktop.
Save a-gu/8313d8523f5e8a08e80b54beb1d7b241 to your computer and use it in GitHub Desktop.
Rewrites the WebToon viewer to still be functional with fewer resources
// ==UserScript==
// @name WebToon Light
// @version 1.0
// @description Rewrites the WebToon viewer to still be functional with fewer resources
// @author Andrew Gu
// @match https://www.webtoons.com/*viewer
// @match https://www.webtoons.com/*viewer?*
// @updateURL https://gist.github.com/a-gu/8313d8523f5e8a08e80b54beb1d7b241/raw/97ff557a0267dfc3929e63cf41873c161008239f/webtoon_light.user.js
// @grant none
// @run-at document-end
// ==/UserScript==
/*
Designed to be used in tandem with filtering rules like (uBlock Origin):
webtoons.com * 1p-script block
webtoons.com * 3p-script block
webtoons.com * image allow
webtoons.com * inline-script allow
*/
(function() {
'use strict';
const USER_STYLE = `
/* Global */
body {
margin: 0;
height: 100vh;
overflow-y: hidden;
display: grid;
grid-template-columns: 20em auto;
grid-template-areas: "sidebar content" "sidebar content";
background-color: #000000;
color: #ffffff
}
a {
color: #88ff88;
text-decoration: none;
padding: 0.2em;
}
a:not(.subj),
.episode_cont li[data-episode-no] {
transform: scale(1.0);
transition: transform 0.2s ease
}
:not(.episode_cont li[data-episode-no]) > a:not(.subj):hover,
.episode_cont li[data-episode-no]:hover {
transform: scale(1.05)
}
/* Sidebar */
.sidebar {
display: flex;
flex-flow: column nowrap;
height: 100%;
overflow: hidden
}
/* Info */
.subj_info {
padding: 0.5em
}
.subj_episode, .subj_info>a {
text-overflow: ellipsis;
overflow: hidden;
display: block;
margin: 0
}
/* Pagination */
.paginate {
padding: 0.5em;
border-bottom: 0.25em dashed #222222;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
margin-bottom: 0.25em;
align-items: center
}
/* Episodes List */
.episode_cont {
flex-shrink: 1;
flex-grow: 1;
overflow-y: auto;
word-break: break-word;
overflow-x: hidden
}
.episode_cont>ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-flow: column-reverse nowrap
}
.episode_cont li[data-episode-no]>a {
display: flex;
flex-flow: row nowrap;
align-items: center
}
.episode_cont li[data-episode-no]:nth-child(2n) {
background-color: #ffffff22
}
.episode_cont li[data-episode-no] .subj {
padding: 0.5em
}
.episode_cont li[data-episode-no].current {
z-index: 9;
background-color: #88ff8833
}
.episode_cont li[data-episode-no].current a {
color: #ffffff
}
/* Images */
#_imageList {
line-height: 0;
overflow-y: auto;
}
`
// Extract elements and create custon layout
let info = document.querySelector('#toolbar > .info > .subj_info'),
pages = document.querySelector('#toolbar > .paginate'),
episodes = document.querySelector('#toolbar > #topEpisodeList .episode_cont'),
images = document.querySelector('#_imageList')
let content = document.createDocumentFragment(),
sidebar = document.createElement('div'),
style = document.createElement('style')
style.setAttribute('type', 'text/css')
style.innerHTML = USER_STYLE
sidebar.classList.add('sidebar')
sidebar.appendChild(info)
sidebar.appendChild(pages)
pages.querySelector('.pg_prev em').innerText = '< Prev'
pages.querySelector('.pg_next em').innerText = 'Next >'
sidebar.appendChild(episodes)
content.appendChild(sidebar)
content.appendChild(images)
// Rewrite all images
Array.from(content.querySelectorAll('img[src*="transparency.png"][data-url]')).forEach(img => {
img.setAttribute('loading', 'lazy');
img.setAttribute('src', img.getAttribute('data-url'));
['ondragstart', 'onselectstart', 'oncontextmenu', 'data-url', 'class'].forEach(attr => img.removeAttribute(attr))
})
// Clear page and write new content
document.open()
document.write('<!DOCTYPE html><html><head></head><body></body></html>')
document.close()
document.head.appendChild(style)
document.body.appendChild(content)
// Scroll to current episode
let episode = (new URL(window.location)).searchParams.get('episode_no'),
episode_li = document.querySelector(`.episode_cont li[data-episode-no="${episode}"]`)
episode_li.classList.add('current');
(episode_li.nextElementSibling || episode_li).scrollIntoView()
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment