feat(frontend): Misskey Gamesのリストに鯖缶指定のチャンネルを載せる (MisskeyIO#383)
This commit is contained in:
parent
7884901950
commit
ac79f1fdc1
|
@ -376,6 +376,8 @@ pinnedPages: "Pinned Pages"
|
||||||
pinnedPagesDescription: "Enter the paths of the Pages you want to pin to the top page of this instance, separated by line breaks."
|
pinnedPagesDescription: "Enter the paths of the Pages you want to pin to the top page of this instance, separated by line breaks."
|
||||||
pinnedClipId: "ID of the clip to pin"
|
pinnedClipId: "ID of the clip to pin"
|
||||||
pinnedNotes: "Pinned notes"
|
pinnedNotes: "Pinned notes"
|
||||||
|
featuredGameChannels: "Featured Misskey Games Channels"
|
||||||
|
featuredGameChannelsDescription: "Enter the channels you want to pin to Misskey Games, separated by line breaks."
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "Enable hCaptcha"
|
enableHcaptcha: "Enable hCaptcha"
|
||||||
hcaptchaSiteKey: "Site key"
|
hcaptchaSiteKey: "Site key"
|
||||||
|
|
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
|
@ -1536,6 +1536,14 @@ export interface Locale extends ILocale {
|
||||||
* ピン留めされたノート
|
* ピン留めされたノート
|
||||||
*/
|
*/
|
||||||
"pinnedNotes": string;
|
"pinnedNotes": string;
|
||||||
|
/**
|
||||||
|
* Misskey Gamesのピン留めチャンネル
|
||||||
|
*/
|
||||||
|
"featuredGameChannels": string;
|
||||||
|
/**
|
||||||
|
* Misskey Gamesにピン留めしたいチャンネルを改行で区切って記述します。
|
||||||
|
*/
|
||||||
|
"featuredGameChannelsDescription": string;
|
||||||
/**
|
/**
|
||||||
* hCaptcha
|
* hCaptcha
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -380,6 +380,8 @@ pinnedPages: "ピン留めページ"
|
||||||
pinnedPagesDescription: "サーバーのトップページにピン留めしたいページのパスを改行で区切って記述します。"
|
pinnedPagesDescription: "サーバーのトップページにピン留めしたいページのパスを改行で区切って記述します。"
|
||||||
pinnedClipId: "ピン留めするクリップのID"
|
pinnedClipId: "ピン留めするクリップのID"
|
||||||
pinnedNotes: "ピン留めされたノート"
|
pinnedNotes: "ピン留めされたノート"
|
||||||
|
featuredGameChannels: "Misskey Gamesのピン留めチャンネル"
|
||||||
|
featuredGameChannelsDescription: "Misskey Gamesにピン留めしたいチャンネルを改行で区切って記述します。"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "hCaptchaを有効にする"
|
enableHcaptcha: "hCaptchaを有効にする"
|
||||||
hcaptchaSiteKey: "サイトキー"
|
hcaptchaSiteKey: "サイトキー"
|
||||||
|
|
|
@ -379,6 +379,8 @@ pinnedPages: "고정한 페이지"
|
||||||
pinnedPagesDescription: "서버의 대문에 고정하고 싶은 페이지의 경로를 한 줄에 하나씩 적습니다."
|
pinnedPagesDescription: "서버의 대문에 고정하고 싶은 페이지의 경로를 한 줄에 하나씩 적습니다."
|
||||||
pinnedClipId: "고정할 클립의 ID"
|
pinnedClipId: "고정할 클립의 ID"
|
||||||
pinnedNotes: "고정된 노트"
|
pinnedNotes: "고정된 노트"
|
||||||
|
featuredGameChannels: "Misskey Games에 고정할 채널"
|
||||||
|
featuredGameChannelsDescription: "Misskey Games에 고정할 채널을 한 줄에 하나씩 적습니다."
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "hCaptcha 활성화"
|
enableHcaptcha: "hCaptcha 활성화"
|
||||||
hcaptchaSiteKey: "사이트 키"
|
hcaptchaSiteKey: "사이트 키"
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class FeaturedGamesChannel1706081039979 {
|
||||||
|
name = 'FeaturedGamesChannel1706081039979'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "featuredGameChannels" character varying(1024) array NOT NULL DEFAULT '{}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "featuredGameChannels"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -97,5 +97,14 @@ export class ChannelEntityService {
|
||||||
} : {}),
|
} : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public async packMany(
|
||||||
|
channels: (MiChannel['id'] | MiChannel)[],
|
||||||
|
me: { id: MiUser['id'] } | null | undefined,
|
||||||
|
detailed?: boolean,
|
||||||
|
): Promise<Packed<'Channel'>[]> {
|
||||||
|
return (await Promise.allSettled(channels.map(x => this.pack(x, me, detailed))))
|
||||||
|
.filter(result => result.status === 'fulfilled')
|
||||||
|
.map(result => (result as PromiseFulfilledResult<Packed<'Channel'>>).value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -591,4 +591,9 @@ export class MiMeta {
|
||||||
length: 3072, array: true, default: '{}',
|
length: 3072, array: true, default: '{}',
|
||||||
})
|
})
|
||||||
public urlPreviewDenyList: string[];
|
public urlPreviewDenyList: string[];
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024, array: true, default: '{}',
|
||||||
|
})
|
||||||
|
public featuredGameChannels: string[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ import * as ep___blocking_delete from './endpoints/blocking/delete.js';
|
||||||
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
||||||
import * as ep___channels_create from './endpoints/channels/create.js';
|
import * as ep___channels_create from './endpoints/channels/create.js';
|
||||||
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
||||||
|
import * as ep___channels_featured_games from './endpoints/channels/featured-games.js';
|
||||||
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
||||||
import * as ep___channels_followed from './endpoints/channels/followed.js';
|
import * as ep___channels_followed from './endpoints/channels/followed.js';
|
||||||
import * as ep___channels_owned from './endpoints/channels/owned.js';
|
import * as ep___channels_owned from './endpoints/channels/owned.js';
|
||||||
|
@ -482,6 +483,7 @@ const $blocking_delete: Provider = { provide: 'ep:blocking/delete', useClass: ep
|
||||||
const $blocking_list: Provider = { provide: 'ep:blocking/list', useClass: ep___blocking_list.default };
|
const $blocking_list: Provider = { provide: 'ep:blocking/list', useClass: ep___blocking_list.default };
|
||||||
const $channels_create: Provider = { provide: 'ep:channels/create', useClass: ep___channels_create.default };
|
const $channels_create: Provider = { provide: 'ep:channels/create', useClass: ep___channels_create.default };
|
||||||
const $channels_featured: Provider = { provide: 'ep:channels/featured', useClass: ep___channels_featured.default };
|
const $channels_featured: Provider = { provide: 'ep:channels/featured', useClass: ep___channels_featured.default };
|
||||||
|
const $channels_featured_games: Provider = { provide: 'ep:channels/featured-games', useClass: ep___channels_featured_games.default };
|
||||||
const $channels_follow: Provider = { provide: 'ep:channels/follow', useClass: ep___channels_follow.default };
|
const $channels_follow: Provider = { provide: 'ep:channels/follow', useClass: ep___channels_follow.default };
|
||||||
const $channels_followed: Provider = { provide: 'ep:channels/followed', useClass: ep___channels_followed.default };
|
const $channels_followed: Provider = { provide: 'ep:channels/followed', useClass: ep___channels_followed.default };
|
||||||
const $channels_owned: Provider = { provide: 'ep:channels/owned', useClass: ep___channels_owned.default };
|
const $channels_owned: Provider = { provide: 'ep:channels/owned', useClass: ep___channels_owned.default };
|
||||||
|
@ -862,6 +864,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$blocking_list,
|
$blocking_list,
|
||||||
$channels_create,
|
$channels_create,
|
||||||
$channels_featured,
|
$channels_featured,
|
||||||
|
$channels_featured_games,
|
||||||
$channels_follow,
|
$channels_follow,
|
||||||
$channels_followed,
|
$channels_followed,
|
||||||
$channels_owned,
|
$channels_owned,
|
||||||
|
@ -1236,6 +1239,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$blocking_list,
|
$blocking_list,
|
||||||
$channels_create,
|
$channels_create,
|
||||||
$channels_featured,
|
$channels_featured,
|
||||||
|
$channels_featured_games,
|
||||||
$channels_follow,
|
$channels_follow,
|
||||||
$channels_followed,
|
$channels_followed,
|
||||||
$channels_owned,
|
$channels_owned,
|
||||||
|
|
|
@ -107,6 +107,7 @@ import * as ep___blocking_delete from './endpoints/blocking/delete.js';
|
||||||
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
import * as ep___blocking_list from './endpoints/blocking/list.js';
|
||||||
import * as ep___channels_create from './endpoints/channels/create.js';
|
import * as ep___channels_create from './endpoints/channels/create.js';
|
||||||
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
import * as ep___channels_featured from './endpoints/channels/featured.js';
|
||||||
|
import * as ep___channels_featured_games from './endpoints/channels/featured-games.js';
|
||||||
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
import * as ep___channels_follow from './endpoints/channels/follow.js';
|
||||||
import * as ep___channels_followed from './endpoints/channels/followed.js';
|
import * as ep___channels_followed from './endpoints/channels/followed.js';
|
||||||
import * as ep___channels_owned from './endpoints/channels/owned.js';
|
import * as ep___channels_owned from './endpoints/channels/owned.js';
|
||||||
|
@ -481,6 +482,7 @@ const eps = [
|
||||||
['blocking/list', ep___blocking_list],
|
['blocking/list', ep___blocking_list],
|
||||||
['channels/create', ep___channels_create],
|
['channels/create', ep___channels_create],
|
||||||
['channels/featured', ep___channels_featured],
|
['channels/featured', ep___channels_featured],
|
||||||
|
['channels/featured-games', ep___channels_featured_games],
|
||||||
['channels/follow', ep___channels_follow],
|
['channels/follow', ep___channels_follow],
|
||||||
['channels/followed', ep___channels_followed],
|
['channels/followed', ep___channels_followed],
|
||||||
['channels/owned', ep___channels_owned],
|
['channels/owned', ep___channels_owned],
|
||||||
|
|
|
@ -382,6 +382,13 @@ export const meta = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
featuredGameChannels: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
backgroundImageUrl: {
|
backgroundImageUrl: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
|
@ -589,6 +596,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
|
perUserListTimelineCacheMax: instance.perUserListTimelineCacheMax,
|
||||||
notesPerOneAd: instance.notesPerOneAd,
|
notesPerOneAd: instance.notesPerOneAd,
|
||||||
urlPreviewDenyList: instance.urlPreviewDenyList,
|
urlPreviewDenyList: instance.urlPreviewDenyList,
|
||||||
|
featuredGameChannels: instance.featuredGameChannels,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,9 +150,16 @@ export const paramDef = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
urlPreviewDenyList: { type: 'array', nullable: true, items: {
|
urlPreviewDenyList: {
|
||||||
type: 'string',
|
type: 'array', nullable: true, items: {
|
||||||
} },
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
featuredGameChannels: {
|
||||||
|
type: 'array', nullable: true, items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -208,6 +215,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.urlPreviewDenyList = ps.urlPreviewDenyList.filter(Boolean);
|
set.urlPreviewDenyList = ps.urlPreviewDenyList.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(ps.featuredGameChannels)) {
|
||||||
|
set.featuredGameChannels = ps.featuredGameChannels.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.themeColor !== undefined) {
|
if (ps.themeColor !== undefined) {
|
||||||
set.themeColor = ps.themeColor;
|
set.themeColor = ps.themeColor;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and other misskey contributors
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import type { ChannelsRepository } from '@/models/_.js';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['channels'],
|
||||||
|
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'Channel',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {},
|
||||||
|
required: [],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.channelsRepository)
|
||||||
|
private channelsRepository: ChannelsRepository,
|
||||||
|
|
||||||
|
private metaService: MetaService,
|
||||||
|
private channelEntityService: ChannelEntityService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
const meta = await this.metaService.fetch();
|
||||||
|
|
||||||
|
if (meta.featuredGameChannels.length === 0) return [];
|
||||||
|
|
||||||
|
const channels = await this.channelsRepository.findBy({
|
||||||
|
id: In(meta.featuredGameChannels)
|
||||||
|
});
|
||||||
|
|
||||||
|
return await this.channelEntityService.packMany(channels, me);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
const channels = await query.limit(10).getMany();
|
const channels = await query.limit(10).getMany();
|
||||||
|
|
||||||
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
|
return await this.channelEntityService.packMany(channels, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,14 +48,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder(), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.channelFollowingsRepository.createQueryBuilder('followings'), ps.sinceId, ps.untilId)
|
||||||
.andWhere({ followerId: me.id });
|
.andWhere('followings.followerId = :meId', { meId: me.id })
|
||||||
|
.innerJoinAndSelect('followings.followee', 'channel');
|
||||||
|
|
||||||
const followings = await query
|
const followings = await query
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
||||||
return await Promise.all(followings.map(x => this.channelEntityService.pack(x.followeeId, me)));
|
return await this.channelEntityService.packMany(followings.map(x => x.followee!), me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,12 +45,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.channelFavoritesRepository.createQueryBuilder('favorite')
|
const query = this.channelFavoritesRepository.createQueryBuilder('favorite')
|
||||||
.andWhere('favorite.userId = :meId', { meId: me.id })
|
.andWhere('favorite.userId = :meId', { meId: me.id })
|
||||||
.leftJoinAndSelect('favorite.channel', 'channel');
|
.innerJoinAndSelect('favorite.channel', 'channel');
|
||||||
|
|
||||||
const favorites = await query
|
const favorites = await query
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
||||||
return await Promise.all(favorites.map(x => this.channelEntityService.pack(x.channel!, me)));
|
return await this.channelEntityService.packMany(favorites.map(x => x.channel!), me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
||||||
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
|
return await this.channelEntityService.packMany(channels, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
||||||
return await Promise.all(channels.map(x => this.channelEntityService.pack(x, me)));
|
return await this.channelEntityService.packMany(channels, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
|
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
|
|
||||||
|
<MkTextarea v-model="featuredGameChannels">
|
||||||
|
<template #label>{{ i18n.ts.featuredGameChannels }}</template>
|
||||||
|
<template #caption>{{ i18n.ts.featuredGameChannelsDescription }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts.files }}</template>
|
<template #label>{{ i18n.ts.files }}</template>
|
||||||
|
|
||||||
|
@ -171,6 +176,7 @@ const maintainerName = ref<string | null>(null);
|
||||||
const maintainerEmail = ref<string | null>(null);
|
const maintainerEmail = ref<string | null>(null);
|
||||||
const impressumUrl = ref<string | null>(null);
|
const impressumUrl = ref<string | null>(null);
|
||||||
const pinnedUsers = ref<string>('');
|
const pinnedUsers = ref<string>('');
|
||||||
|
const featuredGameChannels = ref<string>('');
|
||||||
const cacheRemoteFiles = ref<boolean>(false);
|
const cacheRemoteFiles = ref<boolean>(false);
|
||||||
const cacheRemoteSensitiveFiles = ref<boolean>(false);
|
const cacheRemoteSensitiveFiles = ref<boolean>(false);
|
||||||
const enableServiceWorker = ref<boolean>(false);
|
const enableServiceWorker = ref<boolean>(false);
|
||||||
|
@ -193,6 +199,7 @@ async function init(): Promise<void> {
|
||||||
maintainerEmail.value = meta.maintainerEmail;
|
maintainerEmail.value = meta.maintainerEmail;
|
||||||
impressumUrl.value = meta.impressumUrl;
|
impressumUrl.value = meta.impressumUrl;
|
||||||
pinnedUsers.value = meta.pinnedUsers.join('\n');
|
pinnedUsers.value = meta.pinnedUsers.join('\n');
|
||||||
|
featuredGameChannels.value = meta.featuredGameChannels.join('\n');
|
||||||
cacheRemoteFiles.value = meta.cacheRemoteFiles;
|
cacheRemoteFiles.value = meta.cacheRemoteFiles;
|
||||||
cacheRemoteSensitiveFiles.value = meta.cacheRemoteSensitiveFiles;
|
cacheRemoteSensitiveFiles.value = meta.cacheRemoteSensitiveFiles;
|
||||||
enableServiceWorker.value = meta.enableServiceWorker;
|
enableServiceWorker.value = meta.enableServiceWorker;
|
||||||
|
@ -216,6 +223,7 @@ async function save(): void {
|
||||||
maintainerEmail: maintainerEmail.value,
|
maintainerEmail: maintainerEmail.value,
|
||||||
impressumUrl: impressumUrl.value,
|
impressumUrl: impressumUrl.value,
|
||||||
pinnedUsers: pinnedUsers.value.split('\n'),
|
pinnedUsers: pinnedUsers.value.split('\n'),
|
||||||
|
featuredGameChannels: featuredGameChannels.value.split('\n'),
|
||||||
cacheRemoteFiles: cacheRemoteFiles.value,
|
cacheRemoteFiles: cacheRemoteFiles.value,
|
||||||
cacheRemoteSensitiveFiles: cacheRemoteSensitiveFiles.value,
|
cacheRemoteSensitiveFiles: cacheRemoteSensitiveFiles.value,
|
||||||
enableServiceWorker: enableServiceWorker.value,
|
enableServiceWorker: enableServiceWorker.value,
|
||||||
|
|
|
@ -19,16 +19,25 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkA>
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<MkPagination v-slot="{items}" :pagination="featuredPagination">
|
||||||
|
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_margin" :channel="channel"/>
|
||||||
|
</MkPagination>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { i18n } from '@/i18n.js';
|
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
|
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||||
|
|
||||||
definePageMetadata({
|
definePageMetadata({
|
||||||
title: 'Misskey Games',
|
title: 'Misskey Games',
|
||||||
icon: 'ti ti-device-gamepad',
|
icon: 'ti ti-device-gamepad',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const featuredPagination = {
|
||||||
|
endpoint: 'channels/featured-games' as const,
|
||||||
|
noPaging: true,
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -722,6 +722,9 @@ type ChannelsCreateResponse = operations['channels/create']['responses']['200'][
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type ChannelsFavoriteRequest = operations['channels/favorite']['requestBody']['content']['application/json'];
|
type ChannelsFavoriteRequest = operations['channels/favorite']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type ChannelsFeaturedGamesResponse = operations['channels/featured-games']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
|
type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
@ -1246,6 +1249,7 @@ declare namespace entities {
|
||||||
ChannelsCreateRequest,
|
ChannelsCreateRequest,
|
||||||
ChannelsCreateResponse,
|
ChannelsCreateResponse,
|
||||||
ChannelsFeaturedResponse,
|
ChannelsFeaturedResponse,
|
||||||
|
ChannelsFeaturedGamesResponse,
|
||||||
ChannelsFollowRequest,
|
ChannelsFollowRequest,
|
||||||
ChannelsFollowedRequest,
|
ChannelsFollowedRequest,
|
||||||
ChannelsFollowedResponse,
|
ChannelsFollowedResponse,
|
||||||
|
|
|
@ -1109,6 +1109,17 @@ declare module '../api.js' {
|
||||||
credential?: string | null,
|
credential?: string | null,
|
||||||
): Promise<SwitchCaseResponseType<E, P>>;
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *No*
|
||||||
|
*/
|
||||||
|
request<E extends 'channels/featured-games', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No description provided.
|
* No description provided.
|
||||||
*
|
*
|
||||||
|
|
|
@ -145,6 +145,7 @@ import type {
|
||||||
ChannelsCreateRequest,
|
ChannelsCreateRequest,
|
||||||
ChannelsCreateResponse,
|
ChannelsCreateResponse,
|
||||||
ChannelsFeaturedResponse,
|
ChannelsFeaturedResponse,
|
||||||
|
ChannelsFeaturedGamesResponse,
|
||||||
ChannelsFollowRequest,
|
ChannelsFollowRequest,
|
||||||
ChannelsFollowedRequest,
|
ChannelsFollowedRequest,
|
||||||
ChannelsFollowedResponse,
|
ChannelsFollowedResponse,
|
||||||
|
@ -666,6 +667,7 @@ export type Endpoints = {
|
||||||
'blocking/list': { req: BlockingListRequest; res: BlockingListResponse };
|
'blocking/list': { req: BlockingListRequest; res: BlockingListResponse };
|
||||||
'channels/create': { req: ChannelsCreateRequest; res: ChannelsCreateResponse };
|
'channels/create': { req: ChannelsCreateRequest; res: ChannelsCreateResponse };
|
||||||
'channels/featured': { req: EmptyRequest; res: ChannelsFeaturedResponse };
|
'channels/featured': { req: EmptyRequest; res: ChannelsFeaturedResponse };
|
||||||
|
'channels/featured-games': { req: EmptyRequest; res: ChannelsFeaturedGamesResponse };
|
||||||
'channels/follow': { req: ChannelsFollowRequest; res: EmptyResponse };
|
'channels/follow': { req: ChannelsFollowRequest; res: EmptyResponse };
|
||||||
'channels/followed': { req: ChannelsFollowedRequest; res: ChannelsFollowedResponse };
|
'channels/followed': { req: ChannelsFollowedRequest; res: ChannelsFollowedResponse };
|
||||||
'channels/owned': { req: ChannelsOwnedRequest; res: ChannelsOwnedResponse };
|
'channels/owned': { req: ChannelsOwnedRequest; res: ChannelsOwnedResponse };
|
||||||
|
|
|
@ -147,6 +147,7 @@ export type BlockingListResponse = operations['blocking/list']['responses']['200
|
||||||
export type ChannelsCreateRequest = operations['channels/create']['requestBody']['content']['application/json'];
|
export type ChannelsCreateRequest = operations['channels/create']['requestBody']['content']['application/json'];
|
||||||
export type ChannelsCreateResponse = operations['channels/create']['responses']['200']['content']['application/json'];
|
export type ChannelsCreateResponse = operations['channels/create']['responses']['200']['content']['application/json'];
|
||||||
export type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
|
export type ChannelsFeaturedResponse = operations['channels/featured']['responses']['200']['content']['application/json'];
|
||||||
|
export type ChannelsFeaturedGamesResponse = operations['channels/featured-games']['responses']['200']['content']['application/json'];
|
||||||
export type ChannelsFollowRequest = operations['channels/follow']['requestBody']['content']['application/json'];
|
export type ChannelsFollowRequest = operations['channels/follow']['requestBody']['content']['application/json'];
|
||||||
export type ChannelsFollowedRequest = operations['channels/followed']['requestBody']['content']['application/json'];
|
export type ChannelsFollowedRequest = operations['channels/followed']['requestBody']['content']['application/json'];
|
||||||
export type ChannelsFollowedResponse = operations['channels/followed']['responses']['200']['content']['application/json'];
|
export type ChannelsFollowedResponse = operations['channels/followed']['responses']['200']['content']['application/json'];
|
||||||
|
|
|
@ -918,6 +918,15 @@ export type paths = {
|
||||||
*/
|
*/
|
||||||
post: operations['channels/featured'];
|
post: operations['channels/featured'];
|
||||||
};
|
};
|
||||||
|
'/channels/featured-games': {
|
||||||
|
/**
|
||||||
|
* channels/featured-games
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *No*
|
||||||
|
*/
|
||||||
|
post: operations['channels/featured-games'];
|
||||||
|
};
|
||||||
'/channels/follow': {
|
'/channels/follow': {
|
||||||
/**
|
/**
|
||||||
* channels/follow
|
* channels/follow
|
||||||
|
@ -4789,6 +4798,7 @@ export type operations = {
|
||||||
perUserListTimelineCacheMax: number;
|
perUserListTimelineCacheMax: number;
|
||||||
notesPerOneAd: number;
|
notesPerOneAd: number;
|
||||||
urlPreviewDenyList?: string[];
|
urlPreviewDenyList?: string[];
|
||||||
|
featuredGameChannels: string[];
|
||||||
backgroundImageUrl: string | null;
|
backgroundImageUrl: string | null;
|
||||||
deeplAuthKey: string | null;
|
deeplAuthKey: string | null;
|
||||||
deeplIsPro: boolean;
|
deeplIsPro: boolean;
|
||||||
|
@ -8862,6 +8872,7 @@ export type operations = {
|
||||||
silencedHosts?: string[] | null;
|
silencedHosts?: string[] | null;
|
||||||
sensitiveMediaHosts?: string[] | null;
|
sensitiveMediaHosts?: string[] | null;
|
||||||
urlPreviewDenyList?: string[] | null;
|
urlPreviewDenyList?: string[] | null;
|
||||||
|
featuredGameChannels?: string[] | null;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10677,6 +10688,52 @@ export type operations = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* channels/featured-games
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *No*
|
||||||
|
*/
|
||||||
|
'channels/featured-games': {
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Channel'][];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* channels/follow
|
* channels/follow
|
||||||
* @description No description provided.
|
* @description No description provided.
|
||||||
|
|
Loading…
Reference in a new issue