diff --git a/locales/index.d.ts b/locales/index.d.ts index 5089f7802e..c9b6c6c816 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -4984,6 +4984,18 @@ export interface Locale extends ILocale { * お問い合わせ */ "inquiry": string; + /** + * ページ閲覧数 + */ + "pageViewCount": string; + /** + * 人気のユーザーの算出基準 + */ + "preferPopularUserFactor": string; + /** + * ページ閲覧数はローカルユーザーにのみ適用されます(リモートユーザーはフォロワー数で表示されます)。「無効」に設定すると、ローカル・リモートどちらの「人気のユーザー」セクションも表示されなくなります。 + */ + "preferPopularUserFactorDescription": string; "_delivery": { /** * 配信状態 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index a03d792140..96fb3bae68 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1242,6 +1242,9 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ noDescription: "説明文はありません" alwaysConfirmFollow: "フォローの際常に確認する" inquiry: "お問い合わせ" +pageViewCount: "ページ閲覧数" +preferPopularUserFactor: "人気のユーザーの算出基準" +preferPopularUserFactorDescription: "ページ閲覧数はローカルユーザーにのみ適用されます(リモートユーザーはフォロワー数で表示されます)。「無効」に設定すると、ローカル・リモートどちらの「人気のユーザー」セクションも表示されなくなります。" _delivery: status: "配信状態" diff --git a/packages/backend/migration/1720879227657-preferPopularUserFactor.js b/packages/backend/migration/1720879227657-preferPopularUserFactor.js new file mode 100644 index 0000000000..b70e5b5aa4 --- /dev/null +++ b/packages/backend/migration/1720879227657-preferPopularUserFactor.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class PreferPopularUserFactor1720879227657 { + name = 'PreferPopularUserFactor1720879227657' + + async up(queryRunner) { + await queryRunner.query(`CREATE TYPE "meta_preferPopularUserFactor_enum" AS ENUM('follower', 'pv', 'none')`) + await queryRunner.query(`ALTER TABLE "meta" ADD "preferPopularUserFactor" "meta_preferPopularUserFactor_enum" NOT NULL DEFAULT 'follower'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "preferPopularUserFactor"`); + await queryRunner.query(`DROP TYPE "meta_preferPopularUserFactor_enum"`); + } +} diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 09641ce485..b5b5ab5c03 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -128,6 +128,8 @@ export class MetaEntityService { mediaProxy: this.config.mediaProxy, enableUrlPreview: instance.urlPreviewEnabled, + + preferPopularUserFactor: instance.preferPopularUserFactor, }; return packed; diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index ad306fcad6..3ae7c0e1b4 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -620,4 +620,10 @@ export class MiMeta { nullable: true, }) public urlPreviewUserAgent: string | null; + + @Column('enum', { + enum: ['follower', 'pv', 'none'], + default: 'follower', + }) + public preferPopularUserFactor: 'follower' | 'pv' | 'none'; } diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts index e7bc6356e5..42dfc65632 100644 --- a/packages/backend/src/models/json-schema/meta.ts +++ b/packages/backend/src/models/json-schema/meta.ts @@ -211,6 +211,11 @@ export const packedMetaLiteSchema = { type: 'boolean', optional: false, nullable: false, }, + preferPopularUserFactor: { + type: 'string', + optional: false, nullable: false, + enum: ['follower', 'pv', 'none'], + }, backgroundImageUrl: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index eee02a7123..146ac48384 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -481,6 +481,11 @@ export const meta = { type: 'string', optional: false, nullable: true, }, + preferPopularUserFactor: { + type: 'string', + optional: false, nullable: false, + enum: ['follower', 'pv', 'none'], + }, }, }, } as const; @@ -614,6 +619,7 @@ export default class extends Endpoint { // eslint- urlPreviewRequireContentLength: instance.urlPreviewRequireContentLength, urlPreviewUserAgent: instance.urlPreviewUserAgent, urlPreviewSummaryProxyUrl: instance.urlPreviewSummaryProxyUrl, + preferPopularUserFactor: instance.preferPopularUserFactor, }; }); } diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 4e28ee6877..13e291a046 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -160,6 +160,10 @@ export const paramDef = { urlPreviewRequireContentLength: { type: 'boolean' }, urlPreviewUserAgent: { type: 'string', nullable: true }, urlPreviewSummaryProxyUrl: { type: 'string', nullable: true }, + preferPopularUserFactor: { + type: 'string', + enum: ['follower', 'pv', 'none'], + }, }, required: [], } as const; @@ -617,6 +621,10 @@ export default class extends Endpoint { // eslint- set.urlPreviewSummaryProxyUrl = value === '' ? null : value; } + if (ps.preferPopularUserFactor !== undefined) { + set.preferPopularUserFactor = ps.preferPopularUserFactor; + } + const before = await this.metaService.fetch(true); await this.metaService.update(set); diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index 6f45c212ec..0acc956984 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -50,10 +50,24 @@ SPDX-License-Identifier: AGPL-3.0-only - - - - + + + +
+ + + + + + + + + + + + +
+
@@ -222,6 +236,8 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import MkButton from '@/components/MkButton.vue'; import MkFolder from '@/components/MkFolder.vue'; import MkSelect from '@/components/MkSelect.vue'; +import MkRadios from '@/components/MkRadios.vue'; +import { entities as MisskeyEntities } from 'misskey-js'; const name = ref(null); const shortName = ref(null); @@ -249,6 +265,7 @@ const urlPreviewMaximumContentLength = ref(1024 * 1024 * 10); const urlPreviewRequireContentLength = ref(true); const urlPreviewUserAgent = ref(null); const urlPreviewSummaryProxyUrl = ref(null); +const preferPopularUserFactor = ref('follower'); async function init(): Promise { const meta = await misskeyApi('admin/meta'); @@ -278,6 +295,7 @@ async function init(): Promise { urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength; urlPreviewUserAgent.value = meta.urlPreviewUserAgent; urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl; + preferPopularUserFactor.value = meta.preferPopularUserFactor; } async function save() { @@ -308,6 +326,7 @@ async function save() { urlPreviewRequireContentLength: urlPreviewRequireContentLength.value, urlPreviewUserAgent: urlPreviewUserAgent.value, urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value, + preferPopularUserFactor: preferPopularUserFactor.value, }); fetchInstance(true); diff --git a/packages/frontend/src/pages/explore.users.vue b/packages/frontend/src/pages/explore.users.vue index 398cb2c3f4..6c8ecd7ff8 100644 --- a/packages/frontend/src/pages/explore.users.vue +++ b/packages/frontend/src/pages/explore.users.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only