git @ Cat's Eye Technologies The-Dipple / master python / gen_md_capture_bookmarklet.py
master

Tree @master (Download .tar.gz)

gen_md_capture_bookmarklet.py @masterraw · history · blame

#!/usr/bin/env python3

# SPDX-FileCopyrightText: Chris Pressey, the creator of this work, has dedicated it to the public domain.
# For more information, please refer to <https://unlicense.org/>
# SPDX-License-Identifier: Unlicense

# Python script to create a JavaScript bookmarklet that converts the HTML contents
# of a pre-specified element to Markdown, and copies that to the clipboard.

import sys

JAVASCRIPT = r"""
function elemToMarkdown(elem) {
  function processNode(node, listDepth = 0) {
    if (node.nodeType === 3) return node.textContent;
    if (node.nodeType !== 1) return '';

    if (node.dataset.state === "closed") return '';

    let tag = node.tagName.toLowerCase();
    const indent = '  '.repeat(listDepth);
    let result = '';

    if (tag === 'div' && node.dataset.testid === 'user-message') tag = 'blockquote';

    switch(tag) {
      case 'h1': return '# ' + node.textContent + '\n\n';
      case 'h2': return '## ' + node.textContent + '\n\n';
      case 'h3': return '### ' + node.textContent + '\n\n';
      case 'h4': return '#### ' + node.textContent + '\n\n';
      case 'h5': return '##### ' + node.textContent + '\n\n';
      case 'h6': return '###### ' + node.textContent + '\n\n';
      case 'p': return processChildren(node, listDepth) + '\n\n';
      case 'br': return '\n';
      case 'strong': case 'b': return '**' + node.textContent + '**';
      case 'em': case 'i': return '*' + node.textContent + '*';
      case 'code': return '`' + node.textContent + '`';
      case 'pre': return '```\n' + node.textContent + '\n```\n\n';
      case 'a': return '[' + node.textContent + '](' + (node.href || '') + ')';
      case 'ul':
        for (const li of node.children) {
          if (li.tagName.toLowerCase() === 'li') {
            result += indent + '- ' + processChildren(li, listDepth + 1).trim() + '\n';
          }
        }
        return result + (listDepth === 0 ? '\n' : '');
      case 'ol':
        let i = 1;
        for (const li of node.children) {
          if (li.tagName.toLowerCase() === 'li') {
            result += indent + i++ + '. ' + processChildren(li, listDepth + 1).trim() + '\n';
          }
        }
        return result + (listDepth === 0 ? '\n' : '');
      case 'blockquote':
        return '> ' + processChildren(node, listDepth).trim().replace(/\n/g, '\n> ') + '\n\n';
      case 'table': {
        const rows = [...node.querySelectorAll('tr')];
        if (rows.length === 0) return '';
        const cells = row => [...row.querySelectorAll('td, th')].map(c => processChildren(c, listDepth).trim().replace(/\|/g, '\\|'));
        const firstRowCells = cells(rows[0]);
        const isHeaderRow = row => [...row.querySelectorAll('th')].length > 0;
        let headerCells, dataRows;
        if (isHeaderRow(rows[0])) {
          headerCells = firstRowCells;
          dataRows = rows.slice(1);
        } else {
          headerCells = firstRowCells.map(() => '');
          dataRows = rows;
        }
        const separator = headerCells.map(() => '---');
        const toRow = cols => '| ' + cols.join(' | ') + ' |';
        result = toRow(headerCells) + '\n' + toRow(separator) + '\n';
        for (const row of dataRows) {
          result += toRow(cells(row)) + '\n';
        }
        return result + '\n';
      }
      case 'button':
        return '';
      default:
        return processChildren(node, listDepth);
    }
  }

  function processChildren(node, listDepth) {
    let result = '';
    for (const child of node.childNodes) {
      result += processNode(child, listDepth);
    }
    return result;
  }

  return processNode(elem).trim();
}

async function convertAndCopy(selector) {
  const el = document.querySelector(selector);
  if (!el) {
    alert('Element not found: ' + selector);
    return;
  }

  const md = elemToMarkdown(el);

  try {
    await navigator.clipboard.writeText(md);
    console.log('Markdown copied to clipboard!');
    return md;
  } catch (err) {
    console.error('Failed to copy:', err);
    alert('Failed to copy to clipboard');
  }
}
"""

def main():
    minified_code = JAVASCRIPT.replace("\n", "")
    selector = ".flex-1.flex.flex-col.px-4.max-w-3xl.mx-auto.w-full.pt-1"

    sys.stdout.write("javascript:(function(){" + minified_code + ";convertAndCopy('" + selector + "');})();\n");


if __name__ == "__main__":
    main()