Draggable and easy to use comment scraper. Made for personal use with the goal to look for malware advertisements.
当前为
// ==UserScript==
// @name Comment Scraper
// @namespace discord.gg/@simonvhs
// @version 1.6
// @description Draggable and easy to use comment scraper. Made for personal use with the goal to look for malware advertisements.
// @author Simon (dork)
// @match https://www.kogama.com/games/play/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const MAX_FILE_SIZE = 8 * 1024 * 1024; // Newest Webhook file size limit
let processed_requests = 0;
let total_pages = 0;
const extractGameIdFromUrl = () => {
const match = window.location.pathname.match(/\/games\/play\/([^/]+)\//);
return match ? match[1] : null;
};
const createMenu = () => {
const style = document.createElement('style');
style.innerHTML = `
#ayaka-menu {
position: fixed;
top: 20px;
left: 20px;
width: 300px;
background: #121212;
color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
font-family: Arial, sans-serif;
z-index: 9999;
}
#ayaka-menu h1 {
font-size: 18px;
margin-bottom: 10px;
text-align: center;
color: #72bcd4;
}
#ayaka-menu input, #ayaka-menu button {
width: 100%;
margin: 10px 0;
padding: 10px;
border-radius: 5px;
border: none;
}
#ayaka-menu input {
background: #1e1e1e;
color: white;
}
#ayaka-menu button {
background: linear-gradient(90deg, #6dd5fa, #1e90ff);
color: white;
cursor: pointer;
transition: transform 0.2s;
}
#ayaka-menu button:hover {
transform: scale(1.05);
}
#ayaka-progress {
font-size: 14px;
text-align: center;
margin-top: 10px;
}
`;
document.head.appendChild(style);
const menu = document.createElement('div');
menu.id = 'ayaka-menu';
menu.innerHTML = `
<h1>Comment Scraper</h1>
<input id="webhook-url" type="text" placeholder="Webhook URL">
<input id="total-pages" type="number" placeholder="Total Pages">
<button id="send-button">Send</button>
<div id="ayaka-progress">Progress: 0 / 0</div>
`;
document.body.appendChild(menu);
makeDraggable(menu);
document.getElementById('total-pages').addEventListener('input', (e) => {
total_pages = parseInt(e.target.value, 10);
updateProgress();
});
};
const makeDraggable = (element) => {
let isDragging = false, startX, startY, initialX, initialY;
element.addEventListener('mousedown', (e) => {
isDragging = true;
startX = e.clientX;
startY = e.clientY;
initialX = element.offsetLeft;
initialY = element.offsetTop;
document.addEventListener('mousemove', onDrag);
document.addEventListener('mouseup', onStopDrag);
});
const onDrag = (e) => {
if (!isDragging) return;
const dx = e.clientX - startX;
const dy = e.clientY - startY;
element.style.left = `${initialX + dx}px`;
element.style.top = `${initialY + dy}px`;
};
const onStopDrag = () => {
isDragging = false;
document.removeEventListener('mousemove', onDrag);
document.removeEventListener('mouseup', onStopDrag);
};
};
const fetchPage = async (url) => {
const response = await fetch(url);
if (response.ok) {
processed_requests++;
updateProgress();
return await response.json();
} else {
throw new Error(`Failed to fetch ${url}`);
}
};
const sendFileToWebhook = async (webhookUrl, fileData, fileName) => {
const blob = new Blob([fileData], { type: 'text/plain' });
const formData = new FormData();
formData.append('file', blob, fileName);
const response = await fetch(webhookUrl, {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error('Failed to send file');
}
console.log('File sent successfully');
};
const formatCommentData = (comment) => {
const content = JSON.parse(comment._data).data || 'No Content';
const createdAt = new Date(comment.created).toLocaleString();
return `[${createdAt}] ${comment.profile_username} (${comment.profile_id}): ${content}`;
};
const generateMetadata = () => {
const date = new Date().toLocaleString();
const gameId = extractGameIdFromUrl();
return `Date: ${date}\nGame ID: ${gameId}\nTotal Pages: ${total_pages}\n\n▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃▃\n\n `;
};
const updateProgress = () => {
const progressText = `${processed_requests} / ${total_pages}`;
document.getElementById('ayaka-progress').textContent = `Progress: ${progressText}`;
};
const processAllComments = async (webhookUrl) => {
const fetchPromises = [];
let currentPage = 1;
while (currentPage <= total_pages) {
const pageUrl = `https://www.kogama.com/game/${extractGameIdFromUrl()}/comment/?page=${currentPage}&count=400`;
fetchPromises.push(fetchPage(pageUrl));
currentPage++;
}
try {
const allPageResults = await Promise.all(fetchPromises);
let allComments = [];
allPageResults.forEach((result) => {
if (result.data) {
allComments = allComments.concat(result.data);
}
});
allComments.sort((a, b) => new Date(b.created) - new Date(a.created));
const formattedData = allComments.map(formatCommentData).join('\n');
const totalComments = formattedData.split('\n').length;
let currentFileData = generateMetadata();
let currentFileSize = 0;
let fileCount = 1;
let fileDataBuffer = currentFileData + formattedData;
if (new Blob([fileDataBuffer]).size > MAX_FILE_SIZE) {
await sendFileToWebhook(webhookUrl, fileDataBuffer, `comments_${fileCount}.txt`);
fileCount++;
fileDataBuffer = formattedData;
}
if (fileDataBuffer) {
await sendFileToWebhook(webhookUrl, fileDataBuffer, `comments_${fileCount}.txt`);
}
console.log('All comments processed and files sent!');
} catch (err) {
console.error('Error processing comments:', err);
}
};
const startProcess = async () => {
const webhookUrl = document.getElementById('webhook-url').value;
if (!webhookUrl || isNaN(total_pages) || total_pages <= 0) {
alert('Please fill all fields correctly.');
return;
}
processed_requests = 0;
updateProgress();
await processAllComments(webhookUrl);
};
createMenu();
document.getElementById('send-button').addEventListener('click', startProcess);
})();