WykopObserve

API WykopObserve dla dodatków na wykop.pl - daje API, które robi pętlę z callbackiem, po wpisach z filtrowaniem wedłów różnych kryteriów.

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/437595/1002297/WykopObserve.js

  1. // observe module start
  2.  
  3. const {wykopObserve, filterGroups, loginUser, getAdjacentEls} = (function () {
  4.  
  5. const headerProfileElement = "header-profile-element";
  6. const linkPageAuthorElement = "link-page-author-element"; // element osoby która dodała ten link
  7. const mikroblogPageComment = "mikroblog-page-comment";
  8. const mikroblogPageSubComment = "mikroblog-page-sub-comment";
  9. const linkPageComment = "link-page-comment";
  10. const linkPageSubComment = "link-page-sub-comment";
  11. const wpisPageComment = "wpis-page-comment";
  12. const wpisPageSubComment = "wpis-page-sub-comment";
  13. const tagPageComment = "tag-page-comment";
  14. const tagPageSubComment = "tag-page-sub-comment";
  15. const mojPageComment = "moj-page-comment";
  16. const mojPageSubComment = "moj-page-sub-comment";
  17. const mikroblogPageWriteElement = "mikroblog-page-write-element";
  18. const linkPageWriteElement = "link-page-write-element";
  19. const wpisPageWriteElement = "wpis-page-write-element";
  20. const tagPageWriteElement = "tag-page-write-element";
  21. const ludziePageWriteElement = "ludzie-page-write-element";
  22. const mojPageWriteElement = "moj-page-write-element";
  23. const ludziePageLinkSubComment = "ludzie-page-link-sub-comment";
  24. const ludziePageWpisComment = "ludzie-page-wpis-comment";
  25. const ludziePageWpisSubComment = "ludzie-page-wpis-sub-comment";
  26. const glownaPageComment = "glowna-page-comment";
  27. const mikroblogLinkWpisGlownaTagMojComment = [
  28. mikroblogPageComment,
  29. linkPageComment,
  30. wpisPageComment,
  31. glownaPageComment,
  32. tagPageComment,
  33. mojPageComment,
  34. ];
  35. const mikroblogLinkWpisTagSubMojComment = [
  36. mikroblogPageSubComment,
  37. linkPageSubComment,
  38. wpisPageSubComment,
  39. tagPageSubComment,
  40. mojPageSubComment,
  41. ];
  42. const mikroblogLinkWpisGlownaTagMojCommentOrSubComment = [
  43. ...mikroblogLinkWpisGlownaTagMojComment,
  44. ...mikroblogLinkWpisTagSubMojComment,
  45. ];
  46. const ludziePageCommentOrSubComment = [
  47. ludziePageLinkSubComment,
  48. ludziePageWpisComment,
  49. ludziePageWpisSubComment
  50. ]
  51. const writeElement = [
  52. mikroblogPageWriteElement,
  53. linkPageWriteElement,
  54. wpisPageWriteElement,
  55. tagPageWriteElement,
  56. ludziePageWriteElement,
  57. mojPageWriteElement,
  58. ];
  59. const places = [
  60. headerProfileElement,
  61. linkPageAuthorElement,
  62. mikroblogPageComment,
  63. mikroblogPageSubComment,
  64. linkPageComment,
  65. linkPageSubComment,
  66. wpisPageComment,
  67. wpisPageSubComment,
  68. tagPageComment,
  69. tagPageSubComment,
  70. mojPageComment,
  71. mojPageSubComment,
  72. mikroblogPageWriteElement,
  73. linkPageWriteElement,
  74. wpisPageWriteElement,
  75. tagPageWriteElement,
  76. ludziePageWriteElement,
  77. mojPageWriteElement,
  78. ludziePageLinkSubComment,
  79. ludziePageWpisComment,
  80. ludziePageWpisSubComment,
  81. glownaPageComment,
  82. //"chat-page-comment",
  83. //"chat-page-write-element",
  84. //"own-page-author-element", // element osoby która utworzyła własną treść w edytorze wykopowym
  85. ];
  86. const otherFilter = "other";
  87. const getWykopPageType = ()=>location.pathname.split("/")[1];
  88. const hasSub = (profileEl)=>profileEl.parentElement.parentElement.parentElement.classList.contains("sub");
  89. const getSub = (profileEl)=>hasSub(profileEl)?"-sub":"";
  90. function getProfiles (scopeEl, placesFilter) {
  91. const profiles = [];
  92. const loggedUserEl = document.querySelector('.logged-user > a');
  93. if (loggedUserEl && placesFilter.includes(headerProfileElement)) {
  94. profiles.push(loggedUserEl);
  95. }
  96. const userCardEl = document.querySelector('.usercard > a');
  97. if (getWykopPageType() === "link" && userCardEl && placesFilter.includes(linkPageAuthorElement)) {
  98. profiles.push(userCardEl);
  99. }
  100. // UWAGA: to filtruje tylko wstępnie. później filtruje się pojedynczo w observer
  101. //if (getWykopPageType() === "mikroblog" && placesArr.includes(mikroblogPageComment)) {
  102. //profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entry"] .profile')));
  103. //}
  104. //if (getWykopPageType() === "mikroblog" && placesFilter.includes(mikroblogPageSubComment)) {
  105. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entrycomment"] .profile')));
  106. //}
  107. if (getWykopPageType() === "link" && placesFilter.includes(linkPageComment)) {
  108. profiles.push(...Array.from(scopeEl.querySelectorAll(':not(.sub) [data-type="comment"] .profile')));
  109. } // nie odkomentowywać, bo dam się dynamicznie nie aktualizują ani nie doładowują ukryte, bo one są tylko hidden.
  110. if (getWykopPageType() === "link" && placesFilter.includes(linkPageSubComment)) {
  111. profiles.push(...Array.from(scopeEl.querySelectorAll('.sub [data-type="comment"] .profile')));
  112. }
  113. //if (getWykopPageType() === "wpis" && placesArr.includes(wpisPageComment)) {
  114. //profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entry"] .profile')));
  115. //}
  116. //if (getWykopPageType() === "wpis" && placesFilter.includes(wpisPageSubComment)) {
  117. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entrycomment"] .profile')));
  118. //}
  119. //if (getWykopPageType() === "tag" && placesArr.includes(tagPageComment)) {
  120. //profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entry"] .profile')));
  121. //}
  122. //if (getWykopPageType() === "tag" && placesFilter.includes(tagPageSubComment)) {
  123. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entrycomment"] .profile')));
  124. //}
  125. //if (getWykopPageType() === "moj" && placesFilter.includes(mojPageSubComment)) {
  126. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entrycomment"] .profile')));
  127. //}
  128. if (getWykopPageType() === "mikroblog" && placesFilter.includes(mikroblogPageWriteElement)) {
  129. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-submitflag="commentSubmit"] .profile')));
  130. }
  131. if (getWykopPageType() === "link" && placesFilter.includes(linkPageWriteElement)) {
  132. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-submitflag="commentSubmit"] .profile')));
  133. }
  134. if (getWykopPageType() === "wpis" && placesFilter.includes(wpisPageWriteElement)) {
  135. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-submitflag="commentSubmit"] .profile')));
  136. }
  137. if (getWykopPageType() === "tag" && placesFilter.includes(tagPageWriteElement)) {
  138. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-submitflag="commentSubmit"] .profile')));
  139. }
  140. if (getWykopPageType() === "ludzie" && placesFilter.includes(ludziePageWriteElement)) {
  141. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-submitflag="commentSubmit"] .profile')));
  142. }
  143. if (getWykopPageType() === "moj" && placesFilter.includes(mojPageWriteElement)) {
  144. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-submitflag="commentSubmit"] .profile')));
  145. }
  146. if (getWykopPageType() === "ludzie" && placesFilter.includes(ludziePageLinkSubComment)) {
  147. profiles.push(...Array.from(scopeEl.querySelectorAll(':not(.sub) [data-type="comment"] .profile')));
  148. }
  149. //if (getWykopPageType() === "ludzie" && placesArr.includes(ludziePageWpisComment)) {
  150. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entry"] .profile')));
  151. // bez if-a, żeby observer się dodał, a filtrowane w observer-ze i w allFn
  152. // reszta zapytań [data-type="entry"] .profile za-komentowana, żeby nie powielać.
  153. // glownaPageComment też
  154. //}
  155. //if (getWykopPageType() === "ludzie" && placesFilter.includes(ludziePageWpisSubComment)) {
  156. profiles.push(...Array.from(scopeEl.querySelectorAll('[data-type="entrycomment"] .profile')));
  157. //}
  158. if (profiles.length===0) { console.log("profiles is empty"); }
  159. return profiles;
  160. }
  161. function getPlace (profileEl) {
  162. let place = "other";
  163. if (profileEl === document.querySelector('.logged-user > a')) {
  164. place = headerProfileElement;
  165. } else
  166. if (getWykopPageType() === "link" && profileEl === document.querySelector('.usercard > a')) {
  167. place = linkPageAuthorElement;
  168. } else
  169. if (getWykopPageType() === "ludzie" && profileEl.parentElement.matches('[data-type="comment"]')) {
  170. place = ludziePageLinkSubComment;
  171. } else
  172. if (getWykopPageType() === "ludzie" && profileEl.parentElement.matches('[data-type="entry"]')) {
  173. place = ludziePageWpisComment;
  174. } else
  175. if (getWykopPageType() === "ludzie" && profileEl.parentElement.matches('[data-type="entrycomment"]')) {
  176. place = ludziePageWpisSubComment;
  177. } else
  178. if (getWykopPageType() === "ludzie" && profileEl.parentElement.matches('[data-submitflag="commentSubmit"]')) {
  179. place = ludziePageWpisSubComment;
  180. } else
  181. if (document.querySelector(".grid .info")?.textContent?.includes("Strona główna")
  182. &&
  183. profileEl.parentElement.matches('[data-type="entry"]')) {
  184. place = glownaPageComment;
  185. } else
  186. if (["ludzie","link","tag","mikroblog","wpis","moj"].includes(getWykopPageType())) {
  187. place = `${getWykopPageType()}-page${getSub(profileEl)}-comment`;
  188. }
  189. if (place === "") { console.log("place null", profileEl); }
  190. return place;
  191. }
  192. function getProfileElNick(profileEl) {
  193. const nickB = profileEl.getAttribute("href").split("/");
  194. const nick = nickB[nickB.length-2];
  195. return nick;
  196. }
  197. const getSex = avatarEl=>avatarEl.classList.contains("male")?"male":avatarEl.classList.contains("female")?"female":null;
  198. async function wykopObserve (userFilters, callbackFn, {once=false,delay=null}) {
  199. const cleanP = [...(new Set(userFilters.flat(Infinity)))];
  200. userFilters = cleanP.filter(p=>[...places, otherFilter].includes(p));
  201. const ff = cleanP.filter(p=>![...places, otherFilter].includes(p));
  202. if (ff.length>0) { console.warn(`[WykopObserve] faulty filters: ${ff.map(f=>`"${f}"`).join(", ")}.`); }
  203. const sym = Symbol();
  204. function getAttrs (profileEl) {
  205. const avatarEl = profileEl.querySelector(".avatar");
  206. const place = getPlace(profileEl);
  207. const isFirstTime = profileEl.parentElement.parentElement[sym]!==true;
  208. const nick = getProfileElNick(profileEl);
  209. const authorSex = getSex(avatarEl);
  210. const attrs = {place, isFirstTime, nick, authorSex};
  211. return attrs;
  212. }
  213. function getElements (profileEl) {
  214. const liEL = profileEl.parentElement.parentElement;
  215. return {
  216. profileEl,
  217. liEl: liEL.matches("li")?liEL:null,
  218. contentEl: profileEl.parentElement.querySelector(".text > p")
  219. };
  220. }
  221. async function cbFn (elements, attrs) {
  222. await callbackFn(elements, attrs);
  223. //if (delay >= 0) { await delayFn(delay); }
  224. }
  225. function addCommentOrSubCommentChangeObserver (cbFn, parentProfileEl, placesFilter) {
  226. const profileElObserver = new MutationObserver((mutations)=> {
  227. //console.log("profilEl mutation");
  228. const target = mutations[0].target;
  229. if (!(target instanceof HTMLElement)) { return false; }
  230. const profileEl = target.querySelector(".profile");
  231. const attrs = getAttrs(profileEl);
  232. const elements = getElements(profileEl);
  233. if (placesFilter.includes(attrs.place)) {
  234. cbFn(elements, attrs);
  235. }
  236. });
  237. profileElObserver.observe( parentProfileEl.parentElement.parentElement, {childList: true} );
  238. };
  239. async function cbAndObserveChanges (scopeEl, observe=true) {
  240. const placesFilter = userFilters;
  241. const profiles = getProfiles(scopeEl, placesFilter);
  242. for (const profileEl of profiles) {
  243. const attrs = getAttrs(profileEl);
  244. const elements = getElements(profileEl);
  245. if (placesFilter.includes(attrs.place) && (observe===false || once === false || attrs.isFirstTime === true)) {
  246. await cbFn(elements, attrs);
  247. if (observe) { addCommentOrSubCommentChangeObserver(cbFn, profileEl, placesFilter); }
  248. profileEl.parentElement.parentElement[sym] = true;
  249. }
  250. // addCommentOrSubCommentChangeObserver
  251. // trzeba dodać do każdego Comment i SubComment, bo to obserwuje modyfikację konkretnego elementu pod względem posiadania
  252. // brody. nie sprawdza ilości a modyfikację elementu (np. usunięcie, edycję).
  253. // obsługuje: usunięcie(stan "usunięty"), stan edycji(jak jest pole do wpisywania to też odświeża avatar), stan po edycji.
  254. // modyfikacja WpisPageComment też trigger-uje observera.
  255. }
  256. }
  257. function addSubObserver (subOrStreamEl, callback=()=>{}) {
  258. //if (subOrStreamEl.dataset.hasOwnProperty("childCount")) { return false; }
  259. if (subOrStreamEl[sym]===true) { return false; }
  260. //subOrStreamEl.dataset.childCount = `${subOrStreamEl.childElementCount}`;
  261. const subObserver = new MutationObserver(async function(mutations) {
  262. const target = mutations[0].target;
  263. if (!(target instanceof HTMLElement)) { return false; }
  264. //target.dataset.childCount = `${target.childElementCount}`;
  265. await cbAndObserveChanges(target);
  266. callback();
  267. });
  268. subObserver.observe( subOrStreamEl, {childList: true} );
  269. subOrStreamEl[sym]=false;
  270. };
  271. function observeExpandSubComments () {
  272. const subEls = Array.from( document.querySelectorAll(".sub") );
  273. subEls.forEach((subEl)=>addSubObserver(subEl));
  274. }
  275. function cbAndObserveOnNewAndInfiniteScrollInTagPage () {
  276. const streamEl = document.querySelector(".comments-stream");
  277. addSubObserver(streamEl, observeExpandSubComments);
  278. }
  279. await cbAndObserveChanges(document);
  280. // dodaje do wpisPageComment lub wpisPgeSubComment i obserwuje modyfikacje
  281. // nie reaguje na ładowanie dodatkowych postów w tagu.
  282. observeExpandSubComments();
  283. // dodaje dla wpisPageSubComment, gdy rozwinąć dodatkowe zwinięte komentarze wpisPageSubComment
  284. // w link, mikroblog, na profilu też działa doładowywanie. (w link niepotrzebne właściwie)
  285. cbAndObserveOnNewAndInfiniteScrollInTagPage();
  286. // dodaje dla tagPageComment, doładowane jako nowe albo z infinite scroll
  287. // nie dodaje observer dla expandSubComments
  288. const refresh = ()=>cbAndObserveChanges(document, false);
  289. return {refresh};
  290. // const wpisZeroObserver = new MutationObserver(async function(mutations) {
  291. // const liEl = mutations[0].target;
  292. // if (!(liEl instanceof HTMLElement)) { return false; }
  293. // const subEl = liEl.querySelector(".sub");
  294. // if (!(subEl instanceof HTMLElement)) { return false; }
  295. // if (!(liEl.childElementCount !== 1 && subEl)) { return false; }
  296. // await cbAndObserveChanges(subEl);
  297. // subEl.dataset.childCount = `${subEl.childElementCount}`;
  298. // addSubObserver(subEl);
  299. // });
  300. // function subZeroFn () {
  301. // const streamElChildren = Array.from( document.querySelector(".comments-stream").children );
  302. // streamElChildren.forEach((liEl)=>{
  303. // if (!(liEl.childElementCount === 1)) { return false; }
  304. // wpisZeroObserver.observe( liEl, {childList: true} );
  305. // });
  306. // }
  307. //subZeroFn();
  308. // raczej nic nie robi
  309. // dodaje dla wpisPageSubComment ale setNowAndObserveChanges też to robi?
  310. // nie dodaje gdy zmienia się liczba wpisPageSubComment
  311. // nie dodaje, gdy rozwinąć dodatkowe zwinięte komentarze wpisPageSubComment
  312. }
  313. function getLogin () {
  314. const avatarEl = document.querySelector(".logged-user img.avatar");
  315. if (!(avatarEl instanceof HTMLImageElement)) { return false; }
  316. return {login:avatarEl.alt, sex:getSex(avatarEl)};
  317. }
  318. function getAdjacentEls(liEl) {
  319. return liEl?.parentElement?.children||[];
  320. }
  321. //} // observe lib end
  322. return {wykopObserve, loginUser:getLogin(), getAdjacentEls, filterGroups: {
  323. all: places,
  324. mikroblogLinkWpisGlownaTagMojComment,
  325. mikroblogLinkWpisTagSubMojComment,
  326. mikroblogLinkWpisGlownaTagMojCommentOrSubComment,
  327. ludziePageCommentOrSubComment,
  328. writeElement,
  329. }};
  330. })();
  331. // observe module end

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址