X(Twitter) - 为用户添加备注(别名/标签)

为用户添加备注(别名/标签)功能,以帮助识别和搜索,并支持 WebDAV 同步功能

  1. // ==UserScript==
  2. // @name X(Twitter) - Add notes to the user
  3. // @name:zh-CN X(Twitter) - 为用户添加备注(别名/标签)
  4. // @name:zh-TW X(Twitter) - 為使用者新增備註(別名/標籤)
  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.14
  9. // @description Add notes (aliases/tags) for users to help identify and search, and support WebDAV sync
  10. // @description:zh-CN 为用户添加备注(别名/标签)功能,以帮助识别和搜索,并支持 WebDAV 同步功能
  11. // @description:zh-TW 為使用者新增備註(別名/標籤)功能,以幫助識別和搜尋,並支援 WebDAV 同步功能
  12. // @author pana
  13. // @license GNU General Public License v3.0 or later
  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: 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2IoMTAxLCAxMTksIDEzNCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYigxMDEsIDExOSwgMTM0KSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)',
  40. NOTE_BLUE: 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)'
  41. };
  42. const selector = {
  43. root: '#react-root',
  44. homepage: {
  45. id: 'div[data-testid="User-Name"] a[role="link"] > div[dir] > span',
  46. article: 'article',
  47. toolBar: '[tabindex="0"]:scope [role="group"][id]',
  48. showName: 'div[data-testid="User-Name"] a[role="link"] > div > div[dir] > span',
  49. reprintA: 'a[role][dir][id]',
  50. reprintName: '[data-testid="socialContext"] [dir]',
  51. at: '[data-testid="tweetText"] a[dir][role="link"]',
  52. blockquote: 'div[aria-labelledby][id] div[id] div[role="link"]',
  53. blockquoteId: 'div[data-testid="User-Name"] div[tabindex] div[dir]',
  54. blockquoteShowName: 'div[data-testid="User-Name"] div[dir]'
  55. },
  56. userpage: {
  57. main: '.css-175oi2r.r-ttdzmv.r-1ifxtd0',
  58. id: '[data-testid="UserName"] div[tabindex] div[dir] > span',
  59. showName: '[data-testid="UserName"] div[dir] > span',
  60. follow: '.css-175oi2r.r-obd0qt.r-18u37iz.r-1w6e6rj.r-1h0z5md.r-dnmrzs'
  61. },
  62. comment: {
  63. toolBar: '[tabindex="-1"]:scope [role="group"][id]'
  64. },
  65. hover: {
  66. panel: 'div[data-testid="HoverCard"] > div > div',
  67. userAvatar: '[data-testid^="UserAvatar-Container-"]',
  68. id: 'a[role="link"]',
  69. showName: 'a[role="link"] > div > [dir] > span'
  70. },
  71. modal: {
  72. cell: '[aria-labelledby="modal-header"] [data-testid="UserCell"]',
  73. id: 'a[role="link"]',
  74. showName: 'a[role="link"] > div > [dir] > span'
  75. },
  76. follow: {
  77. cell: '[data-testid="cellInnerDiv"] [data-testid="UserCell"]',
  78. id: 'a[role="link"]',
  79. showName: 'a[role="link"] > div > [dir] > span'
  80. },
  81. rightRecommended: {
  82. cell: '[role="complementary"] [data-testid="UserCell"]',
  83. id: 'a[role="link"]',
  84. showName: 'a[role="link"] > div > [dir]'
  85. }
  86. };
  87. const nameSet = {
  88. blueTag: 'note-obj-twitter-blue-tag',
  89. noteBtn: 'note-obj-twitter-note-btn',
  90. panelBtn: 'note-obj-twitter-panel-btn',
  91. beforeFollowNoteBtn: 'note-obj-twitter-before-follow-note-btn',
  92. baseToolBarBtn: 'note-obj-twitter-base-tool-bar-btn',
  93. commentToolBarBtn: 'note-obj-twitter-comment-tool-bar-btn'
  94. };
  95. const style = `
  96. .${nameSet.blueTag} {
  97. background-color: #3c81df;
  98. color: #fff;
  99. display: inline-flex;
  100. align-items: center;
  101. padding: 2px 10px;
  102. line-height: 100%;
  103. border-radius: 50px;
  104. }
  105. .${nameSet.noteBtn} {
  106. background-image: ${TWITTER_ICON.NOTE_GRAY};
  107. background-repeat: no-repeat;
  108. background-position: center;
  109. background-color: rgba(0, 0, 0, 0);
  110. border-bottom-left-radius: 9999px;
  111. border-bottom-right-radius: 9999px;
  112. border-top-left-radius: 9999px;
  113. border-top-right-radius: 9999px;
  114. transition-property: background-color, box-shadow;
  115. transition-duration: 0.2s;
  116. }
  117. .${nameSet.noteBtn}:hover {
  118. background-image: ${TWITTER_ICON.NOTE_BLUE};
  119. background-color: rgba(29, 161, 242, .1);
  120. }
  121. .${nameSet.panelBtn} {
  122. height: 32px;
  123. width: 32px;
  124. margin: 5px 0px 0px 0px;
  125. background-size: 28px auto;
  126. cursor: pointer !important;
  127. border-radius: 0px;
  128. }
  129. .${nameSet.panelBtn}:hover::after {
  130. content: "";
  131. display: flex;
  132. position: relative;
  133. background-color: rgba(29, 161, 242, .1);
  134. width: 48px;
  135. height: 48px;
  136. top: -8px;
  137. left: -8px;
  138. border-radius: 99px;
  139. }
  140. .${nameSet.beforeFollowNoteBtn} {
  141. height: 36px;
  142. width: 36px;
  143. background-image: ${TWITTER_ICON.NOTE_BLUE};
  144. background-repeat: no-repeat;
  145. background-size: 19px auto;
  146. background-position: center;
  147. margin-bottom: 12px;
  148. margin-right: 12px;
  149. cursor: pointer;
  150. border: 1px solid rgba(29, 161, 242, 1);
  151. border-bottom-left-radius: 9999px;
  152. border-bottom-right-radius: 9999px;
  153. border-top-left-radius: 9999px;
  154. border-top-right-radius: 9999px;
  155. background-color: rgba(0, 0, 0, 0);
  156. transition-property: background-color, box-shadow;
  157. transition-duration: 0.2s;
  158. }
  159. .${nameSet.beforeFollowNoteBtn}:hover {
  160. background-color: rgba(29, 161, 242, .1);
  161. }
  162. .${nameSet.baseToolBarBtn} {
  163. height: 18px;
  164. width: 18px;
  165. margin: 0px -40px 0px 0px;
  166. background-size: 20px auto;
  167. border-radius: 0px;
  168. margin: 0 12px;
  169. }
  170. .${nameSet.baseToolBarBtn}:hover::after {
  171. content: "";
  172. position: absolute;
  173. background-color: rgba(29, 161, 242, .1);
  174. width: 34px;
  175. height: 34px;
  176. top: -8px;
  177. right: 5px;
  178. border-radius: 99px;
  179. }
  180. .${nameSet.commentToolBarBtn} {
  181. height: 24px;
  182. width: 24px;
  183. margin: 10px 0px 0px 0px;
  184. background-size: 24px auto;
  185. border-radius: 0px;
  186. cursor: pointer;
  187. margin-left: 12px;
  188. }
  189. .${nameSet.commentToolBarBtn}:hover::after {
  190. content: "";
  191. position: absolute;
  192. background-color: rgba(29, 161, 242, .1);
  193. width: 38px;
  194. height: 38px;
  195. top: 3px;
  196. right: -2px;
  197. border-radius: 99px;
  198. }
  199. ${selector.homepage.showName}, ${selector.modal.showName} {
  200. white-space: normal;
  201. }
  202. .note-obj-add-frame-dialog button {
  203. text-align: center;
  204. }
  205. .note-obj-management-frame-save-content,
  206. .note-obj-management-frame-cancel-content,
  207. .note-obj-group-frame-save-content,
  208. .note-obj-group-frame-cancel-content {
  209. font-size: 12px;
  210. }`;
  211. const noteObj = new Note_Obj({
  212. id: 'myTwitterNote',
  213. script: {
  214. author: {
  215. name: 'pana',
  216. homepage: 'https://gf.qytechs.cn/zh-CN/users/193133-pana'
  217. },
  218. url: 'https://gf.qytechs.cn/scripts/404587',
  219. updated: UPDATED
  220. },
  221. style,
  222. changeEvent: changeEvent,
  223. settings: {
  224. showToolbarButton: {
  225. type: 'checkbox',
  226. lang: {
  227. 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)',
  228. zhHans: '在每条推特下方的工具栏里显示"备注"按钮 (如果在用户的悬停信息面板里没有此按钮时,可以打开此选项)',
  229. zhHant: '在每條推特下方的工具欄裡顯示"備註"按鈕 (如果在使用者的懸停資訊面板裡沒有此按鈕時,可以開啟此選項)'
  230. },
  231. default: false,
  232. event: insertToolbarButtonEvent
  233. },
  234. disableInTweets: {
  235. type: 'checkbox',
  236. lang: {
  237. en: 'Disable replacing @user with @note in tweets',
  238. zhHans: '禁用将推文中的 @user 替换为 @note',
  239. zhHant: '禁用將推文中的 @user 替換為 @note'
  240. },
  241. default: false,
  242. event: disableInTweetsEvent
  243. }
  244. }
  245. });
  246. function atFilter(text) {
  247. return text.replace(/^@/, '');
  248. }
  249. function hrefComparator(href) {
  250. return /^\/[^/]+$/i.test(href);
  251. }
  252. function toolBarNoteButton(ele, state) {
  253. const eleId = noteObj.fn.getText(ele, selector.homepage.id, 'error', atFilter);
  254. if (eleId) {
  255. const eleName = noteObj.fn.getText(ele, selector.homepage.showName, 'info');
  256. const homepageToolBar = noteObj.fn.query(ele, selector.homepage.toolBar, 'info');
  257. const commentToolBar = noteObj.fn.query(ele, selector.comment.toolBar, 'info');
  258. if (homepageToolBar) {
  259. const homepageToolBarBtn = noteObj.fn.query(homepageToolBar, '.' + Note_Obj.btnClassName, 'none');
  260. if (state) {
  261. !homepageToolBarBtn && homepageToolBar.appendChild(noteObj.createNoteBtn(eleId, eleName, [nameSet.noteBtn, nameSet.baseToolBarBtn]));
  262. } else {
  263. homepageToolBarBtn && homepageToolBarBtn.remove();
  264. }
  265. }
  266. if (commentToolBar) {
  267. const commentToolBarBtn = noteObj.fn.query(commentToolBar, '.' + Note_Obj.btnClassName, 'none');
  268. if (state) {
  269. !commentToolBarBtn && commentToolBar.appendChild(noteObj.createNoteBtn(eleId, eleName, [nameSet.noteBtn, nameSet.commentToolBarBtn]));
  270. } else {
  271. commentToolBarBtn && commentToolBarBtn.remove();
  272. }
  273. }
  274. }
  275. }
  276. function homepageNote(ele, changeId) {
  277. const eleId = noteObj.fn.getText(ele, selector.homepage.id, 'error', atFilter);
  278. if (eleId) {
  279. if (changeId) {
  280. changeId === eleId && noteObj.handler(eleId, ele, selector.homepage.showName, {
  281. add: 'span',
  282. className: [nameSet.blueTag]
  283. });
  284. } else {
  285. const eleName = noteObj.fn.getText(ele, selector.homepage.showName, 'info');
  286. noteObj.handler(eleId, ele, selector.homepage.showName, {
  287. add: 'span',
  288. className: [nameSet.blueTag]
  289. }, eleName);
  290. }
  291. }
  292. }
  293. function reprintANote(ele, changeId) {
  294. const reprintA = noteObj.fn.queryAnchor(ele, selector.homepage.reprintA, 'info');
  295. if (reprintA) {
  296. const eleId = noteObj.fn.getIdFromUrl(reprintA.href);
  297. if (!changeId || changeId === eleId) {
  298. noteObj.handler(eleId, reprintA, selector.homepage.reprintName, {
  299. add: 'span',
  300. className: [nameSet.blueTag],
  301. offsetWidth: 30
  302. });
  303. }
  304. }
  305. }
  306. function blockquoteNote(ele, changeId) {
  307. const blockquote = noteObj.fn.query(ele, selector.homepage.blockquote, 'info');
  308. if (blockquote) {
  309. const blockquoteUser = noteObj.fn.query(blockquote, selector.homepage.blockquoteShowName);
  310. if (blockquoteUser) {
  311. const eleId = noteObj.fn.getText(blockquote, selector.homepage.blockquoteId, 'error', atFilter);
  312. if (!changeId || changeId === eleId) {
  313. noteObj.handler(eleId, blockquoteUser, undefined, {
  314. add: 'span',
  315. className: [nameSet.blueTag]
  316. });
  317. }
  318. }
  319. }
  320. }
  321. function homepageAtNote(ele, state, changeId) {
  322. for (const atUser of noteObj.fn.queryAllAnchor(ele, selector.homepage.at, 'info')) {
  323. if (hrefComparator(atUser.getAttribute('href') || '')) {
  324. const atUserId = noteObj.fn.getIdFromUrl(atUser.href);
  325. if (!changeId || changeId === atUserId) {
  326. noteObj.handler(atUserId, atUser, undefined, {
  327. prefix: '@',
  328. restore: state
  329. });
  330. }
  331. }
  332. }
  333. }
  334. function userpageNote(ele, changeId) {
  335. const eleId = noteObj.fn.getText(ele, selector.userpage.id, 'error', atFilter);
  336. if (changeId) {
  337. changeId === eleId && noteObj.handler(eleId, ele, selector.userpage.showName, {
  338. add: 'span',
  339. className: [nameSet.blueTag]
  340. });
  341. } else {
  342. const eleName = noteObj.fn.getText(ele, selector.userpage.showName, 'info');
  343. noteObj.handler(eleId, ele, selector.userpage.showName, {
  344. add: 'span',
  345. className: [nameSet.blueTag]
  346. }, eleName);
  347. }
  348. }
  349. function followNote(ele, changeId) {
  350. spanItemNote(ele, selector.follow.id, selector.follow.showName, changeId);
  351. }
  352. function rightRecommendedNote(ele, changeId) {
  353. spanItemNote(ele, selector.rightRecommended.id, selector.rightRecommended.showName, changeId);
  354. }
  355. function modalNote(ele, changeId) {
  356. spanItemNote(ele, selector.modal.id, selector.modal.showName, changeId);
  357. }
  358. function spanItemNote(ele, idSelector, nameSelector, changeId) {
  359. const eleId = noteObj.fn.getUrlId(ele, idSelector);
  360. if (!changeId || changeId === eleId) {
  361. noteObj.handler(eleId, ele, nameSelector, {
  362. add: 'span',
  363. className: [nameSet.blueTag]
  364. });
  365. }
  366. }
  367. function disableInTweetsEvent(status) {
  368. noteObj.fn.queryAll(selector.homepage.article, 'none').forEach(ele => {
  369. homepageAtNote(ele, status);
  370. });
  371. }
  372. function insertToolbarButtonEvent(status) {
  373. noteObj.fn.queryAll(selector.homepage.article, 'none').forEach(ele => {
  374. toolBarNoteButton(ele, status);
  375. });
  376. }
  377. function changeEvent(changeId) {
  378. noteObj.fn.queryAll(selector.homepage.article, 'none').forEach(ele => {
  379. homepageNote(ele, changeId);
  380. reprintANote(ele, changeId);
  381. blockquoteNote(ele, changeId);
  382. homepageAtNote(ele, noteObj.getOtherConfig().disableInTweets === true, changeId);
  383. });
  384. noteObj.fn.queryAll(selector.userpage.main).forEach(ele => {
  385. userpageNote(ele, changeId);
  386. });
  387. noteObj.fn.queryAll(selector.follow.cell, 'info').forEach(ele => {
  388. followNote(ele, changeId);
  389. });
  390. noteObj.fn.queryAll(selector.rightRecommended.cell).forEach(ele => {
  391. rightRecommendedNote(ele, changeId);
  392. });
  393. noteObj.fn.queryAll(selector.modal.cell, 'info').forEach(ele => {
  394. modalNote(ele, changeId);
  395. });
  396. }
  397. function init() {
  398. const arriveOption = {
  399. fireOnAttributesModification: true,
  400. existing: true
  401. };
  402. const rootDom = noteObj.fn.query(selector.root);
  403. if (rootDom === null) {
  404. return;
  405. }
  406. noteObj.arrive(rootDom, selector.homepage.article, arriveOption, ele => {
  407. toolBarNoteButton(ele, noteObj.getOtherConfig().showToolbarButton === true);
  408. homepageNote(ele);
  409. reprintANote(ele);
  410. blockquoteNote(ele);
  411. const disableInTweets = noteObj.getOtherConfig().disableInTweets === true;
  412. if (!disableInTweets) {
  413. homepageAtNote(ele, disableInTweets);
  414. }
  415. });
  416. noteObj.arrive(rootDom, selector.userpage.main, arriveOption, ele => {
  417. const eleId = noteObj.fn.getText(ele, selector.userpage.id, 'error', atFilter);
  418. if (eleId) {
  419. const eleName = noteObj.fn.getText(ele, selector.userpage.showName, 'info');
  420. let followNoteBtn;
  421. const userpageFollow = noteObj.fn.query(ele, selector.userpage.follow);
  422. if (userpageFollow) {
  423. followNoteBtn = noteObj.createNoteBtn(eleId, eleName, [nameSet.beforeFollowNoteBtn, 'css-901oao']);
  424. userpageFollow.insertAdjacentElement('afterbegin', followNoteBtn);
  425. }
  426. const userIdChange = new MutationObserver(() => {
  427. const newUserId = noteObj.fn.getText(ele, selector.userpage.id, 'error', atFilter);
  428. if (newUserId) {
  429. noteObj.handler('', ele, selector.userpage.showName, {
  430. add: 'span',
  431. className: [nameSet.blueTag]
  432. });
  433. const newUserName = noteObj.fn.getText(ele, selector.userpage.showName, 'info');
  434. if (followNoteBtn) {
  435. followNoteBtn.remove();
  436. followNoteBtn = noteObj.createNoteBtn(newUserId, newUserName, [nameSet.beforeFollowNoteBtn, 'css-901oao']);
  437. userpageFollow && userpageFollow.insertAdjacentElement('afterbegin', followNoteBtn);
  438. }
  439. noteObj.handler(newUserId, ele, selector.userpage.showName, {
  440. add: 'span',
  441. className: [nameSet.blueTag]
  442. }, newUserName);
  443. }
  444. });
  445. const obId = noteObj.fn.query(ele, selector.userpage.id);
  446. obId && userIdChange.observe(obId, {
  447. subtree: true,
  448. characterData: true
  449. });
  450. }
  451. userpageNote(ele);
  452. });
  453. noteObj.arrive(rootDom, selector.follow.cell, arriveOption, ele => {
  454. followNote(ele);
  455. });
  456. noteObj.arrive(rootDom, selector.rightRecommended.cell, arriveOption, ele => {
  457. rightRecommendedNote(ele);
  458. });
  459. noteObj.arrive(rootDom, selector.modal.cell, arriveOption, ele => {
  460. modalNote(ele);
  461. });
  462. noteObj.arrive(rootDom, selector.hover.panel, arriveOption, ele => {
  463. const eleId = noteObj.fn.getUrlId(ele, selector.hover.id);
  464. if (eleId) {
  465. const userShowNameText = noteObj.fn.getText(ele, selector.hover.showName, 'info');
  466. const userAvatar = noteObj.fn.query(ele, selector.hover.userAvatar);
  467. userAvatar && userAvatar.after(noteObj.createNoteBtn(eleId, userShowNameText, [nameSet.noteBtn, nameSet.panelBtn]));
  468. noteObj.handler(eleId, ele, selector.hover.showName, {
  469. add: 'span',
  470. className: [nameSet.blueTag]
  471. }, userShowNameText);
  472. }
  473. });
  474. }
  475. init();
  476. })();

QingJ © 2025

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