// ==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 http://greasyfork.icu/zh-CN/users/193133-pana
// @homepage http://greasyfork.icu/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/[email protected]/minified/arrive.min.js
// @require https://gcore.jsdelivr.net/npm/[email protected]/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
// ==/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: 'http://greasyfork.icu/zh-CN/users/193133-pana',
},
address: 'http://greasyfork.icu/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);
})();