From e1846e2e6aa5fb270a15275bffcd917c490df523 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 08:17:00 +0900
Subject: [PATCH 01/11] :art:

---
 packages/frontend/src/components/MkInstanceStats.vue | 4 ++--
 packages/frontend/src/pages/about.vue                | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/packages/frontend/src/components/MkInstanceStats.vue b/packages/frontend/src/components/MkInstanceStats.vue
index 3500a340a8..382aaf16ef 100644
--- a/packages/frontend/src/components/MkInstanceStats.vue
+++ b/packages/frontend/src/components/MkInstanceStats.vue
@@ -31,7 +31,7 @@
 				</MkSelect>
 			</div>
 			<div class="chart _panel">
-				<MkChart :src="chartSrc" :span="chartSpan" :limit="chartLimit" :detailed="detailed"></MkChart>
+				<MkChart :src="chartSrc" :span="chartSpan" :limit="chartLimit" :detailed="true"></MkChart>
 			</div>
 		</div>
 	</MkFolder>
@@ -122,7 +122,7 @@ Chart.register(
 	Filler,
 );
 
-const chartLimit = 90;
+const chartLimit = 500;
 let chartSpan = $ref<'hour' | 'day'>('hour');
 let chartSrc = $ref('active-users');
 let heatmapSrc = $ref('active-users');
diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue
index 0ed692c5c5..5091114c21 100644
--- a/packages/frontend/src/pages/about.vue
+++ b/packages/frontend/src/pages/about.vue
@@ -76,7 +76,7 @@
 		<XFederation/>
 	</MkSpacer>
 	<MkSpacer v-else-if="tab === 'charts'" :content-max="1000" :margin-min="20">
-		<MkInstanceStats :chart-limit="500" :detailed="true"/>
+		<MkInstanceStats/>
 	</MkSpacer>
 </MkStickyContainer>
 </template>

From fcfcb8da1df5dfbbafb41b971b92e366c21b1f33 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 08:18:58 +0900
Subject: [PATCH 02/11] 13.0.0-beta.9

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index bb1892b4a2..3a914e6ae9 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "13.0.0-beta.8",
+	"version": "13.0.0-beta.9",
 	"codename": "indigo",
 	"repository": {
 		"type": "git",

From b2d6561bc6ed2e15f1c66a879ad1eadbffcbee8f Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 08:43:13 +0900
Subject: [PATCH 03/11] enhance(server): clean emoji response

---
 CHANGELOG.md                                  |   5 +
 .../backend/src/core/CustomEmojiService.ts    | 132 ------------------
 .../src/core/entities/EmojiEntityService.ts   |   6 +-
 .../src/core/entities/NoteEntityService.ts    |   5 +-
 .../entities/NotificationEntityService.ts     |   4 +-
 .../src/core/entities/UserEntityService.ts    |   1 -
 packages/backend/src/models/schema/note.ts    |  18 ---
 packages/backend/src/models/schema/user.ts    |  19 ---
 .../backend/src/server/api/endpoints/meta.ts  |   3 +-
 .../components/MkReactionsViewer.reaction.vue |   1 -
 packages/frontend/src/instance.ts             |   1 -
 11 files changed, 9 insertions(+), 186 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 499d087cb3..26ff198ebd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,11 @@ You should also include the user name that made the change.
 - 新たに動的なPagesを作ることはできなくなりました
 	- 代わりに今後AiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能の実装を予定しています。
 - iOS15以下のデバイスはサポートされなくなりました
+- API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました
+	- 絵文字画像を表示するには、`<instance host>/emoji/<emoji name>.webp`にリクエストすると画像が返ります。
+	- e.g. `https://p1.a9z.dev/emoji/misskey.webp`
+	- remote: `https://p1.a9z.dev/emoji/syuilo_birth_present@mk.f72u.net.webp`
+- API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました
 
 ### Improvements
 - Push notification of Antenna note @tamaina
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index f0be952612..18b4067f61 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -1,29 +1,14 @@
 import { Inject, Injectable } from '@nestjs/common';
 import { DataSource, In, IsNull } from 'typeorm';
-import { GlobalEventService } from '@/core/GlobalEventService.js';
 import { DI } from '@/di-symbols.js';
 import { IdService } from '@/core/IdService.js';
 import type { DriveFile } from '@/models/entities/DriveFile.js';
 import type { Emoji } from '@/models/entities/Emoji.js';
-import { Cache } from '@/misc/cache.js';
-import type { Note } from '@/models/entities/Note.js';
 import type { EmojisRepository } from '@/models/index.js';
-import { UtilityService } from '@/core/UtilityService.js';
-import { ReactionService } from '@/core/ReactionService.js';
 import { bindThis } from '@/decorators.js';
 
-/**
- * 添付用絵文字情報
- */
-type PopulatedEmoji = {
-	name: string;
-	url: string;
-};
-
 @Injectable()
 export class CustomEmojiService {
-	private cache: Cache<Emoji | null>;
-
 	constructor(
 		@Inject(DI.db)
 		private db: DataSource,
@@ -32,11 +17,7 @@ export class CustomEmojiService {
 		private emojisRepository: EmojisRepository,
 
 		private idService: IdService,
-		private globalEventServie: GlobalEventService,
-		private utilityService: UtilityService,
-		private reactionService: ReactionService,
 	) {
-		this.cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
 	}
 
 	@bindThis
@@ -63,117 +44,4 @@ export class CustomEmojiService {
 
 		return emoji;
 	}
-	
-	@bindThis
-	private normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
-	// クエリに使うホスト
-		let host = src === '.' ? null	// .はローカルホスト (ここがマッチするのはリアクションのみ)
-			: src === undefined ? noteUserHost	// ノートなどでホスト省略表記の場合はローカルホスト (ここがリアクションにマッチすることはない)
-			: this.utilityService.isSelfHost(src) ? null	// 自ホスト指定
-			: (src || noteUserHost);	// 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない)
-
-		host = this.utilityService.toPunyNullable(host);
-
-		return host;
-	}
-
-	@bindThis
-	private parseEmojiStr(emojiName: string, noteUserHost: string | null) {
-		const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/);
-		if (!match) return { name: null, host: null };
-
-		const name = match[1];
-
-		// ホスト正規化
-		const host = this.utilityService.toPunyNullable(this.normalizeHost(match[2], noteUserHost));
-
-		return { name, host };
-	}
-
-	/**
- * 添付用絵文字情報を解決する
- * @param emojiName ノートやユーザープロフィールに添付された、またはリアクションのカスタム絵文字名 (:は含めない, リアクションでローカルホストの場合は@.を付ける (これはdecodeReactionで可能))
- * @param noteUserHost ノートやユーザープロフィールの所有者のホスト
- * @returns 絵文字情報, nullは未マッチを意味する
- */
-	@bindThis
-	public async populateEmoji(emojiName: string, noteUserHost: string | null): Promise<PopulatedEmoji | null> {
-		const { name, host } = this.parseEmojiStr(emojiName, noteUserHost);
-		if (name == null) return null;
-
-		const queryOrNull = async () => (await this.emojisRepository.findOneBy({
-			name,
-			host: host ?? IsNull(),
-		})) ?? null;
-
-		const emoji = await this.cache.fetch(`${name} ${host}`, queryOrNull);
-
-		if (emoji == null) return null;
-
-		const isLocal = emoji.host == null;
-		// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
-		const emojiUrl = emoji.publicUrl || emoji.originalUrl;
-		const url = emojiUrl;
-
-		return {
-			name: emojiName,
-			url,
-		};
-	}
-
-	/**
- * 複数の添付用絵文字情報を解決する (キャシュ付き, 存在しないものは結果から除外される)
- */
-	@bindThis
-	public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<PopulatedEmoji[]> {
-		const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
-		return emojis.filter((x): x is PopulatedEmoji => x != null);
-	}
-
-	@bindThis
-	public aggregateNoteEmojis(notes: Note[]) {
-		let emojis: { name: string | null; host: string | null; }[] = [];
-		for (const note of notes) {
-			emojis = emojis.concat(note.emojis
-				.map(e => this.parseEmojiStr(e, note.userHost)));
-			if (note.renote) {
-				emojis = emojis.concat(note.renote.emojis
-					.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
-				if (note.renote.user) {
-					emojis = emojis.concat(note.renote.user.emojis
-						.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
-				}
-			}
-			const customReactions = Object.keys(note.reactions).map(x => this.reactionService.decodeReaction(x)).filter(x => x.name != null) as typeof emojis;
-			emojis = emojis.concat(customReactions);
-			if (note.user) {
-				emojis = emojis.concat(note.user.emojis
-					.map(e => this.parseEmojiStr(e, note.userHost)));
-			}
-		}
-		return emojis.filter(x => x.name != null) as { name: string; host: string | null; }[];
-	}
-
-	/**
- * 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します
- */
-	@bindThis
-	public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> {
-		const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null);
-		const emojisQuery: any[] = [];
-		const hosts = new Set(notCachedEmojis.map(e => e.host));
-		for (const host of hosts) {
-			emojisQuery.push({
-				name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)),
-				host: host ?? IsNull(),
-			});
-		}
-		const _emojis = emojisQuery.length > 0 ? await this.emojisRepository.find({
-			where: emojisQuery,
-			select: ['name', 'host', 'originalUrl', 'publicUrl'],
-		}) : [];
-		for (const emoji of _emojis) {
-			this.cache.set(`${emoji.name} ${emoji.host}`, emoji);
-		}
-	}
 }
diff --git a/packages/backend/src/core/entities/EmojiEntityService.ts b/packages/backend/src/core/entities/EmojiEntityService.ts
index f1c7ee9035..8a2dc70eda 100644
--- a/packages/backend/src/core/entities/EmojiEntityService.ts
+++ b/packages/backend/src/core/entities/EmojiEntityService.ts
@@ -22,7 +22,6 @@ export class EmojiEntityService {
 	@bindThis
 	public async pack(
 		src: Emoji['id'] | Emoji,
-		opts: { omitUrl?: boolean } = {},
 	): Promise<Packed<'Emoji'>> {
 		const emoji = typeof src === 'object' ? src : await this.emojisRepository.findOneByOrFail({ id: src });
 
@@ -32,17 +31,14 @@ export class EmojiEntityService {
 			name: emoji.name,
 			category: emoji.category,
 			host: emoji.host,
-			// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
-			url: opts.omitUrl ? undefined : (emoji.publicUrl || emoji.originalUrl),
 		};
 	}
 
 	@bindThis
 	public packMany(
 		emojis: any[],
-		opts: { omitUrl?: boolean } = {},
 	) {
-		return Promise.all(emojis.map(x => this.pack(x, opts)));
+		return Promise.all(emojis.map(x => this.pack(x)));
 	}
 }
 
diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts
index 73d3184957..2b179643f3 100644
--- a/packages/backend/src/core/entities/NoteEntityService.ts
+++ b/packages/backend/src/core/entities/NoteEntityService.ts
@@ -11,12 +11,12 @@ import type { User } from '@/models/entities/User.js';
 import type { Note } from '@/models/entities/Note.js';
 import type { NoteReaction } from '@/models/entities/NoteReaction.js';
 import type { UsersRepository, NotesRepository, FollowingsRepository, PollsRepository, PollVotesRepository, NoteReactionsRepository, ChannelsRepository, DriveFilesRepository } from '@/models/index.js';
+import { bindThis } from '@/decorators.js';
 import type { OnModuleInit } from '@nestjs/common';
 import type { CustomEmojiService } from '../CustomEmojiService.js';
 import type { ReactionService } from '../ReactionService.js';
 import type { UserEntityService } from './UserEntityService.js';
 import type { DriveFileEntityService } from './DriveFileEntityService.js';
-import { bindThis } from '@/decorators.js';
 
 @Injectable()
 export class NoteEntityService implements OnModuleInit {
@@ -300,7 +300,6 @@ export class NoteEntityService implements OnModuleInit {
 			repliesCount: note.repliesCount,
 			reactions: this.reactionService.convertLegacyReactions(note.reactions),
 			tags: note.tags.length > 0 ? note.tags : undefined,
-			emojis: this.customEmojiService.populateEmojis(note.emojis.concat(reactionEmojiNames), host),
 			fileIds: note.fileIds,
 			files: this.driveFileEntityService.packMany(note.fileIds),
 			replyId: note.replyId,
@@ -385,8 +384,6 @@ export class NoteEntityService implements OnModuleInit {
 			}
 		}
 
-		await this.customEmojiService.prefetchEmojis(this.customEmojiService.aggregateNoteEmojis(notes));
-
 		return await Promise.all(notes.map(n => this.pack(n, me, {
 			...options,
 			_hint_: {
diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts
index 346faae6b0..208d653877 100644
--- a/packages/backend/src/core/entities/NotificationEntityService.ts
+++ b/packages/backend/src/core/entities/NotificationEntityService.ts
@@ -8,12 +8,12 @@ import type { Notification } from '@/models/entities/Notification.js';
 import type { NoteReaction } from '@/models/entities/NoteReaction.js';
 import type { Note } from '@/models/entities/Note.js';
 import type { Packed } from '@/misc/schema.js';
+import { bindThis } from '@/decorators.js';
 import type { OnModuleInit } from '@nestjs/common';
 import type { CustomEmojiService } from '../CustomEmojiService.js';
 import type { UserEntityService } from './UserEntityService.js';
 import type { NoteEntityService } from './NoteEntityService.js';
 import type { UserGroupInvitationEntityService } from './UserGroupInvitationEntityService.js';
-import { bindThis } from '@/decorators.js';
 
 @Injectable()
 export class NotificationEntityService implements OnModuleInit {
@@ -143,8 +143,6 @@ export class NotificationEntityService implements OnModuleInit {
 			myReactionsMap.set(target, myReactions.find(reaction => reaction.noteId === target) ?? null);
 		}
 
-		await this.customEmojiService.prefetchEmojis(this.customEmojiService.aggregateNoteEmojis(notes));
-
 		return await Promise.all(notifications.map(x => this.pack(x, {
 			_hintForEachNotes_: {
 				myReactions: myReactionsMap,
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index 4a027d1de6..1fafbd4f13 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -408,7 +408,6 @@ export class UserEntityService implements OnModuleInit {
 				faviconUrl: instance.faviconUrl,
 				themeColor: instance.themeColor,
 			} : undefined) : undefined,
-			emojis: this.customEmojiService.populateEmojis(user.emojis, user.host),
 			onlineStatus: this.getOnlineStatus(user),
 			driveCapacityOverrideMb: user.driveCapacityOverrideMb,
 
diff --git a/packages/backend/src/models/schema/note.ts b/packages/backend/src/models/schema/note.ts
index 7cc70cdeaf..72c0c62285 100644
--- a/packages/backend/src/models/schema/note.ts
+++ b/packages/backend/src/models/schema/note.ts
@@ -141,24 +141,6 @@ export const packedNoteSchema = {
 			type: 'boolean',
 			optional: true, nullable: false,
 		},
-		emojis: {
-			type: 'array',
-			optional: false, nullable: false,
-			items: {
-				type: 'object',
-				optional: false, nullable: false,
-				properties: {
-					name: {
-						type: 'string',
-						optional: false, nullable: false,
-					},
-					url: {
-						type: 'string',
-						optional: false, nullable: true,
-					},
-				},
-			},
-		},
 		reactions: {
 			type: 'object',
 			optional: false, nullable: false,
diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts
index 1c8fe97858..dd549ad0d1 100644
--- a/packages/backend/src/models/schema/user.ts
+++ b/packages/backend/src/models/schema/user.ts
@@ -55,25 +55,6 @@ export const packedUserLiteSchema = {
 			type: 'boolean',
 			nullable: false, optional: true,
 		},
-		emojis: {
-			type: 'array',
-			nullable: false, optional: false,
-			items: {
-				type: 'object',
-				nullable: false, optional: false,
-				properties: {
-					name: {
-						type: 'string',
-						nullable: false, optional: false,
-					},
-					url: {
-						type: 'string',
-						nullable: false, optional: false,
-						format: 'url',
-					},
-				},
-			},
-		},
 		onlineStatus: {
 			type: 'string',
 			format: 'url',
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 66c9f0620a..05da011979 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -309,7 +309,6 @@ export const paramDef = {
 	type: 'object',
 	properties: {
 		detail: { type: 'boolean', default: true },
-		omitEmojiUrl: { type: 'boolean', default: false },
 	},
 	required: [],
 } as const;
@@ -391,7 +390,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
 				backgroundImageUrl: instance.backgroundImageUrl,
 				logoImageUrl: instance.logoImageUrl,
 				maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, // 後方互換性のため
-				emojis: await this.emojiEntityService.packMany(emojis, { omitUrl: ps.omitEmojiUrl }),
+				emojis: await this.emojiEntityService.packMany(emojis),
 				defaultLightTheme: instance.defaultLightTheme,
 				defaultDarkTheme: instance.defaultDarkTheme,
 				ads: ads.map(ad => ({
diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
index 8f2f48dcd7..f3c77231db 100644
--- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
@@ -81,7 +81,6 @@ useTooltip(buttonRef, async (showing) => {
 	os.popup(XDetails, {
 		showing,
 		reaction: props.reaction,
-		emojis: props.note.emojis,
 		users,
 		count: props.count,
 		targetElement: buttonRef.value,
diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts
index c6fd1756a5..51464f32fb 100644
--- a/packages/frontend/src/instance.ts
+++ b/packages/frontend/src/instance.ts
@@ -15,7 +15,6 @@ export const instance: Misskey.entities.InstanceMetadata = reactive(instanceData
 export async function fetchInstance() {
 	const meta = await api('meta', {
 		detail: false,
-		omitEmojiUrl: true,
 	});
 
 	for (const [k, v] of Object.entries(meta)) {

From 7157fd663c0b3c2a6a3e08fbed22df0871053698 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 08:46:27 +0900
Subject: [PATCH 04/11] =?UTF-8?q?fix(server):=20driveCapacityOverrideMb?=
 =?UTF-8?q?=E3=81=8C=E5=85=AC=E9=96=8B=E6=83=85=E5=A0=B1=E3=81=AB=E3=81=AA?=
 =?UTF-8?q?=E3=81=A3=E3=81=A6=E3=81=84=E3=82=8B=E3=81=AE=E3=82=92=E4=BF=AE?=
 =?UTF-8?q?=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/backend/src/core/entities/UserEntityService.ts | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index 1fafbd4f13..3f75755496 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -409,7 +409,6 @@ export class UserEntityService implements OnModuleInit {
 				themeColor: instance.themeColor,
 			} : undefined) : undefined,
 			onlineStatus: this.getOnlineStatus(user),
-			driveCapacityOverrideMb: user.driveCapacityOverrideMb,
 
 			...(opts.detail ? {
 				url: profile!.url,
@@ -446,6 +445,9 @@ export class UserEntityService implements OnModuleInit {
 						userId: user.id,
 					}).then(result => result >= 1)
 					: false,
+				...(isMe || opts.includeSecrets ? {
+					driveCapacityOverrideMb: user.driveCapacityOverrideMb,
+				} : {}),
 			} : {}),
 
 			...(opts.detail && isMe ? {

From 6f648fc058640d49952a72685bbfad9e6e591c58 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 08:51:35 +0900
Subject: [PATCH 05/11] clean up

---
 CHANGELOG.md                                           |  1 +
 .../backend/src/core/entities/UserEntityService.ts     |  2 --
 packages/backend/src/models/schema/user.ts             | 10 ----------
 3 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 26ff198ebd..550a5fcf95 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@ You should also include the user name that made the change.
 	- e.g. `https://p1.a9z.dev/emoji/misskey.webp`
 	- remote: `https://p1.a9z.dev/emoji/syuilo_birth_present@mk.f72u.net.webp`
 - API: `user`および`note`エンティティに`emojis`プロパティが含まれなくなりました
+- API: `user`エンティティに`avatarColor`および`bannerColor`プロパティが含まれなくなりました
 
 ### Improvements
 - Push notification of Antenna note @tamaina
diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts
index 3f75755496..a123746220 100644
--- a/packages/backend/src/core/entities/UserEntityService.ts
+++ b/packages/backend/src/core/entities/UserEntityService.ts
@@ -392,7 +392,6 @@ export class UserEntityService implements OnModuleInit {
 			host: user.host,
 			avatarUrl: this.getAvatarUrlSync(user),
 			avatarBlurhash: user.avatar?.blurhash ?? null,
-			avatarColor: null, // 後方互換性のため
 			isAdmin: user.isAdmin ?? falsy,
 			isModerator: user.isModerator ?? falsy,
 			isBot: user.isBot ?? falsy,
@@ -418,7 +417,6 @@ export class UserEntityService implements OnModuleInit {
 				lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
 				bannerUrl: user.banner ? this.driveFileEntityService.getPublicUrl(user.banner, false) : null,
 				bannerBlurhash: user.banner?.blurhash ?? null,
-				bannerColor: null, // 後方互換性のため
 				isLocked: user.isLocked,
 				isSilenced: user.isSilenced ?? falsy,
 				isSuspended: user.isSuspended ?? falsy,
diff --git a/packages/backend/src/models/schema/user.ts b/packages/backend/src/models/schema/user.ts
index dd549ad0d1..aac5e9332c 100644
--- a/packages/backend/src/models/schema/user.ts
+++ b/packages/backend/src/models/schema/user.ts
@@ -32,11 +32,6 @@ export const packedUserLiteSchema = {
 			type: 'any',
 			nullable: true, optional: false,
 		},
-		avatarColor: {
-			type: 'any',
-			nullable: true, optional: false,
-			default: null,
-		},
 		isAdmin: {
 			type: 'boolean',
 			nullable: false, optional: true,
@@ -101,11 +96,6 @@ export const packedUserDetailedNotMeOnlySchema = {
 			type: 'any',
 			nullable: true, optional: false,
 		},
-		bannerColor: {
-			type: 'any',
-			nullable: true, optional: false,
-			default: null,
-		},
 		isLocked: {
 			type: 'boolean',
 			nullable: false, optional: false,

From 51d8d2abbfe8fc9cef42b5ef6598243c5e7c5926 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 09:12:42 +0900
Subject: [PATCH 06/11] cache emoji response

---
 .../backend/src/server/web/ClientServerService.ts  | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 02b779d741..7206653a44 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -228,6 +228,8 @@ export class ClientServerService {
 				return;
 			}
 
+			reply.header('Cache-Control', 'public, max-age=3600');
+
 			const name = path.split('@')[0].replace('.webp', '');
 			const host = path.split('@')[1]?.replace('.webp', '');
 
@@ -244,7 +246,7 @@ export class ClientServerService {
 
 			reply.header('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\'');
 
-			const url = new URL("/proxy/emoji.webp", this.config.url);
+			const url = new URL('/proxy/emoji.webp', this.config.url);
 			// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
 			url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
 			url.searchParams.set('emoji', '1');
@@ -347,15 +349,15 @@ export class ClientServerService {
 		fastify.get('/opensearch.xml', async (request, reply) => {
 			const meta = await this.metaService.fetch();
 
-			const name = meta.name || "Misskey";
-			let content = "";
-			content += `<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">`;
+			const name = meta.name || 'Misskey';
+			let content = '';
+			content += '<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">';
 			content += `<ShortName>${name} Search</ShortName>`;
 			content += `<Description>${name} Search</Description>`;
-			content += `<InputEncoding>UTF-8</InputEncoding>`;
+			content += '<InputEncoding>UTF-8</InputEncoding>';
 			content += `<Image width="16" height="16" type="image/x-icon">${this.config.url}/favicon.ico</Image>`;
 			content += `<Url type="text/html" template="${this.config.url}/search?q={searchTerms}"/>`;
-			content += `</OpenSearchDescription>`;
+			content += '</OpenSearchDescription>';
 
 			reply.header('Content-Type', 'application/opensearchdescription+xml');
 			return await reply.send(content);

From 61408652521d4b9020fd54cd748d69d876fc03ee Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 09:14:53 +0900
Subject: [PATCH 07/11] tweak max-age

---
 packages/backend/src/server/web/ClientServerService.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 7206653a44..7ef178403b 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -228,7 +228,7 @@ export class ClientServerService {
 				return;
 			}
 
-			reply.header('Cache-Control', 'public, max-age=3600');
+			reply.header('Cache-Control', 'public, max-age=86400');
 
 			const name = path.split('@')[0].replace('.webp', '');
 			const host = path.split('@')[1]?.replace('.webp', '');

From ced29ceed12c4d389223dadab61f900e6450e898 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 09:20:36 +0900
Subject: [PATCH 08/11] New Crowdin updates (#9421)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Slovak)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Thai)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Slovak)
---
 locales/de-DE.yml |  2 ++
 locales/en-US.yml |  2 ++
 locales/ja-KS.yml |  7 +++++++
 locales/ko-KR.yml |  1 +
 locales/pl-PL.yml | 15 +++++++++++++++
 locales/sk-SK.yml |  6 ++++++
 locales/th-TH.yml |  8 +++++---
 locales/uk-UA.yml | 25 +++++++++++++++++++++++++
 locales/zh-CN.yml |  1 +
 locales/zh-TW.yml |  2 ++
 10 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 67ddd9fded..3ecfaa0563 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -914,6 +914,8 @@ windowMaximize: "Maximieren"
 windowRestore: "Wiederherstellen"
 caption: "Beschreibung"
 loggedInAsBot: "Momentan als Bot angemeldet"
+tools: "Werkzeuge"
+cannotLoad: "Kann nicht geladen werden"
 _sensitiveMediaDetection:
   description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
   sensitivity: "Erkennungssensitivität"
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 98b094d66a..ecdd8492ee 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -914,6 +914,8 @@ windowMaximize: "Maximize"
 windowRestore: "Restore"
 caption: "Caption"
 loggedInAsBot: "Currently logged in as bot"
+tools: "Tools"
+cannotLoad: "Unable to load"
 _sensitiveMediaDetection:
   description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
   sensitivity: "Detection sensitivity"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 7d53fc0b70..994fe9a195 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -49,6 +49,7 @@ deleteAndEdit: "ほかして直す"
 deleteAndEditConfirm: "このノートをほかして書き直すんか?このノートへのリアクション、Renote、返信も全部消えてまうで。"
 addToList: "リストに入れたる"
 sendMessage: "メッセージを送る"
+copyRSS: "RSSをコピー"
 copyUsername: "ユーザー名をコピー"
 searchUser: "ユーザーを検索"
 reply: "返事"
@@ -456,6 +457,8 @@ language: "言語"
 uiLanguage: "UIの表示言語"
 groupInvited: "グループに招待されとるで"
 aboutX: "{x}について"
+emojiStyle: "絵文字のスタイル"
+native: "ネイティブ"
 disableDrawer: "メニューをドロワーで表示せぇへん"
 youHaveNoGroups: "グループがあらへんねぇ。"
 joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループ作ってからやってな"
@@ -714,6 +717,7 @@ accentColor: "アクセント"
 textColor: "文字"
 saveAs: "名前を付けて保存"
 advanced: "高度"
+advancedSettings: "高度な設定"
 value: "値"
 createdAt: "作成した日"
 updatedAt: "更新日時"
@@ -910,6 +914,8 @@ windowMaximize: "最大化"
 windowRestore: "元に戻す"
 caption: "キャプション"
 loggedInAsBot: "Botアカウントでログイン中やで"
+tools: "ツール"
+cannotLoad: "読み込めへんで"
 _sensitiveMediaDetection:
   description: "機械学習を使って自動でセンシティブなメディアを検出して、モデレーションに役立てることができるで。サーバーの負荷が少し増えてまうなあ。"
   sensitivity: "検出感度やで"
@@ -1310,6 +1316,7 @@ _widgets:
   serverMetric: "サーバーメトリクス"
   aiscript: "AiScriptコンソール"
   aichan: "藍"
+  userList: "ユーザーリスト"
   _userList:
     chooseList: "リストを選ぶ"
 _cw:
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index 7fe0d9b664..ae92a8c016 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -717,6 +717,7 @@ accentColor: "강조 색상"
 textColor: "문자 색"
 saveAs: "다른 이름으로 저장"
 advanced: "고급"
+advancedSettings: "고급 설정"
 value: "값"
 createdAt: "생성된 날짜"
 updatedAt: "수정한 날짜"
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index e63888dbf5..6c3b100885 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -2,6 +2,7 @@
 _lang_: "Polski"
 headlineMisskey: "Sieć połączona wpisami"
 introMisskey: "Misskey jest serwisem mikroblogowym typu open source.\nMisskey to opensource'owy serwis mikroblogowy, w którym możesz tworzyć \"notatki\", aby dzielić się tym, co się dzieje i opowiadać wszystkim o sobie.\nMożesz również użyć funkcji \"Reakcje\", aby szybko dodać własne reakcje do notatek innych użytkowników👍.\nOdkrywaj nowy świat🚀!"
+poweredByMisskeyDescription: "{name} jest jedną z usług działającą na otwartoźródłowej platformie <b>Misskey</b> (określana jako \"instancja Misskey\")."
 monthAndDay: "{month}-{day}"
 search: "Szukaj"
 notifications: "Powiadomienia"
@@ -48,6 +49,7 @@ deleteAndEdit: "Usuń i edytuj"
 deleteAndEditConfirm: "Czy na pewno chcesz usunąć ten wpis i zedytować go? Utracisz wszystkie reakcje, udostępnienia i odpowiedzi do tego wpisu."
 addToList: "Dodaj do listy"
 sendMessage: "Wyślij wiadomość"
+copyRSS: "Kopiuj RSS"
 copyUsername: "Kopiuj nazwę użytkownika"
 searchUser: "Wyszukiwanie użytkowników"
 reply: "Odpowiedz"
@@ -346,6 +348,8 @@ recaptcha: "reCAPTCHA"
 enableRecaptcha: "Włącz reCAPTCHA"
 recaptchaSiteKey: "Klucz strony"
 recaptchaSecretKey: "Tajny klucz"
+turnstile: "Turnstile"
+enableTurnstile: "Włącz Turnstile"
 turnstileSiteKey: "Klucz strony"
 turnstileSecretKey: "Tajny klucz"
 avoidMultiCaptchaConfirm: "Używanie wielu Captchy może spowodować zakłócenia. Czy chcesz wyłączyć inną Captchę? Możesz zostawić wiele jednocześnie, klikając Anuluj."
@@ -450,6 +454,8 @@ language: "Język"
 uiLanguage: "Język wyświetlania UI"
 groupInvited: "Zaproszony(-a) do grupy"
 aboutX: "O {x}"
+emojiStyle: "Styl emoji"
+native: "Natywny"
 disableDrawer: "Nie używaj menu w stylu szuflady"
 youHaveNoGroups: "Nie masz żadnych grup"
 joinOrCreateGroup: "Uzyskaj zaproszenie do dołączenia do grupy lub utwórz własną grupę."
@@ -824,7 +830,16 @@ size: "Rozmiar"
 numberOfColumn: "Liczba kolumn"
 searchByGoogle: "Szukaj"
 indefinitely: "Nigdy"
+tenMinutes: "10 minut"
+oneHour: "1 godzina"
+oneDay: "1 dzień"
+oneWeek: "1 tydzień"
 file: "Pliki"
+recommended: "Zalecane"
+check: "Zweryfikuj"
+deleteAccount: "Usuń konto"
+document: "Dokumentacja"
+numberOfPageCache: "Ilość stron w cache"
 logoutConfirm: "Czy na pewno chcesz się wylogować?"
 lastActiveDate: "Ostatnio użyte w"
 statusbar: "Pasek stanu"
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 5c921669f2..03a531e63b 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -49,6 +49,7 @@ deleteAndEdit: "Odstrániť a upraviť"
 deleteAndEditConfirm: "Naozaj chcete odstrániť túto poznámku a upraviť ju? Stratíte tým všetky reakcie a odpovede na ňu."
 addToList: "Pridať do zoznamu"
 sendMessage: "Odoslať správu"
+copyRSS: "Kopírovať RSS"
 copyUsername: "Kopírovať meno používateľa"
 searchUser: "Hľadať používateľov"
 reply: "Odpovedať"
@@ -456,6 +457,8 @@ language: "Jazyk"
 uiLanguage: "Jazyk používateľského prostredia"
 groupInvited: "Pozvať do skupiny"
 aboutX: "O {x}"
+emojiStyle: "Štýl emoji"
+native: "Natívne"
 disableDrawer: "Nepoužívať šuflíkové menu"
 youHaveNoGroups: "Nemáte žiadne skupiny"
 joinOrCreateGroup: "Požiadajte o pozvanie do existujúcej skupiny alebo vytvorte novú."
@@ -713,6 +716,7 @@ accentColor: "Akcent"
 textColor: "Text"
 saveAs: "Uložiť ako..."
 advanced: "Rozšírené"
+advancedSettings: "Rozšírené nastavenia"
 value: "Hodnoty"
 createdAt: "Vytvorené"
 updatedAt: "Upravené"
@@ -906,6 +910,8 @@ sendPushNotificationReadMessageCaption: "Na chvíľu sa zobrazí oznámenie \"{e
 windowMaximize: "Maximalizovať"
 windowRestore: "Obnoviť"
 caption: "Nadpis"
+tools: "Nástroje"
+cannotLoad: "Nedá sa načítať."
 _sensitiveMediaDetection:
   description: "Strojové učenie sa použije na automatickú detekciu citlivých médií na účely ich moderovania. Mierne sa zvýši zaťaženie servera."
   sensitivity: "Citlivosť detekcie"
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index 6f5a2511d0..d2b408dc4c 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -164,7 +164,7 @@ host: "โฮสต์"
 selectUser: "เลือกผู้ใช้งาน"
 recipient: "ผู้รับ"
 annotation: "ความคิดเห็น"
-federation: "สหพันธ์"
+federation: "เฟดิเวิร์ส"
 instances: "ตัวอย่าง"
 registeredAt: "จดทะเบียนที่"
 latestRequestSentAt: "ส่งคำขอล่าสุดไปแล้ว"
@@ -228,10 +228,10 @@ newPassword: "รหัสผ่านใหม่"
 newPasswordRetype: "ใส่รหัสผ่านใหม่อีกครั้ง"
 attachFile: "แนบไฟล์"
 more: "เพิ่มเติม!"
-featured: "เป็นจุดเด่น"
+featured: "ไฮไลท์"
 usernameOrUserId: "ชื่อผู้ใช้หรือรหัสผู้ใช้งาน"
 noSuchUser: "ไม่มีผู้ใช้นี้อยู่ในระบบ"
-lookup: "ค้นหา"
+lookup: "การค้นหา"
 announcements: "ประกาศ"
 imageUrl: "url รูปภาพ"
 remove: "ลบ"
@@ -914,6 +914,8 @@ windowMaximize: "ขยายใหญ่สุดแล้ว"
 windowRestore: "เลิกทำ"
 caption: "รายละเอียด"
 loggedInAsBot: "ล็อกอินเป็นบอตอยู่ในขณะนี้"
+tools: "เครื่องมือ"
+cannotLoad: "ไม่สามารถโหลดได้"
 _sensitiveMediaDetection:
   description: "ลดความพยายามในการดูแลเซิร์ฟเวอร์ผ่านการจดจำสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่อง การทำสิ่งนี้อาจจะเพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
   sensitivity: "การตรวจจับความไว"
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index bf99f34c42..cb52a86d98 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -1019,6 +1019,8 @@ _mfm:
   font: "Шрифт"
   fontDescription: "Встановлює шрифт для контенту."
   rotate: "Обертати"
+  plain: "Звичайний"
+  plainDescription: "Деактивує всі ефекти MFM, що містяться в цьому ефекті MFM."
 _instanceTicker:
   none: "Не відображати"
   remote: "Відображати для віддалених користувачів"
@@ -1053,6 +1055,7 @@ _wordMute:
 _instanceMute:
   instanceMuteDescription2: "Розділяйте новими рядками"
   title: "Приховує нотатки з перелічених інстансів."
+  heading: "Список заглушених інстансів"
 _theme:
   explore: "Оглянути теми"
   install: "Встановити тему"
@@ -1070,7 +1073,10 @@ _theme:
   color: "Колір"
   key: "Ключ"
   func: "Функції"
+  funcKind: "Тип функції"
   argument: "Аргумент"
+  alpha: "Непрозорість"
+  darken: "Затемнення"
   lighten: "Яскравість"
   inputConstantName: "Введіть назву константи"
   importInfo: "Вставляючи сюди код теми, ви можете добавити її до редактору тем"
@@ -1165,10 +1171,17 @@ _tutorial:
   step7_1: "Вітаю! Ви пройшли ознайомлення з Misskey."
   step7_2: "Якщо ви хочете більше дізнатись про Misskey, зайдіть в розділ {help}."
   step7_3: "Насолоджуйтесь Misskey! 🚀"
+  step8_1: "Наостанку, чи бажаєте ви ввімкнути push-сповіщення?"
   step8_3: "Ви завжди можете змінити цей параметр пізніше."
 _2fa:
+  alreadyRegistered: "Двофакторна автентифікація вже налаштована."
   registerDevice: "Зареєструвати новий пристрій"
   registerKey: "Зареєструвати новий ключ безпеки"
+  step1: "Спершу встановіть на свій пристрій програму автентифікації (наприклад {a} або {b})."
+  step2: "Потім відскануйте QR-код, який відображається на цьому екрані."
+  step2Url: "Ви також можете ввести цю URL-адресу, якщо використовуєте програму для ПК:"
+  step3: "Щоб завершити налаштування, введіть токен, наданий вашою програмою."
+  step4: "Відтепер будь-які майбутні спроби входу вимагатимуть такого токена."
 _permissions:
   "read:account": "Переглядати дані профілю"
   "write:account": "Змінити дані акаунту"
@@ -1186,6 +1199,7 @@ _permissions:
   "write:mutes": "Змінювати список ігнорованих"
   "write:notes": "Писати і видаляти нотатки"
   "read:notifications": "Переглядати сповіщення"
+  "write:notifications": "Керування сповіщеннями"
   "read:reactions": "Переглядати реакції"
   "write:reactions": "Змінювати реакції"
   "write:votes": "Голосувати в опитуваннях"
@@ -1224,7 +1238,9 @@ _widgets:
   activity: "Активність"
   photos: "Фото"
   digitalClock: "Цифровий годинник"
+  unixClock: "Unix-годинник"
   federation: "Федіверс"
+  instanceCloud: "Хмара інстансів"
   postForm: "Створення нотатки"
   slideshow: "Слайд-шоу"
   button: "Кнопка"
@@ -1232,6 +1248,8 @@ _widgets:
   jobQueue: "Черга завдань"
   serverMetric: "Показники сервера "
   aiscript: "Консоль AiScript"
+  aichan: "Ai"
+  userList: "Список користувачів"
   _userList:
     chooseList: "Виберіть список"
 _cw:
@@ -1301,16 +1319,23 @@ _exportOrImport:
   muteList: "Ігнорувати"
   blockingList: "Заблокувати"
   userLists: "Списки"
+  excludeMutingUsers: "Виключити ігнорованих користувачів"
+  excludeInactiveUsers: "Виключити неактивних користувачів"
 _charts:
   federation: "Федіверс"
   apRequest: "Запити"
+  usersIncDec: "Зміни кількості користувачів"
   usersTotal: "Загальна кількість користувачів"
   activeUsers: "Активні користувачі"
+  notesIncDec: "Зміни кількості нотаток"
+  localNotesIncDec: "Зміни кількості локальних нотаток"
+  remoteNotesIncDec: "Зміни кількості віддалених нотаток"
   notesTotal: "Загальна кількість нотаток"
   filesIncDec: "Зміни кількості файлів"
   filesTotal: "Загальна кількість файлів"
 _instanceCharts:
   requests: "Запити"
+  users: "Зміни кількості користувачів"
   usersTotal: "Сумарна кількість користувачів"
   notes: "Різниця кількості зроблених записів"
   notesTotal: "Сумарна кількість нотаток"
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index d2a79ff566..e042fc2a20 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -914,6 +914,7 @@ windowMaximize: "最大化"
 windowRestore: "还原"
 caption: "标题"
 loggedInAsBot: "已登录的Bot"
+tools: "工具"
 _sensitiveMediaDetection:
   description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。"
   sensitivity: "检测敏感度"
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index 82a75fd98c..d78ecd2025 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -717,6 +717,7 @@ accentColor: "重點色彩"
 textColor: "文字"
 saveAs: "另存為..."
 advanced: "進階"
+advancedSettings: "進階設定"
 value: "數值"
 createdAt: "建立於"
 updatedAt: "最後更新"
@@ -913,6 +914,7 @@ windowMaximize: "最大化"
 windowRestore: "復原"
 caption: "標題"
 loggedInAsBot: "以機器人帳號登入中"
+tools: "工具"
 _sensitiveMediaDetection:
   description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
   sensitivity: "檢測敏感度"

From d52e8cfbc7767c274b1cba01d6a17942fe1bc1d3 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 09:25:15 +0900
Subject: [PATCH 09/11] 13.0.0-beta.10

---
 package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 3a914e6ae9..0fbbdf584a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "misskey",
-	"version": "13.0.0-beta.9",
+	"version": "13.0.0-beta.10",
 	"codename": "indigo",
 	"repository": {
 		"type": "git",

From cb237a04285757e4449a4875febc9256833d29d1 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 31 Dec 2022 13:18:27 +0900
Subject: [PATCH 10/11] :art:

---
 packages/frontend/src/components/MkRetentionHeatmap.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/frontend/src/components/MkRetentionHeatmap.vue b/packages/frontend/src/components/MkRetentionHeatmap.vue
index f8ae401faa..547fe70a8c 100644
--- a/packages/frontend/src/components/MkRetentionHeatmap.vue
+++ b/packages/frontend/src/components/MkRetentionHeatmap.vue
@@ -72,7 +72,7 @@ async function renderChart() {
 	const wide = rootEl.offsetWidth > 600;
 	const narrow = rootEl.offsetWidth < 400;
 
-	const maxDays = wide ? 20 : narrow ? 10 : 15;
+	const maxDays = wide ? 20 : narrow ? 7 : 14;
 
 	const raw = await os.api('retention', { });