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-16 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Copy HTML to Anki
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.8
  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 questionElement = docClone.querySelector('.container.card');
  40. let questionField = questionElement ? questionElement.innerHTML : '';
  41. console.log("Question Field:", questionField);
  42.  
  43. let hintField = Array.from(docClone.querySelectorAll('.options'))
  44. .map(option => option.innerText.trim())
  45. .filter(text => text)
  46. .map(text => `<p>${text}</p>`)
  47. .join('') || '';
  48. console.log("Hint Field:", hintField);
  49.  
  50. let answerField = Array.from(docClone.querySelectorAll('.options.correct'))
  51. .map(option => option.innerText.trim())
  52. .filter(text => text)
  53. .map(text => `<p>${text}</p>`)
  54. .join('') || '';
  55. console.log("Answer Field:", answerField);
  56.  
  57. let additionalInfoField = docClone.querySelector('.feedback')?.innerText.trim() || '';
  58. console.log("Additional Info Field:", additionalInfoField);
  59.  
  60. // Create the note fields
  61. let noteFields = {
  62. "Front": questionField,
  63. "Options": hintField,
  64. "Back": answerField,
  65. "Extra": additionalInfoField
  66. };
  67.  
  68. console.log("Note fields to be sent to Anki:", noteFields);
  69.  
  70. GM_xmlhttpRequest({
  71. method: "POST",
  72. url: "http://localhost:8765",
  73. data: JSON.stringify({
  74. "action": "addNote",
  75. "version": 6,
  76. "params": {
  77. "note": {
  78. "deckName": "Default",
  79. "modelName": "Basic Build",
  80. "fields": noteFields,
  81. "tags": ["newimport"]
  82. }
  83. }
  84. }),
  85. headers: {
  86. "Content-Type": "application/json"
  87. },
  88. onload: function(response) {
  89. console.log("Response from AnkiConnect:", response);
  90. if (response.status === 200) {
  91. console.log("Note fields sent to Anki successfully!");
  92. } else {
  93. console.error("Failed to send note fields to Anki.");
  94. }
  95. }
  96. });
  97. }
  98.  
  99. // Add event listener for the keyboard shortcut (Ctrl+Shift+Y)
  100. document.addEventListener('keydown', function(event) {
  101. if (event.ctrlKey && event.shiftKey && event.code === 'KeyY') {
  102. copyHtmlToAnki();
  103. }
  104. });
  105.  
  106. // Register the menu command to Tampermonkey menu
  107. GM_registerMenuCommand("Copy HTML to Anki", copyHtmlToAnki);
  108. })();