Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- (function() {
- const archives = { world: [], global: [] };
- const hud = document.createElement('div');
- hud.id = 'archiver-hud';
- hud.style = `
- position: fixed; top: 50px; left: 50px; width: 350px;
- background: #1a1a1a; color: #fff; padding: 0;
- border-radius: 10px; z-index: 10000; font-family: sans-serif;
- box-shadow: 0 8px 24px rgba(0,0,0,0.6); border: 1px solid #333; overflow: hidden;
- `;
- hud.innerHTML = `
- <div id="hud-handle" style="background: #2a2a2a; padding: 10px; cursor: move; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #333;">
- <span style="font-weight: bold; font-size: 12px; pointer-events: none;">Chat Archiver + Live</span>
- <button id="close-hud" style="background: none; border: none; color: #888; cursor: pointer; font-size: 18px; line-height: 1;">×</button>
- </div>
- <div style="padding: 12px;">
- <div style="margin-bottom: 10px; display: flex; gap: 15px; align-items: center; font-size: 11px; color: #ccc;">
- <div style="display: flex; align-items: center;">
- <input type="checkbox" id="ts-toggle" checked style="margin-right: 6px; cursor: pointer;">
- <label for="ts-toggle" style="cursor: pointer;">Timestamps</label>
- </div>
- <div style="display: flex; align-items: center;">
- <input type="checkbox" id="pre-toggle" checked style="margin-right: 6px; cursor: pointer;">
- <label for="pre-toggle" style="cursor: pointer;">Show Previews</label>
- </div>
- </div>
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px;">
- <button id="exp-world" style="padding: 8px; background: #333; color: white; border: 1px solid #444; border-radius: 4px; cursor: pointer; font-size: 10px;">Export World (<span id="w-count">0</span>)</button>
- <button id="exp-global" style="padding: 8px; background: #333; color: white; border: 1px solid #444; border-radius: 4px; cursor: pointer; font-size: 10px;">Export Global (<span id="g-count">0</span>)</button>
- </div>
- <div id="preview-container">
- <div style="font-size: 10px; color: #888; margin-bottom: 4px;">Live World:</div>
- <div id="pre-world" style="height: 80px; background: #000; border: 1px solid #333; overflow-y: auto; padding: 6px; font-size: 11px; margin-bottom: 10px; color: #00ffcc; word-break: break-all; width: 100%; box-sizing: border-box;"></div>
- <div style="font-size: 10px; color: #888; margin-bottom: 4px;">Live Global:</div>
- <div id="pre-global" style="height: 80px; background: #000; border: 1px solid #333; overflow-y: auto; padding: 6px; font-size: 11px; color: #ff99aa; word-break: break-all; width: 100%; box-sizing: border-box;"></div>
- </div>
- </div>
- `;
- document.body.appendChild(hud);
- // --- Dragging Logic ---
- let isDragging = false, startX, startY, initialLeft, initialTop;
- const handle = document.getElementById('hud-handle');
- const move = (e) => {
- if (!isDragging) return;
- const clientX = e.clientX || (e.touches ? e.touches[0].clientX : 0);
- const clientY = e.clientY || (e.touches ? e.touches[0].clientY : 0);
- hud.style.left = (initialLeft + (clientX - startX)) + 'px';
- hud.style.top = (initialTop + (clientY - startY)) + 'px';
- };
- handle.onmousedown = (e) => { isDragging = true; startX = e.clientX; startY = e.clientY; initialLeft = hud.offsetLeft; initialTop = hud.offsetTop; e.preventDefault(); };
- handle.ontouchstart = (e) => { isDragging = true; startX = e.touches[0].clientX; startY = e.touches[0].clientY; initialLeft = hud.offsetLeft; initialTop = hud.offsetTop; };
- document.onmousemove = move;
- document.ontouchmove = (e) => { if(isDragging) e.preventDefault(); move(e); };
- document.onmouseup = document.ontouchend = () => { isDragging = false; };
- // --- Toggle Logic ---
- const tsToggle = document.getElementById('ts-toggle');
- const preToggle = document.getElementById('pre-toggle');
- const preContainer = document.getElementById('preview-container');
- tsToggle.onchange = () => {
- const display = tsToggle.checked ? 'inline' : 'none';
- document.querySelectorAll('.msg-ts').forEach(el => el.style.display = display);
- };
- preToggle.onchange = () => {
- preContainer.style.display = preToggle.checked ? 'block' : 'none';
- };
- // --- Archiving & Preview Logic ---
- const archiveMessage = (channel, node) => {
- const user = node.querySelector('a')?.innerText || "System";
- const text = node.querySelector('span:last-child')?.innerText || "";
- let rawTS = node.querySelector('a')?.title || new Date().toLocaleString();
- const timestamp = rawTS.includes(',') ? rawTS.split(',')[1].trim() : rawTS;
- archives[channel].push({ timestamp, user, text });
- document.getElementById(`${channel[0]}-count`).innerText = archives[channel].length;
- const preview = document.getElementById(`pre-${channel}`);
- const msgDiv = document.createElement('div');
- msgDiv.style.marginBottom = "4px";
- const tsDisplay = tsToggle.checked ? 'inline' : 'none';
- msgDiv.innerHTML = `<span class="msg-ts" style="color: #666; display: ${tsDisplay}; font-size: 9px;">[${timestamp}] </span><strong style="color: inherit;">${user}:</strong> <span style="color: #eee;">${text}</span>`;
- preview.appendChild(msgDiv);
- preview.scrollTop = preview.scrollHeight;
- if(preview.children.length > 40) preview.removeChild(preview.firstChild);
- };
- const observer = new MutationObserver((mutations) => {
- mutations.forEach(m => m.addedNodes.forEach(node => {
- if (node.nodeType === 1 && (node.id === '_msg' || node.classList.contains('fade-in'))) {
- const box = node.closest('.chatbox');
- if (box) archiveMessage(box.getAttribute('data-channel'), node);
- }
- }));
- });
- observer.observe(document.getElementById('stacker'), { childList: true, subtree: true });
- // --- Export & Close ---
- const download = (channel) => {
- if (!archives[channel].length) return;
- const logContent = archives[channel].map(m => tsToggle.checked ? `[${m.timestamp}] ${m.user}: ${m.text}` : `${m.user}: ${m.text}`).join('\n');
- const a = Object.assign(document.createElement('a'), {
- href: URL.createObjectURL(new Blob([logContent], { type: 'text/plain' })),
- download: `archive_${channel}_${Date.now()}.txt`
- });
- a.click();
- };
- document.getElementById('exp-world').onclick = () => download('world');
- document.getElementById('exp-global').onclick = () => download('global');
- document.getElementById('close-hud').onclick = () => { observer.disconnect(); hud.remove(); };
- })();
Advertisement
Comments
-
- can you add to paste the archives like pasting it?
-
- If you mean a "copy to clipboard" button that can either copy global or main chat to the clipboard to be pasted, It'll be added later on.
Add Comment
Please, Sign In to add comment