KoGaMa: Export direct messages

Quick and simple script to export your private messages into a textfile.

  1. // ==UserScript==
  2. // @name KoGaMa: Export direct messages
  3. // @namespace github.com/deutschsimmy
  4. // @version 1.5
  5. // @description Quick and simple script to export your private messages into a textfile.
  6. // @author ⛧ simmy
  7. // @match *://www.kogama.com/*
  8. // @grant unsafeWindow
  9. // @grant GM_download
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. let chatData = null;
  16.  
  17. function addExportButton() {
  18. const targetElement = document.querySelector('.F3PyX');
  19. if (targetElement && !document.querySelector('.export-btn')) {
  20. const exportButton = document.createElement('button');
  21. exportButton.className = 'export-btn';
  22. exportButton.title = 'Export chat history to a text file. In case it does not work close and reopen the chat.';
  23. exportButton.style.width = '30px';
  24. exportButton.style.height = '30px';
  25. exportButton.style.background = 'url(https://i.imgur.com/hG5QwIl.gif) center center / 16px 16px no-repeat';
  26. exportButton.style.border = 'none';
  27. exportButton.style.cursor = 'pointer';
  28. exportButton.style.position = 'absolute';
  29. exportButton.style.top = '50%';
  30. exportButton.style.right = '37px';
  31. exportButton.style.transform = 'translateY(-50%)';
  32. targetElement.style.position = 'relative';
  33. targetElement.appendChild(exportButton);
  34.  
  35. exportButton.addEventListener('click', function() {
  36. exportChatHistory();
  37. });
  38. }
  39. }
  40.  
  41. function exportChatHistory() {
  42. if (chatData) {
  43. chatData.reverse();
  44. let formattedChat = chatData.map(message => {
  45. const timestamp = new Date(message.created).toLocaleString();
  46. return `[ ${timestamp} ] ${message.from_username}: ${message.message}`;
  47. }).join('\n');
  48. formattedChat = formattedChat.replace(/\n{2,}/g, '\n');
  49. const filename = `${chatData[0].to_profile_id}.txt`;
  50. const blob = new Blob([formattedChat], { type: 'text/plain' });
  51. const url = URL.createObjectURL(blob);
  52. const downloadLink = document.createElement('a');
  53. downloadLink.href = url;
  54. downloadLink.download = filename;
  55. document.body.appendChild(downloadLink);
  56. downloadLink.click();
  57. document.body.removeChild(downloadLink);
  58. URL.revokeObjectURL(url);
  59. } else {
  60. console.error('No chat data found');
  61. }
  62. }
  63. function monitorRequests() {
  64. const originalOpen = unsafeWindow.XMLHttpRequest.prototype.open;
  65. const originalSend = unsafeWindow.XMLHttpRequest.prototype.send;
  66.  
  67. unsafeWindow.XMLHttpRequest.prototype.open = function(method, url) {
  68. this._url = url;
  69. originalOpen.apply(this, arguments);
  70. };
  71. unsafeWindow.XMLHttpRequest.prototype.send = function(body) {
  72. this.addEventListener('load', function() {
  73. if (this._url.includes('/chat/') && this._url.includes('/history/')) {
  74. const urlParts = this._url.split('/');
  75. const selfId = urlParts[4];
  76. const friendId = urlParts[6];
  77.  
  78. console.log('Detected chat history request:', selfId, friendId);
  79.  
  80. if (this.responseType === '' || this.responseType === 'text') {
  81. chatData = JSON.parse(this.responseText).data;
  82. } else if (this.responseType === 'json') {
  83. chatData = this.response.data;
  84. }
  85.  
  86. addExportButton();
  87. }
  88. });
  89.  
  90. originalSend.apply(this, arguments);
  91. };
  92. }
  93.  
  94. monitorRequests();
  95.  
  96. })();