feat: show unlisted posts from following users in antennas
This commit is contained in:
parent
7a78dceb52
commit
412cdad209
3 changed files with 25 additions and 10 deletions
|
@ -6,6 +6,7 @@ Critical security updates are indicated by the :warning: icon.
|
|||
|
||||
- Introduce new full-text search engine and post search filters
|
||||
- Refactoring
|
||||
- Show unlisted posts from following users in antennas (similar to [Fedibird](https://github.com/fedibird/mastodon/tree/fedibird) and [kmyblue](https://github.com/kmycode/mastodon), unlisted posts from people you don't follow won't be shown)
|
||||
|
||||
## v20240301
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@ import type { Antenna } from "@/models/entities/antenna.js";
|
|||
import type { Note } from "@/models/entities/note.js";
|
||||
import type { User } from "@/models/entities/user.js";
|
||||
import type { UserProfile } from "@/models/entities/user-profile.js";
|
||||
import { Blockings, UserProfiles } from "@/models/index.js";
|
||||
import { Blockings, Followings, UserProfiles } from "@/models/index.js";
|
||||
import { getFullApAccount } from "@/misc/convert-host.js";
|
||||
import * as Acct from "@/misc/acct.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
import type { Packed } from "@/misc/schema.js";
|
||||
import { Cache } from "@/misc/cache.js";
|
||||
import { getWordHardMute } from "@/misc/check-word-mute.js";
|
||||
|
||||
const blockingCache = new Cache<User["id"][]>("blocking", 60 * 5);
|
||||
const hardMutesCache = new Cache<{
|
||||
|
@ -15,6 +15,7 @@ const hardMutesCache = new Cache<{
|
|||
mutedWords: UserProfile["mutedWords"];
|
||||
mutedPatterns: UserProfile["mutedPatterns"];
|
||||
}>("hardMutes", 60 * 5);
|
||||
const followingCache = new Cache<User["id"][]>("following", 60 * 5);
|
||||
|
||||
export async function checkHitAntenna(
|
||||
antenna: Antenna,
|
||||
|
@ -22,11 +23,10 @@ export async function checkHitAntenna(
|
|||
noteUser: { id: User["id"]; username: string; host: string | null },
|
||||
): Promise<boolean> {
|
||||
if (note.visibility === "specified") return false;
|
||||
if (note.visibility === "home") return false;
|
||||
if (!antenna.withReplies && note.replyId != null) return false;
|
||||
if (antenna.withFile) {
|
||||
if (note.fileIds && note.fileIds.length === 0) return false;
|
||||
}
|
||||
if (!antenna.withReplies && note.replyId != null) return false;
|
||||
|
||||
if (antenna.src === "users") {
|
||||
const accts = antenna.users.map((x) => {
|
||||
|
@ -53,14 +53,19 @@ export async function checkHitAntenna(
|
|||
.map((xs) => xs.filter((x) => x !== ""))
|
||||
.filter((xs) => xs.length > 0);
|
||||
|
||||
let text = `${note.text ?? ""} ${note.cw ?? ""}`;
|
||||
if (note.files != null)
|
||||
text += ` ${note.files.map((f) => f.comment ?? "").join(" ")}`;
|
||||
text = text.trim();
|
||||
|
||||
if (keywords.length > 0) {
|
||||
if (note.text == null) return false;
|
||||
|
||||
const matched = keywords.some((and) =>
|
||||
and.every((keyword) =>
|
||||
antenna.caseSensitive
|
||||
? note.text!.includes(keyword)
|
||||
: note.text!.toLowerCase().includes(keyword.toLowerCase()),
|
||||
? text.includes(keyword)
|
||||
: text.toLowerCase().includes(keyword.toLowerCase()),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -78,8 +83,8 @@ export async function checkHitAntenna(
|
|||
const matched = excludeKeywords.some((and) =>
|
||||
and.every((keyword) =>
|
||||
antenna.caseSensitive
|
||||
? note.text!.includes(keyword)
|
||||
: note.text!.toLowerCase().includes(keyword.toLowerCase()),
|
||||
? note.text?.includes(keyword)
|
||||
: note.text?.toLowerCase().includes(keyword.toLowerCase()),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -94,6 +99,16 @@ export async function checkHitAntenna(
|
|||
);
|
||||
if (blockings.includes(antenna.userId)) return false;
|
||||
|
||||
if (note.visibility === "followers" || note.visibility === "home") {
|
||||
const following = await followingCache.fetch(antenna.userId, () =>
|
||||
Followings.find({
|
||||
where: { followerId: antenna.userId },
|
||||
select: ["followeeId"],
|
||||
}).then((relations) => relations.map((relation) => relation.followeeId)),
|
||||
);
|
||||
if (!following.includes(note.userId)) return false;
|
||||
}
|
||||
|
||||
const mutes = await hardMutesCache.fetch(antenna.userId, () =>
|
||||
UserProfiles.findOneByOrFail({
|
||||
userId: antenna.userId,
|
||||
|
|
|
@ -111,8 +111,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
.leftJoinAndSelect("replyUser.banner", "replyUserBanner")
|
||||
.leftJoinAndSelect("renote.user", "renoteUser")
|
||||
.leftJoinAndSelect("renoteUser.avatar", "renoteUserAvatar")
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner")
|
||||
.andWhere("note.visibility != 'home'");
|
||||
.leftJoinAndSelect("renoteUser.banner", "renoteUserBanner");
|
||||
|
||||
generateVisibilityQuery(query, user);
|
||||
generateMutedUserQuery(query, user);
|
||||
|
|
Loading…
Reference in a new issue