CopyMaster

Tool for copying raw text and formated text

  1. // ==UserScript==
  2. // @name CopyMaster
  3. // @namespace http://tampermonkey.net/
  4. // @version 8.0
  5. // @description Tool for copying raw text and formated text
  6. // Advanced tools : formats PDF, DOCX, LibreOffice (ODT), Excel/CSV/ODS, audio, vidéo, images, tabs, etc.
  7. // @author yglsan
  8. // @match *://*/*
  9. // @grant GM_setClipboard
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_notification
  12. // @grant GM_download
  13. // @license Gpl-3.0-or-later
  14. // ==/UserScript==
  15.  
  16. /*
  17. Copyright (C) 2025 Benjamin Moine (yglsan)
  18.  
  19. This program is free software: you can redistribute it and/or modify
  20. it under the terms of the GNU General Public License as published by
  21. the Free Software Foundation, either version 3 of the License, or
  22. (at your option) any later version.
  23.  
  24. This program is distributed in the hope that it will be useful,
  25. but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. GNU General Public License for more details.
  28.  
  29. You should have received a copy of the GNU General Public License
  30. along with this program. If not, see <https://www.gnu.org/licenses/>.
  31. */
  32.  
  33. (function() {
  34. 'use strict';
  35.  
  36. // Création du bouton flottant moderne
  37. const button = document.createElement('button');
  38. button.innerText = '📋 Copier Formaté';
  39. button.style.position = 'fixed';
  40. button.style.bottom = '20px';
  41. button.style.right = '20px';
  42. button.style.padding = '10px 20px';
  43. button.style.background = '#007bff';
  44. button.style.color = 'white';
  45. button.style.border = 'none';
  46. button.style.borderRadius = '10px';
  47. button.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
  48. button.style.cursor = 'pointer';
  49. button.style.fontSize = '16px';
  50. button.style.zIndex = '1000';
  51. button.style.transition = 'background 0.3s';
  52. button.addEventListener('mouseover', () => button.style.background = '#0056b3');
  53. button.addEventListener('mouseout', () => button.style.background = '#007bff');
  54. button.addEventListener('click', copyWithStyles);
  55. document.body.appendChild(button);
  56.  
  57. // Fonction pour copier le contenu formaté avec styles et médias
  58. async function copyWithStyles() {
  59. const selection = window.getSelection();
  60. if (!selection.rangeCount) return;
  61. const range = selection.getRangeAt(0);
  62. const clonedSelection = range.cloneContents();
  63.  
  64. // Ajout des styles inline
  65. clonedSelection.querySelectorAll('*').forEach(el => {
  66. const computedStyle = window.getComputedStyle(el);
  67. el.style.cssText = computedStyle.cssText;
  68. });
  69.  
  70. // Gestion des images
  71. await Promise.all(
  72. Array.from(clonedSelection.querySelectorAll('img')).map(async (img) => {
  73. if (img.src.startsWith('data:')) return;
  74. try {
  75. const response = await fetch(img.src);
  76. const blob = await response.blob();
  77. const reader = new FileReader();
  78. reader.onloadend = () => {
  79. img.src = reader.result;
  80. };
  81. reader.readAsDataURL(blob);
  82. } catch (e) {
  83. console.error('Erreur de téléchargement de l\'image', img.src, e);
  84. }
  85. })
  86. );
  87.  
  88. // Gestion des éléments audio et vidéo
  89. clonedSelection.querySelectorAll('audio, video').forEach(media => {
  90. if (media.src && !media.src.startsWith('data:')) {
  91. fetch(media.src)
  92. .then(res => res.blob())
  93. .then(blob => {
  94. const reader = new FileReader();
  95. reader.onloadend = () => {
  96. media.src = reader.result;
  97. };
  98. reader.readAsDataURL(blob);
  99. })
  100. .catch(err => console.error('Erreur lors du téléchargement du média', media.src, err));
  101. }
  102. });
  103.  
  104. // Gestion des liens
  105. clonedSelection.querySelectorAll('a').forEach(link => {
  106. link.setAttribute('target', '_blank');
  107. });
  108.  
  109. // Reconnaissance avancée de la mise en forme
  110. clonedSelection.querySelectorAll('code, pre').forEach(block => {
  111. block.innerText = '```' + block.innerText + '```'; // Format Markdown
  112. });
  113.  
  114. // Gestion des tableaux
  115. clonedSelection.querySelectorAll('table').forEach(table => {
  116. table.style.borderCollapse = 'collapse';
  117. table.querySelectorAll('td, th').forEach(cell => {
  118. cell.style.border = '1px solid black';
  119. cell.style.padding = '4px';
  120. });
  121. });
  122.  
  123. // Formatage des éléments textuels
  124. clonedSelection.querySelectorAll('b, strong').forEach(el => {
  125. el.innerText = '**' + el.innerText + '**';
  126. });
  127. clonedSelection.querySelectorAll('i, em').forEach(el => {
  128. el.innerText = '*' + el.innerText + '*';
  129. });
  130. clonedSelection.querySelectorAll('u').forEach(el => {
  131. el.innerText = '__' + el.innerText + '__';
  132. });
  133.  
  134. // Conversion en HTML complet
  135. const div = document.createElement('div');
  136. div.appendChild(clonedSelection);
  137. GM_setClipboard(div.innerHTML, 'text/html');
  138.  
  139. // Notification de réussite
  140. GM_notification({
  141. text: 'Contenu copié avec succès dans le presse-papiers !',
  142. title: 'CopyMasterX',
  143. timeout: 3000
  144. });
  145. }
  146.  
  147. // Fonction pour exporter en PDF
  148. function exportToPDF(content) {
  149. const jsPDF = window.jsPDF;
  150. const doc = new jsPDF();
  151. doc.html(content, {
  152. callback: function (doc) {
  153. doc.save('export.pdf');
  154. },
  155. margin: [10, 10, 10, 10],
  156. autoPaging: true
  157. });
  158. }
  159.  
  160. // Fonction pour exporter en DOCX
  161. function exportToDOCX(content) {
  162. const PizZip = window.PizZip;
  163. const Docxtemplater = window.Docxtemplater;
  164.  
  165. const zip = new PizZip();
  166. const doc = new Docxtemplater(zip);
  167. doc.setData({ content });
  168. doc.render();
  169. const out = doc.getZip().generate({ type: 'blob' });
  170. GM_download(out, 'export.docx');
  171. }
  172.  
  173. // Fonction pour exporter en ODT (LibreOffice)
  174. function exportToODT(content) {
  175. const odf = window.odf; // Assurez-vous d'avoir la bibliothèque js-odf importée dans votre projet
  176. const odtDoc = new odf.OdtDocument();
  177. odtDoc.addText(content);
  178. const blob = odtDoc.save();
  179. GM_download(blob, 'export.odt');
  180. }
  181.  
  182. // Fonction pour exporter en CSV
  183. function exportToCSV(table) {
  184. let csv = '';
  185. const rows = table.querySelectorAll('tr');
  186. rows.forEach(row => {
  187. const cells = row.querySelectorAll('th, td');
  188. const rowData = [];
  189. cells.forEach(cell => {
  190. rowData.push('"' + cell.textContent.replace(/"/g, '""') + '"');
  191. });
  192. csv += rowData.join(',') + '\n';
  193. });
  194.  
  195. const blob = new Blob([csv], { type: 'text/csv' });
  196. GM_download(blob, 'export.csv');
  197. }
  198.  
  199. // Fonction pour exporter en Excel
  200. function exportToExcel(table) {
  201. const XLSX = window.XLSX; // Assurez-vous d'avoir la bibliothèque xlsx importée dans votre projet
  202. const wb = XLSX.utils.table_to_book(table);
  203. const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });
  204.  
  205. const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
  206. GM_download(blob, 'export.xlsx');
  207. }
  208.  
  209. // Fonction pour exporter en ODS (LibreOffice)
  210. function exportToODS(table) {
  211. const ODS = window.ODS; // Assurez-vous d'avoir la bibliothèque js-ods importée dans votre projet
  212. const odsDoc = new ODS.Document();
  213. const sheet = odsDoc.addSheet('Sheet1');
  214.  
  215. const rows = table.querySelectorAll('tr');
  216. rows.forEach((row, rowIndex) => {
  217. const cells = row.querySelectorAll('th, td');
  218. cells.forEach((cell, cellIndex) => {
  219. sheet.write(cellIndex, rowIndex, cell.textContent);
  220. });
  221. });
  222.  
  223. const blob = odsDoc.save();
  224. GM_download(blob, 'export.ods');
  225. }
  226.  
  227. // Fonction utilitaire pour convertir le binaire en tableau
  228. function s2ab(s) {
  229. const buf = new ArrayBuffer(s.length);
  230. const view = new Uint8Array(buf);
  231. for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
  232. return buf;
  233. }
  234.  
  235. // Ajout de la gestion de la touche de raccourci
  236. document.addEventListener('keydown', (e) => {
  237. if (e.ctrlKey && e.shiftKey && e.key === 'C') copyWithStyles();
  238. });
  239. })();