smoothretro1982

Simple Chat Archiver v0.5 (w.i.p)

May 17th, 2026 (edited)
303
1
Never
5
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.11 KB | None | 1 0
  1. (function() {
  2. const archives = { world: [], global: [] };
  3.  
  4. const hud = document.createElement('div');
  5. hud.id = 'archiver-hud';
  6. hud.style = `
  7. position: fixed; top: 50px; left: 50px; width: 350px;
  8. background: #1a1a1a; color: #fff; padding: 0;
  9. border-radius: 10px; z-index: 10000; font-family: sans-serif;
  10. box-shadow: 0 8px 24px rgba(0,0,0,0.6); border: 1px solid #333; overflow: hidden;
  11. `;
  12.  
  13. hud.innerHTML = `
  14. <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;">
  15. <span style="font-weight: bold; font-size: 12px; pointer-events: none;">Chat Archiver + Live</span>
  16. <button id="close-hud" style="background: none; border: none; color: #888; cursor: pointer; font-size: 18px; line-height: 1;">&times;</button>
  17. </div>
  18. <div style="padding: 12px;">
  19. <div style="margin-bottom: 10px; display: flex; gap: 15px; align-items: center; font-size: 11px; color: #ccc;">
  20. <div style="display: flex; align-items: center;">
  21. <input type="checkbox" id="ts-toggle" checked style="margin-right: 6px; cursor: pointer;">
  22. <label for="ts-toggle" style="cursor: pointer;">Timestamps</label>
  23. </div>
  24. <div style="display: flex; align-items: center;">
  25. <input type="checkbox" id="pre-toggle" checked style="margin-right: 6px; cursor: pointer;">
  26. <label for="pre-toggle" style="cursor: pointer;">Show Previews</label>
  27. </div>
  28. </div>
  29.  
  30. <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 10px;">
  31. <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>
  32. <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>
  33. </div>
  34.  
  35. <div id="preview-container">
  36. <div style="font-size: 10px; color: #888; margin-bottom: 4px;">Live World:</div>
  37. <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>
  38.  
  39. <div style="font-size: 10px; color: #888; margin-bottom: 4px;">Live Global:</div>
  40. <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>
  41. </div>
  42. </div>
  43. `;
  44. document.body.appendChild(hud);
  45.  
  46. // --- Dragging Logic ---
  47. let isDragging = false, startX, startY, initialLeft, initialTop;
  48. const handle = document.getElementById('hud-handle');
  49. const move = (e) => {
  50. if (!isDragging) return;
  51. const clientX = e.clientX || (e.touches ? e.touches[0].clientX : 0);
  52. const clientY = e.clientY || (e.touches ? e.touches[0].clientY : 0);
  53. hud.style.left = (initialLeft + (clientX - startX)) + 'px';
  54. hud.style.top = (initialTop + (clientY - startY)) + 'px';
  55. };
  56. handle.onmousedown = (e) => { isDragging = true; startX = e.clientX; startY = e.clientY; initialLeft = hud.offsetLeft; initialTop = hud.offsetTop; e.preventDefault(); };
  57. handle.ontouchstart = (e) => { isDragging = true; startX = e.touches[0].clientX; startY = e.touches[0].clientY; initialLeft = hud.offsetLeft; initialTop = hud.offsetTop; };
  58. document.onmousemove = move;
  59. document.ontouchmove = (e) => { if(isDragging) e.preventDefault(); move(e); };
  60. document.onmouseup = document.ontouchend = () => { isDragging = false; };
  61.  
  62. // --- Toggle Logic ---
  63. const tsToggle = document.getElementById('ts-toggle');
  64. const preToggle = document.getElementById('pre-toggle');
  65. const preContainer = document.getElementById('preview-container');
  66.  
  67. tsToggle.onchange = () => {
  68. const display = tsToggle.checked ? 'inline' : 'none';
  69. document.querySelectorAll('.msg-ts').forEach(el => el.style.display = display);
  70. };
  71.  
  72. preToggle.onchange = () => {
  73. preContainer.style.display = preToggle.checked ? 'block' : 'none';
  74. };
  75.  
  76. // --- Archiving & Preview Logic ---
  77. const archiveMessage = (channel, node) => {
  78. const user = node.querySelector('a')?.innerText || "System";
  79. const text = node.querySelector('span:last-child')?.innerText || "";
  80. let rawTS = node.querySelector('a')?.title || new Date().toLocaleString();
  81. const timestamp = rawTS.includes(',') ? rawTS.split(',')[1].trim() : rawTS;
  82.  
  83. archives[channel].push({ timestamp, user, text });
  84. document.getElementById(`${channel[0]}-count`).innerText = archives[channel].length;
  85.  
  86. const preview = document.getElementById(`pre-${channel}`);
  87. const msgDiv = document.createElement('div');
  88. msgDiv.style.marginBottom = "4px";
  89.  
  90. const tsDisplay = tsToggle.checked ? 'inline' : 'none';
  91. 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>`;
  92.  
  93. preview.appendChild(msgDiv);
  94. preview.scrollTop = preview.scrollHeight;
  95. if(preview.children.length > 40) preview.removeChild(preview.firstChild);
  96. };
  97.  
  98. const observer = new MutationObserver((mutations) => {
  99. mutations.forEach(m => m.addedNodes.forEach(node => {
  100. if (node.nodeType === 1 && (node.id === '_msg' || node.classList.contains('fade-in'))) {
  101. const box = node.closest('.chatbox');
  102. if (box) archiveMessage(box.getAttribute('data-channel'), node);
  103. }
  104. }));
  105. });
  106.  
  107. observer.observe(document.getElementById('stacker'), { childList: true, subtree: true });
  108.  
  109. // --- Export & Close ---
  110. const download = (channel) => {
  111. if (!archives[channel].length) return;
  112. const logContent = archives[channel].map(m => tsToggle.checked ? `[${m.timestamp}] ${m.user}: ${m.text}` : `${m.user}: ${m.text}`).join('\n');
  113. const a = Object.assign(document.createElement('a'), {
  114. href: URL.createObjectURL(new Blob([logContent], { type: 'text/plain' })),
  115. download: `archive_${channel}_${Date.now()}.txt`
  116. });
  117. a.click();
  118. };
  119.  
  120. document.getElementById('exp-world').onclick = () => download('world');
  121. document.getElementById('exp-global').onclick = () => download('global');
  122. document.getElementById('close-hud').onclick = () => { observer.disconnect(); hud.remove(); };
  123. })();
Advertisement
Comments
  • RubixYT1
    75 days
    # text 0.05 KB | 0 0
    1. can you add to paste the archives like pasting it?
    • smoothretro1982
      74 days
      # text 0.13 KB | 0 0
      1. 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.
  • User was banned
  • User was banned
  • User was banned
Add Comment
Please, Sign In to add comment