주의!!
인장 바꾸기 버튼은 드래그 > PDF 뽑기 > 배경만 했을 때 플레이어 인장이 나오도록 바꿔주는 버튼이예요
이 부분은 직접 목록에 넣어주셔야 하기 때문에,
F12 > 인장 바꾸기 버튼을 클릭해줌 > 콘솔에 이 링크의 이미지 주소가 필요하다고 나오는 것을~
아래 코드의 var save_info = [ 와 ] 사이에 넣어주셔야 해요
남겨둔 건 형태 예시 삼아서 넣어둔 거니까 그 부분은 지우고 다시 써주세요~~
배경색을 주는 서식 사용 시에 로그에서 블럭이 밀리거나 다른 채팅을 덮는 현상이 있어서 그걸 보완하기 위해 추가 코드를 넣긴 했는데
오류 있으면 앞에 // 붙여서 주석처리 시켜주세요!!
// ==UserScript==
// @name 채팅로그서식 roll20.net
// @namespace Violentmonkey Scripts
// @match https://app.roll20.net/campaigns/chatarchive/*
// @grant none
// @version 1.0
// @author -
// @description 2024. 10. 26. 오후 6:26:58
// ==/UserScript==
function chatStyle(theme = '', color = ''){
var addStyle = [];
if(theme == ''){
var font = 'serif';
var pointfont = 'monospace';
}
if(theme == 'gothic'){
addStyle[0] = new FontFace('NanumsquareNeo', 'url(https://hangeul.pstatic.net/hangeul_static/webfont/NanumSquareNeo/NanumSquareNeoTTF-bRg.woff)');
addStyle[1] = new FontFace('chosungulim', 'url(https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_20-04@1.0/ChosunGu.woff)');
var font = 'NanumsquareNeo';
var pointfont = 'chosungulim';
}
else if(theme == 'serif'){
addStyle[0] = new FontFace('Chosunilbo_myungjo', 'url(https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_one@1.0/Chosunilbo_myungjo.woff)');
addStyle[1] = new FontFace('BookkMyungjo', 'url(https://fastly.jsdelivr.net/gh/projectnoonnu/noonfonts_2302@1.0/BookkMyungjo-Bd.woff2)');
var font = 'Chosunilbo_myungjo';
var pointfont = 'BookkMyungjo';
}
addStyle.map(function(font){
font.load().then(function(loadedFont)
{
document.fonts.add(loadedFont);
})
});
if(color == 'white' || color == ''){
var backcolor = 'white';
var textcolor = 'black';
var textbackcolor = 'rgb(215, 215, 215)';
var desccolor = 'lightgray';
} else if (color == 'black'){
var backcolor = 'rgb(35,35,35)';
var textcolor = 'white';
var textbackcolor = 'rgb(80, 80, 80)';
var desccolor = 'rgb(50, 50, 50)';
}
// 이미지가 포함된 .avatar 요소의 다음 .by 요소 숨기기
document.querySelectorAll(".avatar img").forEach((avatar) => {
const byElement = avatar.closest(".avatar").nextElementSibling.nextElementSibling;
if (byElement && byElement.classList.contains("by")) {
byElement.style.display = "none";
}
});
// 특정 클래스 요소의 스타일 초기화
document.querySelectorAll(".message.whisper .by").forEach((byElement) => {
byElement.style.display = "";
});
// 인장 스타일 지정
document.querySelectorAll('.message .avatar').forEach((avatar) => {
avatar.style.borderRadius = '10px';
avatar.style.overflow = 'hidden';
});
let allMessage = Array.from(document.querySelectorAll(".message:not(:has(table)):not(:has(.inlinerollresult))"));
allMessage.forEach((content) => {
// 기존 HTML 구조에서 텍스트만 추출하여 처리
let nodetext = '';
content.childNodes.forEach((node) => {
if (node.nodeType === Node.TEXT_NODE) {
nodetext = nodetext + node.textContent + '§§'; // innerHTML을 textContent로 수정
} else if (node.nodeName === 'EM') {
nodetext = nodetext + node.textContent + '§§'; // innerHTML을 textContent로 수정
}
});
let modifiedText = nodetext.replace(/(["'])(?=\S*(?:[가-힣a-zA-Z0-9!@#$%^&*()_+{}|:"<>?~`=\[\]\\;',./-]))(\S{2,}|[^"']+?)(\1)/g, (match) => {
return `<span style="color: ${textcolor}; background: ${textbackcolor}; padding: 2px 9px; font-size: 13px; font-family: ${pointfont};">${match.replace(/(\.{3})/g, '…')}</span>`;
});
if(modifiedText) nodelist = modifiedText.split('§§');
else nodelist = nodetext.split('§§');
let newhtml = '';
let num = 0;
content.childNodes.forEach((node) => {
if (node.nodeType === Node.TEXT_NODE) {
newhtml += nodelist[num];
num++;
} else if(node.nodeName === 'EM') {
newhtml += '<em>' + nodelist[num] + '</em>';
num++;
}
else{
newhtml += node.outerHTML;
}
});
content.innerHTML = newhtml;
});
document.querySelectorAll('.message.you').forEach((message) => {
message.classList.remove("you");
});
document.querySelectorAll(".message").forEach((message) => {
message.style.lineHeight = '1.5em';
message.style.fontSize = '12px';
message.style.fontFamily = font;
message.style.color = textcolor;
});
document.querySelectorAll('.message.desc').forEach((desc) => {
desc.style.fontFamily = pointfont;
desc.style.fontStyle = 'normal';
desc.style.fontSize = '13px';
desc.style.backgroundColor = desccolor;
desc.innerHTML = desc.innerHTML.replace(/(\.{3})/g, '…');
});
document.querySelectorAll(".message.desc + .message.desc .spacer").forEach((spacer) => {
spacer.style.display = "none";
});
document.querySelectorAll('.message.desc a').forEach(function(a) {
const computedColor = window.getComputedStyle(a).color;
if (computedColor === 'rgb(255, 255, 255)') {
a.style.margin = '-6px -13px -5px -10px';
}
});
document.querySelectorAll('.message.general').forEach((general) => {
general.style.backgroundColor = backcolor;
});
document.querySelectorAll('.spacer').forEach((spacer) => {
spacer.style.backgroundColor = backcolor;
});
document.querySelectorAll('table').forEach((table) => {
table.style.width = '300px';
table.style.overflow = 'hidden';
});
}
var paginateToggleButton = document.getElementById("paginateToggle");
// '채팅 서식' 버튼 생성
var chatFormatButton = document.createElement("button");
chatFormatButton.classList = 'btn btn-primary';
chatFormatButton.textContent = "채팅 로그 서식 적용";
chatFormatButton.id = "chatFormatButton";
chatFormatButton.style.marginLeft = "10px";
chatFormatButton.addEventListener("click", function() {
chatStyle('', '');
});
paginateToggleButton.insertAdjacentElement("afterend", chatFormatButton);
function changeImages(){
var imglink = [];
var imgs = document.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
var src = imgs[i].getAttribute('src');
if (src && src.indexOf('http') === -1 && !imglink.includes(src)) {
imglink.push(src);
}
}
// 이미지 교체 함수
function changeImage(prev, result) {
if(result == '') return;
var imgs = document.getElementsByTagName('img');
for (var i = 0; i < imgs.length; i++) {
var src = imgs[i].getAttribute('src');
if (src === prev) {
imgs[i].setAttribute('src', result);
}
}
}
// 이 부분에 인장이 필요한 주소와 실제 인장 이미지 주소를 넣어주시면 OK
var save_info = [
['/users/avatar/1720005/30', 'https://files.d20.io/images/355130143/391h9nBIuPVcOwUicvfckA/thumb.png?1692365775512&size=30'],
];
// 결과 배열들
var imglink_result = [];
var imglater = [];
// 매핑 및 추가 작업
imglink.forEach(function(x) {
var match = save_info.find(function(pair) {
return pair[0] === x;
});
if (match) {
imglater.push(match[1]);
} else {
imglater.push('');
console.log('https://app.roll20.net' + x + ' 링크의 이미지 주소가 필요합니다.');
}
});
for (var i = 0; i < imglink.length; i++) {
changeImage(imglink[i], imglater[i]);
}
}
// '채팅 서식' 버튼 생성
var thumbToggleBtn = document.createElement("button");
thumbToggleBtn.classList = 'btn btn-primary';
thumbToggleBtn.textContent = "인장 바꾸기";
thumbToggleBtn.id = "thumbToggle";
thumbToggleBtn.style.marginLeft = "10px";
thumbToggleBtn.addEventListener("click", function() {
changeImages();
});
paginateToggleButton.insertAdjacentElement("afterend", thumbToggleBtn);