arcalive 게시글의 이미지를 미리보여줍니다.
// ==UserScript==
// @name Arcalive gallery view
// @namespace http://tampermonkey.net/
// @version 1.05
// @description arcalive 게시글의 이미지를 미리보여줍니다.
// @author You
// @include /^https:\/\/arca\.live\/b\/([a-z]*)?([?&][a-z]=.*)*/
// @icon https://www.google.com/s2/favicons?sz=64&domain=arca.live
// @grant none
// @license MIT
// ==/UserScript==
//'use strict';
//
/* 파라미터 */
const IS_STRICT_SQUARE_IMAGE_MODE = false; // true로 바꾸면 이미지사이즈가 300x300박스를 초과하지않게됨.
const REMOVE_SIDE_BAR_MODE = false; // true시, 우측의 인기글 사이드바가 사라짐.
/* 사이트의 셀렉터 변경될 경우 수정하기 */
const TABLE_IMAGE_SELECTOR = ".article-content tbody img";
const VIDEO_SELECTOR = ".article-content video";
const IMAGE_SELECTOR = ".article-content img";
const ATTACH_TARGET_SELECTOR = "a.vrow.column .vcol.col-title";
const ARTICLE_CONTAINER_SELECTOR = ''
const ARTICLES_SELECTOR = ".vrow:not(.notice)";
const ARTICLES_WITHOUT_NOTICE_SELECTOR = ".article-list a.vrow.column";
const RATE_IN_ARTICLE_SELECTOR = ".vcol.col-rate"
/* 수정할 일 없음 */
const IMAGE_WIDTH_SMALL = 150;
const IMAGE_WIDTH_NORMAL = 200;
const IMAGE_WIDTH_LARGE = 300;
const IMAGE_WIDTH = IMAGE_WIDTH_LARGE;
const SENSITIVE_WARN_IMG = false; // 민감성 포스팅 이미지를 비우선으로할지말지 표시유무
const FETCH_DELAY = 60; // 바꿀필요없음. 50이하로쓰면 봇감지될가능성높음0
const WIDTH_THRESHOLD = 1800; // 안쓰이는 변수 ( 적용할지말지고민하다 그냥 안씀 ) 당시의도 : px단위. 이 px보다 커야 이미지미리보기가 발생한다
async function start() {
const $table = document.querySelector("body > div.root-container > div.content-wrapper.clearfix > article > div > div.article-list > div.list-table.table");
$table.style.display = 'flex';
$table.style.flexWrap = 'wrap';
$table.style.gap = '5px';
extendContentWrapper();
if (REMOVE_SIDE_BAR_MODE) removeRightSidebar();
const vrows = document.querySelectorAll(ARTICLES_SELECTOR);
vrows.forEach(vrow=>vrowToGallery(vrow));
const vrowsPromiseArray = Array.from(vrows).map((vrow, i) => imageFetchAndAttach(vrow, (i+1) * FETCH_DELAY));
const articles = document.querySelectorAll(ARTICLES_WITHOUT_NOTICE_SELECTOR);
articles.forEach((article) => {
article.style = "height: auto !important";
});
Promise.all(vrowsPromiseArray);
}
addEventListener("load", setTimeout(start, 0));
function vrowToGallery($vrow){
const $title = $vrow.querySelector('.vcol.col-title');
const $rate = $vrow.querySelector(RATE_IN_ARTICLE_SELECTOR);
const $newRate = document.createElement('span');
$newRate.style.fontWeight='bold';
$newRate.style.padding='0 2px';
$newRate.innerText = $rate.textContent;
$title.append($newRate);
$vrow.replaceChildren($title);
}
async function imageFetchAndAttach(vrow, delay) {
// 이미지 페칭해서 붙임.
await new Promise((r) => setTimeout(r, delay));
const response = await fetch(vrow.href);
const text = await response.text();
const html = new DOMParser().parseFromString(text, "text/html");
const tableImage = html.querySelector(TABLE_IMAGE_SELECTOR);
const video = html.querySelector(VIDEO_SELECTOR);
let image;
if(tableImage) {
image = tableImage;
} else if (video && video.width >300) {
image = new Image();
image.src = video.poster;
} else {
const imageCandidates = html.querySelectorAll(IMAGE_SELECTOR);
image = Array.from(imageCandidates).find(image=>SENSITIVE_WARN_IMG || !(image.width===1000 && image.height===667)) ?? new Image(300, 300);
}
fitImageSizeAndAlter(image);
const target = vrow.querySelector(ATTACH_TARGET_SELECTOR);
if (target) {
target.style.width = `${IMAGE_WIDTH}px`;
target.before(image);
}
vrow.style.display='flex';
vrow.style.flexDirection='column';
vrow.style.justifyContent = 'space-between';
vrow.style.width=`${IMAGE_WIDTH}px`
}
function fitImageSizeAndAlter(image) {
const aspectRatio = image.height / image.width;
image.style.display = 'block';
image.style.width = `${IMAGE_WIDTH}px`;
image.style.height = `${aspectRatio * IMAGE_WIDTH}px`;
if(IS_STRICT_SQUARE_IMAGE_MODE){
image.style.display = 'block';
image.style.objectFit = 'contain';
image.style.height = `${IMAGE_WIDTH}px`;
}
}
function removeRightSidebar() {
document.querySelector(".right-sidebar").style.display = "none";
}
function extendContentWrapper() {
const contentWrapper = document.querySelector(".content-wrapper.clearfix");
contentWrapper.style = "margin:0 5rem 0;max-width:100%";
const containerBoard = document.querySelector(".containe-fluid.board-article");
containerBoard.style = "margin:0";
}