diff --git a/src/plugins/implicitRelationships/README.md b/src/plugins/implicitRelationships/README.md index a76e298f..b560bf2c 100644 --- a/src/plugins/implicitRelationships/README.md +++ b/src/plugins/implicitRelationships/README.md @@ -2,6 +2,6 @@ Shows your implicit relationships in the Friends tab. -Implicit relationships on Discord are people with whom you've frecently interacted and share a mutual server; even though Discord thinks you should be friends with them, you haven't added them as friends. +Implicit relationships on Discord are people with whom you've frecently interacted and don't have a relationship with. Even though Discord thinks you should be friends with them, you haven't added them as friends! ![](https://camo.githubusercontent.com/6927161ee0c933f7ef6d61f243cca3e6ea4c8db9d1becd8cbf73c45e1bd0d127/68747470733a2f2f692e646f6c66692e65732f7055447859464662674d2e706e673f6b65793d736e3950343936416c32444c7072) diff --git a/src/plugins/implicitRelationships/index.ts b/src/plugins/implicitRelationships/index.ts index f0be9ee5..13c12ed9 100644 --- a/src/plugins/implicitRelationships/index.ts +++ b/src/plugins/implicitRelationships/index.ts @@ -20,7 +20,7 @@ import { definePluginSettings } from "@api/Settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { findStoreLazy } from "@webpack"; -import { ChannelStore, Constants, FluxDispatcher, GuildStore, RelationshipStore, SnowflakeUtils, UserStore } from "@webpack/common"; +import { Constants, FluxDispatcher, GuildStore, RelationshipStore, RestAPI, SnowflakeUtils, UserStore } from "@webpack/common"; import { Settings } from "Vencord"; const UserAffinitiesStore = findStoreLazy("UserAffinitiesStore"); @@ -121,55 +121,61 @@ export default definePlugin({ : comparator(row); }, + async refreshUserAffinities() { + try { + await RestAPI.get({ url: "/users/@me/affinities/users", retries: 3 }).then(({ body }) => { + FluxDispatcher.dispatch({ + type: "LOAD_USER_AFFINITIES_SUCCESS", + affinities: body, + }); + }); + } catch (e) { + // Not a critical error if this fails for some reason + } + }, + async fetchImplicitRelationships() { // Implicit relationships are defined as users that you: // 1. Have an affinity for - // 2. Do not have a relationship with // TODO: Check how this works with pending/blocked relationships - // 3. Have a mutual guild with + // 2. Do not have a relationship with + await this.refreshUserAffinities(); const userAffinities: Set = UserAffinitiesStore.getUserAffinitiesUserIds(); + const relationships = RelationshipStore.getRelationships(); const nonFriendAffinities = Array.from(userAffinities).filter( id => !RelationshipStore.getRelationshipType(id) ); + nonFriendAffinities.forEach(id => { + relationships[id] = 5; + }); + RelationshipStore.emitChange(); - // I would love to just check user cache here (falling back to the gateway of course) - // However, users in user cache may just be there because they share a DM or group DM with you - // So there's no guarantee that a user being in user cache means they have a mutual with you - // To get around this, we request users we have DMs with, and ignore them below if we don't get them back - const dmUserIds = new Set( - Object.values(ChannelStore.getSortedPrivateChannels()).flatMap(c => c.recipients) - ); - const toRequest = nonFriendAffinities.filter(id => !UserStore.getUser(id) || dmUserIds.has(id)); + const toRequest = nonFriendAffinities.filter(id => !UserStore.getUser(id)); const allGuildIds = Object.keys(GuildStore.getGuilds()); const sentNonce = SnowflakeUtils.fromTimestamp(Date.now()); let count = allGuildIds.length * Math.ceil(toRequest.length / 100); // OP 8 Request Guild Members allows 100 user IDs at a time - const ignore = new Set(toRequest); - const relationships = RelationshipStore.getRelationships(); + // Note: As we are using OP 8 here, implicit relationships who we do not share a guild + // with will not be fetched; so, if they're not otherwise cached, they will not be shown + // This should not be a big deal as these should be rare const callback = ({ chunks }) => { - for (const chunk of chunks) { - const { nonce, members } = chunk; - if (nonce !== sentNonce) return; - members.forEach(member => { - ignore.delete(member.user.id); - }); + const chunkCount = chunks.filter(chunk => chunk.nonce === sentNonce).length; + if (chunkCount === 0) return; - nonFriendAffinities.map(id => UserStore.getUser(id)).filter(user => user && !ignore.has(user.id)).forEach(user => relationships[user.id] = 5); - RelationshipStore.emitChange(); - if (--count === 0) { - // @ts-ignore - FluxDispatcher.unsubscribe("GUILD_MEMBERS_CHUNK_BATCH", callback); - } + count -= chunkCount; + RelationshipStore.emitChange(); + if (count <= 0) { + FluxDispatcher.unsubscribe("GUILD_MEMBERS_CHUNK_BATCH", callback); } }; - // @ts-ignore FluxDispatcher.subscribe("GUILD_MEMBERS_CHUNK_BATCH", callback); for (let i = 0; i < toRequest.length; i += 100) { FluxDispatcher.dispatch({ type: "GUILD_MEMBERS_REQUEST", guildIds: allGuildIds, userIds: toRequest.slice(i, i + 100), + presences: true, nonce: sentNonce, }); }