// ==UserScript==
// @name 아카라이브 썸네일 이미지, 모두 열기
// @version 1.46
// @icon https://www.google.com/s2/favicons?sz=64&domain=arca.live
// @description 아카라이브 썸네일 이미지 생성, 모두 열기 생성, 그 외 잡다한 기능..
// @author ChatGPT
// @match https://arca.live/b/*
// @match https://arca.live/u/scrap_list
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_getValue
// @grant GM_setValue
// @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js
// @namespace Violentmonkey Scripts
// ==/UserScript==
(function() {
'use strict';
var config = {
openAllButton: true,
downAllButton: false,
compressFiles: true,
countImages: false,
originalImage: false,
downNumber: false,
thumbnail: true,
thumbWidth: 100,
thumbHeight: 62,
thumbHover: true,
thumbBlur: true,
thumbShadow: false,
blurAmount: 2,
origThumb: false,
thumbHoverBest: true,
controlButtons: false,
closeButton: false,
bookmarkButton: false,
downButton: false,
scrapList: true,
test01: false,
test02: false
};
function handleSettings() {
var descriptions = {
openAllButton: '모두 열기 버튼 생성',
downAllButton: '모든 이미지 다운로드 버튼 생성',
compressFiles: '모든 이미지를 압축해서 다운로드',
countImages: '모든 이미지의 총 개수를 구하고 진행률 표시',
originalImage: '원본 이미지로 다운로드(체크 해제시 webp저장)',
downNumber: '게시글 번호를 누르면 해당 게시글 이미지 다운로드',
thumbnail: '썸네일 이미지 생성',
thumbWidth: '썸네일 이미지 너비',
thumbHeight: '썸네일 이미지 높이',
thumbHover: '썸네일 이미지에 마우스 오버시 미리보기 이미지 출력',
thumbBlur: '썸네일 이미지 블러 효과',
thumbShadow: '썸네일 이미지 그림자 효과',
blurAmount: '블러 효과의 정도',
origThumb: '썸네일 이미지 클릭 시 원본 이미지 불러오기(유머 채널 개념글)',
thumbHoverBest: '썸네일 이미지에 마우스 오버시 미리보기 이미지 출력(유머 채널 개념글)',
controlButtons: '하단 우측 조작 버튼 생성',
closeButton: '창닫기 버튼 생성',
bookmarkButton: '스크랩 버튼 생성',
downButton: '다운로드 버튼 생성',
scrapList: '스크랩한 게시글 채널별, 탭별 필터링',
test01: '미리보기 이미지를 해당 게시글 다른 이미지 가져오기',
test02: '썸네일 이미지를 해당 게시글 다른 이미지로 대체'
};
var mainConfigKeys = Object.keys(descriptions).filter(key =>
!['compressFiles', 'countImages', 'originalImage', 'downNumber', 'thumbWidth', 'thumbHeight', 'thumbHover', 'thumbBlur', 'blurAmount', 'thumbShadow', 'origThumb', 'thumbHoverBest', 'test01', 'test02', 'closeButton', 'bookmarkButton', 'downButton'].includes(key)
);
function saveConfig() {
for (var key in config) {
if (config.hasOwnProperty(key)) {
GM_setValue(key, config[key]);
}
}
}
function loadConfig() {
for (var key in config) {
if (config.hasOwnProperty(key)) {
config[key] = GM_getValue(key, config[key]);
}
}
}
function createBaseWindow(id, titleText) {
var existingWindow = document.getElementById(id);
if (existingWindow) {
existingWindow.remove();
}
var window = document.createElement('div');
window.id = id;
window.style.position = 'fixed';
window.style.top = '50%';
window.style.left = '50%';
window.style.transform = 'translate(-50%, -50%)';
window.style.width = '250px';
window.style.padding = '20px';
window.style.background = '#ffffff';
window.style.border = '1px solid #cccccc';
window.style.borderRadius = '10px';
window.style.boxShadow = '0px 0px 10px rgba(0, 0, 0, 0.3)';
window.style.zIndex = '9999';
window.style.textAlign = 'left';
window.style.display = 'flex';
window.style.flexDirection = 'column';
window.style.alignItems = 'center';
var title = document.createElement('div');
title.innerHTML = titleText;
title.style.fontSize = '24px';
title.style.fontWeight = 'bold';
title.style.marginBottom = '10px';
window.appendChild(title);
return window;
}
function createDownloadSettingsWindow() {
var thumbnailSettingsWindow = createBaseWindow('thumbnailSettingsWindow', 'Download');
var keys = ['compressFiles', 'countImages', 'originalImage', 'downNumber'];
keys.forEach(function(key) {
var configDiv = document.createElement('div');
configDiv.style.marginBottom = '5px';
configDiv.style.display = 'flex';
configDiv.style.alignItems = 'center';
var label = document.createElement('label');
label.innerHTML = key + ': ';
label.style.marginRight = '5px';
label.style.marginBottom = '3px';
label.title = descriptions[key];
var input = document.createElement('input');
input.type = (typeof config[key] === 'boolean') ? 'checkbox' : 'text';
input.value = config[key];
input.checked = config[key];
if (input.type === 'text') {
input.style.width = '40px';
input.style.height = '20px';
input.style.padding = '0 5px';
}
input.addEventListener('input', (function(key) {
return function(event) {
if (key === 'blurAmount') {
event.target.value = event.target.value.replace(/\D/g, '');
}
config[key] = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
};
})(key));
configDiv.appendChild(label);
configDiv.appendChild(input);
thumbnailSettingsWindow.appendChild(configDiv);
});
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.marginTop = '10px';
var confirmButton = document.createElement('button');
confirmButton.innerHTML = '확인';
confirmButton.style.marginRight = '15px';
confirmButton.style.border = '1px solid #cccccc';
confirmButton.style.borderRadius = '5px';
confirmButton.addEventListener('click', function() {
saveConfig();
thumbnailSettingsWindow.remove();
});
confirmButton.addEventListener('mouseover', function() {
confirmButton.style.background = '#007bff';
confirmButton.style.color = '#ffffff';
});
confirmButton.addEventListener('mouseout', function() {
confirmButton.style.background = '';
confirmButton.style.color = '#000000';
});
buttonContainer.appendChild(confirmButton);
var cancelButton = document.createElement('button');
cancelButton.innerHTML = '취소';
cancelButton.style.border = '1px solid #cccccc';
cancelButton.style.borderRadius = '5px';
cancelButton.addEventListener('click', function() {
thumbnailSettingsWindow.remove();
});
cancelButton.addEventListener('mouseover', function() {
cancelButton.style.background = '#ff0000';
cancelButton.style.color = '#ffffff';
});
cancelButton.addEventListener('mouseout', function() {
cancelButton.style.background = '';
cancelButton.style.color = '#000000';
});
buttonContainer.appendChild(cancelButton);
thumbnailSettingsWindow.appendChild(buttonContainer);
document.body.appendChild(thumbnailSettingsWindow);
}
function createThumbnailSettingsWindow() {
var thumbnailSettingsWindow = createBaseWindow('thumbnailSettingsWindow', 'Thumbnail');
var keys = ['thumbWidth', 'thumbHeight', 'thumbHover', 'thumbBlur', 'blurAmount', 'thumbShadow', 'origThumb', 'thumbHoverBest', 'test01', 'test02'];
keys.forEach(function(key) {
var configDiv = document.createElement('div');
configDiv.style.marginBottom = '5px';
configDiv.style.display = 'flex';
configDiv.style.alignItems = 'center';
var label = document.createElement('label');
label.innerHTML = key + ': ';
label.style.marginRight = '5px';
label.style.marginBottom = '3px';
label.title = descriptions[key];
var input = document.createElement('input');
input.type = (typeof config[key] === 'boolean') ? 'checkbox' : 'text';
input.value = config[key];
input.checked = config[key];
if (input.type === 'text') {
input.style.width = '40px';
input.style.height = '20px';
input.style.padding = '0 5px';
}
input.addEventListener('input', (function(key) {
return function(event) {
if (key === 'blurAmount') {
event.target.value = event.target.value.replace(/\D/g, '');
}
config[key] = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
};
})(key));
configDiv.appendChild(label);
configDiv.appendChild(input);
if (key === 'test01') {
var settingsIcon = document.createElement('span');
settingsIcon.innerHTML = '⚙️';
settingsIcon.style.cursor = 'pointer';
settingsIcon.style.marginLeft = '3px';
settingsIcon.style.marginBottom = '2px';
settingsIcon.addEventListener('click', function() {
if (key === 'test01') {
createLinkSettingsWindow();
}
});
configDiv.appendChild(settingsIcon);
}
thumbnailSettingsWindow.appendChild(configDiv);
});
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.marginTop = '10px';
var confirmButton = document.createElement('button');
confirmButton.innerHTML = '확인';
confirmButton.style.marginRight = '15px';
confirmButton.style.border = '1px solid #cccccc';
confirmButton.style.borderRadius = '5px';
confirmButton.addEventListener('click', function() {
saveConfig();
thumbnailSettingsWindow.remove();
});
confirmButton.addEventListener('mouseover', function() {
confirmButton.style.background = '#007bff';
confirmButton.style.color = '#ffffff';
});
confirmButton.addEventListener('mouseout', function() {
confirmButton.style.background = '';
confirmButton.style.color = '#000000';
});
buttonContainer.appendChild(confirmButton);
var cancelButton = document.createElement('button');
cancelButton.innerHTML = '취소';
cancelButton.style.border = '1px solid #cccccc';
cancelButton.style.borderRadius = '5px';
cancelButton.addEventListener('click', function() {
thumbnailSettingsWindow.remove();
});
cancelButton.addEventListener('mouseover', function() {
cancelButton.style.background = '#ff0000';
cancelButton.style.color = '#ffffff';
});
cancelButton.addEventListener('mouseout', function() {
cancelButton.style.background = '';
cancelButton.style.color = '#000000';
});
buttonContainer.appendChild(cancelButton);
thumbnailSettingsWindow.appendChild(buttonContainer);
document.body.appendChild(thumbnailSettingsWindow);
}
function createControlSettingsWindow() {
var controlSettingsWindow = createBaseWindow('controlSettingsWindow', 'Control Buttons');
var keys = ['closeButton', 'bookmarkButton', 'downButton'];
keys.forEach(function(key) {
var configDiv = document.createElement('div');
configDiv.style.marginBottom = '5px';
configDiv.style.display = 'flex';
configDiv.style.alignItems = 'center';
var label = document.createElement('label');
label.innerHTML = key + ': ';
label.style.marginRight = '5px';
label.style.marginBottom = '3px';
label.title = descriptions[key];
var input = document.createElement('input');
input.type = (typeof config[key] === 'boolean') ? 'checkbox' : 'text';
input.value = config[key];
input.checked = config[key];
if (input.type === 'text') {
input.style.width = '40px';
input.style.height = '20px';
input.style.padding = '0 5px';
}
input.addEventListener('input', (function(key) {
return function(event) {
if (key === 'blurAmount') {
event.target.value = event.target.value.replace(/\D/g, '');
}
config[key] = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
};
})(key));
configDiv.appendChild(label);
configDiv.appendChild(input);
controlSettingsWindow.appendChild(configDiv);
});
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.marginTop = '10px';
var confirmButton = document.createElement('button');
confirmButton.innerHTML = '확인';
confirmButton.style.marginRight = '15px';
confirmButton.style.border = '1px solid #cccccc';
confirmButton.style.borderRadius = '5px';
confirmButton.addEventListener('click', function() {
saveConfig();
controlSettingsWindow.remove();
});
confirmButton.addEventListener('mouseover', function() {
confirmButton.style.background = '#007bff';
confirmButton.style.color = '#ffffff';
});
confirmButton.addEventListener('mouseout', function() {
confirmButton.style.background = '';
confirmButton.style.color = '#000000';
});
buttonContainer.appendChild(confirmButton);
var cancelButton = document.createElement('button');
cancelButton.innerHTML = '취소';
cancelButton.style.border = '1px solid #cccccc';
cancelButton.style.borderRadius = '5px';
cancelButton.addEventListener('click', function() {
controlSettingsWindow.remove();
});
cancelButton.addEventListener('mouseover', function() {
cancelButton.style.background = '#ff0000';
cancelButton.style.color = '#ffffff';
});
cancelButton.addEventListener('mouseout', function() {
cancelButton.style.background = '';
cancelButton.style.color = '#000000';
});
buttonContainer.appendChild(cancelButton);
controlSettingsWindow.appendChild(buttonContainer);
document.body.appendChild(controlSettingsWindow);
}
function createLinkSettingsWindow() {
var linkSettingsWindow = createBaseWindow('linkSettingsWindow', 'Filter Link');
var linkListContainer = document.createElement('div');
linkListContainer.style.marginBottom = '10px';
linkSettingsWindow.appendChild(linkListContainer);
// Load saved links and display them
var savedLinks = GM_getValue('savedLinks', []);
var rowContainer = document.createElement('div');
rowContainer.style.display = 'flex';
rowContainer.style.flexWrap = 'wrap';
rowContainer.style.justifyContent = 'center'; // 가로 중앙 정렬
rowContainer.style.alignItems = 'center'; // 세로 중앙 정렬
rowContainer.style.gap = '10px'; // Adds spacing between items
linkListContainer.appendChild(rowContainer);
savedLinks.forEach(function (link, index) {
var linkDiv = document.createElement('div');
linkDiv.style.display = 'flex';
linkDiv.style.flexDirection = 'column';
linkDiv.style.alignItems = 'center';
linkDiv.style.marginBottom = '10px';
linkDiv.style.width = '60px'; // Ensure all items have a fixed width to align properly
// Create a small thumbnail image
var thumbnail = document.createElement('img');
thumbnail.src = link; // Set the link as the image source
thumbnail.style.width = '50px'; // Adjust thumbnail width
thumbnail.style.height = '50px'; // Adjust thumbnail height
thumbnail.style.objectFit = 'cover'; // Ensure the image fits nicely
thumbnail.style.marginBottom = '5px';
// Add click event to set the link in the input field
thumbnail.addEventListener('click', function () {
var linkInput = document.querySelector('#linkInput'); // 입력창 선택
if (linkInput) {
linkInput.value = link; // 클릭된 이미지의 링크를 입력창에 설정
}
});
var deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';
deleteButton.style.border = '1px solid #cccccc';
deleteButton.style.borderRadius = '5px';
deleteButton.style.marginTop = '5px';
deleteButton.style.fontSize = '12px';
deleteButton.addEventListener('click', function () {
savedLinks.splice(index, 1);
GM_setValue('savedLinks', savedLinks);
createLinkSettingsWindow();
});
linkDiv.appendChild(thumbnail);
linkDiv.appendChild(deleteButton);
rowContainer.appendChild(linkDiv);
});
var addLinkContainer = document.createElement('div');
addLinkContainer.style.display = 'flex';
addLinkContainer.style.alignItems = 'center';
var linkInput = document.createElement('input');
linkInput.type = 'text';
linkInput.id = 'linkInput'; // 입력창에 id를 추가
linkInput.placeholder = '썸네일 이미지 링크 입력';
linkInput.style.flex = '1';
linkInput.style.marginRight = '5px';
linkInput.style.padding = '5px';
linkInput.style.width = '180px'
linkInput.style.fontSize = '12px'; // 글자 크기 줄이기
addLinkContainer.appendChild(linkInput);
var addLinkButton = document.createElement('button');
addLinkButton.textContent = 'Add';
addLinkButton.style.border = '1px solid #cccccc';
addLinkButton.style.borderRadius = '5px';
addLinkButton.addEventListener('click', function () {
var newLink = linkInput.value.trim();
if (newLink && !savedLinks.includes(newLink)) {
savedLinks.push(newLink);
GM_setValue('savedLinks', savedLinks);
createLinkSettingsWindow();
}
});
addLinkContainer.appendChild(linkInput);
addLinkContainer.appendChild(addLinkButton);
linkSettingsWindow.appendChild(addLinkContainer);
var tooltip = document.createElement('div');
tooltip.innerHTML = '해당 게시글의 다른 이미지로 대체';
tooltip.style.fontSize = '12px';
tooltip.style.marginTop = '15px';
tooltip.style.marginBottom = '5px';
tooltip.style.color = 'gray';
linkSettingsWindow.appendChild(tooltip);
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.marginTop = '10px';
var confirmButton = document.createElement('button');
confirmButton.innerHTML = '확인';
confirmButton.style.marginRight = '15px';
confirmButton.style.border = '1px solid #cccccc';
confirmButton.style.borderRadius = '5px';
confirmButton.addEventListener('click', function() {
saveConfig();
linkSettingsWindow.remove();
});
confirmButton.addEventListener('mouseover', function() {
confirmButton.style.background = '#007bff';
confirmButton.style.color = '#ffffff';
});
confirmButton.addEventListener('mouseout', function() {
confirmButton.style.background = '';
confirmButton.style.color = '#000000';
});
buttonContainer.appendChild(confirmButton);
var cancelButton = document.createElement('button');
cancelButton.innerHTML = '취소';
cancelButton.style.border = '1px solid #cccccc';
cancelButton.style.borderRadius = '5px';
cancelButton.addEventListener('click', function() {
linkSettingsWindow.remove();
});
cancelButton.addEventListener('mouseover', function() {
cancelButton.style.background = '#ff0000';
cancelButton.style.color = '#ffffff';
});
cancelButton.addEventListener('mouseout', function() {
cancelButton.style.background = '';
cancelButton.style.color = '#000000';
});
buttonContainer.appendChild(cancelButton);
linkSettingsWindow.appendChild(buttonContainer);
document.body.appendChild(linkSettingsWindow);
}
function createSettingsWindow() {
var settingsWindow = createBaseWindow('settingsWindow', 'Settings');
mainConfigKeys.forEach(function(key) {
var configDiv = document.createElement('div');
configDiv.style.marginBottom = '5px';
configDiv.style.display = 'flex';
configDiv.style.alignItems = 'center';
var label = document.createElement('label');
label.innerHTML = key + ': ';
label.style.marginRight = '5px';
label.style.marginBottom = '3px';
label.title = descriptions[key];
var input = document.createElement('input');
input.type = (typeof config[key] === 'boolean') ? 'checkbox' : 'text';
input.value = config[key];
input.checked = config[key];
if (input.type === 'text') {
input.style.width = '40px';
input.style.height = '20px';
input.style.padding = '0 5px';
}
input.addEventListener('input', (function(key) {
return function(event) {
config[key] = event.target.type === 'checkbox' ? event.target.checked : event.target.value;
};
})(key));
configDiv.appendChild(label);
configDiv.appendChild(input);
if (key === 'downAllButton' || key === 'thumbnail' || key === 'controlButtons' || key === 'test01') {
var settingsIcon = document.createElement('span');
settingsIcon.innerHTML = '⚙️';
settingsIcon.style.cursor = 'pointer';
settingsIcon.style.marginLeft = '3px';
settingsIcon.style.marginBottom = '2px';
settingsIcon.addEventListener('click', function() {
if (key === 'downAllButton') {
createDownloadSettingsWindow();
} else if (key === 'thumbnail') {
createThumbnailSettingsWindow();
} else if (key === 'controlButtons') {
createControlSettingsWindow();
} else if (key === 'test01') {
createLinkSettingsWindow();
}
});
configDiv.appendChild(settingsIcon);
}
settingsWindow.appendChild(configDiv);
});
var tooltip = document.createElement('div');
tooltip.innerHTML = '마우스를 올리면 설명이 나옵니다';
tooltip.style.fontSize = '12px';
tooltip.style.marginTop = '5px';
tooltip.style.marginBottom = '10px';
tooltip.style.color = 'gray';
settingsWindow.appendChild(tooltip);
var buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.marginTop = '10px';
var confirmButton = document.createElement('button');
confirmButton.innerHTML = '확인';
confirmButton.style.marginRight = '15px';
confirmButton.style.border = '1px solid #cccccc';
confirmButton.style.borderRadius = '5px';
confirmButton.addEventListener('click', function() {
saveConfig();
settingsWindow.remove();
location.reload();
});
confirmButton.addEventListener('mouseover', function() {
confirmButton.style.background = '#007bff';
confirmButton.style.color = '#ffffff';
});
confirmButton.addEventListener('mouseout', function() {
confirmButton.style.background = '';
confirmButton.style.color = '#000000';
});
buttonContainer.appendChild(confirmButton);
var cancelButton = document.createElement('button');
cancelButton.innerHTML = '취소';
cancelButton.style.border = '1px solid #cccccc';
cancelButton.style.borderRadius = '5px';
cancelButton.addEventListener('click', function() {
settingsWindow.remove();
});
cancelButton.addEventListener('mouseover', function() {
cancelButton.style.background = '#ff0000';
cancelButton.style.color = '#ffffff';
});
cancelButton.addEventListener('mouseout', function() {
cancelButton.style.background = '';
cancelButton.style.color = '#000000';
});
buttonContainer.appendChild(cancelButton);
settingsWindow.appendChild(buttonContainer);
document.body.appendChild(settingsWindow);
}
loadConfig();
GM_registerMenuCommand('설정', function() {
createSettingsWindow();
});
}
function arcaLiveScrapList() {
const header = document.querySelector('.list-table ');
// 부모 div (전체 컨테이너)
var containerDiv = document.createElement('div');
containerDiv.style.marginBottom = '0.5rem';
// 페이징 요소의 HTML을 가져옵니다.
const paginationHTML = document.querySelector('.pagination.justify-content-center');
const paginationDiv = document.createElement('div');
paginationDiv.innerHTML = paginationHTML.outerHTML;
paginationDiv.style.marginBottom = '0.5rem';
// Create filter div (채널과 탭 필터)
const filterDiv = document.createElement('div');
filterDiv.className = 'filterDiv';
filterDiv.style.display = 'flex';
// Create channel filter
const channelFilter = document.createElement('select');
channelFilter.className = 'form-control select-list-type';
channelFilter.name = 'sort';
channelFilter.style.cssText = 'width: auto; height: 2rem; float: left; padding: 0 0 0 .5rem; font-size: .9rem;';
const defaultChannelOption = document.createElement('option');
defaultChannelOption.value = '';
defaultChannelOption.text = '채널 선택';
channelFilter.appendChild(defaultChannelOption);
filterDiv.appendChild(channelFilter);
// Create tab filter
const tabFilter = document.createElement('select');
tabFilter.className = 'form-control select-list-type';
tabFilter.name = 'sort';
tabFilter.style.cssText = 'width: auto; height: 2rem; float: left; padding: 0 0 0 .5rem; font-size: .9rem;';
const defaultTabOption = document.createElement('option');
defaultTabOption.value = '';
defaultTabOption.text = '탭 선택';
tabFilter.appendChild(defaultTabOption);
filterDiv.appendChild(tabFilter);
// gridContainer에 각 영역 추가
containerDiv.appendChild(paginationDiv);
containerDiv.appendChild(filterDiv);
// 문서의 body에 추가 (혹은 다른 부모 요소에 추가 가능)
header.parentNode.insertBefore(containerDiv, header);
// Collect channels and tabs
const posts = document.querySelectorAll('.vrow.column.filtered, .vrow.column');
const channelTabMap = {};
posts.forEach(post => {
const badges = post.querySelectorAll('.badge');
if (badges.length >= 2) {
const channel = badges[0].textContent.trim();
const tab = badges[1].textContent.trim();
if (!channelTabMap[channel]) {
channelTabMap[channel] = new Set();
}
channelTabMap[channel].add(tab);
}
});
// Populate channel filter
Object.keys(channelTabMap).forEach(channel => {
const option = document.createElement('option');
option.value = channel;
option.text = channel;
channelFilter.appendChild(option);
});
// Update tab filter based on selected channel
function updateTabFilter() {
const selectedChannel = channelFilter.value;
tabFilter.innerHTML = '';
const defaultTabOption = document.createElement('option');
defaultTabOption.value = '';
defaultTabOption.text = '탭 선택';
tabFilter.appendChild(defaultTabOption);
if (selectedChannel && channelTabMap[selectedChannel]) {
channelTabMap[selectedChannel].forEach(tab => {
const option = document.createElement('option');
option.value = tab;
option.text = tab;
tabFilter.appendChild(option);
});
}
filterPosts();
}
// Filter posts based on selected channel and tab
function filterPosts() {
const selectedChannel = channelFilter.value;
const selectedTab = tabFilter.value;
posts.forEach(post => {
const badges = post.querySelectorAll('.badge');
if (badges.length >= 2) {
const postChannel = badges[0].textContent.trim();
const postTab = badges[1].textContent.trim();
if ((selectedChannel === '' || postChannel === selectedChannel) &&
(selectedTab === '' || postTab === selectedTab)) {
post.style.display = '';
} else {
post.style.display = 'none';
}
}
});
}
channelFilter.addEventListener('change', updateTabFilter);
tabFilter.addEventListener('change', filterPosts);
}
function arcaLive() {
// 모두 열기 버튼 생성
if (config.openAllButton) {
var openAllButton = document.createElement('a');
openAllButton.className = 'btn btn-sm btn-primary float-left';
openAllButton.href = '#';
openAllButton.innerHTML = '<span class="ion-android-list"></span><span> 모두 열기 </span>';
openAllButton.style.height = '2rem';
openAllButton.addEventListener('click', function(event) {
event.preventDefault();
// 게시글의 수를 계산
var posts = document.querySelectorAll('a.vrow.column:not(.notice)');
var postCount = 0;
// 필터링된 게시글을 제외한 수를 계산
posts.forEach(function(element) {
var href = element.getAttribute('href');
var classes = element.className.split(' ');
if (href && !classes.includes('filtered') && !classes.includes('filtered-keyword')) {
postCount++;
}
});
// 게시글 수를 포함한 메시지
const confirmMessage = `총 ${postCount}개의 게시글을 한 번에 엽니다.\n계속 진행하시겠습니까?`;
// 확인 메시지 표시
if (confirm(confirmMessage)) {
posts.forEach(function(element) {
var href = element.getAttribute('href');
var classes = element.className.split(' ');
if (href && !classes.includes('filtered') && !classes.includes('filtered-keyword')) {
window.open(href, '_blank');
}
});
}
});
var targetElement = document.querySelector('.form-control.select-list-type');
targetElement.parentNode.insertBefore(openAllButton, targetElement);
}
// 이미지와 동영상 다운로드 버튼 생성
if (config.downAllButton) {
async function getTotalImages(urls) {
let totalImages = 0;
for (const url of urls) {
const response = await fetch(url);
const html = await response.text();
const doc = new DOMParser().parseFromString(html, "text/html");
const imageElements = Array.from(doc.querySelectorAll('.article-body img')).filter(img => !img.classList.contains('arca-emoticon'));
const gifVideoElements = doc.querySelectorAll('video[data-orig="gif"][data-originalurl]');
totalImages += imageElements.length + gifVideoElements.length;
}
return totalImages;
}
async function downloadMediaSequentially(urls, totalImages, compressFiles) {
let totalDownloaded = 0;
// 프로그레스 바 업데이트 함수
function updateProgressBar(progress) {
const progressBar = document.getElementById('progress-bar');
progressBar.style.width = progress + '%';
progressBar.innerHTML = progress + '%';
if (progress === 100) {
setTimeout(() => {
progressBar.style.backgroundColor = 'orange'; // 100%일 때 배경색을 주황색으로 변경
}, 300); // 잠시 딜레이를 주어 애니메이션 완료 후 색상 변경
}
}
async function downloadFile(url, index, type, requestUrl, zip, title) {
const response = await fetch(url);
const blob = await response.blob();
const extension = type === 'img' ? (config.originalImage ? url.split('.').pop().split('?')[0].toLowerCase() : 'webp') : 'gif';
const numbersFromUrl = requestUrl.match(/\d+/)[0];
const fileIndex = index + 1; // Index를 1 증가시킴
// const sanitizedTitle = title.replace(/[^a-zA-Z0-9가-힣\s]/g, '_'); // 파일 이름에 사용할 수 있도록 제목을 정제
const numberedFileName = compressFiles ? `${title}_${String(fileIndex).padStart(2, '0')}.${extension}` : `${numbersFromUrl}_${String(fileIndex).padStart(2, '0')}.${extension}`;
if (zip) {
zip.file(numberedFileName, blob);
} else {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = numberedFileName;
link.click();
}
}
async function processNextUrl() {
for (let index = 0; index < urls.length; index++) {
const url = urls[index];
let zip;
if (compressFiles) {
zip = new JSZip();
}
const response = await fetch(url);
const html = await response.text();
const doc = new DOMParser().parseFromString(html, "text/html");
const titleElement = doc.querySelector('.title-row .title');
let title = '';
if (titleElement) {
const textNodes = Array.from(titleElement.childNodes)
.filter(node => node.nodeType === Node.TEXT_NODE && node.parentElement === titleElement);
if (textNodes.length > 0) {
title = textNodes.map(node => node.textContent.trim()).join('');
}
}
// arca-emoticon 클래스를 가진 이미지를 제외하고 선택
const mediaElements = Array.from(doc.querySelectorAll('.article-body img, .article-body video[data-orig="gif"]')).filter(media => !media.classList.contains('arca-emoticon'));
try {
if (mediaElements.length > 0) {
for (let i = 0; i < mediaElements.length; i++) {
const media = mediaElements[i];
const mediaType = media.tagName.toLowerCase();
const mediaUrl = mediaType === 'img' ? (config.originalImage ? media.getAttribute('src') + "&type=orig" : media.getAttribute('src')) : media.getAttribute('data-originalurl');
if (mediaUrl) {
await downloadFile(mediaUrl, i, mediaType, url, zip, title);
totalDownloaded++;
if (config.countImages) {
const progress = Math.round((totalDownloaded / totalImages) * 100);
updateProgressBar(progress);
}
}
}
if (zip) {
const content = await zip.generateAsync({ type: 'blob' });
const numbersFromUrl = url.match(/\d+/)[0];
const zipFileName = `${numbersFromUrl}.zip`;
const zipLink = document.createElement('a');
zipLink.href = window.URL.createObjectURL(content);
zipLink.download = zipFileName;
zipLink.click();
}
}
} catch (error) {
console.error("Error downloading media:", error);
}
}
}
await processNextUrl();
}
var downloadMediaButton = document.createElement('a');
downloadMediaButton.className = 'btn btn-sm btn-success float-left';
downloadMediaButton.href = '#';
downloadMediaButton.innerHTML = '<span class="ion-android-download"></span><span> 다운로드 </span>';
downloadMediaButton.style.position = 'relative'; // 상대 위치 지정
// 프로그레스 바 스타일을 가진 div 엘리먼트 추가
var progressBar = document.createElement('div');
progressBar.id = 'progress-bar'; // ID 추가
progressBar.style.position = 'absolute'; // 절대 위치 지정
progressBar.style.bottom = '5%';
progressBar.style.left = '0';
progressBar.style.width = '0%'; // 초기 너비는 0%
progressBar.style.height = '10%';
progressBar.style.backgroundColor = 'yellow'; // 프로그레스 바 색상
progressBar.style.borderRadius = 'inherit';
progressBar.style.transition = 'width 0.3s ease-in-out'; // 프로그레스 바 애니메이션
downloadMediaButton.appendChild(progressBar); // 프로그레스 바를 버튼에 추가
downloadMediaButton.addEventListener('click', async function(event) {
event.preventDefault();
var mediaUrls = []; // 다운로드할 미디어 URL을 저장할 배열
document.querySelectorAll('a.vrow.column:not(.notice)').forEach(function(element) {
var href = element.getAttribute('href');
var classes = element.className.split(' ');
if (href && !classes.includes('filtered') && !classes.includes('filtered-keyword')) {
mediaUrls.push(href); // 미디어 URL을 배열에 추가
}
});
const mediaUrlsCount = mediaUrls.length;
if (config.countImages) {
const initialMessage = `총 ${mediaUrlsCount}개의 게시글을 찾았습니다.\n모든 게시글의 이미지를 확인하여 총 개수를 계산합니다.\n계산하는 데 시간이 오래 걸릴 수 있습니다.\n(설정에서 변경 가능)`;
alert(initialMessage);
const totalImages = await getTotalImages(mediaUrls);
const confirmMessage = `다운로드해야 할 이미지의 총 개수는 ${totalImages}개입니다.\n계속해서 다운로드 하시겠습니까?`;
if (confirm(confirmMessage)) {
progressBar.style.width = '0%'; // 초기 너비는 0%
progressBar.style.backgroundColor = 'yellow'; // 프로그레스 바 색상
await downloadMediaSequentially(mediaUrls, totalImages, config.compressFiles); // config.compressFiles 변수 전달
}
} else {
// 프로그레스 바를 사용하지 않을 경우에는 다운로드 여부를 확인하는 창 띄우기
const confirmMessage = `총 ${mediaUrlsCount}개의 게시글을 한 번에 다운로드합니다.\n다운로드를 진행하시겠습니까?`;
if (confirm(confirmMessage)) {
progressBar.style.width = '0%'; // 초기 너비는 0%
progressBar.style.backgroundColor = 'yellow'; // 프로그레스 바 색상
await downloadMediaSequentially(mediaUrls, 0, config.compressFiles); // config.compressFiles 변수 전달
progressBar.style.width = '100%';
progressBar.style.backgroundColor = 'orange'; // 100%일 때 배경색을 주황색으로 변경
}
}
});
var targetElement = document.querySelector('.form-control.select-list-type');
targetElement.parentNode.insertBefore(downloadMediaButton, targetElement);
}
if (config.downNumber) {
// document.addEventListener("DOMContentLoaded", function() {
// });
document.querySelectorAll('.vrow.column:not(.notice) .vcol.col-id').forEach(function(link) {
link.addEventListener('click', async function(event) {
event.preventDefault(); // 기본 동작 방지
link.style.color = 'orange'; // 다운로드 시작 시 노란색으로 변경
const parentHref = link.closest('.vrow.column').getAttribute('href');
await downloadMediaFromUrl(parentHref, config.compressFiles); // compressFiles 변수 전달
link.style.color = 'red'; // 다운로드 완료 시 빨간색으로 변경
});
});
async function downloadMediaFromUrl(url, compressFiles) { // compressFiles 변수 추가
const response = await fetch(url);
const html = await response.text();
const doc = new DOMParser().parseFromString(html, "text/html");
const mediaElements = Array.from(doc.querySelectorAll('.article-body img, .article-body video[data-orig="gif"]')).filter(media => !media.classList.contains('arca-emoticon'));
let zip;
const titleElement = doc.querySelector('.title-row .title');
let title = '';
if (titleElement) {
const textNodes = Array.from(titleElement.childNodes)
.filter(node => node.nodeType === Node.TEXT_NODE && node.parentElement === titleElement);
if (textNodes.length > 0) {
title = textNodes.map(node => node.textContent.trim()).join('');
}
}
async function downloadFile(mediaUrl, index, type) {
const response = await fetch(mediaUrl);
const blob = await response.blob();
const extension = type === 'img' ? (config.originalImage ? mediaUrl.split('.').pop().split('?')[0].toLowerCase() : 'webp') : 'gif';
const fileIndex = index + 1;
const numbersFromUrl = url.match(/\d+/)[0];
// const sanitizedTitle = title.replace(/[^a-zA-Z0-9가-힣\s]/g, '_'); // 파일 이름에 사용할 수 있도록 제목을 정제
const numberedFileName = compressFiles ? `${title}_${String(fileIndex).padStart(2, '0')}.${extension}` : `${numbersFromUrl}_${String(fileIndex).padStart(2, '0')}.${extension}`;
if (compressFiles) {
zip.file(numberedFileName, blob);
} else {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = numberedFileName;
link.click();
}
}
async function processMedia() {
for (let i = 0; i < mediaElements.length; i++) {
const media = mediaElements[i];
const mediaType = media.tagName.toLowerCase();
const mediaUrl = mediaType === 'img' ? (config.originalImage ? media.getAttribute('src') + "&type=orig" : media.getAttribute('src')) : media.getAttribute('data-originalurl');
if (mediaUrl) {
await downloadFile(mediaUrl, i, mediaType);
}
}
}
if (compressFiles) {
zip = new JSZip();
}
await processMedia();
if (compressFiles) {
const content = await zip.generateAsync({ type: 'blob' });
const zipFileName = url.match(/\d+/)[0] + '.zip';
const zipLink = document.createElement('a');
zipLink.href = window.URL.createObjectURL(content);
zipLink.download = zipFileName;
zipLink.click();
}
}
}
if (config.thumbnail) {
document.addEventListener("DOMContentLoaded", function() {
function checkBlackEdge(img, callback) {
var newImg = new Image();
newImg.crossOrigin = 'anonymous';
newImg.onload = function() {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = newImg.width;
canvas.height = newImg.height;
ctx.drawImage(newImg, 0, 0, newImg.width, newImg.height);
var edgeSize = Math.min(newImg.width, newImg.height) * 0.1;
var imgData = ctx.getImageData(0, 0, newImg.width, newImg.height);
var totalPixels = 0;
var blackPixels = 0;
for (var x = 0; x < newImg.width; x++) {
for (var y = 0; y < newImg.height; y++) {
if (x < edgeSize || x >= newImg.width - edgeSize || y < edgeSize || y >= img.height - edgeSize) {
totalPixels++;
var index = (y * newImg.width + x) * 4;
var pixelData = [
imgData.data[index], // Red
imgData.data[index + 1], // Green
imgData.data[index + 2] // Blue
];
if (pixelData[0] === 0 && pixelData[1] === 0 && pixelData[2] === 0) {
blackPixels++;
}
}
}
}
var blackPercentage = blackPixels / totalPixels;
if (blackPercentage >= 0.33) {
callback(true);
} else {
callback(false);
}
};
newImg.onerror = function() {
// 이미지 로드 실패 시에도 콜백 호출하여 처리
callback(false);
};
newImg.src = img.src + "&type=list"; // newImg.src = img.src + "&type=list";
}
function setSecondImg(vrow, img) {
var href = vrow.href;
fetch(href)
.then(response => {
if (!response.ok) {
throw new Error('Request failed with status ' + response.status);
}
return response.text();
})
.then(responseText => {
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(responseText, "text/html");
var contentDiv = htmlDoc.querySelector('div.fr-view.article-content');
if (!contentDiv) {
return;
}
var Tags = contentDiv.querySelectorAll('img, video');
var firstTag = null;
for (var i = 0; i < Tags.length; i++) {
firstTag = Tags[i];
if (firstTag.style.width == '2px' && firstTag.style.height == '2px') {
break;
} else if (firstTag.tagName.toLowerCase() === 'img') {
if (!(img.src.split("?")[0] === firstTag.src.split("?")[0])) {
break;
}
} else if (firstTag.tagName.toLowerCase() === 'video') {
break;
}
}
if (!firstTag) {
return;
}
var videoOriginalSrc = firstTag.getAttribute('data-originalurl');
var videoOriginalSrcType = firstTag.getAttribute('data-orig');
var videoPosterSrc = firstTag.getAttribute('poster');
var changeImgUrl = null;
if (firstTag.tagName.toLowerCase() === 'img') {
changeImgUrl = firstTag.src + "&type=list";
} else if (firstTag.tagName.toLowerCase() === 'video') {
if (videoOriginalSrc && !videoOriginalSrcType) {
changeImgUrl = videoOriginalSrc + "&type=list";
} else if (videoPosterSrc) {
changeImgUrl = videoPosterSrc + "&type=list";
} else {
changeImgUrl = img.src;
}
}
// config.test02가 true일 경우 이미지 변경
if (config.test02) {
img.onload = function () {
img.parentNode.style.border = '2px solid pink';
// img.parentNode.style.boxShadow = 'rgb(255 155 155) 2px 2px 2px';
};
img.src = changeImgUrl;
}
var previewImg = vrow.querySelector('.vrow-preview img')
previewImg.src = changeImgUrl.replace("&type=list", '');
})
.catch(error => {
console.error('Error fetching data:', error);
});
}
const vrows = document.querySelectorAll('a.vrow.column:not(.notice)')
vrows.forEach(function(vrow) {
var vcolId = vrow.querySelector('.vcol.col-id');
var vcolTitle = vrow.querySelector('.vcol.col-title');
vcolId.style.margin = '0';
vcolId.style.height = 'auto';
vcolId.style.display = 'flex';
vcolId.style.alignItems = 'center'; // 세로 가운데 정렬
vcolId.style.justifyContent = 'center'; // 가로 가운데 정렬
var vcolThumb = vrow.querySelector('.vcol.col-thumb');
if (!vcolThumb) {
vcolThumb = document.createElement('span');
vcolThumb.className = 'vcol col-thumb';
vcolThumb.style.width = config.thumbWidth + 'px';
vcolThumb.style.borderRadius = '3px';
vrow.querySelector('.vrow-inner').appendChild(vcolThumb);
vcolTitle.parentNode.insertBefore(vcolThumb, vcolTitle);
}
var vrowPreview = vrow.querySelector('.vrow-preview');
// vrowPreview가 존재할 때만 썸네일을 추가하도록 조건 추가
if (vrowPreview) {
var thumbnailCreated = false; // 썸네일 생성 여부 플래그
function createThumbnail() {
if (thumbnailCreated) return; // 이미 썸네일이 생성되었으면 더 이상 생성하지 않음
var previewImg = vrowPreview.querySelector('img');
if (!previewImg) return;
vrow.style.height = 'auto';
vrow.style.paddingTop = '3.75px';
vrow.style.paddingBottom = '3.75px';
vcolThumb.style.height = config.thumbHeight + 'px';
var thumbImg = vcolThumb.querySelector('img');
if (!thumbImg) {
thumbImg = document.createElement('img');
thumbImg.src = previewImg.src;
thumbImg.style.width = '100%';
thumbImg.style.height = '100%';
thumbImg.style.objectFit = 'cover';
if (config.thumbShadow) {
thumbImg.onload = function () {
vcolThumb.style.boxShadow = 'rgba(0, 0, 0, 0.4) 2px 2px 2px';
}
}
if (config.test01 || config.test02) {
checkBlackEdge(thumbImg, function(hasBlackEdge) {
if (hasBlackEdge) {
setSecondImg(vrow, thumbImg);
}
});
function removeQueryString(url) {
var parsedUrl = new URL(url);
return parsedUrl.origin + parsedUrl.pathname;
}
var savedLinks = GM_getValue('savedLinks', []);
var cleanSrc = removeQueryString(thumbImg.src);
if (savedLinks.some(link => cleanSrc.includes(removeQueryString(link)))) {
setSecondImg(vrow, thumbImg);
console.log("Filtered Image:", vcolId.querySelector('span').textContent, thumbImg.src);
}
}
if (config.thumbBlur) {
thumbImg.style.filter = 'blur(' + config.blurAmount + 'px)';
thumbImg.addEventListener('mouseenter', function() {
thumbImg.style.filter = 'none';
});
thumbImg.addEventListener('mouseleave', function() {
thumbImg.style.filter = 'blur(' + config.blurAmount + 'px)';
});
}
if (config.thumbHover) {
thumbImg.addEventListener('mouseenter', function() {
vrowPreview.style.display = null;
});
thumbImg.addEventListener('mouseleave', function() {
vrowPreview.style.display = 'none';
});
}
vcolThumb.appendChild(thumbImg);
thumbnailCreated = true; // 썸네일 생성 완료
}
vrowPreview.style.display = 'none';
vrowPreview.style.pointerEvents = 'none';
vrowPreview.style.width = '30rem';
vrowPreview.style.height = 'auto';
vrowPreview.style.top = 'auto';
vrowPreview.style.left = (99) + parseFloat(config.thumbWidth) + 'px';
previewImg.src = previewImg.src.replace("&type=list", '');
}
function tryCreateThumbnail(retryCount) {
if (retryCount >= 100 || thumbnailCreated) return; // 썸네일이 이미 생성되었으면 더 이상 시도하지 않음
setTimeout(function() {
if (retryCount === 0) createThumbnail();
tryCreateThumbnail(retryCount + 1);
}, 100);
}
tryCreateThumbnail(0);
}
});
});
}
// 썸네일 클릭 시 원본 이미지 불러오기
if (config.origThumb) {
document.querySelectorAll('a.title.preview-image').forEach(function(link) {
link.addEventListener('click', function(event) {
event.preventDefault(); // 기본 동작 방지
var imageUrl = link.querySelector('img').getAttribute('src').replace(/&type=list/g, '');
window.location.href = imageUrl;
});
});
}
// 개념글 미리보기 이미지 마우스 오버시 보이게
if (config.thumbHoverBest) {
// 이미지 요소 선택
var vrowPreviewImgs = document.querySelectorAll('.vrow.hybrid .title.preview-image .vrow-preview img');
// 각 이미지 요소에 이벤트 추가
vrowPreviewImgs.forEach(function(vrowPreviewImg) {
// 이미지에 호버 이벤트 추가
vrowPreviewImg.addEventListener('mouseenter', function() {
// 이미지의 부모 요소 찾기
var parentDiv = vrowPreviewImg.closest('.vrow.hybrid');
// 복제된 이미지 요소 생성
var duplicatevrowPreviewImg = document.createElement('img');
duplicatevrowPreviewImg.src = vrowPreviewImg.src.replace('&type=list', '');
// 복제된 이미지의 스타일 설정
duplicatevrowPreviewImg.style.position = 'absolute';
duplicatevrowPreviewImg.style.width = '30rem';
duplicatevrowPreviewImg.style.height = 'auto';
duplicatevrowPreviewImg.style.top = 'auto';
duplicatevrowPreviewImg.style.left = '7.5rem'; // 오른쪽으로 10rem 이동
duplicatevrowPreviewImg.style.zIndex = '1';
duplicatevrowPreviewImg.style.padding = '5px';
duplicatevrowPreviewImg.style.border = '1px solid';
duplicatevrowPreviewImg.style.borderRadius = '5px';
duplicatevrowPreviewImg.style.boxSizing = 'content-box';
duplicatevrowPreviewImg.style.backgroundColor = '#fff'; // 배경색
duplicatevrowPreviewImg.style.borderColor = '#bbb'; // 테두리 색상
// vrow hybrid 클래스에 align-items: center; 스타일 추가
parentDiv.classList.add('hybrid');
parentDiv.style.alignItems = 'center'; // 수직 가운데 정렬
// 복제된 이미지 요소를 기존 이미지 요소 다음에 추가
parentDiv.appendChild(duplicatevrowPreviewImg);
// 마우스를 이미지에서 떼었을 때 복제된 이미지 제거
vrowPreviewImg.addEventListener('mouseleave', function() {
duplicatevrowPreviewImg.remove();
});
});
});
}
if (config.controlButtons) {
if ((config.closeButton || config.bookmarkButton || config.downButton)) {
document.addEventListener('DOMContentLoaded', function () {
var articleMenu = document.querySelector('.article-menu.mt-2');
var originalScrapButton = articleMenu ? articleMenu.querySelector('.scrap-btn') : null;
var originalDownloadButton = articleMenu ? articleMenu.querySelector('#imageToZipBtn') : null;
var navControl = document.querySelector('.nav-control');
// 새로운 리스트 아이템 요소를 생성하는 함수
function createNewItem(iconClass, clickHandler, hoverHandler, leaveHandler) {
var newItem = document.createElement('li');
newItem.innerHTML = '<span class="' + iconClass + '"></span>';
newItem.addEventListener('click', clickHandler);
if (hoverHandler) {
newItem.addEventListener('mouseenter', hoverHandler);
}
if (leaveHandler) {
newItem.addEventListener('mouseleave', leaveHandler);
}
return newItem;
}
// 새로운 아이템을 내비게이션 컨트롤 리스트에 추가하거나 업데이트하는 함수
function appendOrUpdateItem(newItem) {
if (navControl) {
if (navControl.children.length > 0) {
navControl.insertBefore(newItem, navControl.firstElementChild);
} else {
navControl.appendChild(newItem);
}
} else {
console.error('내비게이션 컨트롤 리스트를 찾을 수 없습니다.');
}
}
// 다운로드 버튼 생성
if (config.controlButtons && config.downButton) {
if (articleMenu) {
var downloadButton = createNewItem(
'ion-android-download',
downloadButtonClickHandler,
downloadButtonHoverHandler,
downloadButtonLeaveHandler
);
appendOrUpdateItem(downloadButton);
}
}
// 다운로드 버튼 핸들러
function downloadButtonClickHandler() {
originalDownloadButton = articleMenu.querySelector('#imageToZipBtn');
if (originalDownloadButton) {
// 다운로드 버튼 클릭
originalDownloadButton.click();
var progressChecked = false; // 프로그레스 바가 50% 이상인지 체크하는 변수
var intervalId = setInterval(function () {
// 다운로드 진행 상태를 추적할 .download-progress 요소 찾기
var downloadProgress = originalDownloadButton.querySelector('.download-progress');
if (downloadProgress) {
// 프로그레스 바가 존재하면 진행 상태의 width 값 확인
var width = parseFloat(downloadProgress.style.width);
// 50% 이상이면 완료된 것으로 간주
if (width >= 50) {
progressChecked = true;
}
// 프로그레스 바가 진행되면서 다운로드 버튼의 배경색을 조정
downloadButton.style.background = `
linear-gradient(to top, green ${width}%, transparent ${width}%),
#3d414d
`;
// 프로그레스 바가 100%에 도달했을 때
if (width >= 100) {
clearInterval(intervalId); // 애니메이션 종료
downloadButton.style.background = `
linear-gradient(to top, green 100%, transparent 100%),
#3d414d
`;
}
} else {
// 프로그레스 바가 사라졌을 때 (프로그레스 바가 없을 때)
if (progressChecked) {
// 프로그레스 바가 50% 이상이었다면 완료된 것으로 간주
downloadButton.style.background = `
linear-gradient(to top, green 100%, transparent 100%),
#3d414d
`;
} else {
// 프로그레스 바가 50% 미만이었다면 취소로 간주
downloadButton.style.background = `
linear-gradient(to top, green 0%, transparent 0%),
#3d414d
`;
}
clearInterval(intervalId); // 애니메이션 종료
}
}, 10); // 10ms마다 확인
}
}
function downloadButtonHoverHandler() {
this.style.backgroundColor = 'green';
}
function downloadButtonLeaveHandler() {
this.style.backgroundColor = '';
}
// 북마크 버튼 생성
if (config.controlButtons && config.bookmarkButton) {
if (originalScrapButton) {
var bookmarkButton = createNewItem(
'ion-android-bookmark',
bookmarkButtonClickHandler,
bookmarkButtonHoverHandler,
bookmarkButtonLeaveHandler
);
appendOrUpdateItem(bookmarkButton);
// 북마크 버튼 색상을 업데이트하는 함수
function updateButtonColor() {
var buttonText = originalScrapButton.querySelector('.result').textContent.trim();
bookmarkButton.style.backgroundColor = (buttonText === "스크랩 됨") ? '#007bff' : '';
}
// 초기 호출 및 MutationObserver 설정
updateButtonColor();
var observer = new MutationObserver(updateButtonColor);
observer.observe(originalScrapButton.querySelector('.result'), { childList: true, subtree: true });
}
}
// 북마크 버튼 핸들러
function bookmarkButtonClickHandler() {
if (originalScrapButton) {
originalScrapButton.click();
} else {
console.error('원래의 스크랩 버튼을 찾을 수 없습니다.');
}
}
function bookmarkButtonHoverHandler() {
this.style.backgroundColor = '#007bff';
}
function bookmarkButtonLeaveHandler() {
var buttonText = originalScrapButton.querySelector('.result').textContent.trim();
this.style.backgroundColor = (buttonText === "스크랩 됨") ? '#007bff' : '';
}
// 닫기 버튼 생성 및 추가
if (config.controlButtons && config.closeButton) {
var closeButton = createNewItem(
'ion-close-round',
closeButtonClickHandler,
closeButtonHoverHandler,
closeButtonLeaveHandler
);
appendOrUpdateItem(closeButton);
}
// 닫기 버튼 핸들러
function closeButtonClickHandler() {
window.close();
}
function closeButtonHoverHandler() {
this.style.backgroundColor = 'red';
}
function closeButtonLeaveHandler() {
this.style.backgroundColor = '';
}
});
}
}
}
handleSettings();
if (window.location.href.includes('scrap_list')) {
if (config.scrapList){
// arcaLiveScrapList();
setTimeout(arcaLiveScrapList, 0);
}
}
// arcaLive();
setTimeout(arcaLive, 0);
})();