장점은 내가 갖고있는지 여부랑, 파일명을 같이 저장해서 db에 두면 뭐라고 저장해놨는지 보기 편하다는 점이랑
AI작품같은 경우 들어가도 VPN안키면 설명 이미지가 안보이는데 얘는 그런거 무시하고 바로 볼 수 있어서 편함
이미지 없는 복구글 뭐였는지 기억이 안나서 만들었는데 생각보다 반응도 빠릿빠릿하고 편해서 공유해봄
---
스크립트 등록 방법 :
Tempermonkey - 새 스크립트 만들기
아래 펼쳐서 싹다 붙여넣기
// ==UserScript==
// @name RJ Search Helper
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Search for selected text in a local database and show formatted results
// @author FLAG
// @match *://kone.gg/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(function () {
'use strict';
// CSS for the popup and settings
const styles = `
#ark-search-popup {
position: fixed;
z-index: 10000;
background: #222;
color: #fff;
padding: 20px;
padding-top: 40px;
border-radius: 10px;
box-shadow: 0 6px 25px rgba(0,0,0,0.5);
font-family: 'Inter', sans-serif;
font-size: 16px;
width: 640px;
display: none;
border: 1px solid #444;
}
#ark-drag-handle {
position: absolute;
top: 5px; left: 50%;
transform: translateX(-50%);
width: 60px;
height: 6px;
background: #00d1ff;
cursor: move;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
z-index: 10002;
}
#ark-search-popup .result-item { margin-bottom: 8px; line-height: 1.5; border-bottom: 1px solid #333; padding-bottom: 6px; }
#ark-search-popup .close-btn { position: absolute; top: 5px; right: 12px; cursor: pointer; color: #888; font-size: 24px; z-index: 10001; }
#ark-search-popup .close-btn:hover { color: #fff; }
#ark-image-container {
display: flex;
overflow-x: auto;
gap: 12px;
margin-top: 15px;
padding-bottom: 8px;
}
#ark-image-container img {
height: 384px;
border-radius: 6px;
border: 1px solid #444;
flex-shrink: 0;
cursor: pointer;
}
#ark-image-container::-webkit-scrollbar { height: 8px; }
#ark-image-container::-webkit-scrollbar-thumb { background: #555; border-radius: 4px; }
#ark-settings-overlay {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.8);
z-index: 10001;
display: none;
justify-content: center;
align-items: center;
}
#ark-settings-modal {
background: #1e1e1e;
padding: 20px;
border-radius: 10px;
width: 80%;
max-width: 600px;
color: #eee;
}
#ark-db-input {
width: 100%;
height: 300px;
background: #111;
color: #0f0;
border: 1px solid #333;
padding: 10px;
font-family: monospace;
margin: 10px 0;
border-radius: 5px;
}
.ark-btn {
background: #00d1ff;
color: #000;
border: none;
padding: 8px 16px;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}
.ark-btn:hover { background: #00b8e6; }
`;
const styleSheet = document.createElement("style");
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
// Initial Elements
const popup = document.createElement('div');
popup.id = 'ark-search-popup';
document.body.appendChild(popup);
const overlay = document.createElement('div');
overlay.id = 'ark-settings-overlay';
overlay.innerHTML = `
<div id="ark-settings-modal">
<h3>데이터 베이스 관리</h3>
<p>아래에 텍스트를 입력하고 저장 버튼을 눌러주세요.</p>
<textarea id="ark-db-input" placeholder="텍스트를 여기에 붙여넣어주세요..."></textarea>
<div style="text-align: right;">
<button class="ark-btn" id="ark-save-db">저장</button>
<button class="ark-btn" id="ark-close-settings" style="background: #444; color: #fff; margin-left: 10px;">닫기</button>
</div>
</div>
`;
document.body.appendChild(overlay);
// Database access
function getDatabase() {
const raw = GM_getValue('ark_db', '');
return raw.split('\n').map(line => line.trim()).filter(line => line.length > 0);
}
function saveDatabase(text) {
GM_setValue('ark_db', text);
alert('Database updated successfully!');
overlay.style.display = 'none';
}
// Search logic
function search(query) {
if (!query) return { results: [], rjCode: null };
// Extract RJ or ST code (e.g., RJ123456, ST123456)
const match = query.match(/(RJ|ST)\d+/i);
const searchToken = match ? match[0].toUpperCase() : query.trim();
if (!searchToken) return { results: [], rjCode: null };
const db = getDatabase();
const results = db.filter(line => line.toUpperCase().includes(searchToken));
return { results, rjCode: searchToken.startsWith('RJ') ? searchToken : null };
}
function getDLSiteImages(rjCode) {
if (!rjCode) return [];
const numStr = rjCode.substring(2);
const num = parseInt(numStr);
const folderNum = (Math.floor(num / 1000) + 1) * 1000;
const folder = "RJ" + folderNum.toString().padStart(numStr.length, '0');
const baseUrl = `https://img.dlsite.jp/modpub/images2/work/doujin/${folder}/`;
// 5 images as requested (Main + 4 samples)
const suffixes = ["_img_main", "_img_smp1", "_img_smp2", "_img_smp3", "_img_smp4"];
return suffixes.map(s => `${baseUrl}${rjCode.toUpperCase()}${s}.webp`);
}
// Result formatting
function formatResult(line) {
let prefix = "";
const trimmedLine = line.trim();
const hasBrackets = /\[.*\]$/.test(trimmedLine);
const hasMibun = trimmedLine.includes("미번");
if (hasBrackets && hasMibun) {
prefix = "★@ ";
} else if (hasBrackets) {
prefix = "★ ";
} else if (hasMibun) {
prefix = "@ ";
}
return prefix + line;
}
// UI Logic
function showPopup(data, x, y) {
const { results, rjCode } = data;
popup.innerHTML = `
<div id="ark-drag-handle"></div>
<span class="close-btn">×</span>
<h3>Search Results</h3>
<div id="ark-popup-content"></div>
`;
const contentArea = popup.querySelector('#ark-popup-content');
// Dragging logic
const dragHandle = popup.querySelector('#ark-drag-handle');
dragHandle.onmousedown = function (e) {
e.preventDefault();
let startX = e.clientX - popup.offsetLeft;
let startY = e.clientY - popup.offsetTop;
function onMouseMove(e) {
popup.style.left = (e.clientX - startX) + 'px';
popup.style.top = (e.clientY - startY) + 'px';
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
if (results.length === 0) {
contentArea.innerHTML = `<div style="color: #ff4d4d; font-weight: bold;">현재 저장소에 없습니다!</div>`;
} else {
contentArea.innerHTML = `<div style="color: #00d1ff; font-weight: bold; margin-bottom: 10px;">파일을 발견했습니다!</div>`;
results.forEach(res => {
const div = document.createElement('div');
div.className = 'result-item';
div.innerText = formatResult(res);
contentArea.appendChild(div);
});
}
// Add Images if RJ code exists
if (rjCode) {
const imgContainer = document.createElement('div');
imgContainer.id = 'ark-image-container';
// Add horizontal scroll on mouse wheel
imgContainer.addEventListener('wheel', (e) => {
if (e.deltaY !== 0) {
e.preventDefault();
imgContainer.scrollLeft += e.deltaY;
}
});
const images = getDLSiteImages(rjCode);
images.forEach(url => {
const img = document.createElement('img');
img.src = url;
img.onerror = () => img.remove();
img.onclick = () => window.open(url, '_blank');
imgContainer.appendChild(img);
});
contentArea.appendChild(imgContainer);
}
popup.style.left = `30px`;
popup.style.top = `30px`;
popup.style.display = 'block';
popup.querySelector('.close-btn').addEventListener('click', () => {
popup.style.display = 'none';
});
}
// Events
window.addEventListener('keydown', (e) => {
if (e.shiftKey && (e.key === 'Z' || e.key === 'z')) {
const selection = window.getSelection().toString().trim();
if (selection) {
const data = search(selection);
const range = window.getSelection().getRangeAt(0);
const rect = range.getBoundingClientRect();
showPopup(data, rect.left + window.scrollX, rect.bottom + window.scrollY + 10);
}
}
});
// Close popup on click outside
window.addEventListener('mousedown', (e) => {
if (!popup.contains(e.target) && !overlay.contains(e.target)) {
popup.style.display = 'none';
}
});
// Settings Menu
GM_registerMenuCommand("Update Database", () => {
document.getElementById('ark-db-input').value = GM_getValue('ark_db', '');
overlay.style.display = 'flex';
});
document.getElementById('ark-save-db').addEventListener('click', () => {
const text = document.getElementById('ark-db-input').value;
saveDatabase(text);
});
document.getElementById('ark-close-settings').addEventListener('click', () => {
overlay.style.display = 'none';
});
})();
// ==UserScript==
// @name RJ Search Helper
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Search for selected text in a local database and show formatted results
// @author FLAG
// @match *://kone.gg/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(function () {
'use strict';
// CSS for the popup and settings
const styles = `
#ark-search-popup {
position: fixed;
z-index: 10000;
background: #222;
color: #fff;
padding: 20px;
padding-top: 40px;
border-radius: 10px;
box-shadow: 0 6px 25px rgba(0,0,0,0.5);
font-family: 'Inter', sans-serif;
font-size: 16px;
width: 640px;
display: none;
border: 1px solid #444;
}
#ark-drag-handle {
position: absolute;
top: 5px; left: 50%;
transform: translateX(-50%);
width: 60px;
height: 6px;
background: #00d1ff;
cursor: move;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
z-index: 10002;
}
#ark-search-popup .result-item { margin-bottom: 8px; line-height: 1.5; border-bottom: 1px solid #333; padding-bottom: 6px; }
#ark-search-popup .close-btn { position: absolute; top: 5px; right: 12px; cursor: pointer; color: #888; font-size: 24px; z-index: 10001; }
#ark-search-popup .close-btn:hover { color: #fff; }
#ark-image-container {
display: flex;
overflow-x: auto;
gap: 12px;
margin-top: 15px;
padding-bottom: 8px;
}
#ark-image-container img {
height: 384px;
border-radius: 6px;
border: 1px solid #444;
flex-shrink: 0;
cursor: pointer;
}
#ark-image-container::-webkit-scrollbar { height: 8px; }
#ark-image-container::-webkit-scrollbar-thumb { background: #555; border-radius: 4px; }
#ark-settings-overlay {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(0,0,0,0.8);
z-index: 10001;
display: none;
justify-content: center;
align-items: center;
}
#ark-settings-modal {
background: #1e1e1e;
padding: 20px;
border-radius: 10px;
width: 80%;
max-width: 600px;
color: #eee;
}
#ark-db-input {
width: 100%;
height: 300px;
background: #111;
color: #0f0;
border: 1px solid #333;
padding: 10px;
font-family: monospace;
margin: 10px 0;
border-radius: 5px;
}
.ark-btn {
background: #00d1ff;
color: #000;
border: none;
padding: 8px 16px;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}
.ark-btn:hover { background: #00b8e6; }
`;
const styleSheet = document.createElement("style");
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
// Initial Elements
const popup = document.createElement('div');
popup.id = 'ark-search-popup';
document.body.appendChild(popup);
const overlay = document.createElement('div');
overlay.id = 'ark-settings-overlay';
overlay.innerHTML = `
<div id="ark-settings-modal">
<h3>데이터 베이스 관리</h3>
<p>아래에 텍스트를 입력하고 저장 버튼을 눌러주세요.</p>
<textarea id="ark-db-input" placeholder="텍스트를 여기에 붙여넣어주세요..."></textarea>
<div style="text-align: right;">
<button class="ark-btn" id="ark-save-db">저장</button>
<button class="ark-btn" id="ark-close-settings" style="background: #444; color: #fff; margin-left: 10px;">닫기</button>
</div>
</div>
`;
document.body.appendChild(overlay);
// Database access
function getDatabase() {
const raw = GM_getValue('ark_db', '');
return raw.split('\n').map(line => line.trim()).filter(line => line.length > 0);
}
function saveDatabase(text) {
GM_setValue('ark_db', text);
alert('Database updated successfully!');
overlay.style.display = 'none';
}
// Search logic
function search(query) {
if (!query) return { results: [], rjCode: null };
// Extract RJ or ST code (e.g., RJ123456, ST123456)
const match = query.match(/(RJ|ST)\d+/i);
const searchToken = match ? match[0].toUpperCase() : query.trim();
if (!searchToken) return { results: [], rjCode: null };
const db = getDatabase();
const results = db.filter(line => line.toUpperCase().includes(searchToken));
return { results, rjCode: searchToken.startsWith('RJ') ? searchToken : null };
}
function getDLSiteImages(rjCode) {
if (!rjCode) return [];
const numStr = rjCode.substring(2);
const num = parseInt(numStr);
const folderNum = (Math.floor(num / 1000) + 1) * 1000;
const folder = "RJ" + folderNum.toString().padStart(numStr.length, '0');
const baseUrl = `https://img.dlsite.jp/modpub/images2/work/doujin/${folder}/`;
// 5 images as requested (Main + 4 samples)
const suffixes = ["_img_main", "_img_smp1", "_img_smp2", "_img_smp3", "_img_smp4"];
return suffixes.map(s => `${baseUrl}${rjCode.toUpperCase()}${s}.webp`);
}
// Result formatting
function formatResult(line) {
let prefix = "";
const trimmedLine = line.trim();
const hasBrackets = /\[.*\]$/.test(trimmedLine);
const hasMibun = trimmedLine.includes("미번");
if (hasBrackets && hasMibun) {
prefix = "★@ ";
} else if (hasBrackets) {
prefix = "★ ";
} else if (hasMibun) {
prefix = "@ ";
}
return prefix + line;
}
// UI Logic
function showPopup(data, x, y) {
const { results, rjCode } = data;
popup.innerHTML = `
<div id="ark-drag-handle"></div>
<span class="close-btn">×</span>
<h3>Search Results</h3>
<div id="ark-popup-content"></div>
`;
const contentArea = popup.querySelector('#ark-popup-content');
// Dragging logic
const dragHandle = popup.querySelector('#ark-drag-handle');
dragHandle.onmousedown = function (e) {
e.preventDefault();
let startX = e.clientX - popup.offsetLeft;
let startY = e.clientY - popup.offsetTop;
function onMouseMove(e) {
popup.style.left = (e.clientX - startX) + 'px';
popup.style.top = (e.clientY - startY) + 'px';
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
};
if (results.length === 0) {
contentArea.innerHTML = `<div style="color: #ff4d4d; font-weight: bold;">현재 저장소에 없습니다!</div>`;
} else {
contentArea.innerHTML = `<div style="color: #00d1ff; font-weight: bold; margin-bottom: 10px;">파일을 발견했습니다!</div>`;
results.forEach(res => {
const div = document.createElement('div');
div.className = 'result-item';
div.innerText = formatResult(res);
contentArea.appendChild(div);
});
}
// Add Images if RJ code exists
if (rjCode) {
const imgContainer = document.createElement('div');
imgContainer.id = 'ark-image-container';
// Add horizontal scroll on mouse wheel
imgContainer.addEventListener('wheel', (e) => {
if (e.deltaY !== 0) {
e.preventDefault();
imgContainer.scrollLeft += e.deltaY;
}
});
const images = getDLSiteImages(rjCode);
images.forEach(url => {
const img = document.createElement('img');
img.src = url;
img.onerror = () => img.remove();
img.onclick = () => window.open(url, '_blank');
imgContainer.appendChild(img);
});
contentArea.appendChild(imgContainer);
}
popup.style.left = `30px`;
popup.style.top = `30px`;
popup.style.display = 'block';
popup.querySelector('.close-btn').addEventListener('click', () => {
popup.style.display = 'none';
});
}
// Events
window.addEventListener('keydown', (e) => {
if (e.shiftKey && (e.key === 'Z' || e.key === 'z')) {
const selection = window.getSelection().toString().trim();
if (selection) {
const data = search(selection);
const range = window.getSelection().getRangeAt(0);
const rect = range.getBoundingClientRect();
showPopup(data, rect.left + window.scrollX, rect.bottom + window.scrollY + 10);
}
}
});
// Close popup on click outside
window.addEventListener('mousedown', (e) => {
if (!popup.contains(e.target) && !overlay.contains(e.target)) {
popup.style.display = 'none';
}
});
// Settings Menu
GM_registerMenuCommand("Update Database", () => {
document.getElementById('ark-db-input').value = GM_getValue('ark_db', '');
overlay.style.display = 'flex';
});
document.getElementById('ark-save-db').addEventListener('click', () => {
const text = document.getElementById('ark-db-input').value;
saveDatabase(text);
});
document.getElementById('ark-close-settings').addEventListener('click', () => {
overlay.style.display = 'none';
});
})();
---
버그나 수정필요한 부분있으면 말좀
