Last active
November 10, 2020 01:50
-
-
Save FiXato/b5434f66d2af50514bf84721fa249c22 to your computer and use it in GitHub Desktop.
Tweaks for various comics, such as visible alt and title texts, adding ctrl+left/right keyboard shortcuts for previous and next comic, prefetching prev/next link documents, and a kioskmode. Currently supported: xkcd and the (NSFW) comic "Oglaf".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Comics tweaks | |
// @author Filip H.F. "FiXato" Slagter | |
// @namespace http://code.fixato.org/userscripts | |
// @description Some tweaks for various comic sites, such as visible alt text, and kiosk mode. Currently supports: Oglaf, xkcd. | |
// @match https://oglaf.com/* | |
// @match https://www.oglaf.com/* | |
// @match https://xkcd.com/* | |
// @match https://www.xkcd.com/* | |
// @version 2.1 | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @source https://gist.github.com/FiXato/b5434f66d2af50514bf84721fa249c22 | |
// ==/UserScript== | |
/* TODO: | |
- Allow each site to be toggled individually, perhaps even per setting. | |
- Add a small settings panel? At least to toggle KioskMode on/off. | |
- Move this to an actual git repo / project. | |
*/ | |
(function() { | |
'use strict'; | |
/* Change the 'prev' meta-links (used by ctrl+left/right controls) to advance through a series before going to the following previous comic | |
Useful if you catch up on the comic by going backwards. */ | |
const TraverseThroughSeriesWhileReversing = true; | |
// Enabled keyboard shortcuts to go to the previous and next comics with Ctrl + Left Arrow and Ctrl + Right Arrow respectively. | |
const PrevNextKeyControls = true; | |
// Make the comic image's alt and title attributes visible without having to hover over the image. | |
const DisplayImageDescription = true; | |
// Hide header images, as it helps show more of the actual image on screen | |
const HideHeaderImages = true; | |
// Try to prefetch cache the previous (and next) comics | |
const PrefetchPrevNextComics = true; | |
// Add a thumbnail next to the image descriptions? | |
const IncludeThumbnail = true; | |
// Cut down the contents of the page to the bare minimum, and load next and previous items via AJAX/XHR call. Assumes PrevNextKeyControls = true; | |
const KioskMode = true; | |
//If you want to reset states when you reload the page. | |
const ResetTraversal = false; | |
if (KioskMode && ResetTraversal) { reset_traversal(); } | |
var previous_href_before_series, next_href_before_series, current_series_base_href; | |
var page_title_element = document.querySelector('title'); | |
var comic_image = get_comic_image(document); | |
var current_xhr_page_request = undefined; | |
var previous_link = get_link(document, 'previous'); | |
var next_link = get_link(document, 'next'); | |
check_series_traversal(); | |
add_css_styles(); | |
function abort(error_message, obj) { | |
console.error(error_message, obj); | |
throw new Error('Aborted: ' + error_message); | |
} | |
function get_link(doc, type) { | |
if (window.location.host.includes('xkcd.com')) { | |
if (type == 'previous') { return doc.querySelector('.comicNav a[rel*="prev"]'); } | |
else if (type == 'next') { return doc.querySelector('.comicNav a[rel*="next"]'); } | |
else { abort('Comic Tweaks.get_link(): Unsupported link type', type) } | |
} | |
else if (window.location.host.includes('oglaf.com')) { | |
if (type == 'previous') { return doc.querySelector('link[rel*="prev"]'); } | |
else if (type == 'next') { return doc.querySelector('link[rel*="next"]'); } | |
else { abort('Comic Tweaks.get_link(): Unsupported link type', type) } | |
} else { abort('Comic Tweaks.get_link(): Unsupported host', window.location.host); } | |
} | |
if (PrevNextKeyControls) { | |
window.addEventListener('keydown', (e) => { | |
if (e.code == "ArrowLeft" && e.ctrlKey) { | |
if (previous_link) {change_page(previous_link.href);} | |
} else if (e.code == "ArrowRight" && e.ctrlKey) { | |
if (next_link) {change_page(next_link.href);} | |
} | |
}); | |
} | |
if (KioskMode) { | |
document.querySelector('html').classList.add('ComicsTweaksKioskMode'); | |
build_kiosk(); | |
//request_comic_via_xhr(window.location.href); | |
} else { | |
if (HideHeaderImages) {hide_header_images(document);} | |
} | |
if (DisplayImageDescription) {display_image_description();} | |
if (PrefetchPrevNextComics) {prefetch_prev_and_next_links();} | |
function current_page_href() { | |
if(KioskMode && current_xhr_page_request && current_xhr_page_request.responseURL) { | |
return current_xhr_page_request.responseURL; | |
} | |
return window.location.href; | |
} | |
function build_kiosk() { | |
const comics_tweaks_container = document.createElement('div'); | |
comics_tweaks_container.id = 'comics_tweaks_container'; | |
const comic_container = document.createElement('main'); | |
comic_container.id = 'ctc_comic_container'; | |
comic_container.prepend(comic_image); | |
comics_tweaks_container.prepend(comic_container); | |
const page_items_container = document.createElement('div'); | |
page_items_container.id = 'ctc_page_items_container'; | |
const source_document = document.body.cloneNode(true); | |
site_specific_kiosk_setup(comics_tweaks_container, page_items_container); | |
insertAfter(page_items_container, comic_container); | |
document.body.replaceChildren(comics_tweaks_container); | |
console.log('source doc', source_document); | |
} | |
function site_specific_kiosk_setup(comics_tweaks_container, page_items_container) { | |
let host = window.location.host; | |
if (host.includes('oglaf.com')) { | |
const random_image_quote = document.getElementById("ll"); | |
random_image_quote.classList.add('random_image_quote'); | |
const random_image = document.querySelector('#nav a:last-child img'); | |
random_image.classList.add('random_image'); | |
const random_image_container = document.createElement('div'); | |
random_image_container.id = 'ctc_random_image_container'; | |
random_image_container.append(random_image, random_image_quote); | |
page_items_container.append(random_image_container); | |
} | |
} | |
function request_comic_via_xhr(url) { | |
let request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.responseType = "document"; | |
request.send(); | |
request.onload = function() { | |
process_xhr_comic(request); | |
} | |
request.onerror = function() { | |
process_xhr_comic_failure(request); | |
} | |
} | |
function process_xhr_comic(request) { | |
current_xhr_page_request = request; | |
let response = request.response.cloneNode(true); | |
previous_link.href = get_link(response, 'previous').href; | |
next_link.href = get_link(response, 'next').href | |
console.log("processed xhr. New links:", [previous_link.href, next_link.href]); | |
let new_image = get_comic_image(request.response); | |
comic_image.parentNode.replaceChild(new_image, comic_image); | |
comic_image = new_image; | |
window.history.replaceState({ additionalInformation: 'loaded via Comics Tweaks UserScript KioskMode' }, response.title, request.responseURL); | |
page_title_element.innerText = response.querySelector('title').innerText; | |
if (DisplayImageDescription) {display_image_description();} | |
check_series_traversal(); | |
} | |
function process_xhr_comic_failure(request) { | |
console.error("process_xhr_comic_failure", request); | |
current_xhr_page_request = undefined; | |
} | |
function get_comic_image(doc) { | |
if (window.location.host.includes('xkcd.com')) { | |
return doc.querySelector('#comic img'); | |
} | |
else if (window.location.host.includes('oglaf.com')) { | |
return doc.querySelector('#strip'); | |
} else { abort('Comic Tweaks.get_comic_image(): Unsupported host', window.location.host); } | |
} | |
function change_page(url) { | |
console.log("change page", url); | |
if (!KioskMode) { | |
window.location.href = url; | |
} else { | |
request_comic_via_xhr(url); | |
} | |
} | |
function display_image_description() { | |
var alt_text = comic_image.alt; | |
var title_text = comic_image.title; | |
var thumbnail = ''; | |
if(KioskMode && IncludeThumbnail) { | |
thumbnail = comic_image.cloneNode(true); | |
thumbnail.id = undefined; | |
thumbnail.classList.add('thumbnail'); | |
} | |
const image_description = document.createElement('div'); | |
image_description.classList.add("image_descriptions"); | |
const page_title = document.createElement('h2'); | |
page_title.classList.add('page_title'); | |
page_title.textContent = page_title_element.innerText; | |
const image_title = document.createElement('b'); | |
image_title.classList.add('image_title'); | |
image_title.textContent = title_text; | |
const image_alt = document.createElement('i'); | |
image_alt.classList.add('image_alt'); | |
image_alt.textContent = alt_text; | |
let description_body = document.createElement('p'); | |
description_body.classList.add('container'); | |
description_body.classList.add('description_body'); | |
description_body.prepend(image_title, image_alt); | |
image_description.prepend(page_title, thumbnail, description_body); | |
Array.from(document.querySelectorAll('.image_descriptions')).slice(2).slice(-3).forEach((el) => { | |
el.parentNode.removeChild(el); | |
}); | |
document.querySelector('#ctc_page_items_container').prepend(image_description); | |
} | |
function hide_header_images(doc) { | |
doc.querySelectorAll('#tl, #tl + *, #tl + * + *').forEach((element) => { | |
element.style = 'display: none;'; | |
}); | |
} | |
function insertAfter(newNode, referenceNode) { | |
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); | |
} | |
function prefetch_prev_and_next_links() { | |
[previous_link, next_link].forEach((link) => { | |
if (link) {link.rel += " prerender";} | |
}); | |
} | |
function load_series_variables() { | |
previous_href_before_series = GM_getValue('previous_href_before_series'); | |
next_href_before_series = GM_getValue('next_href_before_series'); | |
current_series_base_href = GM_getValue('current_series_base_href'); | |
} | |
function reset_traversal() { | |
GM_setValue('previous_href_before_series', ''); | |
GM_setValue('next_href_before_series', ''); | |
GM_setValue('current_series_base_href', ''); | |
} | |
function add_css_styles() { | |
let style_element = document.createElement('style'); | |
style_element.innerText = ` | |
html.ComicsTweaksKioskMode, html.ComicsTweaksKioskMode body { | |
width: 100%!important; | |
height: 100%!important; | |
margin: 0; | |
padding: 0; | |
position: relative; | |
left: 0; | |
top: 0; | |
right: 0; | |
bottom: 0; | |
} | |
img.thumbnail { | |
max-width: 150px; | |
max-height: 100px; | |
height: auto; | |
width: auto; | |
flex: 0 0 150px; | |
margin: 0.5em; | |
} | |
.image_descriptions ~ .image_descriptions { | |
opacity: 0.3; | |
} | |
.image_descriptions:nth-child(1) + .image_descriptions { | |
opacity: 0.5; | |
} | |
.image_descriptions { | |
display: flex; | |
flex-wrap: wrap; | |
align-items: center; | |
padding: 1em; | |
background-color: rgba(255,255,255, 0.5); | |
margin: 0; | |
padding: 0; | |
} | |
.page_title { | |
margin: 0; | |
margin-block-start: 0; | |
margin-block-end: 0; | |
padding: 0.5em; | |
font-size: 1.2em; | |
text-align: center; | |
font-weight: bold; | |
width: 100%; | |
flex-basis: 100%; | |
} | |
.image_title { | |
margin-bottom: 0.5em; | |
} | |
.container.description_body { | |
flex: 1; | |
display: flex; | |
flex-direction: column; | |
padding: 0.5em; | |
margin-block-start: 0; | |
margin-block-end: 0; | |
} | |
#nav a:last-child { | |
margin-top: 0!important; | |
} | |
#comics_tweaks_container { | |
display: flex; | |
align-items: flex-start; | |
} | |
#comics_tweaks_container #ctc_random_image_container { | |
display: flex; | |
background-color: #cccccc; | |
flex-wrap: wrap; | |
justify-content: space-between; | |
align-items: center; | |
margin: 0; | |
padding: 0; | |
} | |
#comics_tweaks_container .random_image_quote { | |
flex: 0 1; | |
width: initial; | |
height: min-content; | |
} | |
#comics_tweaks_container .random_image { | |
flex: 0 0 100px; | |
max-width: 81px; | |
width: auto; | |
height: auto; | |
} | |
html.ComicsTweaksKioskMode #ctc_comic_container img { | |
float: unset; | |
left: unset; | |
right: unset; | |
top: unset; | |
bottom: unset; | |
width: unset; | |
height: unset; | |
padding: 0; | |
margin: 0; | |
text-align: unset; | |
border: none; | |
} | |
`; | |
document.querySelector('head').prepend(style_element); | |
} | |
function check_series_traversal() { | |
if (TraverseThroughSeriesWhileReversing && window.location.host.includes('oglaf.com')) { | |
console.log('BEFORE', ['current_series_base_href', current_series_base_href], ['previous_link', previous_link.href], ['next_link', next_link.href], ['current_page_href', current_page_href()]); | |
load_series_variables(); | |
if ((current_page_href() + '2/') == next_link.href) { | |
GM_setValue('previous_href_before_series', previous_link.href); | |
GM_setValue('next_href_before_series', next_link.href); | |
GM_setValue('current_series_base_href', current_page_href()); | |
console.log('Start of series', current_page_href()); | |
previous_link.href = next_link.href; | |
} else if (previous_link && previous_link.href.includes(current_series_base_href) && next_link && !next_link.href.includes(current_series_base_href) && current_page_href().includes(current_series_base_href)) { | |
console.log('End of series', current_series_base_href); | |
previous_link.href = previous_href_before_series; | |
console.log('Set prev link to ', previous_link.href, previous_link); | |
GM_setValue('previous_href_before_series', ''); | |
GM_setValue('next_href_before_series', ''); | |
GM_setValue('current_series_base_href', ''); | |
} else if (current_series_base_href && current_page_href().includes(current_series_base_href) && next_link && next_link.href.includes(current_series_base_href)) { | |
console.log("We are still in the " + current_series_base_href + " series", next_link.href, next_link); | |
previous_link.href = next_link.href; | |
} | |
load_series_variables(); | |
console.log('AFTER', ['current_series_base_href', current_series_base_href], ['previous_link', previous_link.href], ['next_link', next_link.href], ['current_page_href', current_page_href()]); | |
} | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment