// ==UserScript==
// @name 개드립 댓글 클리너
// @namespace http://tampermonkey.net/
// @version 1.3.2
// @description 댓글 자동 삭제 + 개드립콘 포함 + 원문 표시 + 진행상황 표시 개선
// @author Qoo
// @include https://www.dogdrip.net/index.php?mid=front&act=dispMemberOwnComment*
// @include https://www.dogdrip.net/index.php?act=dispMemberOwnComment*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const btn = document.createElement("button");
btn.innerText = "댓글삭제";
btn.style.position = "fixed";
btn.style.top = "10px";
btn.style.left = "10px";
btn.style.zIndex = "9999";
btn.style.padding = "10px";
btn.style.backgroundColor = "#ff6600";
btn.style.color = "#fff";
btn.style.border = "none";
btn.style.cursor = "pointer";
document.body.appendChild(btn);
const statusText = document.createElement("div");
statusText.style.position = "fixed";
statusText.style.top = "50px";
statusText.style.left = "10px";
statusText.style.zIndex = "9999";
statusText.style.backgroundColor = "rgba(0,0,0,0.7)";
statusText.style.color = "#fff";
statusText.style.padding = "8px 12px";
statusText.style.borderRadius = "4px";
statusText.style.fontSize = "14px";
statusText.textContent = "준비 완료";
document.body.appendChild(statusText);
const checkboxWrapper = document.createElement("label");
checkboxWrapper.style.position = "fixed";
checkboxWrapper.style.top = "90px";
checkboxWrapper.style.left = "10px";
checkboxWrapper.style.zIndex = "9999";
checkboxWrapper.style.backgroundColor = "rgba(255,255,255,0.9)";
checkboxWrapper.style.padding = "6px 10px";
checkboxWrapper.style.borderRadius = "4px";
checkboxWrapper.style.fontSize = "14px";
checkboxWrapper.style.display = "inline-block";
checkboxWrapper.style.cursor = "pointer";
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.style.marginRight = "5px";
const checkboxText = document.createTextNode("개드립콘 포함");
checkboxWrapper.appendChild(checkbox);
checkboxWrapper.appendChild(checkboxText);
document.body.appendChild(checkboxWrapper);
async function deleteComment(postNumber, commentNumber) {
const tokenMeta = document.querySelector('meta[name="csrf-token"]');
if (!tokenMeta) {
statusText.textContent = "CSRF 토큰이 없습니다.";
return false;
}
const token = tokenMeta.getAttribute('content');
const deleteUrl = "https://www.dogdrip.net/";
const bodyData = new URLSearchParams({
_filter: 'delete_comment',
error_return_url: '',
act: 'procBoardDeleteComment',
mid: 'free',
page: 1,
document_srl: postNumber,
comment_srl: commentNumber,
module: 'board',
_rx_ajax_compat: 'XMLRPC',
_rx_csrf_token: token,
});
try {
const response = await fetch(deleteUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': token,
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json, text/javascript, */*; q=0.01',
},
referrer: `https://www.dogdrip.net/index.php?mid=free&document_srl=${postNumber}&act=dispBoardDeleteComment&comment_srl=${commentNumber}`,
referrerPolicy: 'no-referrer-when-downgrade',
body: bodyData.toString(),
credentials: 'include',
mode: 'cors',
});
const text = await response.text();
return text.includes("삭제가 완료되었습니다");
} catch (error) {
statusText.textContent = `오류: ${error}`;
return false;
}
}
async function deleteComments() {
const baseUrl = "https://www.dogdrip.net/index.php?act=dispMemberOwnComment&mid=front&page=";
let page = 1;
let allComments = [];
const includeDogdripcon = checkbox.checked;
async function fetchPage(pageNumber) {
const response = await fetch(`${baseUrl}${pageNumber}`);
if (!response.ok) {
statusText.textContent = `페이지 ${pageNumber} 로딩 실패`;
return null;
}
const text = await response.text();
return new DOMParser().parseFromString(text, "text/html");
}
async function getCommentsOnPage(pageNumber) {
const doc = await fetchPage(pageNumber);
if (!doc) return [];
const rows = doc.querySelectorAll("table tbody tr td a");
const comments = [];
if (rows.length === 0) return null;
for (let aTag of rows) {
const content = aTag.textContent.trim();
const href = aTag.getAttribute("href");
if (!href || content === "[삭제 되었습니다]" || content === "삭제 된 글입니다.") continue;
if (!includeDogdripcon) {
const html = aTag.innerHTML;
if (html.includes("@dogdrip") || html.includes("dogcon") || html.includes("emoticon")) continue;
}
const match = href.match(/^\/(\d+)\?comment_srl=(\d+)/);
if (match) {
comments.push({ postNumber: match[1], commentNumber: match[2], content });
}
}
return comments;
}
while (true) {
statusText.textContent = `페이지 ${page} 댓글 수집 중...`;
const comments = await getCommentsOnPage(page);
if (!comments) break;
allComments = allComments.concat(comments);
page++;
await new Promise(resolve => setTimeout(resolve, 1000));
}
if (allComments.length === 0) {
statusText.textContent = "삭제할 댓글이 없습니다.";
return;
}
let processed = 0;
let deletedCount = 0;
for (let { postNumber, commentNumber, content } of allComments) {
processed++;
statusText.textContent = `[${processed} / ${allComments.length}] "${content}" 댓글 삭제 진행중...`;
const success = await deleteComment(postNumber, commentNumber);
if (success) deletedCount++;
await new Promise(resolve => setTimeout(resolve, 3000));
}
statusText.textContent = `모든 댓글 삭제 완료 (${deletedCount}/${allComments.length})`;
}
btn.addEventListener("click", deleteComments);
})();
크롬 템퍼몽키 확장프로그램을 까신 다음에 해당 코드를 복붙하시면 됩니다.
그럼 내가 쓴 댓글창에
좌측상단 해당 UI가 생기게 됩니다.
개드립콘 포함 체크 여부에 따라서 개드립콘을 남기거나 함께 지울 수 있습니다.
댓글삭제 버튼을 누르게 되면
댓글페이지를 차례대로 체크하면서 댓글을 수집합니다.
이후 댓글삭제 진행 상황이 텍스트로 표시되게 되며
마지막으로 삭제 완료로 끝나게 됩니다. 해당 스크립트가 작동중일때는 페이지를 이탈하지 말아주세요.
#개드립 지우개 #개드립 클리너
'Development' 카테고리의 다른 글
[템퍼몽키] 개드립 차단메모 (0) | 2025.06.29 |
---|---|
개드립 댓글 클리너 (0) | 2024.12.29 |