2023-01-13 05:40:33 +01:00
|
|
|
|
import rndstr from "rndstr";
|
|
|
|
|
import type { Note } from "@/models/entities/note.js";
|
|
|
|
|
import type { User } from "@/models/entities/user.js";
|
|
|
|
|
import { Notes, UserProfiles, NoteReactions } from "@/models/index.js";
|
|
|
|
|
import { generateMutedUserQuery } from "./generate-muted-user-query.js";
|
|
|
|
|
import { generateBlockedUserQuery } from "./generate-block-query.js";
|
2020-02-18 11:05:11 +01:00
|
|
|
|
|
|
|
|
|
// TODO: リアクション、Renote、返信などをしたノートは除外する
|
|
|
|
|
|
|
|
|
|
export async function injectFeatured(timeline: Note[], user?: User | null) {
|
|
|
|
|
if (timeline.length < 5) return;
|
|
|
|
|
|
|
|
|
|
if (user) {
|
2022-03-26 07:34:00 +01:00
|
|
|
|
const profile = await UserProfiles.findOneByOrFail({ userId: user.id });
|
2020-02-18 11:05:11 +01:00
|
|
|
|
if (!profile.injectFeaturedNote) return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const max = 30;
|
|
|
|
|
const day = 1000 * 60 * 60 * 24 * 3; // 3日前まで
|
|
|
|
|
|
2023-01-13 05:40:33 +01:00
|
|
|
|
const query = Notes.createQueryBuilder("note")
|
|
|
|
|
.addSelect("note.score")
|
|
|
|
|
.where("note.userHost IS NULL")
|
|
|
|
|
.andWhere("note.score > 0")
|
|
|
|
|
.andWhere("note.createdAt > :date", { date: new Date(Date.now() - day) })
|
2020-02-18 11:05:11 +01:00
|
|
|
|
.andWhere(`note.visibility = 'public'`)
|
2023-01-13 05:40:33 +01:00
|
|
|
|
.innerJoinAndSelect("note.user", "user");
|
2020-02-18 11:05:11 +01:00
|
|
|
|
|
2020-02-21 22:49:12 +01:00
|
|
|
|
if (user) {
|
2023-01-13 05:40:33 +01:00
|
|
|
|
query.andWhere("note.userId != :userId", { userId: user.id });
|
2020-02-21 22:49:12 +01:00
|
|
|
|
|
2020-07-28 02:38:41 +02:00
|
|
|
|
generateMutedUserQuery(query, user);
|
2021-08-17 14:48:59 +02:00
|
|
|
|
generateBlockedUserQuery(query, user);
|
2020-02-20 05:38:40 +01:00
|
|
|
|
|
2023-01-13 05:40:33 +01:00
|
|
|
|
const reactionQuery = NoteReactions.createQueryBuilder("reaction")
|
|
|
|
|
.select("reaction.noteId")
|
|
|
|
|
.where("reaction.userId = :userId", { userId: user.id });
|
2020-02-21 22:49:12 +01:00
|
|
|
|
|
2023-01-13 05:40:33 +01:00
|
|
|
|
query.andWhere(`note.id NOT IN (${reactionQuery.getQuery()})`);
|
2020-02-21 22:49:12 +01:00
|
|
|
|
}
|
2020-02-18 11:05:11 +01:00
|
|
|
|
|
2023-01-13 05:40:33 +01:00
|
|
|
|
const notes = await query.orderBy("note.score", "DESC").take(max).getMany();
|
2020-02-18 11:05:11 +01:00
|
|
|
|
|
|
|
|
|
if (notes.length === 0) return;
|
|
|
|
|
|
|
|
|
|
// Pick random one
|
|
|
|
|
const featured = notes[Math.floor(Math.random() * notes.length)];
|
|
|
|
|
|
2023-01-13 05:40:33 +01:00
|
|
|
|
(featured as any)._featuredId_ = rndstr("a-z0-9", 8);
|
2020-02-18 11:05:11 +01:00
|
|
|
|
|
|
|
|
|
// Inject featured
|
|
|
|
|
timeline.splice(3, 0, featured);
|
|
|
|
|
}
|