CopyMaster

Tool for copying raw text and formated text

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         CopyMaster
// @namespace    http://tampermonkey.net/
// @version      8.0
// @description  Tool for copying raw text and formated text
//               Advanced tools : formats PDF, DOCX, LibreOffice (ODT),  Excel/CSV/ODS,  audio, vidéo, images, tabs, etc.
// @author       yglsan
// @match        *://*/*
// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_download
// @license      Gpl-3.0-or-later
// ==/UserScript==

/*
  Copyright (C) 2025 Benjamin Moine (yglsan)

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

(function() {
    'use strict';

    // Création du bouton flottant moderne
    const button = document.createElement('button');
    button.innerText = '📋 Copier Formaté';
    button.style.position = 'fixed';
    button.style.bottom = '20px';
    button.style.right = '20px';
    button.style.padding = '10px 20px';
    button.style.background = '#007bff';
    button.style.color = 'white';
    button.style.border = 'none';
    button.style.borderRadius = '10px';
    button.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)';
    button.style.cursor = 'pointer';
    button.style.fontSize = '16px';
    button.style.zIndex = '1000';
    button.style.transition = 'background 0.3s';
    button.addEventListener('mouseover', () => button.style.background = '#0056b3');
    button.addEventListener('mouseout', () => button.style.background = '#007bff');
    button.addEventListener('click', copyWithStyles);
    document.body.appendChild(button);

    // Fonction pour copier le contenu formaté avec styles et médias
    async function copyWithStyles() {
        const selection = window.getSelection();
        if (!selection.rangeCount) return;
        const range = selection.getRangeAt(0);
        const clonedSelection = range.cloneContents();

        // Ajout des styles inline
        clonedSelection.querySelectorAll('*').forEach(el => {
            const computedStyle = window.getComputedStyle(el);
            el.style.cssText = computedStyle.cssText;
        });

        // Gestion des images
        await Promise.all(
            Array.from(clonedSelection.querySelectorAll('img')).map(async (img) => {
                if (img.src.startsWith('data:')) return;
                try {
                    const response = await fetch(img.src);
                    const blob = await response.blob();
                    const reader = new FileReader();
                    reader.onloadend = () => {
                        img.src = reader.result;
                    };
                    reader.readAsDataURL(blob);
                } catch (e) {
                    console.error('Erreur de téléchargement de l\'image', img.src, e);
                }
            })
        );

        // Gestion des éléments audio et vidéo
        clonedSelection.querySelectorAll('audio, video').forEach(media => {
            if (media.src && !media.src.startsWith('data:')) {
                fetch(media.src)
                    .then(res => res.blob())
                    .then(blob => {
                        const reader = new FileReader();
                        reader.onloadend = () => {
                            media.src = reader.result;
                        };
                        reader.readAsDataURL(blob);
                    })
                    .catch(err => console.error('Erreur lors du téléchargement du média', media.src, err));
            }
        });

        // Gestion des liens
        clonedSelection.querySelectorAll('a').forEach(link => {
            link.setAttribute('target', '_blank');
        });

        // Reconnaissance avancée de la mise en forme
        clonedSelection.querySelectorAll('code, pre').forEach(block => {
            block.innerText = '```' + block.innerText + '```'; // Format Markdown
        });

        // Gestion des tableaux
        clonedSelection.querySelectorAll('table').forEach(table => {
            table.style.borderCollapse = 'collapse';
            table.querySelectorAll('td, th').forEach(cell => {
                cell.style.border = '1px solid black';
                cell.style.padding = '4px';
            });
        });

        // Formatage des éléments textuels
        clonedSelection.querySelectorAll('b, strong').forEach(el => {
            el.innerText = '**' + el.innerText + '**';
        });
        clonedSelection.querySelectorAll('i, em').forEach(el => {
            el.innerText = '*' + el.innerText + '*';
        });
        clonedSelection.querySelectorAll('u').forEach(el => {
            el.innerText = '__' + el.innerText + '__';
        });

        // Conversion en HTML complet
        const div = document.createElement('div');
        div.appendChild(clonedSelection);
        GM_setClipboard(div.innerHTML, 'text/html');

        // Notification de réussite
        GM_notification({
            text: 'Contenu copié avec succès dans le presse-papiers !',
            title: 'CopyMasterX',
            timeout: 3000
        });
    }

    // Fonction pour exporter en PDF
    function exportToPDF(content) {
        const jsPDF = window.jsPDF;
        const doc = new jsPDF();
        doc.html(content, {
            callback: function (doc) {
                doc.save('export.pdf');
            },
            margin: [10, 10, 10, 10],
            autoPaging: true
        });
    }

    // Fonction pour exporter en DOCX
    function exportToDOCX(content) {
        const PizZip = window.PizZip;
        const Docxtemplater = window.Docxtemplater;

        const zip = new PizZip();
        const doc = new Docxtemplater(zip);
        doc.setData({ content });
        doc.render();
        const out = doc.getZip().generate({ type: 'blob' });
        GM_download(out, 'export.docx');
    }

    // Fonction pour exporter en ODT (LibreOffice)
    function exportToODT(content) {
        const odf = window.odf; // Assurez-vous d'avoir la bibliothèque js-odf importée dans votre projet
        const odtDoc = new odf.OdtDocument();
        odtDoc.addText(content);
        const blob = odtDoc.save();
        GM_download(blob, 'export.odt');
    }

    // Fonction pour exporter en CSV
    function exportToCSV(table) {
        let csv = '';
        const rows = table.querySelectorAll('tr');
        rows.forEach(row => {
            const cells = row.querySelectorAll('th, td');
            const rowData = [];
            cells.forEach(cell => {
                rowData.push('"' + cell.textContent.replace(/"/g, '""') + '"');
            });
            csv += rowData.join(',') + '\n';
        });

        const blob = new Blob([csv], { type: 'text/csv' });
        GM_download(blob, 'export.csv');
    }

    // Fonction pour exporter en Excel
    function exportToExcel(table) {
        const XLSX = window.XLSX; // Assurez-vous d'avoir la bibliothèque xlsx importée dans votre projet
        const wb = XLSX.utils.table_to_book(table);
        const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' });

        const blob = new Blob([s2ab(wbout)], { type: 'application/octet-stream' });
        GM_download(blob, 'export.xlsx');
    }

    // Fonction pour exporter en ODS (LibreOffice)
    function exportToODS(table) {
        const ODS = window.ODS; // Assurez-vous d'avoir la bibliothèque js-ods importée dans votre projet
        const odsDoc = new ODS.Document();
        const sheet = odsDoc.addSheet('Sheet1');

        const rows = table.querySelectorAll('tr');
        rows.forEach((row, rowIndex) => {
            const cells = row.querySelectorAll('th, td');
            cells.forEach((cell, cellIndex) => {
                sheet.write(cellIndex, rowIndex, cell.textContent);
            });
        });

        const blob = odsDoc.save();
        GM_download(blob, 'export.ods');
    }

    // Fonction utilitaire pour convertir le binaire en tableau
    function s2ab(s) {
        const buf = new ArrayBuffer(s.length);
        const view = new Uint8Array(buf);
        for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
        return buf;
    }

    // Ajout de la gestion de la touche de raccourci
    document.addEventListener('keydown', (e) => {
        if (e.ctrlKey && e.shiftKey && e.key === 'C') copyWithStyles();
    });
})();