Vocabulary Builder

Vocabulary to Anki Cards.

  1. // ==UserScript==
  2. // @name Vocabulary Builder
  3. // @namespace derjoker
  4. // @version 0.0.6
  5. // @description Vocabulary to Anki Cards.
  6. // @author Feng Ya
  7. // @match https://www.duden.de/rechtschreibung/*
  8. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. // Your code here...
  15. /* global $ */
  16.  
  17. const KEY_ID = 'kvb';
  18.  
  19. $(`button.${KEY_ID}`).remove();
  20.  
  21. // storage
  22. function storage() {
  23. function get(key) {
  24. const item = window.localStorage.getItem(key) || '[]';
  25. return new Set(JSON.parse(item));
  26. }
  27.  
  28. function set(key, item) {
  29. window.localStorage.setItem(key, JSON.stringify(Array.from(item)));
  30. }
  31.  
  32. function add(key, value) {
  33. const item = get(key);
  34. item.add(value);
  35. set(key, item);
  36. }
  37.  
  38. function remove(key, value) {
  39. const item = get(key);
  40. item.delete(value);
  41. if (item.size) set(key, item);
  42. else window.localStorage.removeItem(key);
  43. }
  44.  
  45. function keys() {
  46. const keys = [];
  47. for (let i = 0; i < window.localStorage.length; i++) {
  48. const key = window.localStorage.key(i);
  49. if (key.startsWith(KEY_ID)) keys.push(key);
  50. }
  51. return keys;
  52. }
  53.  
  54. function items() {
  55. return keys().map(key => ({
  56. key,
  57. value: JSON.parse(window.localStorage.getItem(key)),
  58. }));
  59. }
  60.  
  61. function clear() {
  62. keys().forEach(key => {
  63. window.localStorage.removeItem(key);
  64. });
  65. }
  66.  
  67. return { add, remove, items, clear };
  68. }
  69.  
  70. // const names = window.location.pathname.split('/')
  71. // const stem = names[names.length - 1]
  72. const stem = window.location.pathname.split('/').pop();
  73. const word = $('section#block-system-main > h1')
  74. .text()
  75. .replace(/\u00AD/g, '');
  76.  
  77. let contents = [];
  78.  
  79. const section = $('h2:contains("Bedeutungsübersicht")').parents('section');
  80.  
  81. section.find('div.entry').each((_, entry) => {
  82. const clone = $(entry).clone();
  83. clone.find('figure').remove();
  84. clone.find('.term-section').remove();
  85. const definition = clone.text().trim();
  86.  
  87. $(entry)
  88. .find('.term-section')
  89. .each((_, el) => {
  90. const b = $(el).find('h3:contains("Beispiel") + span');
  91. if (b.length) {
  92. contents.push({
  93. definition,
  94. example: b.text().trim(),
  95. });
  96. }
  97.  
  98. const w = $(el).find(
  99. 'h3:contains("Wendungen, Redensarten, Sprichwörter") + span'
  100. );
  101. const clone = w.parent().clone();
  102. clone.find('h3').remove();
  103. if (w.length) {
  104. contents.push({
  105. definition,
  106. example: clone.text().trim(),
  107. });
  108. }
  109.  
  110. $(el)
  111. .find('ul > li')
  112. .each((_, li) => {
  113. const example = $(li)
  114. .text()
  115. .trim();
  116. contents.push({
  117. definition,
  118. example,
  119. });
  120. });
  121. });
  122. });
  123.  
  124. section.find('ol > li > a').each((_, a) => {
  125. const definition = $(a)
  126. .text()
  127. .trim();
  128. const href = $(a).attr('href');
  129. // $(href).prepend('<input type="checkbox" />')
  130. $(href)
  131. .find('.term-section')
  132. .each((_, el) => {
  133. const b = $(el).find('h3:contains("Beispiel") + span');
  134. if (b.length) {
  135. contents.push({
  136. definition,
  137. example: b.text().trim(),
  138. });
  139. }
  140.  
  141. const w = $(el).find(
  142. 'h3:contains("Wendungen, Redensarten, Sprichwörter") + span'
  143. );
  144. const clone = w.parent().clone();
  145. clone.find('h3').remove();
  146. if (w.length) {
  147. contents.push({
  148. definition,
  149. example: clone.text().trim(),
  150. });
  151. }
  152.  
  153. $(el)
  154. .find('ul > li')
  155. .each((_, li) => {
  156. const example = $(li)
  157. .text()
  158. .trim();
  159. contents.push({
  160. definition,
  161. example,
  162. });
  163. });
  164. });
  165. });
  166.  
  167. const key = KEY_ID + '-' + stem;
  168. window.localStorage.setItem(
  169. key,
  170. JSON.stringify(contents.map(data => Object.assign({ word }, data)))
  171. );
  172. console.log(key);
  173.  
  174. const save = $(`<button class="${KEY_ID}">Save</button>`).click(() => {
  175. const s = storage();
  176. console.log('click');
  177. console.log(s.items());
  178. const items = [].concat(...s.items().map(item => item.value));
  179. console.log(items);
  180. const csv = new CsvWriter();
  181. const encodedUri =
  182. 'data:text/csv;charset=utf-8,' +
  183. encodeURIComponent(
  184. csv.arrayToCSV(items.map(item => Object.values(item)))
  185. );
  186.  
  187. const w = window.open(null, 'CSV');
  188. w.location.href = encodedUri;
  189.  
  190. s.clear();
  191. });
  192.  
  193. $('body').prepend(save);
  194.  
  195. // CSV Writer
  196. function CsvWriter(del, enc) {
  197. this.del = del || ','; // CSV Delimiter
  198. this.enc = enc || '"'; // CSV Enclosure
  199.  
  200. // Convert Object to CSV column
  201. this.escapeCol = function(col) {
  202. if (isNaN(col)) {
  203. // is not boolean or numeric
  204. if (!col) {
  205. // is null or undefined
  206. col = '';
  207. } else {
  208. // is string or object
  209. col = String(col);
  210. if (col.length > 0) {
  211. // use regex to test for del, enc, \r or \n
  212. // if(new RegExp( '[' + this.del + this.enc + '\r\n]' ).test(col)) {
  213.  
  214. // escape inline enclosure
  215. col = col.split(this.enc).join(this.enc + this.enc);
  216.  
  217. // wrap with enclosure
  218. col = this.enc + col + this.enc;
  219. }
  220. }
  221. }
  222. return col;
  223. };
  224.  
  225. // Convert an Array of columns into an escaped CSV row
  226. this.arrayToRow = function(arr) {
  227. var arr2 = arr.slice(0);
  228.  
  229. var i;
  230.  
  231. var ii = arr2.length;
  232. for (i = 0; i < ii; i++) {
  233. arr2[i] = this.escapeCol(arr2[i]);
  234. }
  235. return arr2.join(this.del);
  236. };
  237.  
  238. // Convert a two-dimensional Array into an escaped multi-row CSV
  239. this.arrayToCSV = function(arr) {
  240. var arr2 = arr.slice(0);
  241.  
  242. var i;
  243.  
  244. var ii = arr2.length;
  245. for (i = 0; i < ii; i++) {
  246. arr2[i] = this.arrayToRow(arr2[i]);
  247. }
  248. return arr2.join('\r\n');
  249. };
  250. }
  251. })();