Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: タイムラインから投稿を除外するオプション #82

Merged
merged 3 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/backend/src/core/FanoutTimelineEndpointService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type TimelineOptions = {
excludeReplies?: boolean;
excludePureRenotes: boolean;
withCats: boolean;
withoutBots: boolean;
dbFallback: (untilId: string | null, sinceId: string | null, limit: number) => Promise<MiNote[]>,
};

Expand Down Expand Up @@ -104,6 +105,11 @@ export class FanoutTimelineEndpointService {
filter = (note) => (note.user ? note.user.isCat : false) && parentFilter(note);
}

if (ps.withoutBots) {
const parentFilter = filter;
filter = (note) => (!note.user || !note.user.isBot) && parentFilter(note);
}

if (ps.me) {
const me = ps.me;
const [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
redisTimelines: [`channelTimeline:${channel.id}`],
excludePureRenotes: false,
withCats: false,
withoutBots: false,
dbFallback: async (untilId, sinceId, limit) => {
return await this.getFromDb({ untilId, sinceId, limit, channelId: channel.id }, me);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const paramDef = {
withFiles: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
withCats: { type: 'boolean', default: false },
withoutBots: { type: 'boolean', default: false },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
Expand Down Expand Up @@ -102,6 +103,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withCats) {
query.andWhere('(select "isCat" from "user" where id = note."userId")');
}

if (ps.withoutBots) {
query.andWhere('(SELECT "isBot" FROM "user" WHERE id = note."userId") = FALSE');
}
//#endregion

const timeline = await query.limit(ps.limit).getMany();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export const paramDef = {
withRenotes: { type: 'boolean', default: true },
withReplies: { type: 'boolean', default: false },
withCats: { type: 'boolean', default: false },
withoutBots: { type: 'boolean', default: false },
},
required: [],
} as const;
Expand Down Expand Up @@ -115,6 +116,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withReplies: ps.withReplies,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me);

process.nextTick(() => {
Expand Down Expand Up @@ -155,6 +157,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
alwaysIncludeMyNotes: true,
excludePureRenotes: !ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
dbFallback: async (untilId, sinceId, limit) => await this.getFromDb({
untilId,
sinceId,
Expand All @@ -165,6 +168,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withReplies: ps.withReplies,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me),
});

Expand All @@ -186,6 +190,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: boolean,
withReplies: boolean,
withCats: boolean,
withoutBots: boolean,
}, me: MiLocalUser) {
const followees = await this.userFollowingService.getFollowees(me.id);
const followingChannels = await this.channelFollowingsRepository.find({
Expand Down Expand Up @@ -276,6 +281,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withCats) {
query.andWhere('(select "isCat" from "user" where id = note."userId")');
}

if (ps.withoutBots) {
query.andWhere('(SELECT "isBot" FROM "user" WHERE id = note."userId") = FALSE');
}
//#endregion

return await query.limit(ps.limit).getMany();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const paramDef = {
withRenotes: { type: 'boolean', default: true },
withReplies: { type: 'boolean', default: false },
withCats: { type: 'boolean', default: false },
withoutBots: { type: 'boolean', default: false },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
Expand Down Expand Up @@ -100,6 +101,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withReplies: ps.withReplies,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me);

process.nextTick(() => {
Expand All @@ -126,13 +128,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
alwaysIncludeMyNotes: true,
excludePureRenotes: !ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
dbFallback: async (untilId, sinceId, limit) => await this.getFromDb({
untilId,
sinceId,
limit,
withFiles: ps.withFiles,
withReplies: ps.withReplies,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me),
});

Expand All @@ -153,6 +157,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: boolean,
withReplies: boolean,
withCats: boolean,
withoutBots: boolean,
}, me: MiLocalUser | null) {
const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'),
ps.sinceId, ps.untilId)
Expand Down Expand Up @@ -188,6 +193,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
query.andWhere('(select "isCat" from "user" where id = note."userId")');
}

if (ps.withoutBots) {
query.andWhere('(SELECT "isBot" FROM "user" WHERE id = note."userId") = FALSE');
}

return await query.limit(ps.limit).getMany();
}
}
21 changes: 20 additions & 1 deletion packages/backend/src/server/api/endpoints/notes/timeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const paramDef = {
withFiles: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
withCats: { type: 'boolean', default: false },
withoutBots: { type: 'boolean', default: false },
},
required: [],
} as const;
Expand Down Expand Up @@ -89,6 +90,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withRenotes: ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me);

process.nextTick(() => {
Expand All @@ -115,6 +117,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
alwaysIncludeMyNotes: true,
excludePureRenotes: !ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
noteFilter: note => {
if (note.reply && note.reply.visibility === 'followers') {
if (!Object.hasOwn(followings, note.reply.userId)) return false;
Expand All @@ -132,6 +135,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withRenotes: ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me),
});

Expand All @@ -143,7 +147,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
});
}

private async getFromDb(ps: { untilId: string | null; sinceId: string | null; limit: number; includeMyRenotes: boolean; includeRenotedMyNotes: boolean; includeLocalRenotes: boolean; withFiles: boolean; withRenotes: boolean; withCats: boolean; }, me: MiLocalUser) {
private async getFromDb(ps: {
untilId: string | null;
sinceId: string | null;
limit: number;
includeMyRenotes: boolean;
includeRenotedMyNotes: boolean;
includeLocalRenotes: boolean;
withFiles: boolean;
withRenotes: boolean;
withCats: boolean;
withoutBots: boolean;
}, me: MiLocalUser) {
const followees = await this.userFollowingService.getFollowees(me.id);
const followingChannels = await this.channelFollowingsRepository.find({
where: {
Expand Down Expand Up @@ -249,6 +264,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (ps.withCats) {
query.andWhere('(select "isCat" from "user" where id = note."userId")');
}

if (ps.withoutBots) {
query.andWhere('(SELECT "isBot" FROM "user" WHERE id = note."userId") = FALSE');
}
//#endregion

return await query.limit(ps.limit).getMany();
Expand Down
9 changes: 9 additions & 0 deletions packages/backend/src/server/api/endpoints/users/notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const paramDef = {
withReplies: { type: 'boolean', default: false },
withRenotes: { type: 'boolean', default: true },
withChannelNotes: { type: 'boolean', default: false },
withoutBots: { type: 'boolean', default: false },
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
Expand Down Expand Up @@ -105,6 +106,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withRenotes: ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me);

return await this.noteEntityService.packMany(timeline, me);
Expand All @@ -130,6 +132,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
excludeNoFiles: ps.withChannelNotes && ps.withFiles, // userTimelineWithChannel may include notes without files
excludePureRenotes: !ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
noteFilter: note => {
if (note.channel?.isSensitive && !isSelf) return false;
if (note.visibility === 'specified' && (!me || (me.id !== note.userId && !note.visibleUserIds.some(v => v === me.id)))) return false;
Expand All @@ -146,6 +149,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: ps.withFiles,
withRenotes: ps.withRenotes,
withCats: ps.withCats,
withoutBots: ps.withoutBots,
}, me),
});

Expand All @@ -162,6 +166,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
withFiles: boolean,
withCats: boolean,
withRenotes: boolean,
withoutBots: boolean,
}, me: MiLocalUser | null) {
const isSelf = me && (me.id === ps.userId);

Expand Down Expand Up @@ -207,6 +212,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
query.andWhere('(select "isCat" from "user" where id = note."userId")');
}

if (ps.withoutBots) {
query.andWhere('(SELECT "isBot" FROM "user" WHERE id = note."userId") = FALSE');
}

return await query.limit(ps.limit).getMany();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class GlobalTimelineChannel extends Channel {
public static requireCredential = false as const;
private withRenotes: boolean;
private withFiles: boolean;
private withoutBots: boolean;

constructor(
private metaService: MetaService,
Expand All @@ -38,6 +39,7 @@ class GlobalTimelineChannel extends Channel {

this.withRenotes = params.withRenotes ?? true;
this.withFiles = params.withFiles ?? false;
this.withoutBots = params.withoutBots ?? false;

// Subscribe events
this.subscriber.on('notesStream', this.onNote);
Expand All @@ -46,6 +48,7 @@ class GlobalTimelineChannel extends Channel {
@bindThis
private async onNote(note: Packed<'Note'>) {
if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return;
if (this.withoutBots && note.user.isBot) return;

if (note.visibility !== 'public') return;
if (note.channelId != null) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class HomeTimelineChannel extends Channel {
public static kind = 'read:account';
private withRenotes: boolean;
private withFiles: boolean;
private withoutBots: boolean;

constructor(
private noteEntityService: NoteEntityService,
Expand All @@ -32,6 +33,7 @@ class HomeTimelineChannel extends Channel {
public async init(params: any) {
this.withRenotes = params.withRenotes ?? true;
this.withFiles = params.withFiles ?? false;
this.withoutBots = params.withoutBots ?? false;

this.subscriber.on('notesStream', this.onNote);
}
Expand All @@ -41,6 +43,7 @@ class HomeTimelineChannel extends Channel {
const isMe = this.user!.id === note.userId;

if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return;
if (this.withoutBots && note.user.isBot) return;

if (note.channelId) {
if (!this.followingChannels.has(note.channelId)) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class HybridTimelineChannel extends Channel {
private withRenotes: boolean;
private withReplies: boolean;
private withFiles: boolean;
private withoutBots: boolean;

constructor(
private metaService: MetaService,
Expand All @@ -41,6 +42,7 @@ class HybridTimelineChannel extends Channel {
this.withRenotes = params.withRenotes ?? true;
this.withReplies = params.withReplies ?? false;
this.withFiles = params.withFiles ?? false;
this.withoutBots = params.withoutBots ?? false;

// Subscribe events
this.subscriber.on('notesStream', this.onNote);
Expand All @@ -51,6 +53,7 @@ class HybridTimelineChannel extends Channel {
const isMe = this.user!.id === note.userId;

if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return;
if (this.withoutBots && note.user.isBot) return;

// チャンネルの投稿ではなく、自分自身の投稿 または
// チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class LocalTimelineChannel extends Channel {
private withRenotes: boolean;
private withReplies: boolean;
private withFiles: boolean;
private withoutBots: boolean;

constructor(
private metaService: MetaService,
Expand All @@ -40,6 +41,7 @@ class LocalTimelineChannel extends Channel {
this.withRenotes = params.withRenotes ?? true;
this.withReplies = params.withReplies ?? false;
this.withFiles = params.withFiles ?? false;
this.withoutBots = params.withoutBots ?? false;

// Subscribe events
this.subscriber.on('notesStream', this.onNote);
Expand All @@ -48,6 +50,7 @@ class LocalTimelineChannel extends Channel {
@bindThis
private async onNote(note: Packed<'Note'>) {
if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return;
if (this.withoutBots && note.user.isBot) return;

if (note.user.host !== null) return;
if (note.visibility !== 'public') return;
Expand Down
4 changes: 4 additions & 0 deletions packages/cherrypick-js/etc/cherrypick-js.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,7 @@ export type Channels = {
withRenotes?: boolean;
withFiles?: boolean;
withCats?: boolean;
withoutBots?: boolean;
};
events: {
note: (payload: Note) => void;
Expand All @@ -663,6 +664,7 @@ export type Channels = {
withReplies?: boolean;
withFiles?: boolean;
withCats?: boolean;
withoutBots?: boolean;
};
events: {
note: (payload: Note) => void;
Expand All @@ -675,6 +677,7 @@ export type Channels = {
withReplies?: boolean;
withFiles?: boolean;
withCats?: boolean;
withoutBots?: boolean;
};
events: {
note: (payload: Note) => void;
Expand All @@ -686,6 +689,7 @@ export type Channels = {
withRenotes?: boolean;
withFiles?: boolean;
withCats?: boolean;
withoutBots?: boolean;
};
events: {
note: (payload: Note) => void;
Expand Down
Loading
Loading