Sleazy Fork is available in English.
Full-res images + reader mode + smooth scroll + compact On/Off toggles (R: On/Off, F: On/Off) + keyboard navigation + persistent settings
// ==UserScript==
// @name Kemono Comfy View
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Full-res images + reader mode + smooth scroll + compact On/Off toggles (R: On/Off, F: On/Off) + keyboard navigation + persistent settings
// @author L1Z4RD
// @match https://kemono.cr/*/user/*/post/*
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// Persistent settings
let readerMode = localStorage.getItem('kc_readerMode') === 'false' ? false : true;
let fitToScreen = localStorage.getItem('kc_fitToScreen') === 'false' ? false : true;
let currentIndex = 0;
let isScrolling = false;
function getImages() {
return Array.from(document.querySelectorAll('.post__files img'));
}
function upgradeGallery() {
const links = document.querySelectorAll('a.fileThumb');
links.forEach(link => {
const fullUrl = link.href;
const img = link.querySelector('img');
if (!img || !fullUrl) return;
if (img.dataset.fullresApplied) return;
img.src = fullUrl;
img.srcset = "";
img.loading = "eager";
img.dataset.fullresApplied = "true";
});
applyLayout();
}
function applyLayout() {
const container = document.querySelector('.post__files') || document.body;
const imgs = getImages();
if (readerMode) {
container.style.display = "flex";
container.style.flexDirection = "column";
container.style.alignItems = "center";
container.style.gap = "40px";
imgs.forEach(img => {
img.style.display = "block";
if (fitToScreen) {
img.style.maxHeight = "100vh";
img.style.maxWidth = "100%";
img.style.objectFit = "contain";
} else {
img.style.maxHeight = "none";
img.style.maxWidth = "100%";
}
});
} else {
container.style.display = "";
imgs.forEach(img => {
img.style.maxHeight = "";
img.style.maxWidth = "";
});
}
}
function scrollToImage(index) {
const imgs = getImages();
if (index < 0 || index >= imgs.length) return;
currentIndex = index;
imgs[index].scrollIntoView({ behavior: "smooth", block: "center" });
}
function handleWheel(e) {
if (!readerMode) return;
e.preventDefault();
if (isScrolling) return;
isScrolling = true;
if (e.deltaY > 0) scrollToImage(currentIndex + 1);
else scrollToImage(currentIndex - 1);
setTimeout(() => { isScrolling = false; }, 400);
}
function detectCurrentImage() {
const imgs = getImages();
let closestIndex = 0;
let closestDistance = Infinity;
imgs.forEach((img, index) => {
const rect = img.getBoundingClientRect();
const center = Math.abs(rect.top + rect.height / 2 - window.innerHeight / 2);
if (center < closestDistance) {
closestDistance = center;
closestIndex = index;
}
});
currentIndex = closestIndex;
}
function createToggle(labelText, initialState, onChange) {
const wrapper = document.createElement('label');
wrapper.className = 'kc-toggle-label';
const stateText = document.createElement('span');
stateText.textContent = initialState ? 'On' : 'Off';
stateText.style.fontWeight = 'bold';
wrapper.textContent = labelText + ': ';
wrapper.appendChild(stateText);
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = initialState;
checkbox.style.display = 'none';
checkbox.onchange = () => {
onChange(checkbox.checked);
stateText.textContent = checkbox.checked ? 'On' : 'Off';
};
wrapper.appendChild(checkbox);
wrapper.onclick = () => {
checkbox.checked = !checkbox.checked;
checkbox.onchange();
};
return wrapper;
}
function createStyles() {
const style = document.createElement('style');
style.textContent = `
.kc-toggle-label {
cursor: pointer;
background: rgba(255,255,255,0.15);
border-radius: 6px;
padding: 3px 6px;
color: #fff;
font-size: 12px;
user-select: none;
display: inline-flex;
justify-content: space-between;
align-items: center;
min-width: 50px;
transition: background 0.2s;
}
.kc-toggle-label:hover {
background: rgba(255,255,255,0.25);
}
`;
document.head.appendChild(style);
}
function createUI() {
createStyles();
const panel = document.createElement('div');
panel.style.position = "fixed";
panel.style.top = "10px";
panel.style.right = "10px";
panel.style.zIndex = "9999";
panel.style.display = "flex";
panel.style.flexDirection = "row";
panel.style.gap = "6px";
panel.style.background = "rgba(0,0,0,0.6)";
panel.style.padding = "4px";
panel.style.borderRadius = "6px";
const readerToggle = createToggle('R', readerMode, val => {
readerMode = val;
localStorage.setItem('kc_readerMode', val);
applyLayout();
});
const fitToggle = createToggle('F', fitToScreen, val => {
fitToScreen = val;
localStorage.setItem('kc_fitToScreen', val);
applyLayout();
});
panel.appendChild(readerToggle);
panel.appendChild(fitToggle);
document.body.appendChild(panel);
}
function handleKeyboard(e) {
if (!readerMode) return;
switch (e.key) {
case 'ArrowDown':
case ' ':
scrollToImage(currentIndex + 1); e.preventDefault(); break;
case 'ArrowUp':
scrollToImage(currentIndex - 1); e.preventDefault(); break;
}
}
window.addEventListener('load', () => {
upgradeGallery();
createUI();
window.addEventListener('wheel', handleWheel, { passive: false });
window.addEventListener('scroll', detectCurrentImage);
window.addEventListener('keydown', handleKeyboard);
});
const observer = new MutationObserver(() => upgradeGallery());
observer.observe(document.body, { childList: true, subtree: true });
})();