X(Twitter) - Indexed DB Version Add notes to the user

Add notes (aliases/tags) for users to help identify and search, optimized for large datasets

  1. // ==UserScript==
  2. // @name X(Twitter) - Indexed DB Version Add notes to the user
  3. // @name:zh-CN X(Twitter) - Indexed DB 增强版为用户添加备注(别名/标签)
  4. // @name:zh-TW X(Twitter) - Indexed DB 增强版為使用者新增備註(別名/標籤)
  5. // @namespace https://gf.qytechs.cn/zh-CN/users/193133-pana
  6. // @homepage https://gf.qytechs.cn/zh-CN/users/193133-pana
  7. // @icon data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+
  8. // @version 6.1.15
  9. // @description Add notes (aliases/tags) for users to help identify and search, optimized for large datasets
  10. // @description:zh-CN 为用户添加备注(别名/标签)功能,针对大数据量优化,帮助识别和搜索
  11. // @description:zh-TW 為使用者新增備註(別名/標籤)功能,針對大數據量最佳化,幫助識別和搜尋
  12. // @author pana
  13. // @license GNU General Public License v3.0
  14. // @compatible chrome
  15. // @compatible firefox
  16. // @match *://x.com/*
  17. // @match *://*twitter.com/*
  18. // @require https://gcore.jsdelivr.net/gh/LightAPIs/greasy-fork-library@47d998f5f1e438fe137647b8735b1e17a77e4b69/Note_Obj.js
  19. // @connect *
  20. // @noframes
  21. // @grant GM_info
  22. // @grant GM_getValue
  23. // @grant GM_setValue
  24. // @grant GM_deleteValue
  25. // @grant GM_listValues
  26. // @grant GM_openInTab
  27. // @grant GM_addStyle
  28. // @grant GM_xmlhttpRequest
  29. // @grant GM_registerMenuCommand
  30. // @grant GM_unregisterMenuCommand
  31. // @grant GM_addValueChangeListener
  32. // @grant GM_removeValueChangeListener
  33. // ==/UserScript==
  34.  
  35. (function () {
  36. "use strict";
  37. const UPDATED = "2024-05-15";
  38. const TWITTER_ICON = {
  39. NOTE_GRAY:
  40. "url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2IoMTAxLCAxMTksIDEzNCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYigxMDEsIDExOSwgMTM0KSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)",
  41. NOTE_BLUE:
  42. "url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)",
  43. };
  44. const selector = {
  45. root: "#react-root",
  46. homepage: {
  47. id: 'div[data-testid="User-Name"] a[role="link"] > div[dir] > span',
  48. article: "article",
  49. toolBar: '[tabindex="0"]:scope [role="group"][id]',
  50. showName:
  51. 'div[data-testid="User-Name"] a[role="link"] > div > div[dir] > span',
  52. reprintA: "a[role][dir][id]",
  53. reprintName: '[data-testid="socialContext"] [dir]',
  54. at: '[data-testid="tweetText"] a[dir][role="link"]',
  55. blockquote: 'div[aria-labelledby][id] div[id] div[role="link"]',
  56. blockquoteId: 'div[data-testid="User-Name"] div[tabindex] div[dir]',
  57. blockquoteShowName: 'div[data-testid="User-Name"] div[dir]',
  58. },
  59. userpage: {
  60. main: ".css-175oi2r.r-ttdzmv.r-1ifxtd0",
  61. id: '[data-testid="UserName"] div[tabindex] div[dir] > span',
  62. showName: '[data-testid="UserName"] div[dir] > span',
  63. follow: ".css-175oi2r.r-obd0qt.r-18u37iz.r-1w6e6rj.r-1h0z5md.r-dnmrzs",
  64. },
  65. comment: {
  66. toolBar: '[tabindex="-1"]:scope [role="group"][id]',
  67. },
  68. hover: {
  69. panel: 'div[data-testid="HoverCard"] > div > div',
  70. userAvatar: '[data-testid^="UserAvatar-Container-"]',
  71. id: 'a[role="link"]',
  72. showName: 'a[role="link"] > div > [dir] > span',
  73. },
  74. modal: {
  75. cell: '[aria-labelledby="modal-header"] [data-testid="UserCell"]',
  76. id: 'a[role="link"]',
  77. showName: 'a[role="link"] > div > [dir] > span',
  78. },
  79. follow: {
  80. cell: '[data-testid="cellInnerDiv"] [data-testid="UserCell"]',
  81. id: 'a[role="link"]',
  82. showName: 'a[role="link"] > div > [dir] > span',
  83. },
  84. rightRecommended: {
  85. cell: '[role="complementary"] [data-testid="UserCell"]',
  86. id: 'a[role="link"]',
  87. showName: 'a[role="link"] > div > [dir]',
  88. },
  89. };
  90. const nameSet = {
  91. blueTag: "note-obj-twitter-blue-tag",
  92. noteBtn: "note-obj-twitter-note-btn",
  93. panelBtn: "note-obj-twitter-panel-btn",
  94. beforeFollowNoteBtn: "note-obj-twitter-before-follow-note-btn",
  95. baseToolBarBtn: "note-obj-twitter-base-tool-bar-btn",
  96. commentToolBarBtn: "note-obj-twitter-comment-tool-bar-btn",
  97. };
  98. const style = `
  99. .${nameSet.blueTag} {
  100. background-color: #3c81df;
  101. color: #fff;
  102. display: inline-flex;
  103. align-items: center;
  104. padding: 2px 10px;
  105. line-height: 100%;
  106. border-radius: 50px;
  107. }
  108. .${nameSet.noteBtn} {
  109. background-image: ${TWITTER_ICON.NOTE_GRAY};
  110. background-repeat: no-repeat;
  111. background-position: center;
  112. background-color: rgba(0, 0, 0, 0);
  113. border-bottom-left-radius: 9999px;
  114. border-bottom-right-radius: 9999px;
  115. border-top-left-radius: 9999px;
  116. border-top-right-radius: 9999px;
  117. transition-property: background-color, box-shadow;
  118. transition-duration: 0.2s;
  119. }
  120. .${nameSet.noteBtn}:hover {
  121. background-image: ${TWITTER_ICON.NOTE_BLUE};
  122. background-color: rgba(29, 161, 242, .1);
  123. }
  124. .${nameSet.panelBtn} {
  125. height: 32px;
  126. width: 32px;
  127. margin: 5px 0px 0px 0px;
  128. background-size: 28px auto;
  129. cursor: pointer !important;
  130. border-radius: 0px;
  131. }
  132. .${nameSet.panelBtn}:hover::after {
  133. content: "";
  134. display: flex;
  135. position: relative;
  136. background-color: rgba(29, 161, 242, .1);
  137. width: 48px;
  138. height: 48px;
  139. top: -8px;
  140. left: -8px;
  141. border-radius: 99px;
  142. }
  143. .${nameSet.beforeFollowNoteBtn} {
  144. height: 36px;
  145. width: 36px;
  146. background-image: ${TWITTER_ICON.NOTE_BLUE};
  147. background-repeat: no-repeat;
  148. background-size: 19px auto;
  149. background-position: center;
  150. margin-bottom: 12px;
  151. margin-right: 12px;
  152. cursor: pointer;
  153. border: 1px solid rgba(29, 161, 242, 1);
  154. border-bottom-left-radius: 9999px;
  155. border-bottom-right-radius: 9999px;
  156. border-top-left-radius: 9999px;
  157. border-top-right-radius: 9999px;
  158. background-color: rgba(0, 0, 0, 0);
  159. transition-property: background-color, box-shadow;
  160. transition-duration: 0.2s;
  161. }
  162. .${nameSet.beforeFollowNoteBtn}:hover {
  163. background-color: rgba(29, 161, 242, .1);
  164. }
  165. .${nameSet.baseToolBarBtn} {
  166. height: 18px;
  167. width: 18px;
  168. margin: 0px -40px 0px 0px;
  169. background-size: 20px auto;
  170. border-radius: 0px;
  171. margin: 0 12px;
  172. }
  173. .${nameSet.baseToolBarBtn}:hover::after {
  174. content: "";
  175. position: absolute;
  176. background-color: rgba(29, 161, 242, .1);
  177. width: 34px;
  178. height: 34px;
  179. top: -8px;
  180. right: 5px;
  181. border-radius: 99px;
  182. }
  183. .${nameSet.commentToolBarBtn} {
  184. height: 24px;
  185. width: 24px;
  186. margin: 10px 0px 0px 0px;
  187. background-size: 24px auto;
  188. border-radius: 0px;
  189. cursor: pointer;
  190. margin-left: 12px;
  191. }
  192. .${nameSet.commentToolBarBtn}:hover::after {
  193. content: "";
  194. position: absolute;
  195. background-color: rgba(29, 161, 242, .1);
  196. width: 38px;
  197. height: 38px;
  198. top: 3px;
  199. right: -2px;
  200. border-radius: 99px;
  201. }
  202. ${selector.homepage.showName}, ${selector.modal.showName} {
  203. white-space: normal;
  204. }
  205. .note-obj-add-frame-dialog button {
  206. text-align: center;
  207. }
  208. .note-obj-management-frame-save-content,
  209. .note-obj-management-frame-cancel-content,
  210. .note-obj-group-frame-save-content,
  211. .note-obj-group-frame-cancel-content {
  212. font-size: 12px;
  213. }`;
  214. const noteObj = new Note_Obj({
  215. id: "myTwitterNote",
  216. script: {
  217. author: {
  218. name: "pana",
  219. homepage: "https://gf.qytechs.cn/zh-CN/users/193133-pana",
  220. },
  221. url: "https://gf.qytechs.cn/scripts/404587",
  222. updated: UPDATED,
  223. },
  224. style,
  225. changeEvent: changeEvent,
  226. settings: {
  227. showToolbarButton: {
  228. type: "checkbox",
  229. lang: {
  230. en: 'Display the "Note" button in the toolbar below each tweet (if there is no such button in the user\'s hover information panel, this option can be turned on)',
  231. zhHans:
  232. '在每条推特下方的工具栏里显示"备注"按钮 (如果在用户的悬停信息面板里没有此按钮时,可以打开此选项)',
  233. zhHant:
  234. '在每條推特下方的工具欄裡顯示"備註"按鈕 (如果在使用者的懸停資訊面板裡沒有此按鈕時,可以開啟此選項)',
  235. },
  236. default: false,
  237. event: insertToolbarButtonEvent,
  238. },
  239. disableInTweets: {
  240. type: "checkbox",
  241. lang: {
  242. en: "Disable replacing @user with @note in tweets",
  243. zhHans: "禁用将推文中的 @user 替换为 @note",
  244. zhHant: "禁用將推文中的 @user 替換為 @note",
  245. },
  246. default: false,
  247. event: disableInTweetsEvent,
  248. },
  249. },
  250. });
  251. function atFilter(text) {
  252. return text.replace(/^@/, "");
  253. }
  254. function hrefComparator(href) {
  255. return /^\/[^/]+$/i.test(href);
  256. }
  257. function toolBarNoteButton(ele, state) {
  258. const eleId = noteObj.fn.getText(
  259. ele,
  260. selector.homepage.id,
  261. "error",
  262. atFilter
  263. );
  264. if (eleId) {
  265. const eleName = noteObj.fn.getText(
  266. ele,
  267. selector.homepage.showName,
  268. "info"
  269. );
  270. const homepageToolBar = noteObj.fn.query(
  271. ele,
  272. selector.homepage.toolBar,
  273. "info"
  274. );
  275. const commentToolBar = noteObj.fn.query(
  276. ele,
  277. selector.comment.toolBar,
  278. "info"
  279. );
  280. if (homepageToolBar) {
  281. const homepageToolBarBtn = noteObj.fn.query(
  282. homepageToolBar,
  283. "." + Note_Obj.btnClassName,
  284. "none"
  285. );
  286. if (state) {
  287. !homepageToolBarBtn &&
  288. homepageToolBar.appendChild(
  289. noteObj.createNoteBtn(eleId, eleName, [
  290. nameSet.noteBtn,
  291. nameSet.baseToolBarBtn,
  292. ])
  293. );
  294. } else {
  295. homepageToolBarBtn && homepageToolBarBtn.remove();
  296. }
  297. }
  298. if (commentToolBar) {
  299. const commentToolBarBtn = noteObj.fn.query(
  300. commentToolBar,
  301. "." + Note_Obj.btnClassName,
  302. "none"
  303. );
  304. if (state) {
  305. !commentToolBarBtn &&
  306. commentToolBar.appendChild(
  307. noteObj.createNoteBtn(eleId, eleName, [
  308. nameSet.noteBtn,
  309. nameSet.commentToolBarBtn,
  310. ])
  311. );
  312. } else {
  313. commentToolBarBtn && commentToolBarBtn.remove();
  314. }
  315. }
  316. }
  317. }
  318. function homepageNote(ele, changeId) {
  319. const eleId = noteObj.fn.getText(
  320. ele,
  321. selector.homepage.id,
  322. "error",
  323. atFilter
  324. );
  325. if (eleId) {
  326. if (changeId) {
  327. changeId === eleId &&
  328. noteObj.handler(eleId, ele, selector.homepage.showName, {
  329. add: "span",
  330. className: [nameSet.blueTag],
  331. });
  332. } else {
  333. const eleName = noteObj.fn.getText(
  334. ele,
  335. selector.homepage.showName,
  336. "info"
  337. );
  338. noteObj.handler(
  339. eleId,
  340. ele,
  341. selector.homepage.showName,
  342. {
  343. add: "span",
  344. className: [nameSet.blueTag],
  345. },
  346. eleName
  347. );
  348. }
  349. }
  350. }
  351. function reprintANote(ele, changeId) {
  352. const reprintA = noteObj.fn.queryAnchor(
  353. ele,
  354. selector.homepage.reprintA,
  355. "info"
  356. );
  357. if (reprintA) {
  358. const eleId = noteObj.fn.getIdFromUrl(reprintA.href);
  359. if (!changeId || changeId === eleId) {
  360. noteObj.handler(eleId, reprintA, selector.homepage.reprintName, {
  361. add: "span",
  362. className: [nameSet.blueTag],
  363. offsetWidth: 30,
  364. });
  365. }
  366. }
  367. }
  368. function blockquoteNote(ele, changeId) {
  369. const blockquote = noteObj.fn.query(
  370. ele,
  371. selector.homepage.blockquote,
  372. "info"
  373. );
  374. if (blockquote) {
  375. const blockquoteUser = noteObj.fn.query(
  376. blockquote,
  377. selector.homepage.blockquoteShowName
  378. );
  379. if (blockquoteUser) {
  380. const eleId = noteObj.fn.getText(
  381. blockquote,
  382. selector.homepage.blockquoteId,
  383. "error",
  384. atFilter
  385. );
  386. if (!changeId || changeId === eleId) {
  387. noteObj.handler(eleId, blockquoteUser, undefined, {
  388. add: "span",
  389. className: [nameSet.blueTag],
  390. });
  391. }
  392. }
  393. }
  394. }
  395. function homepageAtNote(ele, state, changeId) {
  396. for (const atUser of noteObj.fn.queryAllAnchor(
  397. ele,
  398. selector.homepage.at,
  399. "info"
  400. )) {
  401. if (hrefComparator(atUser.getAttribute("href") || "")) {
  402. const atUserId = noteObj.fn.getIdFromUrl(atUser.href);
  403. if (!changeId || changeId === atUserId) {
  404. noteObj.handler(atUserId, atUser, undefined, {
  405. prefix: "@",
  406. restore: state,
  407. });
  408. }
  409. }
  410. }
  411. }
  412. function userpageNote(ele, changeId) {
  413. const eleId = noteObj.fn.getText(
  414. ele,
  415. selector.userpage.id,
  416. "error",
  417. atFilter
  418. );
  419. if (changeId) {
  420. changeId === eleId &&
  421. noteObj.handler(eleId, ele, selector.userpage.showName, {
  422. add: "span",
  423. className: [nameSet.blueTag],
  424. });
  425. } else {
  426. const eleName = noteObj.fn.getText(
  427. ele,
  428. selector.userpage.showName,
  429. "info"
  430. );
  431. noteObj.handler(
  432. eleId,
  433. ele,
  434. selector.userpage.showName,
  435. {
  436. add: "span",
  437. className: [nameSet.blueTag],
  438. },
  439. eleName
  440. );
  441. }
  442. }
  443. function followNote(ele, changeId) {
  444. spanItemNote(ele, selector.follow.id, selector.follow.showName, changeId);
  445. }
  446. function rightRecommendedNote(ele, changeId) {
  447. spanItemNote(
  448. ele,
  449. selector.rightRecommended.id,
  450. selector.rightRecommended.showName,
  451. changeId
  452. );
  453. }
  454. function modalNote(ele, changeId) {
  455. spanItemNote(ele, selector.modal.id, selector.modal.showName, changeId);
  456. }
  457. function spanItemNote(ele, idSelector, nameSelector, changeId) {
  458. const eleId = noteObj.fn.getUrlId(ele, idSelector);
  459. if (!changeId || changeId === eleId) {
  460. noteObj.handler(eleId, ele, nameSelector, {
  461. add: "span",
  462. className: [nameSet.blueTag],
  463. });
  464. }
  465. }
  466. function disableInTweetsEvent(status) {
  467. noteObj.fn.queryAll(selector.homepage.article, "none").forEach((ele) => {
  468. homepageAtNote(ele, status);
  469. });
  470. }
  471. function insertToolbarButtonEvent(status) {
  472. noteObj.fn.queryAll(selector.homepage.article, "none").forEach((ele) => {
  473. toolBarNoteButton(ele, status);
  474. });
  475. }
  476. function changeEvent(changeId) {
  477. const articles = noteObj.fn.queryAll(selector.homepage.article, "none");
  478.  
  479. batchProcess(articles, (ele) => {
  480. try {
  481. homepageNote(ele, changeId);
  482. reprintANote(ele, changeId);
  483. blockquoteNote(ele, changeId);
  484. homepageAtNote(
  485. ele,
  486. noteObj.getOtherConfig().disableInTweets === true,
  487. changeId
  488. );
  489. } catch (e) {
  490. console.error("Process element error:", e);
  491. }
  492. });
  493.  
  494. noteObj.fn.queryAll(selector.userpage.main).forEach((ele) => {
  495. userpageNote(ele, changeId);
  496. });
  497. noteObj.fn.queryAll(selector.follow.cell, "info").forEach((ele) => {
  498. followNote(ele, changeId);
  499. });
  500. noteObj.fn.queryAll(selector.rightRecommended.cell).forEach((ele) => {
  501. rightRecommendedNote(ele, changeId);
  502. });
  503. noteObj.fn.queryAll(selector.modal.cell, "info").forEach((ele) => {
  504. modalNote(ele, changeId);
  505. });
  506. }
  507. function init() {
  508. try {
  509. const arriveOption = {
  510. fireOnAttributesModification: true,
  511. existing: true,
  512. };
  513.  
  514. const rootDom = noteObj.fn.query(selector.root);
  515. if (!rootDom) {
  516. console.warn("Root element not found");
  517. return;
  518. }
  519.  
  520. const throttledCallback = throttle((ele) => {
  521. try {
  522. toolBarNoteButton(
  523. ele,
  524. noteObj.getOtherConfig().showToolbarButton === true
  525. );
  526. homepageNote(ele);
  527. reprintANote(ele);
  528. blockquoteNote(ele);
  529.  
  530. const disableInTweets =
  531. noteObj.getOtherConfig().disableInTweets === true;
  532. if (!disableInTweets) {
  533. homepageAtNote(ele, disableInTweets);
  534. }
  535. } catch (e) {
  536. console.error("Article processing error:", e);
  537. }
  538. }, 100);
  539.  
  540. noteObj.arrive(
  541. rootDom,
  542. selector.homepage.article,
  543. arriveOption,
  544. throttledCallback
  545. );
  546.  
  547. noteObj.arrive(rootDom, selector.userpage.main, arriveOption, (ele) => {
  548. const eleId = noteObj.fn.getText(
  549. ele,
  550. selector.userpage.id,
  551. "error",
  552. atFilter
  553. );
  554. if (eleId) {
  555. const eleName = noteObj.fn.getText(
  556. ele,
  557. selector.userpage.showName,
  558. "info"
  559. );
  560. let followNoteBtn;
  561. const userpageFollow = noteObj.fn.query(
  562. ele,
  563. selector.userpage.follow
  564. );
  565. if (userpageFollow) {
  566. followNoteBtn = noteObj.createNoteBtn(eleId, eleName, [
  567. nameSet.beforeFollowNoteBtn,
  568. "css-901oao",
  569. ]);
  570. userpageFollow.insertAdjacentElement("afterbegin", followNoteBtn);
  571. }
  572. const userIdChange = new MutationObserver(() => {
  573. const newUserId = noteObj.fn.getText(
  574. ele,
  575. selector.userpage.id,
  576. "error",
  577. atFilter
  578. );
  579. if (newUserId) {
  580. noteObj.handler("", ele, selector.userpage.showName, {
  581. add: "span",
  582. className: [nameSet.blueTag],
  583. });
  584. const newUserName = noteObj.fn.getText(
  585. ele,
  586. selector.userpage.showName,
  587. "info"
  588. );
  589. if (followNoteBtn) {
  590. followNoteBtn.remove();
  591. followNoteBtn = noteObj.createNoteBtn(newUserId, newUserName, [
  592. nameSet.beforeFollowNoteBtn,
  593. "css-901oao",
  594. ]);
  595. userpageFollow &&
  596. userpageFollow.insertAdjacentElement(
  597. "afterbegin",
  598. followNoteBtn
  599. );
  600. }
  601. noteObj.handler(
  602. newUserId,
  603. ele,
  604. selector.userpage.showName,
  605. {
  606. add: "span",
  607. className: [nameSet.blueTag],
  608. },
  609. newUserName
  610. );
  611. }
  612. });
  613. const obId = noteObj.fn.query(ele, selector.userpage.id);
  614. obId &&
  615. userIdChange.observe(obId, {
  616. subtree: true,
  617. characterData: true,
  618. });
  619. }
  620. userpageNote(ele);
  621. });
  622. noteObj.arrive(rootDom, selector.follow.cell, arriveOption, (ele) => {
  623. followNote(ele);
  624. });
  625. noteObj.arrive(
  626. rootDom,
  627. selector.rightRecommended.cell,
  628. arriveOption,
  629. (ele) => {
  630. rightRecommendedNote(ele);
  631. }
  632. );
  633. noteObj.arrive(rootDom, selector.modal.cell, arriveOption, (ele) => {
  634. modalNote(ele);
  635. });
  636. noteObj.arrive(rootDom, selector.hover.panel, arriveOption, (ele) => {
  637. const eleId = noteObj.fn.getUrlId(ele, selector.hover.id);
  638. if (eleId) {
  639. const userShowNameText = noteObj.fn.getText(
  640. ele,
  641. selector.hover.showName,
  642. "info"
  643. );
  644. const userAvatar = noteObj.fn.query(ele, selector.hover.userAvatar);
  645. userAvatar &&
  646. userAvatar.after(
  647. noteObj.createNoteBtn(eleId, userShowNameText, [
  648. nameSet.noteBtn,
  649. nameSet.panelBtn,
  650. ])
  651. );
  652. noteObj.handler(
  653. eleId,
  654. ele,
  655. selector.hover.showName,
  656. {
  657. add: "span",
  658. className: [nameSet.blueTag],
  659. },
  660. userShowNameText
  661. );
  662. }
  663. });
  664. } catch (error) {
  665. console.error("Initialization failed:", error);
  666. }
  667. }
  668. init();
  669. })();

QingJ © 2025

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