mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 15:34:13 +00:00 
			
		
		
		
	add: Bot Trending Toggle, Hide Bot in Timeline client option
This commit is contained in:
		
							parent
							
								
									fa5cf36602
								
							
						
					
					
						commit
						c21d255604
					
				
					 19 changed files with 90 additions and 1 deletions
				
			
		
							
								
								
									
										16
									
								
								packages/backend/migration/1697603945000-BotTrending.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								packages/backend/migration/1697603945000-BotTrending.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
/*
 | 
			
		||||
 * SPDX-FileCopyrightText: syuilo and other misskey contributors
 | 
			
		||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export class BotTrending1697603945000 {
 | 
			
		||||
    name = 'BotTrending1697603945000'
 | 
			
		||||
 | 
			
		||||
    async up(queryRunner) {
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" ADD "enableBotTrending" boolean NOT NULL DEFAULT true`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async down(queryRunner) {
 | 
			
		||||
        await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableBotTrending"`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -511,7 +511,11 @@ export class NoteCreateService implements OnApplicationShutdown {
 | 
			
		|||
 | 
			
		||||
		// ハッシュタグ更新
 | 
			
		||||
		if (data.visibility === 'public' || data.visibility === 'home') {
 | 
			
		||||
			if (user.isBot && meta.enableBotTrending) {
 | 
			
		||||
				this.hashtagService.updateHashtags(user, tags);
 | 
			
		||||
			} else if (!user.isBot) {
 | 
			
		||||
				this.hashtagService.updateHashtags(user, tags);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Increment notes count (user)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -247,6 +247,11 @@ export class MiMeta {
 | 
			
		|||
	})
 | 
			
		||||
	public enableSensitiveMediaDetectionForVideos: boolean;
 | 
			
		||||
 | 
			
		||||
	@Column('boolean', {
 | 
			
		||||
		default: false,
 | 
			
		||||
	})
 | 
			
		||||
	public enableBotTrending: boolean;
 | 
			
		||||
 | 
			
		||||
	@Column('varchar', {
 | 
			
		||||
		length: 1024,
 | 
			
		||||
		nullable: true,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -178,6 +178,10 @@ export const meta = {
 | 
			
		|||
				type: 'boolean',
 | 
			
		||||
				optional: false, nullable: false,
 | 
			
		||||
			},
 | 
			
		||||
			enableBotTrending: {
 | 
			
		||||
				type: 'boolean',
 | 
			
		||||
				optional: false, nullable: false,
 | 
			
		||||
			},
 | 
			
		||||
			proxyAccountId: {
 | 
			
		||||
				type: 'string',
 | 
			
		||||
				optional: false, nullable: true,
 | 
			
		||||
| 
						 | 
				
			
			@ -391,6 +395,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity,
 | 
			
		||||
				setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically,
 | 
			
		||||
				enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos,
 | 
			
		||||
				enableBotTrending: instance.enableBotTrending,
 | 
			
		||||
				proxyAccountId: instance.proxyAccountId,
 | 
			
		||||
				summalyProxy: instance.summalyProxy,
 | 
			
		||||
				email: instance.email,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,7 @@ export const paramDef = {
 | 
			
		|||
		sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] },
 | 
			
		||||
		setSensitiveFlagAutomatically: { type: 'boolean' },
 | 
			
		||||
		enableSensitiveMediaDetectionForVideos: { type: 'boolean' },
 | 
			
		||||
		enableBotTrending: { type: 'boolean' },
 | 
			
		||||
		proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true },
 | 
			
		||||
		maintainerName: { type: 'string', nullable: true },
 | 
			
		||||
		maintainerEmail: { type: 'string', nullable: true },
 | 
			
		||||
| 
						 | 
				
			
			@ -301,6 +302,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				set.enableSensitiveMediaDetectionForVideos = ps.enableSensitiveMediaDetectionForVideos;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ps.enableBotTrending !== undefined) {
 | 
			
		||||
				set.enableBotTrending = ps.enableBotTrending;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (ps.proxyAccountId !== undefined) {
 | 
			
		||||
				set.proxyAccountId = ps.proxyAccountId;
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,6 +40,7 @@ export const paramDef = {
 | 
			
		|||
	type: 'object',
 | 
			
		||||
	properties: {
 | 
			
		||||
		withFiles: { type: 'boolean', default: false },
 | 
			
		||||
		withBots: { type: 'boolean', default: true },
 | 
			
		||||
		withRenotes: { type: 'boolean', default: true },
 | 
			
		||||
		limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
 | 
			
		||||
		sinceId: { type: 'string', format: 'misskey:id' },
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +88,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
			if (ps.withFiles) {
 | 
			
		||||
				query.andWhere('note.fileIds != \'{}\'');
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (!ps.withBots) query.andWhere('user.isBot = FALSE');
 | 
			
		||||
			//#endregion
 | 
			
		||||
 | 
			
		||||
			const timeline = await query.limit(ps.limit).getMany();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,6 +56,7 @@ export const paramDef = {
 | 
			
		|||
		withFiles: { type: 'boolean', default: false },
 | 
			
		||||
		withRenotes: { type: 'boolean', default: true },
 | 
			
		||||
		withReplies: { type: 'boolean', default: false },
 | 
			
		||||
		withBots: { type: 'boolean', default: true },
 | 
			
		||||
	},
 | 
			
		||||
	required: [],
 | 
			
		||||
} as const;
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +135,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				.leftJoinAndSelect('renote.user', 'renoteUser')
 | 
			
		||||
				.leftJoinAndSelect('note.channel', 'channel');
 | 
			
		||||
 | 
			
		||||
			if (!ps.withBots) query.andWhere('user.isBot = FALSE');
 | 
			
		||||
 | 
			
		||||
			let timeline = await query.getMany();
 | 
			
		||||
 | 
			
		||||
			timeline = timeline.filter(note => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ export const paramDef = {
 | 
			
		|||
		withFiles: { type: 'boolean', default: false },
 | 
			
		||||
		withRenotes: { type: 'boolean', default: true },
 | 
			
		||||
		withReplies: { type: 'boolean', default: false },
 | 
			
		||||
		withBots: { type: 'boolean', default: true },
 | 
			
		||||
		excludeNsfw: { type: 'boolean', default: false },
 | 
			
		||||
		limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
 | 
			
		||||
		sinceId: { type: 'string', format: 'misskey:id' },
 | 
			
		||||
| 
						 | 
				
			
			@ -119,6 +120,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				.leftJoinAndSelect('renote.user', 'renoteUser')
 | 
			
		||||
				.leftJoinAndSelect('note.channel', 'channel');
 | 
			
		||||
 | 
			
		||||
			if (!ps.withBots) query.andWhere('user.isBot = FALSE');
 | 
			
		||||
 | 
			
		||||
			let timeline = await query.getMany();
 | 
			
		||||
 | 
			
		||||
			timeline = timeline.filter(note => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
 | 
			
		|||
import { QueryService } from '@/core/QueryService.js';
 | 
			
		||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
 | 
			
		||||
import { DI } from '@/di-symbols.js';
 | 
			
		||||
import { MetaService } from '@/core/MetaService.js';
 | 
			
		||||
 | 
			
		||||
export const meta = {
 | 
			
		||||
	tags: ['notes', 'hashtags'],
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
 | 
			
		||||
		private noteEntityService: NoteEntityService,
 | 
			
		||||
		private queryService: QueryService,
 | 
			
		||||
		private metaService: MetaService,
 | 
			
		||||
	) {
 | 
			
		||||
		super(meta, paramDef, async (ps, me) => {
 | 
			
		||||
			const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId)
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +82,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				.leftJoinAndSelect('reply.user', 'replyUser')
 | 
			
		||||
				.leftJoinAndSelect('renote.user', 'renoteUser');
 | 
			
		||||
 | 
			
		||||
			const meta = await this.metaService.fetch(true);
 | 
			
		||||
 | 
			
		||||
			if (!meta.enableBotTrending) query.andWhere('user.isBot = FALSE');
 | 
			
		||||
 | 
			
		||||
			this.queryService.generateVisibilityQuery(query, me);
 | 
			
		||||
			if (me) this.queryService.generateMutedUserQuery(query, me);
 | 
			
		||||
			if (me) this.queryService.generateBlockedUserQuery(query, me);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@ export const paramDef = {
 | 
			
		|||
		includeLocalRenotes: { type: 'boolean', default: true },
 | 
			
		||||
		withFiles: { type: 'boolean', default: false },
 | 
			
		||||
		withRenotes: { type: 'boolean', default: true },
 | 
			
		||||
		withBots: { type: 'boolean', default: true },
 | 
			
		||||
	},
 | 
			
		||||
	required: [],
 | 
			
		||||
} as const;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +98,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 | 
			
		|||
				.leftJoinAndSelect('renote.user', 'renoteUser')
 | 
			
		||||
				.leftJoinAndSelect('note.channel', 'channel');
 | 
			
		||||
 | 
			
		||||
			if (!ps.withBots) query.andWhere('user.isBot = FALSE');
 | 
			
		||||
 | 
			
		||||
			let timeline = await query.getMany();
 | 
			
		||||
 | 
			
		||||
			timeline = timeline.filter(note => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ class GlobalTimelineChannel extends Channel {
 | 
			
		|||
	public static requireCredential = false;
 | 
			
		||||
	private withRenotes: boolean;
 | 
			
		||||
	private withFiles: boolean;
 | 
			
		||||
	private withBots: boolean;
 | 
			
		||||
 | 
			
		||||
	constructor(
 | 
			
		||||
		private metaService: MetaService,
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +41,7 @@ class GlobalTimelineChannel extends Channel {
 | 
			
		|||
 | 
			
		||||
		this.withRenotes = params.withRenotes ?? true;
 | 
			
		||||
		this.withFiles = params.withFiles ?? false;
 | 
			
		||||
		this.withBots = params.withBots ?? true;
 | 
			
		||||
 | 
			
		||||
		// Subscribe events
 | 
			
		||||
		this.subscriber.on('notesStream', this.onNote);
 | 
			
		||||
| 
						 | 
				
			
			@ -48,6 +50,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.withBots && note.user.isBot) return;
 | 
			
		||||
 | 
			
		||||
		if (note.visibility !== 'public') return;
 | 
			
		||||
		if (note.channelId != null) return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ class HybridTimelineChannel extends Channel {
 | 
			
		|||
	public static requireCredential = true;
 | 
			
		||||
	private withRenotes: boolean;
 | 
			
		||||
	private withReplies: boolean;
 | 
			
		||||
	private withBots: boolean;
 | 
			
		||||
	private withFiles: boolean;
 | 
			
		||||
 | 
			
		||||
	constructor(
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +42,7 @@ class HybridTimelineChannel extends Channel {
 | 
			
		|||
 | 
			
		||||
		this.withRenotes = params.withRenotes ?? true;
 | 
			
		||||
		this.withReplies = params.withReplies ?? false;
 | 
			
		||||
		this.withBots = params.withBots ?? true;
 | 
			
		||||
		this.withFiles = params.withFiles ?? false;
 | 
			
		||||
 | 
			
		||||
		// Subscribe events
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +52,7 @@ class HybridTimelineChannel extends Channel {
 | 
			
		|||
	@bindThis
 | 
			
		||||
	private async onNote(note: Packed<'Note'>) {
 | 
			
		||||
		if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return;
 | 
			
		||||
		if (!this.withBots && note.user.isBot) return;
 | 
			
		||||
 | 
			
		||||
		// チャンネルの投稿ではなく、自分自身の投稿 または
 | 
			
		||||
		// チャンネルの投稿ではなく、その投稿のユーザーをフォローしている または
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ class LocalTimelineChannel extends Channel {
 | 
			
		|||
	public static requireCredential = false;
 | 
			
		||||
	private withRenotes: boolean;
 | 
			
		||||
	private withReplies: boolean;
 | 
			
		||||
	private withBots: boolean;
 | 
			
		||||
	private withFiles: boolean;
 | 
			
		||||
 | 
			
		||||
	constructor(
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +41,7 @@ class LocalTimelineChannel extends Channel {
 | 
			
		|||
 | 
			
		||||
		this.withRenotes = params.withRenotes ?? true;
 | 
			
		||||
		this.withReplies = params.withReplies ?? false;
 | 
			
		||||
		this.withBots = params.withBots ?? true;
 | 
			
		||||
		this.withFiles = params.withFiles ?? false;
 | 
			
		||||
 | 
			
		||||
		// Subscribe events
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +51,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.withBots && note.user.isBot) return;
 | 
			
		||||
 | 
			
		||||
		if (note.user.host !== null) return;
 | 
			
		||||
		if (note.visibility !== 'public') return;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,11 +25,13 @@ const props = withDefaults(defineProps<{
 | 
			
		|||
	sound?: boolean;
 | 
			
		||||
	withRenotes?: boolean;
 | 
			
		||||
	withReplies?: boolean;
 | 
			
		||||
	withBots?: boolean;
 | 
			
		||||
	onlyFiles?: boolean;
 | 
			
		||||
}>(), {
 | 
			
		||||
	withRenotes: true,
 | 
			
		||||
	withReplies: false,
 | 
			
		||||
	onlyFiles: false,
 | 
			
		||||
	withBots: true,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits<{
 | 
			
		||||
| 
						 | 
				
			
			@ -93,11 +95,13 @@ if (props.src === 'antenna') {
 | 
			
		|||
	query = {
 | 
			
		||||
		withRenotes: props.withRenotes,
 | 
			
		||||
		withReplies: props.withReplies,
 | 
			
		||||
		withBots: props.withBots,
 | 
			
		||||
		withFiles: props.onlyFiles ? true : undefined,
 | 
			
		||||
	};
 | 
			
		||||
	connection = stream.useChannel('localTimeline', {
 | 
			
		||||
		withRenotes: props.withRenotes,
 | 
			
		||||
		withReplies: props.withReplies,
 | 
			
		||||
		withBots: props.withBots,
 | 
			
		||||
		withFiles: props.onlyFiles ? true : undefined,
 | 
			
		||||
	});
 | 
			
		||||
	connection.on('note', prepend);
 | 
			
		||||
| 
						 | 
				
			
			@ -106,11 +110,13 @@ if (props.src === 'antenna') {
 | 
			
		|||
	query = {
 | 
			
		||||
		withRenotes: props.withRenotes,
 | 
			
		||||
		withReplies: props.withReplies,
 | 
			
		||||
		withBots: props.withBots,
 | 
			
		||||
		withFiles: props.onlyFiles ? true : undefined,
 | 
			
		||||
	};
 | 
			
		||||
	connection = stream.useChannel('hybridTimeline', {
 | 
			
		||||
		withRenotes: props.withRenotes,
 | 
			
		||||
		withReplies: props.withReplies,
 | 
			
		||||
		withBots: props.withBots,
 | 
			
		||||
		withFiles: props.onlyFiles ? true : undefined,
 | 
			
		||||
	});
 | 
			
		||||
	connection.on('note', prepend);
 | 
			
		||||
| 
						 | 
				
			
			@ -118,10 +124,12 @@ if (props.src === 'antenna') {
 | 
			
		|||
	endpoint = 'notes/global-timeline';
 | 
			
		||||
	query = {
 | 
			
		||||
		withRenotes: props.withRenotes,
 | 
			
		||||
		withBots: props.withBots,
 | 
			
		||||
		withFiles: props.onlyFiles ? true : undefined,
 | 
			
		||||
	};
 | 
			
		||||
	connection = stream.useChannel('globalTimeline', {
 | 
			
		||||
		withRenotes: props.withRenotes,
 | 
			
		||||
		withBots: props.withBots,
 | 
			
		||||
		withFiles: props.onlyFiles ? true : undefined,
 | 
			
		||||
	});
 | 
			
		||||
	connection.on('note', prepend);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		|||
					</MkSwitch>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<div class="_panel" style="padding: 16px;">
 | 
			
		||||
					<MkSwitch v-model="enableBotTrending">
 | 
			
		||||
						<template #label>Populate Hashtags with Bots</template>
 | 
			
		||||
						<template #caption>Turning this off will stop Bots from populating Hashtags</template>
 | 
			
		||||
					</MkSwitch>
 | 
			
		||||
				</div>
 | 
			
		||||
 | 
			
		||||
				<div class="_panel" style="padding: 16px;">
 | 
			
		||||
					<MkSwitch v-model="enableIdenticonGeneration">
 | 
			
		||||
						<template #label>{{ i18n.ts.enableIdenticonGeneration }}</template>
 | 
			
		||||
| 
						 | 
				
			
			@ -61,6 +68,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
 | 
			
		|||
 | 
			
		||||
let enableServerMachineStats: boolean = $ref(false);
 | 
			
		||||
let enableAchievements: boolean = $ref(false);
 | 
			
		||||
let enableBotTrending: boolean = $ref(false);
 | 
			
		||||
let enableIdenticonGeneration: boolean = $ref(false);
 | 
			
		||||
let enableChartsForRemoteUser: boolean = $ref(false);
 | 
			
		||||
let enableChartsForFederatedInstances: boolean = $ref(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -69,6 +77,7 @@ async function init() {
 | 
			
		|||
	const meta = await os.api('admin/meta');
 | 
			
		||||
	enableServerMachineStats = meta.enableServerMachineStats;
 | 
			
		||||
	enableAchievements = meta.enableAchievements;
 | 
			
		||||
	enableBotTrending = meta.enableBotTrending;
 | 
			
		||||
	enableIdenticonGeneration = meta.enableIdenticonGeneration;
 | 
			
		||||
	enableChartsForRemoteUser = meta.enableChartsForRemoteUser;
 | 
			
		||||
	enableChartsForFederatedInstances = meta.enableChartsForFederatedInstances;
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +87,7 @@ function save() {
 | 
			
		|||
	os.apiWithDialog('admin/update-meta', {
 | 
			
		||||
		enableServerMachineStats,
 | 
			
		||||
		enableAchievements,
 | 
			
		||||
		enableBotTrending,
 | 
			
		||||
		enableIdenticonGeneration,
 | 
			
		||||
		enableChartsForRemoteUser,
 | 
			
		||||
		enableChartsForFederatedInstances,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,6 +152,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		|||
				<MkSwitch v-model="enableInfiniteScroll">{{ i18n.ts.enableInfiniteScroll }}</MkSwitch>
 | 
			
		||||
				<MkSwitch v-model="keepScreenOn">{{ i18n.ts.keepScreenOn }}</MkSwitch>
 | 
			
		||||
				<MkSwitch v-model="clickToOpen">{{ i18n.ts.clickToOpen }}</MkSwitch>
 | 
			
		||||
				<MkSwitch v-model="showBots">Show bots in timeline</MkSwitch>
 | 
			
		||||
			</div>
 | 
			
		||||
			<MkSelect v-model="serverDisconnectedBehavior">
 | 
			
		||||
				<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
 | 
			
		||||
| 
						 | 
				
			
			@ -227,6 +228,7 @@ const showClipButtonInNoteFooter = computed(defaultStore.makeGetterSetter('showC
 | 
			
		|||
const reactionsDisplaySize = computed(defaultStore.makeGetterSetter('reactionsDisplaySize'));
 | 
			
		||||
const collapseRenotes = computed(defaultStore.makeGetterSetter('collapseRenotes'));
 | 
			
		||||
const clickToOpen = computed(defaultStore.makeGetterSetter('clickToOpen'));
 | 
			
		||||
const showBots = computed(defaultStore.makeGetterSetter('tlWithBots'));
 | 
			
		||||
const collapseFiles = computed(defaultStore.makeGetterSetter('collapseFiles'));
 | 
			
		||||
const autoloadConversation = computed(defaultStore.makeGetterSetter('autoloadConversation'));
 | 
			
		||||
const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
			
		|||
					:withRenotes="withRenotes"
 | 
			
		||||
					:withReplies="withReplies"
 | 
			
		||||
					:onlyFiles="onlyFiles"
 | 
			
		||||
					:withBots="withBots"
 | 
			
		||||
					:sound="true"
 | 
			
		||||
					@queue="queueUpdated"
 | 
			
		||||
				/>
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +64,7 @@ let srcWhenNotSignin = $ref(isLocalTimelineAvailable ? 'local' : 'global');
 | 
			
		|||
const src = $computed({ get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin), set: (x) => saveSrc(x) });
 | 
			
		||||
const withRenotes = $ref(true);
 | 
			
		||||
const withReplies = $ref($i ? defaultStore.state.tlWithReplies : false);
 | 
			
		||||
const withBots = $ref($i ? defaultStore.state.tlWithBots : true);
 | 
			
		||||
const onlyFiles = $ref(false);
 | 
			
		||||
 | 
			
		||||
watch($$(src), () => queue = 0);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -373,6 +373,10 @@ export const defaultStore = markRaw(new Storage('base', {
 | 
			
		|||
		where: 'device',
 | 
			
		||||
		default: false,
 | 
			
		||||
	},
 | 
			
		||||
	tlWithBots: {
 | 
			
		||||
		where: 'device',
 | 
			
		||||
		default: true,
 | 
			
		||||
	},
 | 
			
		||||
}));
 | 
			
		||||
 | 
			
		||||
// TODO: 他のタブと永続化されたstateを同期
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -405,6 +405,7 @@ export type AdminInstanceMetadata = DetailedInstanceMetadata & {
 | 
			
		|||
	app192IconUrl: string | null;
 | 
			
		||||
	app512IconUrl: string | null;
 | 
			
		||||
	manifestJsonOverride: string;
 | 
			
		||||
	enableBotTrending: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ServerInfo = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue