From 7747ec5b6de17e8ce20e1cf59649e5e98aec9991 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 23 Jan 2021 20:05:44 +0900
Subject: [PATCH 1/5] Update ja-JP.yml

---
 locales/ja-JP.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index fa215847d..992f6c842 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -678,7 +678,7 @@ onlineUsersCount: "{n}人がオンライン"
 nUsers: "{n}ユーザー"
 nNotes: "{n}ノート"
 sendErrorReports: "エラーリポートを送信"
-sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がMisskeyに共有され、ソフトウェアの品質向上に役立てることができます。"
+sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がMisskeyに共有され、ソフトウェアの品質向上に役立てることができます。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。"
 myTheme: "マイテーマ"
 backgroundColor: "背景"
 accentColor: "アクセント"

From 6d33b366f8f18b0724c4a3d8cbfa6a7a4112b805 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sun, 17 Apr 2022 21:18:18 +0900
Subject: [PATCH 2/5] fix ogp rendering and refactor

---
 packages/backend/src/models/entities/user.ts  |  4 +--
 .../backend/src/models/repositories/user.ts   | 28 +++++++++++++------
 .../backend/src/server/api/common/signin.ts   |  2 +-
 packages/backend/src/server/index.ts          | 20 ++++++-------
 packages/backend/src/server/web/feed.ts       |  6 ++--
 packages/backend/src/server/web/index.ts      | 19 ++++++++-----
 .../backend/src/server/web/views/clip.pug     |  2 +-
 .../backend/src/server/web/views/note.pug     |  2 +-
 .../backend/src/server/web/views/page.pug     |  2 +-
 .../backend/src/server/web/views/user.pug     |  3 +-
 10 files changed, 51 insertions(+), 37 deletions(-)

diff --git a/packages/backend/src/models/entities/user.ts b/packages/backend/src/models/entities/user.ts
index c76824c97..29d9a0c2c 100644
--- a/packages/backend/src/models/entities/user.ts
+++ b/packages/backend/src/models/entities/user.ts
@@ -1,6 +1,6 @@
 import { Entity, Column, Index, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
-import { DriveFile } from './drive-file.js';
 import { id } from '../id.js';
+import { DriveFile } from './drive-file.js';
 
 @Entity()
 @Index(['usernameLower', 'host'], { unique: true })
@@ -207,7 +207,7 @@ export class User {
 
 	@Column('boolean', {
 		default: false,
-		comment: 'Whether to show users replying to other users in the timeline'
+		comment: 'Whether to show users replying to other users in the timeline',
 	})
 	public showTimelineReplies: boolean;
 
diff --git a/packages/backend/src/models/repositories/user.ts b/packages/backend/src/models/repositories/user.ts
index 2f4b7d678..541fbaf00 100644
--- a/packages/backend/src/models/repositories/user.ts
+++ b/packages/backend/src/models/repositories/user.ts
@@ -1,7 +1,6 @@
 import { EntityRepository, Repository, In, Not } from 'typeorm';
 import Ajv from 'ajv';
 import { User, ILocalUser, IRemoteUser } from '@/models/entities/user.js';
-import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js';
 import config from '@/config/index.js';
 import { Packed } from '@/misc/schema.js';
 import { awaitAll, Promiseable } from '@/prelude/await-all.js';
@@ -9,8 +8,9 @@ import { populateEmojis } from '@/misc/populate-emojis.js';
 import { getAntennas } from '@/misc/antenna-cache.js';
 import { USER_ACTIVE_THRESHOLD, USER_ONLINE_THRESHOLD } from '@/const.js';
 import { Cache } from '@/misc/cache.js';
-import { Instance } from '../entities/instance.js';
 import { db } from '@/db/postgre.js';
+import { Instance } from '../entities/instance.js';
+import { Notes, NoteUnreads, FollowRequests, Notifications, MessagingMessages, UserNotePinings, Followings, Blockings, Mutings, UserProfiles, UserSecurityKeys, UserGroupJoinings, Pages, Announcements, AnnouncementReads, Antennas, AntennaNotes, ChannelFollowings, Instances, DriveFiles } from '../index.js';
 
 const userInstanceCache = new Cache<Instance | null>(1000 * 60 * 60 * 3);
 
@@ -112,7 +112,7 @@ export const UserRepository = db.getRepository(User).extend({
 		const joinings = await UserGroupJoinings.findBy({ userId: userId });
 
 		const groupQs = Promise.all(joinings.map(j => MessagingMessages.createQueryBuilder('message')
-			.where(`message.groupId = :groupId`, { groupId: j.userGroupId })
+			.where('message.groupId = :groupId', { groupId: j.userGroupId })
 			.andWhere('message.userId != :userId', { userId: userId })
 			.andWhere('NOT (:userId = ANY(message.reads))', { userId: userId })
 			.andWhere('message.createdAt > :joinedAt', { joinedAt: j.createdAt }) // 自分が加入する前の会話については、未読扱いしない
@@ -204,8 +204,18 @@ export const UserRepository = db.getRepository(User).extend({
 		);
 	},
 
-	getAvatarUrl(user: User): string {
-		// TODO: avatarIdがあるがavatarがない(JOINされてない)場合のハンドリング
+	async getAvatarUrl(user: User): Promise<string> {
+		if (user.avatar) {
+			return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id);
+		} else if (user.avatarId) {
+			const avatar = await DriveFiles.findOneByOrFail({ id: user.avatarId });
+			return DriveFiles.getPublicUrl(avatar, true) || this.getIdenticonUrl(user.id);
+		} else {
+			return this.getIdenticonUrl(user.id);
+		}
+	},
+
+	getAvatarUrlSync(user: User): string {
 		if (user.avatar) {
 			return DriveFiles.getPublicUrl(user.avatar, true) || this.getIdenticonUrl(user.id);
 		} else {
@@ -223,7 +233,7 @@ export const UserRepository = db.getRepository(User).extend({
 		options?: {
 			detail?: D,
 			includeSecrets?: boolean,
-		}
+		},
 	): Promise<IsMeAndIsUserDetailed<ExpectsMe, D>> {
 		const opts = Object.assign({
 			detail: false,
@@ -274,7 +284,7 @@ export const UserRepository = db.getRepository(User).extend({
 			name: user.name,
 			username: user.username,
 			host: user.host,
-			avatarUrl: this.getAvatarUrl(user),
+			avatarUrl: this.getAvatarUrlSync(user),
 			avatarBlurhash: user.avatar?.blurhash || null,
 			avatarColor: null, // 後方互換性のため
 			isAdmin: user.isAdmin || falsy,
@@ -283,7 +293,7 @@ export const UserRepository = db.getRepository(User).extend({
 			isCat: user.isCat || falsy,
 			instance: user.host ? userInstanceCache.fetch(user.host,
 				() => Instances.findOneBy({ host: user.host! }),
-				v => v != null
+				v => v != null,
 			).then(instance => instance ? {
 				name: instance.name,
 				softwareName: instance.softwareName,
@@ -403,7 +413,7 @@ export const UserRepository = db.getRepository(User).extend({
 		options?: {
 			detail?: D,
 			includeSecrets?: boolean,
-		}
+		},
 	): Promise<IsUserDetailed<D>[]> {
 		return Promise.all(users.map(u => this.pack(u, me, options)));
 	},
diff --git a/packages/backend/src/server/api/common/signin.ts b/packages/backend/src/server/api/common/signin.ts
index f1dccee2c..038fd8d96 100644
--- a/packages/backend/src/server/api/common/signin.ts
+++ b/packages/backend/src/server/api/common/signin.ts
@@ -9,7 +9,7 @@ import { publishMainStream } from '@/services/stream.js';
 export default function(ctx: Koa.Context, user: ILocalUser, redirect = false) {
 	if (redirect) {
 		//#region Cookie
-		ctx.cookies.set('igi', user.token, {
+		ctx.cookies.set('igi', user.token!, {
 			path: '/',
 			// SEE: https://github.com/koajs/koa/issues/974
 			// When using a SSL proxy it should be configured to add the "X-Forwarded-Proto: https" header
diff --git a/packages/backend/src/server/index.ts b/packages/backend/src/server/index.ts
index a68cebfeb..b50e38a63 100644
--- a/packages/backend/src/server/index.ts
+++ b/packages/backend/src/server/index.ts
@@ -10,23 +10,23 @@ import mount from 'koa-mount';
 import koaLogger from 'koa-logger';
 import * as slow from 'koa-slow';
 
-import activityPub from './activitypub.js';
-import nodeinfo from './nodeinfo.js';
-import wellKnown from './well-known.js';
+import { IsNull } from 'typeorm';
 import config from '@/config/index.js';
-import apiServer from './api/index.js';
-import fileServer from './file/index.js';
-import proxyServer from './proxy/index.js';
-import webServer from './web/index.js';
 import Logger from '@/services/logger.js';
-import { envOption } from '../env.js';
 import { UserProfiles, Users } from '@/models/index.js';
 import { genIdenticon } from '@/misc/gen-identicon.js';
 import { createTemp } from '@/misc/create-temp.js';
 import { publishMainStream } from '@/services/stream.js';
 import * as Acct from '@/misc/acct.js';
+import { envOption } from '../env.js';
+import activityPub from './activitypub.js';
+import nodeinfo from './nodeinfo.js';
+import wellKnown from './well-known.js';
+import apiServer from './api/index.js';
+import fileServer from './file/index.js';
+import proxyServer from './proxy/index.js';
+import webServer from './web/index.js';
 import { initializeStreamingServer } from './api/streaming.js';
-import { IsNull } from 'typeorm';
 
 export const serverLogger = new Logger('server', 'gray', false);
 
@@ -81,7 +81,7 @@ router.get('/avatar/@:acct', async ctx => {
 	});
 
 	if (user) {
-		ctx.redirect(Users.getAvatarUrl(user));
+		ctx.redirect(Users.getAvatarUrlSync(user));
 	} else {
 		ctx.redirect('/static-assets/user-unknown.png');
 	}
diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts
index eba8dc58d..4abe2885c 100644
--- a/packages/backend/src/server/web/feed.ts
+++ b/packages/backend/src/server/web/feed.ts
@@ -1,8 +1,8 @@
 import { Feed } from 'feed';
+import { In, IsNull } from 'typeorm';
 import config from '@/config/index.js';
 import { User } from '@/models/entities/user.js';
-import { Notes, DriveFiles, UserProfiles } from '@/models/index.js';
-import { In, IsNull } from 'typeorm';
+import { Notes, DriveFiles, UserProfiles, Users } from '@/models/index.js';
 
 export default async function(user: User) {
 	const author = {
@@ -29,7 +29,7 @@ export default async function(user: User) {
 		generator: 'Misskey',
 		description: `${user.notesCount} Notes, ${profile.ffVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.ffVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`,
 		link: author.link,
-		image: user.avatarUrl ? user.avatarUrl : undefined,
+		image: await Users.getAvatarUrl(user),
 		feedLinks: {
 			json: `${author.link}.json`,
 			atom: `${author.link}.atom`,
diff --git a/packages/backend/src/server/web/index.ts b/packages/backend/src/server/web/index.ts
index 48bf6f733..34d56cfd0 100644
--- a/packages/backend/src/server/web/index.ts
+++ b/packages/backend/src/server/web/index.ts
@@ -11,20 +11,20 @@ import send from 'koa-send';
 import favicon from 'koa-favicon';
 import views from 'koa-views';
 import { createBullBoard } from '@bull-board/api';
-import { BullAdapter  } from '@bull-board/api/bullAdapter.js';
+import { BullAdapter } from '@bull-board/api/bullAdapter.js';
 import { KoaAdapter } from '@bull-board/koa';
 
-import packFeed from './feed.js';
+import { IsNull } from 'typeorm';
 import { fetchMeta } from '@/misc/fetch-meta.js';
-import { genOpenapiSpec } from '../api/openapi/gen-spec.js';
 import config from '@/config/index.js';
 import { Users, Notes, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '@/models/index.js';
 import * as Acct from '@/misc/acct.js';
 import { getNoteSummary } from '@/misc/get-note-summary.js';
+import { queues } from '@/queue/queues.js';
+import { genOpenapiSpec } from '../api/openapi/gen-spec.js';
 import { urlPreviewHandler } from './url-preview.js';
 import { manifestHandler } from './manifest.js';
-import { queues } from '@/queue/queues.js';
-import { IsNull } from 'typeorm';
+import packFeed from './feed.js';
 
 const _filename = fileURLToPath(import.meta.url);
 const _dirname = dirname(_filename);
@@ -127,7 +127,7 @@ router.get('/twemoji/(.*)', async ctx => {
 		return;
 	}
 
-	ctx.set('Content-Security-Policy', `default-src 'none'; style-src 'unsafe-inline'`);
+	ctx.set('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\'');
 
 	await send(ctx as any, path, {
 		root: `${_dirname}/../../../node_modules/@discordapp/twemoji/dist/svg/`,
@@ -235,6 +235,7 @@ router.get(['/@:user', '/@:user/:sub'], async (ctx, next) => {
 
 		await ctx.render('user', {
 			user, profile, me,
+			avatarUrl: await Users.getAvatarUrl(user),
 			sub: ctx.params.sub,
 			instanceName: meta.name || 'Misskey',
 			icon: meta.iconUrl,
@@ -274,6 +275,7 @@ router.get('/notes/:note', async (ctx, next) => {
 		await ctx.render('note', {
 			note: _note,
 			profile,
+			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: note.userId })),
 			// TODO: Let locale changeable by instance setting
 			summary: getNoteSummary(_note),
 			instanceName: meta.name || 'Misskey',
@@ -315,6 +317,7 @@ router.get('/@:user/pages/:page', async (ctx, next) => {
 		await ctx.render('page', {
 			page: _page,
 			profile,
+			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: page.userId })),
 			instanceName: meta.name || 'Misskey',
 			icon: meta.iconUrl,
 			themeColor: meta.themeColor,
@@ -346,6 +349,7 @@ router.get('/clips/:clip', async (ctx, next) => {
 		await ctx.render('clip', {
 			clip: _clip,
 			profile,
+			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: clip.userId })),
 			instanceName: meta.name || 'Misskey',
 			icon: meta.iconUrl,
 			themeColor: meta.themeColor,
@@ -370,6 +374,7 @@ router.get('/gallery/:post', async (ctx, next) => {
 		await ctx.render('gallery-post', {
 			post: _post,
 			profile,
+			avatarUrl: await Users.getAvatarUrl(await Users.findOneByOrFail({ id: post.userId })),
 			instanceName: meta.name || 'Misskey',
 			icon: meta.iconUrl,
 			themeColor: meta.themeColor,
@@ -434,7 +439,7 @@ router.get('/cli', async ctx => {
 	});
 });
 
-const override = (source: string, target: string, depth: number = 0) =>
+const override = (source: string, target: string, depth = 0) =>
 	[, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/');
 
 router.get('/flush', async ctx => {
diff --git a/packages/backend/src/server/web/views/clip.pug b/packages/backend/src/server/web/views/clip.pug
index 7a84d50f6..4c692bf59 100644
--- a/packages/backend/src/server/web/views/clip.pug
+++ b/packages/backend/src/server/web/views/clip.pug
@@ -16,7 +16,7 @@ block og
 	meta(property='og:title'       content= title)
 	meta(property='og:description' content= clip.description)
 	meta(property='og:url'         content= url)
-	meta(property='og:image'       content= user.avatarUrl)
+	meta(property='og:image'       content= avatarUrl)
 
 block meta
 	if profile.noCrawle
diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug
index 34b03f983..65696ea13 100644
--- a/packages/backend/src/server/web/views/note.pug
+++ b/packages/backend/src/server/web/views/note.pug
@@ -17,7 +17,7 @@ block og
 	meta(property='og:title'       content= title)
 	meta(property='og:description' content= summary)
 	meta(property='og:url'         content= url)
-	meta(property='og:image'       content= user.avatarUrl)
+	meta(property='og:image'       content= avatarUrl)
 
 block meta
 	if user.host || isRenote || profile.noCrawle
diff --git a/packages/backend/src/server/web/views/page.pug b/packages/backend/src/server/web/views/page.pug
index b6c954802..4219e76a5 100644
--- a/packages/backend/src/server/web/views/page.pug
+++ b/packages/backend/src/server/web/views/page.pug
@@ -16,7 +16,7 @@ block og
 	meta(property='og:title'       content= title)
 	meta(property='og:description' content= page.summary)
 	meta(property='og:url'         content= url)
-	meta(property='og:image'       content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : user.avatarUrl)
+	meta(property='og:image'       content= page.eyeCatchingImage ? page.eyeCatchingImage.thumbnailUrl : avatarUrl)
 
 block meta
 	if profile.noCrawle
diff --git a/packages/backend/src/server/web/views/user.pug b/packages/backend/src/server/web/views/user.pug
index 2adec0f88..119993fdb 100644
--- a/packages/backend/src/server/web/views/user.pug
+++ b/packages/backend/src/server/web/views/user.pug
@@ -3,7 +3,6 @@ extends ./base
 block vars
 	- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
 	- const url = `${config.url}/@${(user.host ? `${user.username}@${user.host}` : user.username)}`;
-	- const img = user.avatarUrl || null;
 
 block title
 	= `${title} | ${instanceName}`
@@ -16,7 +15,7 @@ block og
 	meta(property='og:title'       content= title)
 	meta(property='og:description' content= profile.description)
 	meta(property='og:url'         content= url)
-	meta(property='og:image'       content= img)
+	meta(property='og:image'       content= avatarUrl)
 
 block meta
 	if user.host || profile.noCrawle

From dd86397e857f36fbc06d77feadef00f6c92a3e21 Mon Sep 17 00:00:00 2001
From: xianon <xianon@hotmail.co.jp>
Date: Tue, 19 Apr 2022 22:59:39 +0900
Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=E3=82=A2=E3=83=B3=E3=83=86=E3=83=8A?=
 =?UTF-8?q?=E3=80=81=E3=82=AF=E3=83=AA=E3=83=83=E3=83=97=E3=80=81=E3=83=AA?=
 =?UTF-8?q?=E3=82=B9=E3=83=88=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=82=92=E9=80=9F?=
 =?UTF-8?q?=E3=81=8F=E3=81=99=E3=82=8B=20(#8518)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* アンテナノートを取得するクエリがタイムアウトしないように速くする

* テーブル名を直接指定しないようにする

* クリップの取得を速くする

* リストの取得を速くする
---
 .../backend/src/server/api/endpoints/antennas/notes.ts    | 8 ++------
 packages/backend/src/server/api/endpoints/clips/notes.ts  | 8 ++------
 .../src/server/api/endpoints/notes/user-list-timeline.ts  | 8 ++------
 3 files changed, 6 insertions(+), 18 deletions(-)

diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts
index 004e4c131..8aac55b4a 100644
--- a/packages/backend/src/server/api/endpoints/antennas/notes.ts
+++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts
@@ -57,13 +57,9 @@ export default define(meta, paramDef, async (ps, user) => {
 		throw new ApiError(meta.errors.noSuchAntenna);
 	}
 
-	const antennaQuery = AntennaNotes.createQueryBuilder('joining')
-		.select('joining.noteId')
-		.where('joining.antennaId = :antennaId', { antennaId: antenna.id });
-
 	const query = makePaginationQuery(Notes.createQueryBuilder('note'),
 			ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
-		.andWhere(`note.id IN (${ antennaQuery.getQuery() })`)
+		.innerJoin(AntennaNotes.metadata.targetName, 'antennaNote', 'antennaNote.noteId = note.id')
 		.innerJoinAndSelect('note.user', 'user')
 		.leftJoinAndSelect('user.avatar', 'avatar')
 		.leftJoinAndSelect('user.banner', 'banner')
@@ -75,7 +71,7 @@ export default define(meta, paramDef, async (ps, user) => {
 		.leftJoinAndSelect('renote.user', 'renoteUser')
 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar')
 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner')
-		.setParameters(antennaQuery.getParameters());
+		.andWhere('antennaNote.antennaId = :antennaId', { antennaId: antenna.id });
 
 	generateVisibilityQuery(query, user);
 	generateMutedUserQuery(query, user);
diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts
index 4b6782fca..4ace747ef 100644
--- a/packages/backend/src/server/api/endpoints/clips/notes.ts
+++ b/packages/backend/src/server/api/endpoints/clips/notes.ts
@@ -57,12 +57,8 @@ export default define(meta, paramDef, async (ps, user) => {
 		throw new ApiError(meta.errors.noSuchClip);
 	}
 
-	const clipQuery = ClipNotes.createQueryBuilder('joining')
-		.select('joining.noteId')
-		.where('joining.clipId = :clipId', { clipId: clip.id });
-
 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
-		.andWhere(`note.id IN (${ clipQuery.getQuery() })`)
+		.innerJoin(ClipNotes.metadata.targetName, 'clipNote', 'clipNote.noteId = note.id')
 		.innerJoinAndSelect('note.user', 'user')
 		.leftJoinAndSelect('user.avatar', 'avatar')
 		.leftJoinAndSelect('user.banner', 'banner')
@@ -74,7 +70,7 @@ export default define(meta, paramDef, async (ps, user) => {
 		.leftJoinAndSelect('renote.user', 'renoteUser')
 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar')
 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner')
-		.setParameters(clipQuery.getParameters());
+		.andWhere('clipNote.clipId = :clipId', { clipId: clip.id });
 
 	if (user) {
 		generateVisibilityQuery(query, user);
diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
index 6c6402603..fd4a87903 100644
--- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts
@@ -63,12 +63,8 @@ export default define(meta, paramDef, async (ps, user) => {
 	}
 
 	//#region Construct query
-	const listQuery = UserListJoinings.createQueryBuilder('joining')
-		.select('joining.userId')
-		.where('joining.userListId = :userListId', { userListId: list.id });
-
 	const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId)
-		.andWhere(`note.userId IN (${ listQuery.getQuery() })`)
+		.innerJoin(UserListJoinings.metadata.targetName, 'userListJoining', 'userListJoining.userId = note.userId')
 		.innerJoinAndSelect('note.user', 'user')
 		.leftJoinAndSelect('user.avatar', 'avatar')
 		.leftJoinAndSelect('user.banner', 'banner')
@@ -80,7 +76,7 @@ export default define(meta, paramDef, async (ps, user) => {
 		.leftJoinAndSelect('renote.user', 'renoteUser')
 		.leftJoinAndSelect('renoteUser.avatar', 'renoteUserAvatar')
 		.leftJoinAndSelect('renoteUser.banner', 'renoteUserBanner')
-		.setParameters(listQuery.getParameters());
+		.andWhere('userListJoining.userListId = :userListId', { userListId: list.id });
 
 	generateVisibilityQuery(query, user);
 

From e213c2e8446971549ba8cb8969a3b38d15530b4e Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 16 Apr 2022 13:31:12 +0900
Subject: [PATCH 4/5] remove unused locale

---
 locales/eo-UY.yml | 126 ----------------------------------------------
 locales/index.js  |   1 -
 2 files changed, 127 deletions(-)
 delete mode 100644 locales/eo-UY.yml

diff --git a/locales/eo-UY.yml b/locales/eo-UY.yml
deleted file mode 100644
index 65a593157..000000000
--- a/locales/eo-UY.yml
+++ /dev/null
@@ -1,126 +0,0 @@
----
-ok: "Bone"
-exportRequested: "Vi petis elporton. Ĝi povas bezoni longan tempon. Elportaĵo estos aldonita al disko post elportado."
-importRequested: "Vi petis enportadon. Ĝi povas bezoni longan tempon. "
-pageLoadError: "Fuŝiĝis enlegi paĝon."
-pageLoadErrorDescription: "Ordinare tio okazas pro la retkondiĉo aŭ la staplo de retumilo.\nPurigu la staplon, aŭ refaru poste. "
-youShouldUpgradeClient: "Por montri ĉi paĝon, bonvolu enlegi refoje kaj uzi klienton novversian."
-flagAsCatDescription: "Flagu por montri ke la konton havas kato."
-flagShowTimelineReplies: "Montri respondon de notoj en templinio."
-intro: "Instalado de Misskey finiĝis! Kreu administran konton."
-whenServerDisconnected: "Kiam vi malligiĝas de servilo"
-caseSensitive: "Distingi usklecon"
-markAsReadAllUnreadNotes: "Marki ĉiujn afiŝojn kiel legita"
-checking: "kontrolante..."
-signinFailed: "Fuŝiĝis ensaluti. Bonvolu kontroli uzantnomon kaj pasvorton."
-promote: "Reklamata"
-updateRemoteUser: "Aktualigi informon de foraj uzantoj"
-yourAccountSuspendedTitle: "La konto estas frostigita."
-tokenRequested: "Alirpermeso al konto"
-abuseReports: "Raportoj"
-reportAbuse: "Raportoj"
-reportAbuseOf: "raporti {name}n"
-reporter: "Informanto"
-reporterOrigin: "Raportanto"
-pollVotesCount: "Nombro de voĉdonado"
-invalidValue: "Nevalida valoro"
-notRecommended: "Evitindaj"
-switchAccount: "Ŝanĝi konton"
-configure: "Agordi"
-popularPosts: "Populara noto"
-expiration: "Limtempo"
-priority: "Prioritato"
-squareAvatars: "Montri bildsimbolon kiel kvadrata"
-misskeyUpdated: "Misskey ĝisdatiĝis!"
-whatIsNew: "Montri novaĵojn"
-accountDeletionInProgress: "La konto estas forviŝanta."
-resolved: "Solvita"
-unresolved: "Nesolvita"
-filter: "Filtrilo"
-deleteAccountConfirm: "La konto estos forviŝita. Ĉu vi daŭrigas fari?"
-voteConfirm: "Ĉu vi voĉdonas {choice}n?"
-hide: "Kaŝi"
-overridedDeviceKind: "tipo de aparato"
-size: "Grandeco"
-searchByGoogle: "Serĉi en Guglo-Serĉilo"
-mutePeriod: "Daŭro de silentigo"
-indefinitely: "Sen limdato"
-tenMinutes: "Je 10 minutoj"
-oneHour: "Je 1 horo"
-oneDay: "Je 1 tago"
-oneWeek: "Je 1 semajno"
-failedToFetchAccountInformation: "Malsukcesas akiri informon de konto"
-_emailUnavailable:
-  mx: "Ĉi retpoŝto-servilo ne estas uzebla."
-_signup:
-  almostThere: "Preskaŭ plenumita"
-_accountDelete:
-  requestAccountDelete: "Peti forviŝi konton"
-  started: "Forviŝado komenciĝis."
-_gallery:
-  my: "Mia afiŝo"
-_aboutMisskey:
-  donate: "Mondonaci al Misskey"
-_channel:
-  notesCount: "{n} notoj"
-_theme:
-  explore: "Serĉi koloraron"
-  install: "Instali koloraron"
-  installedThemes: "Instalita koloraro"
-  make: "Krei koloraron"
-  addConstant: "Aldoni konstanton"
-  constant: "Konstanto"
-  keys:
-    shadow: "Ombro"
-    infoBg: "Fono de informo"
-_widgets:
-  photos: "Fotoj"
-_cw:
-  chars: "{count} literoj"
-_poll:
-  expiration: "Limtempo"
-_pages:
-  script:
-    blocks:
-      _add:
-        arg1: "A"
-        arg2: "B"
-      _subtract:
-        arg1: "A"
-        arg2: "B"
-      _multiply:
-        arg1: "A"
-        arg2: "B"
-      _divide:
-        arg1: "A"
-        arg2: "B"
-      _mod:
-        arg1: "A"
-        arg2: "B"
-      _eq:
-        arg1: "A"
-        arg2: "B"
-      _notEq:
-        arg1: "A"
-        arg2: "B"
-      _and:
-        arg1: "A"
-        arg2: "B"
-      _or:
-        arg1: "A"
-        arg2: "B"
-      _lt:
-        arg1: "A"
-        arg2: "B"
-      _gt:
-        arg1: "A"
-        arg2: "B"
-      _ltEq:
-        arg1: "A"
-        arg2: "B"
-      _gtEq:
-        arg1: "A"
-        arg2: "B"
-_notification:
-  _types:
-    pollEnded: "Enketo finiĝis"
diff --git a/locales/index.js b/locales/index.js
index b271b79b7..98c30fe01 100644
--- a/locales/index.js
+++ b/locales/index.js
@@ -19,7 +19,6 @@ const languages = [
 	'da-DK',
 	'de-DE',
 	'en-US',
-	'eo-UY',
 	'es-ES',
 	'fr-FR',
 	'id-ID',

From 3658f19d9800f331b3331080ac700dbae5db987a Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 23 Apr 2022 19:54:09 +0900
Subject: [PATCH 5/5] 12.110.1

---
 CHANGELOG.md | 6 ++++++
 package.json | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 211710134..dff67b40d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,12 @@
 You should also include the user name that made the change.
 -->
 
+## 12.110.1 (2022/04/23)
+
+### Bugfixes
+- Fix GOP rendering @syuilo
+- Improve performance of antenna, clip, and list @xianon
+
 ## 12.110.0 (2022/04/11)
 
 ### Improvements
diff --git a/package.json b/package.json
index 13d70929b..606e2b733 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "12.110.0",
+	"version": "12.110.1",
 	"codename": "indigo",
 	"repository": {
 		"type": "git",