2021. 1. 6. 오전 11:17:30
As of
// ==UserScript==
// @name Infinite scroller
// @namespace Violentmonkey Scripts
// @match https://*.arca.live/*
// @grant none
// @version 1.0.2
// @author awk
// @description 2021. 1. 6. 오전 11:17:30
// ==/UserScript==
// bounce-back element size
const bounceBackBuffer = 96;
// last-checked page
let scrolledPage = 1;
let isLoading = false;
// from Arca Refresher@LeKAKiD v2.6.8
function getTimeStr(datetime) {
const date = new Date(datetime);
let hh = date.getHours();
let mm = date.getMinutes();
if (hh.toString().length == 1) {
hh = `0${hh}`;
}
if (mm.toString().length == 1) {
mm = `0${mm}`;
}
return `${hh}:${mm}`;
}
function in24(datetime) {
const target = new Date(datetime);
const criteria = new Date();
criteria.setHours(criteria.getHours() - 24);
if (target > criteria) return true;
return false;
}
const bounceBack = () => {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
scrollBy({
'top': -bounceBackBuffer,
'left': 0,
'behavior': 'smooth'
});
}
};
const getArticleId = elem => ~~elem.href.match(/\/b\/[^/]+\/(\d+)/)[1];
const loadMore = async () => {
if(isLoading) return;
isLoading = true;
// true if scrolledPage value is reached to unread page
let reached = false;
const currentArticles = [...document.querySelectorAll('.vrow')];
const currentLastArticleId = getArticleId(currentArticles[currentArticles.length - 1]);
// determine if current page doesn't include any article
if(!currentLastArticleId) {
isLoading = false;
return;
}
while(!reached) {
++scrolledPage;
// get next-page url
const nextPage = (() => {
// determine if current url includes page information
if(location.href.match(/[&?]p=(\d+)/)) {
return location.href.replace(/[&?]p=\d+/, pageString => {
return pageString.replace(/\d+/, scrolledPage);
});
}
// determine if current url includes query string
else if(location.href.match(/\?.+?=.+?/)){
return `${location.href}&p=${scrolledPage}`;
}
// it might be first-page of the board
else {
return `${location.href}?p=${scrolledPage}`;
}
})();
console.log(nextPage);
// fetch and parse next-page DOM
const nextPageDOM = await fetch(nextPage)
.then(res => res.text())
.then(pageText => new DOMParser().parseFromString(pageText, 'text/html'));
const nextPageLastArticle = nextPageDOM.querySelector('.vrow:last-child');
// determine if reached to end
if(!nextPageLastArticle || nextPageLastArticle.classList.length != 1) {
// reached to end
bounceBack();
break;
}
// determine if reached to unread page
const nextPageLastArticleId = getArticleId(nextPageLastArticle);
if(currentLastArticleId > nextPageLastArticleId) {
// filter unread articles
const unreadArticles = [...nextPageDOM.querySelectorAll('.vrow')].filter(article => {
// filter out notices
if(article.classList.length != 1) return false;
return getArticleId(article) < currentLastArticleId;
});
// attach unread articles with applying <time> js
const articleList = document.querySelector('.list-table');
unreadArticles.forEach(article => {
const time = article.querySelector('time');
if (time && in24(time.dateTime)) {
time.innerText = getTimeStr(time.dateTime);
}
articleList.appendChild(article)
});
break;
}
}
isLoading = false;
return;
}
window.addEventListener('load', e => {
// load current page
const pageMatch = location.href.match(/[&?]p=(\d+)/);
console.log(location.href);
scrolledPage = pageMatch ? ~~pageMatch[1] : 1;
// attach bounce-back element
const bounceBackElement = document.createElement('div');
bounceBackElement.style.width = 'inherit';
bounceBackElement.style.height = `${bounceBackBuffer}px`;
// center-align text
bounceBackElement.style.textAlign = 'center';
bounceBackElement.style.lineHeight = `${bounceBackBuffer}px`;
// element color
bounceBackElement.style.backgroundColor = 'grey';
bounceBackElement.style.color = 'white';
// element text
bounceBackElement.innerText = 'Loading next page...';
bounceBackElement.fontWeight = 'bold';
document.body.appendChild(bounceBackElement);
// apply smooth-scroll for bounce-back
document.body.style.scrollBehavior = 'smooth';
});
window.addEventListener('scroll', e => {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
loadMore();
}
});