DuoLingots

More duolingots!!!!1111

  1. // ==UserScript==
  2. // @name DuoLingots
  3. // @namespace https://github.com/liuch/duolingo-scripts
  4. // @include Https://*duolingo.com/*
  5. // @include https://forum.duolingo.com/*
  6. // @version 0.2.0
  7. // @grant none
  8. // @description More duolingots!!!!1111
  9. // @author Maevings0
  10. // @license MIT License
  11. // ==/UserScript==
  12.  
  13. function inject(f) { //Inject the script into the document idk
  14. var script;
  15. script = document.createElement('script');
  16. script.type = 'text/javascript';
  17. script.setAttribute('name', 'duogivelingots');
  18. script.textContent = '(' + f.toString() + ')()';
  19. document.head.appendChild(script);
  20. }
  21. inject(f);
  22.  
  23.  
  24. function f() {
  25.  
  26. var observe = {
  27. observer: null,
  28. root_el: null,
  29. p_func: null,
  30.  
  31. set: function(func) {
  32. this.root_el = document.getElementsByTagName("body")[0];
  33. if (this.root_el) {
  34. this.p_func = func;
  35. this.observer = new MutationObserver(function(mutations) {
  36. if (observe.p_func) {
  37. observe.stop();
  38. observe.p_func()
  39. observe.start();
  40. }
  41. });
  42. }
  43. },
  44.  
  45. start: function() {
  46. this.observer.observe(this.root_el, { childList: true, subtree: true });
  47. },
  48.  
  49. stop: function() {
  50. this.observer.disconnect();
  51. }
  52. };
  53.  
  54. var post_id = null;
  55.  
  56. var update_comment = function(id, link_el) {
  57. var el = null;
  58. if (link_el.parentElement.parentElement.children.length == 2) {
  59. el = link_el.parentElement.parentElement.children[1];
  60. }
  61. else {
  62. var span1 = document.createElement("span");
  63. span1.setAttribute("class", "_5j_V-");
  64. var span2 = document.createElement("span");
  65. span2.setAttribute("class", "_2ySWm");
  66. var span3 = document.createElement("span");
  67. span3.setAttribute("class", "fl9X4");
  68. span3.appendChild(document.createTextNode("0"));
  69. span1.appendChild(span2);
  70. span1.appendChild(span3);
  71. link_el.parentElement.parentElement.appendChild(span1);
  72. el = span1;
  73. }
  74. if (el) {
  75. el.childNodes[1].childNodes[0].nodeValue = parseInt(el.childNodes[1].childNodes[0].nodeValue) + 1;
  76. }
  77. };
  78.  
  79. function get_toolbar_element() {
  80. var el = document.querySelector("div._3mmdn>div>a.XHOsr._3xRJe");
  81. if (!el) {
  82. el = document.querySelector("div._1vD0u.H_C0j>span._2XMOE.dRGy3.H_C0j>span._2cbOJ._3MxB2"); // new design
  83. if (!el)
  84. console.warn("DuoMoreLingots: Cannot find a toolbar element");
  85. }
  86. return el;
  87. }
  88.  
  89. function total_lingots() {
  90. var lingots = 0;
  91. var el = get_toolbar_element();
  92. if (el) {
  93. if (el.nodeName == "A")
  94. lingots = parseInt(el.childNodes[1].nodeValue);
  95. else
  96. lingots = parseInt(el.childNodes[0].nodeValue); // new design
  97. }
  98. return lingots;
  99. }
  100.  
  101. function decrement_total_lingots() {
  102. var el = get_toolbar_element();
  103. if (el) {
  104. var num = total_lingots();
  105. if (num > 0) {
  106. num -= 1;
  107. }
  108. if (el.nodeName == "A")
  109. el.childNodes[1].nodeValue = num;
  110. else
  111. el.childNodes[0].nodeValue = num; // new design
  112. }
  113. }
  114.  
  115. function update_view(id, el) {
  116. observe.stop()
  117. decrement_total_lingots();
  118. update_comment(id, el);
  119. observe.start();
  120. }
  121.  
  122. var send_one = function(id, el) {
  123. if (total_lingots() > 0) {
  124. fetch("https://forum-api.duolingo.com/comments/" + id + "/love", {
  125. method: 'POST',
  126. credentials: 'include'
  127. }).then(function() {
  128. update_view(id, el);
  129. });
  130. }
  131. };
  132.  
  133. function set_interval_limited(id, num, timeout, el) {
  134. if (num <= 0) {
  135. return;
  136. }
  137. setTimeout(function() {
  138. send_one(id, el);
  139. set_interval_limited(id, num - 1, timeout, el);
  140. }, timeout);
  141. }
  142.  
  143. var lover = function(id, el) {
  144. var num = parseInt(prompt("How many lingots would you like to give away?", "1"));
  145. if (num > 0 && (num <= 10 || confirm("Do you really want to give " + num + " lingots away?"))) {
  146. set_interval_limited(id, num, 200, el);
  147. }
  148. return false;
  149. };
  150.  
  151. var new_give_lingots = function(el) {
  152. var id = null;
  153. var e = el.closest("div.uMmEI>div[id]");
  154. if (e) {
  155. id = e.getAttribute("id");
  156. }
  157. else if (el.closest("div._3eQwU")) {
  158. id = post_id;
  159. }
  160.  
  161. if (id) {
  162. lover(id, el);
  163. }
  164. };
  165.  
  166. function capture_click() {
  167. document.addEventListener("click", function(event) {
  168. var el = event.target;
  169. if (el && el.nodeName == "A" && el.classList.contains("dml-givelingots")) {
  170. new_give_lingots(el);
  171. event.stopPropagation();
  172. event.preventDefault();
  173. }
  174. });
  175. }
  176.  
  177. function remove_listener(el) {
  178. var parent = el.parentElement;
  179. var text = el.text;
  180. el.remove();
  181. el = document.createElement("a");
  182. el.setAttribute("href", "javascript:;");
  183. el.setAttribute("class", "_2xNPC dml-givelingots");
  184. el.appendChild(document.createTextNode(text));
  185. parent.appendChild(el);
  186. }
  187.  
  188. var loc_reg = new RegExp("^/comment/([0-9]+)($|\\$)");
  189.  
  190. function try_update() {
  191. var a = loc_reg.exec(document.location.pathname);
  192. if (a) {
  193. post_id = a[1];
  194. var el_list = document.querySelectorAll("span._5j_V->a._2xNPC:not(.dml-givelingots)");
  195. for (var i = 0; i < el_list.length; i++) {
  196. remove_listener(el_list[i]);
  197. }
  198. }
  199. else {
  200. post_id = null;
  201. }
  202. }
  203.  
  204. setTimeout(function() {
  205. try_update();
  206. capture_click();
  207. observe.set(try_update);
  208. observe.start();
  209. }, 100);
  210. }