feat(streaming): no blocking user on my timeline

This commit is contained in:
무라쿠모 2024-08-26 17:12:02 +09:00
parent 77ed6bb32b
commit 30c3154737
No known key found for this signature in database
GPG key ID: 139D6573F92DA9F7
9 changed files with 61 additions and 1 deletions

View file

@ -35,6 +35,7 @@ export default class Connection {
public followingChannels: Set<string> = new Set(); public followingChannels: Set<string> = new Set();
public userIdsWhoMeMuting: Set<string> = new Set(); public userIdsWhoMeMuting: Set<string> = new Set();
public userIdsWhoBlockingMe: Set<string> = new Set(); public userIdsWhoBlockingMe: Set<string> = new Set();
public userIdsWhoMeBlocking: Set<string> = new Set();
public userIdsWhoMeMutingRenotes: Set<string> = new Set(); public userIdsWhoMeMutingRenotes: Set<string> = new Set();
public userMutedInstances: Set<string> = new Set(); public userMutedInstances: Set<string> = new Set();
private fetchIntervalId: NodeJS.Timeout | null = null; private fetchIntervalId: NodeJS.Timeout | null = null;
@ -56,11 +57,12 @@ export default class Connection {
@bindThis @bindThis
public async fetch() { public async fetch() {
if (this.user == null) return; if (this.user == null) return;
const [userProfile, following, followingChannels, userIdsWhoMeMuting, userIdsWhoBlockingMe, userIdsWhoMeMutingRenotes] = await Promise.all([ const [userProfile, following, followingChannels, userIdsWhoMeMuting, userIdsWhoMeBlocking, userIdsWhoBlockingMe, userIdsWhoMeMutingRenotes] = await Promise.all([
this.cacheService.userProfileCache.fetch(this.user.id), this.cacheService.userProfileCache.fetch(this.user.id),
this.cacheService.userFollowingsCache.fetch(this.user.id), this.cacheService.userFollowingsCache.fetch(this.user.id),
this.channelFollowingService.userFollowingChannelsCache.fetch(this.user.id), this.channelFollowingService.userFollowingChannelsCache.fetch(this.user.id),
this.cacheService.userMutingsCache.fetch(this.user.id), this.cacheService.userMutingsCache.fetch(this.user.id),
this.cacheService.userBlockingCache.fetch(this.user.id),
this.cacheService.userBlockedCache.fetch(this.user.id), this.cacheService.userBlockedCache.fetch(this.user.id),
this.cacheService.renoteMutingsCache.fetch(this.user.id), this.cacheService.renoteMutingsCache.fetch(this.user.id),
]); ]);
@ -68,6 +70,7 @@ export default class Connection {
this.following = following; this.following = following;
this.followingChannels = followingChannels; this.followingChannels = followingChannels;
this.userIdsWhoMeMuting = userIdsWhoMeMuting; this.userIdsWhoMeMuting = userIdsWhoMeMuting;
this.userIdsWhoMeBlocking = userIdsWhoMeBlocking;
this.userIdsWhoBlockingMe = userIdsWhoBlockingMe; this.userIdsWhoBlockingMe = userIdsWhoBlockingMe;
this.userIdsWhoMeMutingRenotes = userIdsWhoMeMutingRenotes; this.userIdsWhoMeMutingRenotes = userIdsWhoMeMutingRenotes;
this.userMutedInstances = new Set(userProfile.mutedInstances); this.userMutedInstances = new Set(userProfile.mutedInstances);

View file

@ -42,6 +42,10 @@ export default abstract class Channel {
return this.connection.userIdsWhoMeMutingRenotes; return this.connection.userIdsWhoMeMutingRenotes;
} }
protected get userIdsWhoMeBlocking() {
return this.connection.userIdsWhoMeBlocking;
}
protected get userIdsWhoBlockingMe() { protected get userIdsWhoBlockingMe() {
return this.connection.userIdsWhoBlockingMe; return this.connection.userIdsWhoBlockingMe;
} }
@ -67,6 +71,10 @@ export default abstract class Channel {
// 流れてきたNoteがミュートしているユーザーが関わる // 流れてきたNoteがミュートしているユーザーが関わる
if (isUserRelated(note, this.userIdsWhoMeMuting)) return true; if (isUserRelated(note, this.userIdsWhoMeMuting)) return true;
// 流れてきたNoteがブロックしているユーザーが関わる
if (isUserRelated(note, this.userIdsWhoMeBlocking)) return true;
// 流れてきたNoteがブロックされているユーザーが関わる // 流れてきたNoteがブロックされているユーザーが関わる
if (isUserRelated(note, this.userIdsWhoBlockingMe)) return true; if (isUserRelated(note, this.userIdsWhoBlockingMe)) return true;

View file

@ -49,6 +49,14 @@ class AntennaChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return; if (this.isNoteMutedOrBlocked(note)) return;
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
if (note.reply) {
if (this.isNoteMutedOrBlocked(note.reply)) return;
}
this.connection.cacheNote(note); this.connection.cacheNote(note);
this.send('note', note); this.send('note', note);

View file

@ -48,6 +48,14 @@ class ChannelChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return; if (this.isNoteMutedOrBlocked(note)) return;
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
if (note.reply) {
if (this.isNoteMutedOrBlocked(note.reply)) return;
}
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) { if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote && Object.keys(note.renote.reactions).length > 0) { if (note.renote && Object.keys(note.renote.reactions).length > 0) {
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id); const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);

View file

@ -78,6 +78,14 @@ class GlobalTimelineChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return; if (this.isNoteMutedOrBlocked(note)) return;
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
if (note.reply) {
if (this.isNoteMutedOrBlocked(note.reply)) return;
}
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) { if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote && Object.keys(note.renote.reactions).length > 0) { if (note.renote && Object.keys(note.renote.reactions).length > 0) {
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id); const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);

View file

@ -59,6 +59,7 @@ class HomeTimelineChannel extends Channel {
if (note.reply) { if (note.reply) {
const reply = note.reply; const reply = note.reply;
if (this.isNoteMutedOrBlocked(reply)) return;
if (this.following[note.userId]?.withReplies) { if (this.following[note.userId]?.withReplies) {
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く // 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return; if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
@ -70,6 +71,10 @@ class HomeTimelineChannel extends Channel {
} }
} }
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
// 純粋なリノート(引用リノートでないリノート)の場合 // 純粋なリノート(引用リノートでないリノート)の場合
if (note.renote && isRenotePacked(note) && !isQuotePacked(note)) { if (note.renote && isRenotePacked(note) && !isQuotePacked(note)) {
if (!this.withRenotes) return; if (!this.withRenotes) return;

View file

@ -71,8 +71,15 @@ class HybridTimelineChannel extends Channel {
if (!isMe && !note.visibleUserIds!.includes(this.user!.id)) return; if (!isMe && !note.visibleUserIds!.includes(this.user!.id)) return;
} }
if (this.isNoteMutedOrBlocked(note)) return;
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
if (note.reply) { if (note.reply) {
const reply = note.reply; const reply = note.reply;
if (this.isNoteMutedOrBlocked(reply)) return;
if ((this.following[note.userId]?.withReplies ?? false) || this.withReplies) { if ((this.following[note.userId]?.withReplies ?? false) || this.withReplies) {
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く // 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return; if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;

View file

@ -55,9 +55,14 @@ class LocalTimelineChannel extends Channel {
if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return; if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return;
if (this.withFiles && (note.files === undefined || note.files.length === 0)) return; if (this.withFiles && (note.files === undefined || note.files.length === 0)) return;
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
// 関係ない返信は除外 // 関係ない返信は除外
if (note.reply) { if (note.reply) {
const reply = note.reply; const reply = note.reply;
if (this.isNoteMutedOrBlocked(reply)) return;
if ((this.following[note.userId]?.withReplies ?? false) || this.withReplies) { if ((this.following[note.userId]?.withReplies ?? false) || this.withReplies) {
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く // 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return; if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;

View file

@ -64,6 +64,14 @@ class RoleTimelineChannel extends Channel {
if (this.isNoteMutedOrBlocked(note)) return; if (this.isNoteMutedOrBlocked(note)) return;
if (note.renote) {
if (this.isNoteMutedOrBlocked(note.renote)) return;
}
if (note.reply) {
if (this.isNoteMutedOrBlocked(note.reply)) return;
}
if (this.user && isRenotePacked(note) && !isQuotePacked(note)) { if (this.user && isRenotePacked(note) && !isQuotePacked(note)) {
if (note.renote && Object.keys(note.renote.reactions).length > 0) { if (note.renote && Object.keys(note.renote.reactions).length > 0) {
const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id); const myRenoteReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id);