标签: 4CAF50

  • 【油猴脚本】一键复制网页全文为MarkDown格式文本到剪贴板

    // ==UserScript==
    // @name         ToMD - Convert Content to Markdown
    // @namespace    http://tampermonkey.net/
    // @version      1.0
    // @description  Convert web page content to Markdown format and copy to clipboard
    // @author       Steper Lin
    // @match        *://*/*
    // @grant        GM_addStyle
    // @grant        GM_setClipboard
    // @require      https://cdnjs.cloudflare.com/ajax/libs/turndown/7.1.1/turndown.min.js
    // ==/UserScript==
    
    (function() {
        'use strict';
    
        // Add styles for the button and notification
        GM_addStyle(`
            #tomd-button {
                position: fixed;
                bottom: 20px;
                right: 20px;
                background-color: #4CAF50;
                color: white;
                border: none;
                border-radius: 4px;
                padding: 10px 15px;
                font-size: 14px;
                cursor: pointer;
                z-index: 9999;
                box-shadow: 0 2px 5px rgba(0,0,0,0.3);
                transition: all 0.3s ease;
            }
            #tomd-button:hover {
                background-color: #45a049;
                box-shadow: 0 3px 7px rgba(0,0,0,0.4);
            }
            #tomd-notification {
                position: fixed;
                bottom: 70px;
                right: 20px;
                background-color: #333;
                color: white;
                padding: 10px 15px;
                border-radius: 4px;
                font-size: 14px;
                z-index: 10000;
                opacity: 0;
                transition: opacity 0.3s ease;
                box-shadow: 0 2px 5px rgba(0,0,0,0.3);
            }
            #tomd-notification.show {
                opacity: 1;
            }
        `);
    
        // Create the ToMD button
        const button = document.createElement('button');
        button.id = 'tomd-button';
        button.textContent = 'ToMD';
        document.body.appendChild(button);
    
        // Create notification element
        const notification = document.createElement('div');
        notification.id = 'tomd-notification';
        notification.textContent = 'Markdown copied to clipboard!';
        document.body.appendChild(notification);
    
        // Function to show notification
        function showNotification(message = 'Markdown copied to clipboard!', duration = 2000) {
            notification.textContent = message;
            notification.classList.add('show');
            setTimeout(() => {
                notification.classList.remove('show');
            }, duration);
        }
    
        // Function to detect the main content of the page
        function detectMainContent() {
            // Try different strategies to find the main content
    
            // 1. Look for article tag
            let content = document.querySelector('article');
            if (content && content.textContent.trim().length > 100) {
                return content;
            }
    
            // 2. Look for common content containers
            const contentSelectors = [
                'div.post-content',
                'div.entry-content',
                'div.content',
                'div.post',
                'div.article',
                'div.main-content',
                'main',
                '#content',
                '.content',
                '.post-body',
                '.post-content',
                '.article-content'
            ];
    
            for (const selector of contentSelectors) {
                content = document.querySelector(selector);
                if (content && content.textContent.trim().length > 100) {
                    return content;
                }
            }
    
            // 3. Heuristic approach: Find the element with the most text content
            const paragraphs = document.querySelectorAll('p');
            if (paragraphs.length > 0) {
                // Find which container has the most paragraphs
                const containers = new Map();
    
                paragraphs.forEach(p => {
                    if (p.textContent.trim().length < 20) return; // Skip very short paragraphs
    
                    // Find parent elements up to 4 levels
                    let parent = p.parentElement;
                    for (let i = 0; i < 4 && parent; i++) {
                        containers.set(parent, (containers.get(parent) || 0) + 1);
                        parent = parent.parentElement;
                    }
                });
    
                // Find the container with the most paragraphs
                let maxParagraphs = 0;
                let mainContainer = null;
    
                containers.forEach((count, container) => {
                    if (count > maxParagraphs) {
                        maxParagraphs = count;
                        mainContainer = container;
                    }
                });
    
                if (mainContainer && maxParagraphs >= 3) {
                    return mainContainer;
                }
            }
    
            // 4. Fallback to body if nothing else works
            return document.body;
        }
    
        // Function to convert HTML to Markdown
        function convertToMarkdown(element) {
            // Configure TurndownService for better markdown conversion
            const service = new TurndownService({
                headingStyle: 'atx',
                codeBlockStyle: 'fenced',
                emDelimiter: '*'
            });
    
            // Improve list handling
            service.addRule('listItems', {
                filter: ['li'],
                replacement: function (content, node, options) {
                    content = content.trim().replace(/^\s+|\s+$/g, '');
                    const isOrdered = node.parentNode.nodeName.toLowerCase() === 'ol';
                    const prefix = isOrdered ? '1. ' : '- ';
                    const indent = node.parentNode.parentNode.nodeName.toLowerCase() === 'li' ? '  ' : '';
                    return indent + prefix + content;
                }
            });
    
            // Improve image handling
            service.addRule('images', {
                filter: 'img',
                replacement: function (content, node) {
                    const alt = node.alt || '';
                    const src = node.getAttribute('src') || '';
                    const title = node.title || '';
                    const titlePart = title ? ' "' + title + '"' : '';
                    return src ? '![' + alt + '](' + src + titlePart + ')' : '';
                }
            });
    
            // Clone the element to avoid modifying the actual page
            const clonedElement = element.cloneNode(true);
    
            // Remove unnecessary elements from clone
            const elementsToRemove = [
                'script',
                'style',
                'iframe',
                'nav',
                'header:not(article header)',
                'footer:not(article footer)',
                '.sidebar',
                '.comments',
                '.navigation',
                '.ads',
                '.share-buttons'
            ];
    
            elementsToRemove.forEach(selector => {
                const elements = clonedElement.querySelectorAll(selector);
                elements.forEach(el => el.parentNode?.removeChild(el));
            });
    
            // Convert the HTML to markdown
            return service.turndown(clonedElement.innerHTML);
        }
    
        // Button click handler
        button.addEventListener('click', function() {
            try {
                // Find the main content
                const mainContent = detectMainContent();
    
                if (!mainContent) {
                    showNotification('Could not detect main content on this page.', 3000);
                    return;
                }
    
                // Convert content to Markdown
                const markdown = convertToMarkdown(mainContent);
    
                if (!markdown || markdown.trim().length === 0) {
                    showNotification('No content found to convert.', 3000);
                    return;
                }
    
                // Copy to clipboard
                GM_setClipboard(markdown);
    
                // Show success notification
                showNotification('Markdown copied to clipboard!');
    
            } catch (error) {
                console.error('ToMD Error:', error);
                showNotification('Error converting to Markdown. See console for details.', 4000);
            }
        });
    })();
人生梦想 - 关注前沿的计算机技术 acejoy.com 🐾 步子哥の博客 🐾 背多分论坛 🐾 知差(chai)网