// ==UserScript== // @name Instagram为关注用户添加备注 // @name:en Instagram - Add notes(aliases/tags) to the user // @name:zh-CN Instagram - 为用户添加备注(别名/标签) // @name:zh-TW Instagram - 為用戶添加備註(別名/標籤) // @name:ja Instagram - ユーザーへのメモの追加(エイリアス/ラベル) // @name:ko Instagram - 사용자에게 메모 추가 (별칭/라벨) // @name:fr Instagram - ajouter des notes aux utilisateurs (alias/tag) // @namespace https://greasyfork.org/zh-CN/users/193133-pana // @homepage https://greasyfork.org/zh-CN/users/193133-pana // @icon data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2JhKDI5LDE2MSwyNDIsMS4wMCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYmEoMjksMTYxLDI0MiwxLjAwKSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+ // @version 5.4.0 // @description 为用户添加备注(别名/标签)功能,以帮助识别和搜索 // @description:en Add a note(alias/tag) for users to help identify and search // @description:zh-CN 为用户添加备注(别名/标签)功能,以帮助识别和搜索 // @description:zh-TW 為用戶添加備註(別名/標籤)功能,以幫助識別和搜尋 // @description:ja ユーザーが識別と検索に役立つメモ(エイリアス/タグ)機能を追加する // @description:ko 사용자 식별 및 검색에 도움이되는 메모 (별칭/태그) 기능 추가 // @description:fr Ajouter une fonction de notes (alias/tag) pour les utilisateurs pour aider à identifier et rechercher // @license GNU General Public License v3.0 or later // @compatible chrome // @compatible firefox // @author pana // @match *://*.instagram.com/* // @require https://gcore.jsdelivr.net/npm/arrive@2.4.1/minified/arrive.min.js // @require https://gcore.jsdelivr.net/npm/vue@2.7.10/dist/vue.min.js // @require https://gcore.jsdelivr.net/gh/LightAPIs/greasy-fork-library@59abf2b972ae76013a5bb936a11bbf72869785e0/Note_Obj.js // @grant GM_info // @grant GM.info // @grant GM_getValue // @grant GM.getValue // @grant GM_setValue // @grant GM.setValue // @grant GM_deleteValue // @grant GM.deleteValue // @grant GM_listValues // @grant GM.listValues // @grant GM_openInTab // @grant GM.openInTab // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_addValueChangeListener // @grant GM_removeValueChangeListener // @noframes // @downloadURL none // ==/UserScript== (async function () { 'use strict'; if (typeof Note_Obj !== 'function') { alert('Note_Obj.js was not loaded successfully!'); } const updated = '2023-01-12'; const INS_ICON = { NOTE_BLACK: 'url(data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0cHgiIGhlaWdodD0iMjRweCIgdmlld0JveD0iMCAwIDI0IDI0IiBhcmlhLWxhYmVsbGVkYnk9Im5ld0ljb25UaXRsZSIgc3Ryb2tlPSJyZ2IoMzgsIDM4LCAzOCkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InNxdWFyZSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIgZmlsbD0ibm9uZSIgY29sb3I9InJnYigzOCwgMzgsIDM4KSI+IDx0aXRsZSBpZD0ibmV3SWNvblRpdGxlIj5OZXc8L3RpdGxlPiA8cGF0aCBkPSJNMTkgMTRWMjJIMi45OTk5N1Y0SDEzIi8+IDxwYXRoIGQ9Ik0xNy40NjA4IDQuMDM5MjFDMTguMjQxOCAzLjI1ODE3IDE5LjUwODIgMy4yNTgxNiAyMC4yODkyIDQuMDM5MjFMMjAuOTYwOCA0LjcxMDc5QzIxLjc0MTggNS40OTE4NCAyMS43NDE4IDYuNzU4MTcgMjAuOTYwOCA3LjUzOTIxTDExLjU4NTggMTYuOTE0MkMxMS4yMTA3IDE3LjI4OTMgMTAuNzAyIDE3LjUgMTAuMTcxNiAxNy41TDcuNSAxNy41TDcuNSAxNC44Mjg0QzcuNSAxNC4yOTggNy43MTA3MSAxMy43ODkzIDguMDg1NzkgMTMuNDE0MkwxNy40NjA4IDQuMDM5MjFaIi8+IDxwYXRoIGQ9Ik0xNi4yNSA1LjI1TDE5Ljc1IDguNzUiLz4gPC9zdmc+)', }; const INS_STYLE = ` .note-obj-ins-font-blue-color { color: #336699; } .note-obj-ins-background-box { display: inline-block; align-items: center; white-space: nowrap; border-radius: 50px; padding: 0px 10px; background-color: #336699; color: #fff; } .note-obj-ins-add-btn { background-image: ${INS_ICON.NOTE_BLACK}; background-size: 24px; background-repeat: no-repeat; background-position: center; margin-left: 5px; cursor: pointer; width: 24px; height: 24px; } .note-obj-ins-homepage-btn { margin: 6px !important; } .note-obj-ins-homepage-btn:hover { opacity: 0.5; } .note-obj-ins-userpage-btn { margin-top: 2px; } .note-obj-ins-userpage-tag { display: block; font-size: 20px; margin-bottom: 20px; white-space: nowrap; } .note-obj-ins-font-bold { font-weight: bold; } .note-obj-veryins-blue-tag { background-color: #3c81df; color: #fff; display: inline-flex; align-items: center; padding: 0px 10px; white-space: nowrap; line-height: 100%; border-radius: 50px; padding: 2px 10px; } .note-obj-veryins-userpage-btn { display: inline-block; vertical-align: middle; } .note-obj-ins-left-box { height: 25%; } .note-obj-interface-dark .note-obj-settings-frame-card label { color: #fff; }`; const selector = { homepage: { article: '[role="main"] article', id: '._aaqt a', icon: 'span._aamz', commentId: '._aap6._aap7._aap8 a', commentAt: '._aat6 ._aade > .notranslate', }, homepageStories: { id: '._aad6', idShell: 'li [role="menuitem"]', }, homepageRecommend: { id: '._aak3 ._aap6._aap7._aap8 a', }, userPage: { frame: '._aa_y', id: 'h2', bar: '.x8j4wrb', box: 'ul', common: 'span._aaai', suggest: '._acj1 a.notranslate', infoAt: '.notranslate', userName: '._aa_c > span', }, watchList: { initialItem: '[role="dialog"] [aria-labelledby]', laterItem: '._aaei', id: '._aap6._aap7._aap8 a', }, stories: { id: 'a.notranslate', idShell: '._ac0o', }, dialog: { frame: '[role="dialog"] article', commentId: '._a9zm ._aap6._aap7._aap8 a', commentAt: '._a9zs .notranslate', }, request: { follow: '._aajc ._aap6._aap7._aap8 a', }, suggest: { user: '._aa0- ._aap6._aap7._aap8 a', }, }; function homepageNote(ele, userId = undefined) { const user = Note_Obj.fn.queryA(ele, selector.homepage.id); if (user) { const replaceHomepageID = noteObj.getConfig().other.replaceHomepageID == true; const eleId = Note_Obj.fn.getUserIdFromLink(user.href); if ((userId && userId == eleId) || (!userId && noteObj.judgeUsers(eleId))) { noteObj.handler(eleId, user, null, { add: replaceHomepageID ? null : 'sapn', classname: replaceHomepageID ? 'note-obj-ins-font-blue-color' : 'note-obj-ins-background-box', title: replaceHomepageID, }); } } } function homepageCommentNote(ele, userId = undefined) { for (const comment of Note_Obj.fn.qAllA(ele, selector.homepage.commentId, 'info')) { const commentId = Note_Obj.fn.getUserIdFromLink(comment.href); if ((userId && userId == commentId) || (!userId && noteObj.judgeUsers(commentId))) { noteObj.handler(commentId, comment, null, { classname: 'note-obj-ins-font-blue-color', }); } } } function homepageCommentAtNote(ele, userId = undefined) { if (ele instanceof HTMLAnchorElement) { const commentAtId = Note_Obj.fn.getUserIdFromLink(ele.href); if ((userId && userId == commentAtId) || (!userId && noteObj.judgeUsers(commentAtId))) { noteObj.handler(commentAtId, ele, null, { symbol: { prefix: '@', }, title: true, classname: 'note-obj-ins-font-blue-color', }); } } } function dialogCommentNote(ele, userId = undefined) { if (ele instanceof HTMLAnchorElement) { const picCommentId = Note_Obj.fn.getUserIdFromLink(ele.href); if ((userId && userId == picCommentId) || (!userId && noteObj.judgeUsers(picCommentId))) { noteObj.handler(picCommentId, ele, null, { title: true, classname: 'note-obj-ins-font-blue-color', }); } } } function dialogCommentAtNote(ele, userId = undefined) { if (!ele.classList.contains(selector.homepage.commentId.replace(/^\.|\s+.*$/g, ''))) { if (ele instanceof HTMLAnchorElement) { const picCommentAtId = Note_Obj.fn.getUserIdFromLink(ele.href); if ((userId && userId == picCommentAtId) || (!userId && noteObj.judgeUsers(picCommentAtId))) { noteObj.handler(picCommentAtId, ele, null, { symbol: { prefix: '@', }, title: true, classname: 'note-obj-ins-font-blue-color', }); } } } } function homepageStoriesNote(ele, userId = undefined) { if (ele instanceof HTMLElement) { const homepageStoriesId = Note_Obj.fn.getTextContent(ele, selector.homepageStories.id); if ((userId && userId == homepageStoriesId) || (!userId && noteObj.judgeUsers(homepageStoriesId))) { ele.title = noteObj.getUserTag(homepageStoriesId); } } } function anchorElementNote(ele, userId = undefined) { if (ele instanceof HTMLAnchorElement) { const itemId = Note_Obj.fn.getUserIdFromLink(ele.href); if ((userId && userId == itemId) || (!userId && noteObj.judgeUsers(itemId))) { noteObj.handler(itemId, ele, null, { classname: 'note-obj-ins-font-blue-color', }); } } } function userPageNote(ele, userId = undefined) { const userPageId = Note_Obj.fn.getTextContent(ele, selector.userPage.id); const userPageBox = Note_Obj.fn.query(ele, selector.userPage.box); if (userPageBox) { if (userId) { if (userId == userPageId) { const userPageTag = Note_Obj.fn.querySelector(ele, '.note-obj-user-tag'); userPageTag && userPageTag.remove(); noteObj.judgeUsers(userPageId) && userPageBox.after( noteObj.createNoteTag( userPageId, { secondaryColor: false, offsetWidth: -20, }, 'div', ['note-obj-ins-userpage-tag', 'note-obj-ins-font-blue-color', 'note-obj-ins-font-bold'] ) ); } } else { const userNameText = Note_Obj.fn.getTextContent(ele, selector.userPage.userName, undefined, 'info'); noteObj.judgeUsers(userPageId) && userPageBox.after( noteObj.createNoteTag( userPageId, { secondaryColor: false, offsetWidth: -20, }, 'div', ['note-obj-ins-userpage-tag', 'note-obj-ins-font-blue-color', 'note-obj-ins-font-bold'], userNameText ) ); } } } function userPageCommonNote(ele, userId = undefined) { const showNoteColor = noteObj.getShowNoteColorConfig(); for (const commonUser of Note_Obj.fn.qAll(ele, selector.userPage.common, 'info')) { const commonUserId = commonUser.textContent; if (userId) { if (userId == commonUserId) { if (noteObj.judgeUsers(commonUserId)) { commonUser.title = noteObj.getUserTag(commonUserId); if (showNoteColor) { commonUser.style.setProperty('color', noteObj.getPrimaryColor(commonUserId), 'important'); } else { commonUser.style.setProperty('color', ''); } commonUser.classList.add('note-obj-ins-font-blue-color'); } else { commonUser.title = ''; commonUser.style.setProperty('color', ''); commonUser.classList.remove('note-obj-ins-font-blue-color'); } } } else { if (noteObj.judgeUsers(commonUserId)) { commonUser.title = noteObj.getUserTag(commonUserId); showNoteColor && commonUser.style.setProperty('color', noteObj.getPrimaryColor(commonUserId), 'important'); commonUser.classList.add('note-obj-ins-font-blue-color'); } } } } function userPageInfoAtNote(ele, userId = undefined) { for (const infoAtUser of Note_Obj.fn.qAllA(ele, selector.userPage.infoAt, 'info')) { const infoAtUserId = Note_Obj.fn.getUserIdFromLink(infoAtUser.href); if ((userId && userId == infoAtUserId) || (!userId && noteObj.judgeUsers(infoAtUserId))) { noteObj.handler(infoAtUserId, infoAtUser, null, { symbol: { prefix: '@', }, classname: 'note-obj-ins-font-blue-color', title: true, }); } } } function storiesNote(ele, userId = undefined) { itemNote(ele, selector.stories.id, userId); } function watchListItemNote(ele, userId = undefined) { itemNote(ele, selector.watchList.id, userId); } function itemNote(ele, idSelector, userId = undefined) { const item = Note_Obj.fn.queryA(ele, idSelector); if (item) { const itemId = Note_Obj.fn.getUserIdFromLink(item.href); if ((userId && userId == itemId) || (!userId && noteObj.judgeUsers(itemId))) { noteObj.handler(itemId, item, null, { classname: 'note-obj-ins-font-blue-color', }); } } } function instagramChangeEvent(noteObj, userId = undefined) { for (const article of document.querySelectorAll(selector.homepage.article)) { homepageNote(article, userId); homepageCommentNote(article, userId); for (const commentAt of article.querySelectorAll(selector.homepage.commentAt)) { homepageCommentAtNote(commentAt, userId); } for (const picCommentUser of article.querySelectorAll(selector.dialog.commentId)) { dialogCommentNote(picCommentUser, userId); } for (const picCommentAt of article.querySelectorAll(selector.dialog.commentAt)) { dialogCommentAtNote(picCommentAt, userId); } } for (const homepageStories of document.querySelectorAll(selector.homepageStories.idShell)) { homepageStoriesNote(homepageStories, userId); } for (const homepageRecommend of document.querySelectorAll(selector.homepageRecommend.id)) { anchorElementNote(homepageRecommend, userId); } for (const userPage of document.querySelectorAll(selector.userPage.frame)) { userPageNote(userPage, userId); userPageCommonNote(userPage, userId); userPageInfoAtNote(userPage, userId); } for (const storiesShell of document.querySelectorAll(selector.stories.idShell)) { storiesNote(storiesShell, userId); } for (const initial of document.querySelectorAll(selector.watchList.initialItem)) { watchListItemNote(initial, userId); } for (const later of document.querySelectorAll(selector.watchList.laterItem)) { watchListItemNote(later, userId); } for (const dialog of document.querySelectorAll(selector.dialog.frame)) { homepageNote(dialog, userId); homepageCommentNote(dialog, userId); for (const commentUser of dialog.querySelectorAll(selector.dialog.commentId)) { dialogCommentNote(commentUser, userId); } for (const commentAt of dialog.querySelectorAll(selector.dialog.commentAt)) { dialogCommentAtNote(commentAt, userId); } } for (const follow of document.querySelectorAll(selector.request.follow)) { anchorElementNote(follow, userId); } for (const suggestUser of document.querySelectorAll(selector.suggest.user)) { anchorElementNote(suggestUser, userId); } for (const suggest of document.querySelectorAll(selector.userPage.suggest)) { anchorElementNote(suggest, userId); } } function instagramHomepageEvent(newValue, oldValue) { if (newValue != oldValue) { for (const article of document.querySelectorAll(selector.homepage.article)) { const articleUser = Note_Obj.fn.queryA(article, selector.homepage.id); if (articleUser) { const articleUserId = Note_Obj.fn.getUserIdFromLink(articleUser.href); noteObj.handler(articleUserId, articleUser, null, { add: oldValue ? null : 'span', classname: oldValue ? 'note-obj-ins-font-blue-color' : 'note-obj-ins-background-box', title: oldValue, restore: true, }); noteObj.handler(articleUserId, articleUser, null, { add: newValue ? null : 'span', classname: newValue ? 'note-obj-ins-font-blue-color' : 'note-obj-ins-background-box', title: newValue, }); } } } } function initInstagram(noteObj) { const arriveOption = { fireOnAttributesModification: true, existing: true, }; document.body.arrive(selector.homepage.article, arriveOption, article => { const homepageIcon = Note_Obj.fn.query(article, selector.homepage.icon); const articleUserId = Note_Obj.fn.getHrefUserId(article, selector.homepage.id); if (homepageIcon && articleUserId) { homepageIcon.insertAdjacentElement( 'beforebegin', noteObj.createNoteBtn(articleUserId, null, ['note-obj-ins-add-btn', 'note-obj-ins-homepage-btn'], 'span') ); } homepageNote(article); homepageCommentNote(article); article.arrive(selector.homepage.commentAt, arriveOption, commentAt => { homepageCommentAtNote(commentAt); }); article.arrive(selector.dialog.commentId, arriveOption, picCommentUser => { dialogCommentNote(picCommentUser); }); article.arrive(selector.dialog.commentAt, arriveOption, picCommentAt => { dialogCommentAtNote(picCommentAt); }); }); document.body.arrive(selector.homepageStories.idShell, arriveOption, homepageStories => { homepageStoriesNote(homepageStories); }); document.body.arrive(selector.homepageRecommend.id, arriveOption, homepageRecommend => { anchorElementNote(homepageRecommend); }); document.body.arrive(selector.userPage.frame, arriveOption, userPage => { const userPageBar = Note_Obj.fn.query(userPage, selector.userPage.bar); const userPageId = Note_Obj.fn.getTextContent(userPage, selector.userPage.id); if (userPageBar && userPageId) { const userNameText = Note_Obj.fn.getTextContent(userPage, selector.userPage.userName, undefined, 'info'); userPageBar.after(noteObj.createNoteBtn(userPageId, userNameText, ['note-obj-ins-add-btn', 'note-obj-ins-userpage-btn'])); } userPageNote(userPage); userPageCommonNote(userPage); userPageInfoAtNote(userPage); }); document.body.arrive(selector.stories.idShell, arriveOption, storiesShell => { storiesNote(storiesShell); const stories = Note_Obj.fn.queryA(storiesShell, selector.stories.id); if (stories) { const userIdChange = new MutationObserver(() => { const newUserId = Note_Obj.fn.getUserIdFromLink(stories.href); if (noteObj.judgeUsers(newUserId)) { noteObj.handler(newUserId, stories, null, { classname: 'note-obj-ins-font-blue-color', }); } else { noteObj.handler(newUserId, stories, null, { restore: true, }); } }); userIdChange.observe(stories, { attributeFilter: ['href'], }); } }); document.body.arrive(selector.watchList.initialItem, arriveOption, initial => { watchListItemNote(initial); }); document.body.arrive(selector.watchList.laterItem, arriveOption, later => { watchListItemNote(later); }); document.body.arrive(selector.dialog.frame, arriveOption, dialog => { const homepageIcon = Note_Obj.fn.query(dialog, selector.homepage.icon); const dialogUserId = Note_Obj.fn.getHrefUserId(dialog, selector.homepage.id); if (homepageIcon && dialogUserId) { homepageIcon.insertAdjacentElement( 'beforebegin', noteObj.createNoteBtn(dialogUserId, null, ['note-obj-ins-add-btn', 'note-obj-ins-homepage-btn'], 'span') ); } homepageNote(dialog); homepageCommentNote(dialog); dialog.arrive(selector.dialog.commentId, arriveOption, commentUser => { dialogCommentNote(commentUser); }); dialog.arrive(selector.dialog.commentAt, arriveOption, commentAt => { dialogCommentAtNote(commentAt); }); }); document.body.arrive(selector.request.follow, arriveOption, follow => { anchorElementNote(follow); }); document.body.arrive(selector.suggest.user, arriveOption, suggestUser => { anchorElementNote(suggestUser); }); document.body.arrive(selector.userPage.suggest, arriveOption, suggest => { anchorElementNote(suggest); }); } const noteObj = new Note_Obj('myInstagramNote'); await noteObj.init({ style: INS_STYLE, changeEvent: instagramChangeEvent, script: { author: { name: 'pana', homepage: 'https://greasyfork.org/zh-CN/users/193133-pana', }, address: 'https://greasyfork.org/scripts/387871', updated: updated, library: [ { name: 'arrive.js', version: '2.4.1', url: 'https://github.com/uzairfarooq/arrive', }, ], }, primaryColor: '#336699', settings: { replaceHomepageID: { type: 'checkbox', lang: { en: 'Allow to replace the user ID on the instagram homepage', zh_cn: '允许替换 Instagram 首页上的用户 ID', zh_tw: '允許替換 Instagram 首頁上的用戶 ID', ja: 'Instagram ホームページのユーザーIDの置き換えを許可する', ko: 'Instagram 첫 페이지에 있는 사용자 ID 바꾸기 허용', fr: "Permettre de remplacer l'ID utilisateur sur la page d'accueil Instagram", }, default: true, event: instagramHomepageEvent, }, }, leftBtnBoxClassName: 'note-obj-ins-left-box', }); initInstagram(noteObj); })();