Copy HTML to Anki

Copy specific parts of HTML text and send them to Anki, converting relative URLs to absolute URLs. Trigger with Ctrl+Shift+Y or via Tampermonkey menu.

当前为 2024-07-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Copy HTML to Anki
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.4
  5. // @description Copy specific parts of HTML text and send them to Anki, converting relative URLs to absolute URLs. Trigger with Ctrl+Shift+Y or via Tampermonkey menu.
  6. // @author nabe
  7. // @match *://*/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_registerMenuCommand
  10. // @connect localhost
  11. // @run-at document-end
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. function copyHtmlToAnki() {
  19. // Function to convert relative URLs to absolute URLs
  20. function makeAbsolute(url) {
  21. return new URL(url, document.baseURI).href;
  22. }
  23.  
  24. // Clone the document to manipulate it
  25. let docClone = document.documentElement.cloneNode(true);
  26.  
  27. // Convert all relative URLs to absolute URLs
  28. let elements = docClone.querySelectorAll('[src], [href]');
  29. elements.forEach(function(element) {
  30. if (element.hasAttribute('src')) {
  31. element.setAttribute('src', makeAbsolute(element.getAttribute('src')));
  32. }
  33. if (element.hasAttribute('href')) {
  34. element.setAttribute('href', makeAbsolute(element.getAttribute('href')));
  35. }
  36. });
  37.  
  38. // Extract the text content of specific parts needed
  39. let questionField = Array.from(docClone.querySelectorAll('.container.card *'))
  40. .filter(element => element.nodeName !== 'SVG')
  41. .map(element => element.outerHTML)
  42. .join('') || '';
  43.  
  44. let hintField = Array.from(docClone.querySelectorAll('.options'))
  45. .map(option => option.innerText.trim())
  46. .filter(text => text)
  47. .join('<br>') || '';
  48.  
  49. let answerField = Array.from(docClone.querySelectorAll('.options.correct'))
  50. .map(option => option.innerText.trim())
  51. .filter(text => text)
  52. .join('<br>') || '';
  53.  
  54. let additionalInfoField = docClone.querySelector('.feedback')?.innerText.trim() || '';
  55.  
  56. // Create the note fields
  57. let noteFields = {
  58. "Front": questionField,
  59. "Options": hintField,
  60. "Back": answerField,
  61. "Extra": additionalInfoField
  62. };
  63.  
  64. console.log("Note fields extracted:", noteFields);
  65.  
  66. GM_xmlhttpRequest({
  67. method: "POST",
  68. url: "http://localhost:8765",
  69. data: JSON.stringify({
  70. "action": "addNote",
  71. "version": 6,
  72. "params": {
  73. "note": {
  74. "deckName": "Default",
  75. "modelName": "Basic Build",
  76. "fields": noteFields,
  77. "tags": ["newimport"]
  78. }
  79. }
  80. }),
  81. headers: {
  82. "Content-Type": "application/json"
  83. },
  84. onload: function(response) {
  85. console.log("Response from AnkiConnect:", response);
  86. if (response.status === 200) {
  87. console.log("Note fields sent to Anki!");
  88. } else {
  89. alert("Failed to send note fields to Anki.");
  90. }
  91. }
  92. });
  93. }
  94.  
  95. // Add event listener for the keyboard shortcut (Ctrl+Shift+Y)
  96. document.addEventListener('keydown', function(event) {
  97. if (event.ctrlKey && event.shiftKey && event.code === 'KeyY') {
  98. copyHtmlToAnki();
  99. }
  100. });
  101.  
  102. // Register the menu command to Tampermonkey menu
  103. GM_registerMenuCommand("Copy HTML to Anki", copyHtmlToAnki);
  104. })();