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