Advertisement
Guest User

wykop tag autocomplete followers

a guest
Feb 1st, 2023
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.31 KB | None | 0 0
  1. // ==UserScript==
  2. // @name wykop tag followers
  3. // @namespace https://wykop.pl
  4. // @version 0.1
  5. // @description add follower count to tags autocomplete
  6. // @author 4:19am
  7. // @match https://wykop.pl/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. let interceptors = [];
  12.  
  13. /*
  14. * Add a interceptor.
  15. */
  16. const addInterceptor = (interceptor) => {
  17. interceptors.push(interceptor);
  18. };
  19.  
  20. /*
  21. * Clear interceptors
  22. */
  23. const clearInterceptors = () => {
  24. interceptors = [];
  25. };
  26.  
  27.  
  28. /*
  29. * XML HTPP requests can be intercepted with interceptors.
  30. * Takes a regex to match against requests made and a callback to process the response.
  31. */
  32. const createXmlHttpOverride = (
  33. open
  34. ) => {
  35. return function (
  36. method,
  37. url,
  38. async,
  39. username,
  40. password
  41. ) {
  42. this.addEventListener(
  43. "readystatechange",
  44. function () {
  45. if (this.readyState === 4) {
  46. // Override `onreadystatechange` handler, there's no where else this can go.
  47. // Basically replace the client's with our override for interception.
  48. this.onreadystatechange = (function (
  49. originalOnreadystatechange
  50. ) {
  51. return function (ev) {
  52. // Only intercept JSON requests.
  53. const contentType = this.getResponseHeader("content-type");
  54. if (!contentType || !contentType.includes("application/json")) {
  55. return (
  56. originalOnreadystatechange &&
  57. originalOnreadystatechange.call(this, ev)
  58. );
  59. }
  60.  
  61. // Read data from response.
  62. (async function () {
  63. let success = false;
  64. let data;
  65. try {
  66. data =
  67. this.responseType === "blob"
  68. ? JSON.parse(await this.response.text())
  69. : JSON.parse(this.responseText);
  70. success = true;
  71. } catch (e) {
  72. console.error("Unable to parse response.");
  73. }
  74. if (!success) {
  75. return (
  76. originalOnreadystatechange &&
  77. originalOnreadystatechange.call(this, ev)
  78. );
  79. }
  80.  
  81. for (const i in interceptors) {
  82. const { regex, override, callback } = interceptors[i];
  83.  
  84. // Override.
  85. const match = url.indexOf(regex) !== -1;
  86. if (match) {
  87. if (override) {
  88. try {
  89. data = await callback(data, this);
  90. } catch (e) {
  91. return (
  92. originalOnreadystatechange &&
  93. originalOnreadystatechange.call(this, ev)
  94. );
  95. }
  96. }
  97. }
  98. }
  99.  
  100. // Override the response text.
  101. Object.defineProperty(this, "responseText", {
  102. get() {
  103. return JSON.stringify(data);
  104. },
  105. });
  106.  
  107. // Tell the client callback that we're done.
  108. return (
  109. originalOnreadystatechange &&
  110. originalOnreadystatechange.call(this, ev)
  111. );
  112. }.call(this));
  113. };
  114. })(this.onreadystatechange);
  115. }
  116. },
  117. false
  118. );
  119.  
  120. open.call(this, method, url, async, username, password);
  121. };
  122. };
  123.  
  124. const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
  125. const tagAutocompletionLimit = 5; // to jest obecny limit wykopu (tj ilosci wyswietlanych podpowiedzi). moj skrypt go nie zmienia (narazie), ta zmienna tylko okresla do ilu tagow ma wyciagac liczbe obserwujacych
  126.  
  127. async function tagsAutocompleteOptionInjector (tagsDict) {
  128. let container = document.querySelector('section.inline-autocomplete');
  129.  
  130. let tries = 0;
  131. while (container === null && tries !== false) {
  132. tries += 1;
  133. container = document.querySelector('section.inline-autocomplete');
  134.  
  135. if (tries > 60) {
  136. tries = false;
  137. }
  138.  
  139. if (tries > 40) {
  140. await sleep(50);
  141. }
  142. }
  143.  
  144. tries = 0;
  145. while (container.matches('.waiting') || container.matches('.pending') || tries !== false) {
  146. tries += 1;
  147. container = document.querySelector('section.inline-autocomplete');
  148.  
  149. if (tries > 100) {
  150. tries = false;
  151. }
  152.  
  153. if (tries > 80) {
  154. await sleep(50);
  155. }
  156. }
  157.  
  158. if (container === null) {
  159. return false;
  160. }
  161.  
  162. container.querySelectorAll('span').forEach(
  163. function (span)
  164. {
  165. var followers = tagsDict[span.innerText];
  166.  
  167. if (followers) {
  168. span.innerText += ' (' + followers + ' obs.)';
  169. }
  170. }
  171. );
  172. }
  173.  
  174. async function getTagsFollowers (tags, token) {
  175. const responses = await Promise.all(
  176. tags.map(async tag => {
  177. const res = await fetch(`https://wykop.pl/api/v3/tags/${tag}`,
  178. {
  179. headers: {
  180. 'authorization': 'Bearer ' + token
  181. }
  182. }
  183. );
  184. return res.json();
  185. })
  186. );
  187. return responses;
  188. }
  189.  
  190. async function tagsAutocompleteRequestHandler(data, originalRequest) {
  191. data.data.splice(tagAutocompletionLimit, 5).reverse();
  192. let tags = data.data;
  193.  
  194. tags = tags.map(x => x.name);
  195.  
  196. const responses = await getTagsFollowers(tags, window.localStorage.getItem("token"));
  197. let tagsWithFollowers = responses.map(x => ({"name": x.data.name, "followers": x.data.followers}) );
  198. let tagsDict = Object.fromEntries(responses.map(x => ['#' + x.data.name, x.data.followers]));
  199.  
  200. tagsAutocompleteOptionInjector(tagsDict);
  201. return {"data": tagsWithFollowers};
  202. }
  203.  
  204. const main = () => {
  205. addInterceptor({
  206. regex: "wykop.pl/api/v3/tags/autocomplete",
  207. callback: tagsAutocompleteRequestHandler,
  208. override: true
  209. });
  210.  
  211. XMLHttpRequest.prototype.open = createXmlHttpOverride(
  212. XMLHttpRequest.prototype.open
  213. );
  214. };
  215.  
  216. main();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement