// ==UserScript==
// @name kone base64 자동복호화
// @namespace http://tampermonkey.net/
// @version 0.240
// @description base64코드 자동복호화
// @author SYJ
// @match https://arca.live/*
// @match https://kone.gg/s/somisoft*
// @icon https://www.google.com/s2/favicons?sz=64&domain=arca.live
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addValueChangeListener
// @license MIT
// ==/UserScript==
// 자주 바뀜. 취약한 셀렉터
const SHADOW_ROOT_SELECTOR = "body main div.prose-container";
async function main(){
const isAutoMode = await GM_getValue('toggleVal', true);
if (isAutoMode) {
setTimeout(autoApply, 1000);
}
else {
setTimeout(manuallyApply, 1000);
}
}
function doDecode(text) {
///'use strict';
let result = text;
result = dec(/aHR0c[0-9A-Za-z+]{20,}[=]{0,2}/, result); //aHR0c:1회인코딩된것.
result = dec(/YUhSMGN[0-9A-Za-z]{20,}[=]{0,2}/, result); //YUhSMGN:2회인코딩된것.
result = dec(/WVVoU01HTklUVFp[0-9A-Za-z+]{20,}[=]{0,2}/, result); //aHR0c:1회인코딩된것.
result = dec(/V1ZWb1UwMUhUa2[0-9A-Za-z]{20,}[=]{0,2}/, result); //YUhSMGN:2회인코딩된것.
result = dec(/[0-9A-Za-z]{30,}[=]{1,2}/, result); //문자열 30회 + '=' 1~2회
result = dec(/[0-9A-Za-z]{200,}[=]{0,2}/, result); //문자열 200회 + '=' 0~2회
return result;
}
function dec(reg, text) {
let result = text;
try {
while (reg.test(result)) {
const original = reg.exec(result)[0];
let decoded = original;
while (decoded.match(/aHR0c[0-9A-Za-z]{8,}[=]{0,2}/) == null){
decoded = atob(decoded);
}
decoded = atob(decoded); console.log(decoded);
result = result.replace(original, decoded);
}
return result;
}
catch(e) { console.log('er', e);
return text;}
}
function manuallyApply() {
document.body.addEventListener('dblclick', function(e) {
console.log('더블클릭 감지! 🎉',e.target,event.composedPath()[0]);
const el = e.composedPath()[0];
const original = el.textContent;
const decodedLink = doDecode(original);
if (original === decodedLink) return;
while(el.firstChild) el.removeChild(el.firstChild);
el.appendChild(makeATag(decodedLink));
})
}
function autoApply() {
const contents = Array.from(document.body.querySelectorAll('main p'));
const mainContents = Array.from(document.querySelector(SHADOW_ROOT_SELECTOR)?.shadowRoot?.querySelectorAll('p') ?? []);
contents.push(...mainContents);
for (const el of contents) {
const original = el.textContent;
const decodedLink = doDecode(original);
if (original === decodedLink) continue;
while(el.firstChild) el.removeChild(el.firstChild);
console.log(makeATag(decodedLink))
el.appendChild(makeATag(decodedLink));
}
}
function makeATag(link){
const aTag = document.createElement('a');
aTag.href = link;
aTag.textContent = link;
aTag.target = '_blank';
aTag.rel = 'noreferrer';
return aTag;
}
window.addEventListener('load', ()=>{
main();
setInterval(main, 1500);
});
// UI
/* 프롬프트형 입력
(async function(){
let v = await GM_getValue('myValue', 123);
let menuId;
function registerMenu(){
if(menuId) GM_unregisterMenuCommand(menuId);
// 레이블에 현재 v 를 포함
menuId = GM_registerMenuCommand(
`설정 입력 (현재 값: ${v})`,
async () => {
const input = prompt('새 값을 입력하세요:', v);
if(input !== null){
const n = parseInt(input);
if(!isNaN(n)){
v = n;
await GM_setValue('myValue', v);
registerMenu(); // 메뉴 레이블 갱신
} else {
alert('숫자만 입력하세요');
}
}
}
);
}
registerMenu();
// — 여기서 v 를 실제 화면에 표시하거나 쓰고 싶다면,
// document.body.append(`현재 값: ${v}`) 같은 DOM 추가로 처리하세요.
})();
*/
(async function() {
// 1) 값 로드
let val = await GM_getValue('toggleVal', false);
let menuId;
// 2) 배지 생성
/* const badge = document.createElement('div');
Object.assign(badge.style, {
position: 'fixed',
top: '10px',
right: '10px',
padding: '4px 8px',
background: 'rgba(0,0,0,0.7)',
color: '#fff',
fontSize: '14px',
borderRadius: '4px',
zIndex: '9999',
});
document.body.append(badge);
*/
// 3) 렌더 함수
function render() {
// 메뉴 해제 후 다시 등록
if (menuId) GM_unregisterMenuCommand(menuId);
menuId = GM_registerMenuCommand(
`자동모드 토글 (현재: ${val?'ON':'OFF'})`,
toggleValue
);
// 배지 업데이트
//badge.textContent = `현재 값: ${val}`;
}
// 4) 토글 함수 (즉시 UI 업데이트 포함)
async function toggleValue() {
const newVal = !val;
await GM_setValue('toggleVal', newVal);
val = newVal; // 변수 갱신
render(); // 메뉴·배지 즉시 갱신
}
// 초기 렌더
render();
})();