Merge 2ae054a5aa into d6caa4d9c4
This commit is contained in:
commit
82e5d57503
38 changed files with 1119 additions and 85 deletions
20
locales/index.d.ts
vendored
20
locales/index.d.ts
vendored
|
|
@ -730,6 +730,14 @@ export interface Locale extends ILocale {
|
|||
* にゃにゃにゃ??
|
||||
*/
|
||||
"flagAsCatDescription": string;
|
||||
/**
|
||||
* 自動TTS機能が欲しい。
|
||||
*/
|
||||
"flagAsVI": string;
|
||||
/**
|
||||
* 自動TTS機能が必要な場合は有効にしてください。 権限のあるユーザーグループに所属している場合、特定の範囲で自動TTS機能を有効にします。
|
||||
*/
|
||||
"flagAsVIDescription": string;
|
||||
/**
|
||||
* タイムラインにノートへの返信を表示する
|
||||
*/
|
||||
|
|
@ -6891,6 +6899,10 @@ export interface Locale extends ILocale {
|
|||
* 翻訳機能の利用
|
||||
*/
|
||||
"canUseTranslator": string;
|
||||
/**
|
||||
* TTS機能の利用
|
||||
*/
|
||||
"canUseTTS": string;
|
||||
/**
|
||||
* アイコンデコレーションの最大取付個数
|
||||
*/
|
||||
|
|
@ -6937,6 +6949,10 @@ export interface Locale extends ILocale {
|
|||
* botユーザー
|
||||
*/
|
||||
"isBot": string;
|
||||
/**
|
||||
* TTSユーザー
|
||||
*/
|
||||
"isVI": string;
|
||||
/**
|
||||
* サスペンド済みユーザー
|
||||
*/
|
||||
|
|
@ -7328,6 +7344,10 @@ export interface Locale extends ILocale {
|
|||
* Misskeyを翻訳
|
||||
*/
|
||||
"translation": string;
|
||||
/**
|
||||
* Misskeyを変換
|
||||
*/
|
||||
"convert": string;
|
||||
/**
|
||||
* Misskeyに寄付
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ flagAsBot: "Botとして設定"
|
|||
flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。"
|
||||
flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!"
|
||||
flagAsCatDescription: "にゃにゃにゃ??"
|
||||
flagAsVI: "自動TTS機能が欲しい。"
|
||||
flagAsVIDescription: "自動TTS機能が必要な場合は有効にしてください。 権限のあるユーザーグループに所属している場合、特定の範囲で自動TTS機能を有効にします。"
|
||||
flagShowTimelineReplies: "タイムラインにノートへの返信を表示する"
|
||||
flagShowTimelineRepliesDescription: "オンにすると、タイムラインにユーザーのノート以外にもそのユーザーの他のノートへの返信を表示します。"
|
||||
autoAcceptFollowed: "フォロー中ユーザーからのフォロリクを自動承認"
|
||||
|
|
@ -1780,6 +1782,7 @@ _role:
|
|||
canHideAds: "広告の非表示"
|
||||
canSearchNotes: "ノート検索の利用"
|
||||
canUseTranslator: "翻訳機能の利用"
|
||||
canUseTTS: "TTS機能の利用"
|
||||
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
|
||||
canImportAntennas: "アンテナのインポートを許可"
|
||||
canImportBlocking: "ブロックのインポートを許可"
|
||||
|
|
@ -1792,6 +1795,7 @@ _role:
|
|||
isRemote: "リモートユーザー"
|
||||
isCat: "猫ユーザー"
|
||||
isBot: "botユーザー"
|
||||
isVI: "TTSユーザー"
|
||||
isSuspended: "サスペンド済みユーザー"
|
||||
isLocked: "鍵アカウントユーザー"
|
||||
isExplorable: "「アカウントを見つけやすくする」が有効なユーザー"
|
||||
|
|
@ -1910,6 +1914,7 @@ _aboutMisskey:
|
|||
original: "オリジナル"
|
||||
thisIsModifiedVersion: "{name}はオリジナルのMisskeyを改変したバージョンを使用しています。"
|
||||
translation: "Misskeyを翻訳"
|
||||
convert: "Misskeyを変換"
|
||||
donate: "Misskeyに寄付"
|
||||
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰"
|
||||
patrons: "支援者"
|
||||
|
|
|
|||
19
packages/backend/migration/1724683952000-tts.js
Normal file
19
packages/backend/migration/1724683952000-tts.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class TTSIntegration1724683952000 {
|
||||
constructor() {
|
||||
this.name = 'TTSIntegration1724683952000';
|
||||
}
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfAuthKey" character varying(128)`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfAuthKey"`);
|
||||
}
|
||||
}
|
||||
|
||||
45
packages/backend/migration/1724683962000-tts.js
Normal file
45
packages/backend/migration/1724683962000-tts.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class TTSIntegration1724683962000 {
|
||||
constructor() {
|
||||
this.name = 'TTSIntegration1724683962000';
|
||||
}
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "user" ADD "isVI" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isVI" IS 'Whether the User needs auto TTS.'`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfSpace" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfSpaceName" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfexampleAudioURL" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfexampleText" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfexampleLang" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfslice" character varying(128) DEFAULT 'Slice once every 4 sentences'`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hftopK" INTEGER DEFAULT 15`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hftopP" INTEGER DEFAULT 100`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfTemperature" INTEGER DEFAULT 100`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfnrm" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfSpeedRate" INTEGER DEFAULT 125`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "hfdas" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`COMMENT ON COLUMN "user"."isVI" IS NULL`);
|
||||
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isVI"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfSpace"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfSpaceName"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfexampleAudioURL"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfexampleText"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfexampleLang"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfslice"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hftopK"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hftopP"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfTemperature"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfnrm"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfSpeedRate"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "hfdas"`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +81,7 @@
|
|||
"@fastify/multipart": "9.0.1",
|
||||
"@fastify/static": "8.0.1",
|
||||
"@fastify/view": "10.0.1",
|
||||
"@gradio/client": "1.6.0-beta.3",
|
||||
"@misskey-dev/sharp-read-bmp": "1.2.0",
|
||||
"@misskey-dev/summaly": "5.1.0",
|
||||
"@napi-rs/canvas": "0.1.56",
|
||||
|
|
@ -134,8 +135,8 @@
|
|||
"json5": "2.2.3",
|
||||
"jsonld": "8.3.2",
|
||||
"jsrsasign": "11.1.0",
|
||||
"meilisearch": "0.42.0",
|
||||
"juice": "11.0.0",
|
||||
"meilisearch": "0.42.0",
|
||||
"mfm-js": "0.24.0",
|
||||
"microformats-parser": "2.0.2",
|
||||
"mime-types": "2.1.35",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ export type RolePolicies = {
|
|||
canManageAvatarDecorations: boolean;
|
||||
canSearchNotes: boolean;
|
||||
canUseTranslator: boolean;
|
||||
canUseTTS: boolean;
|
||||
canHideAds: boolean;
|
||||
driveCapacityMb: number;
|
||||
alwaysMarkNsfw: boolean;
|
||||
|
|
@ -78,6 +79,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
|||
canManageAvatarDecorations: false,
|
||||
canSearchNotes: false,
|
||||
canUseTranslator: true,
|
||||
canUseTTS: true,
|
||||
canHideAds: false,
|
||||
driveCapacityMb: 100,
|
||||
alwaysMarkNsfw: false,
|
||||
|
|
@ -256,6 +258,10 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
|||
case 'isCat': {
|
||||
return user.isCat;
|
||||
}
|
||||
// Auto TTS
|
||||
case 'isVI': {
|
||||
return user.isVI;
|
||||
}
|
||||
// 「ユーザを見つけやすくする」が有効なアカウント
|
||||
case 'isExplorable': {
|
||||
return user.isExplorable;
|
||||
|
|
@ -383,6 +389,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
|||
canManageAvatarDecorations: calc('canManageAvatarDecorations', vs => vs.some(v => v === true)),
|
||||
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
|
||||
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
|
||||
canUseTTS: calc('canUseTTS', vs => vs.some(v => v === true)),
|
||||
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
|
||||
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
|
||||
alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)),
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ function generateDummyUser(override?: Partial<MiUser>): MiUser {
|
|||
isLocked: false,
|
||||
isBot: false,
|
||||
isCat: true,
|
||||
isVI: false,
|
||||
isRoot: false,
|
||||
isExplorable: true,
|
||||
isHibernated: false,
|
||||
|
|
@ -198,6 +199,7 @@ function toPackedUserLite(user: MiUser, override?: Packed<'UserLite'>): Packed<'
|
|||
})),
|
||||
isBot: user.isBot,
|
||||
isCat: user.isCat,
|
||||
isVI: user.isVI,
|
||||
emojis: user.emojis,
|
||||
onlineStatus: 'active',
|
||||
badgeRoles: [],
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ export class MetaEntityService {
|
|||
enableServiceWorker: instance.enableServiceWorker,
|
||||
|
||||
translatorAvailable: instance.deeplAuthKey != null,
|
||||
ttsAvailable: instance.hfAuthKey != null,
|
||||
|
||||
serverRules: instance.serverRules,
|
||||
|
||||
|
|
|
|||
|
|
@ -490,6 +490,7 @@ export class UserEntityService implements OnModuleInit {
|
|||
}))) : [],
|
||||
isBot: user.isBot,
|
||||
isCat: user.isCat,
|
||||
isVI: user.isVI,
|
||||
instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? {
|
||||
name: instance.name,
|
||||
softwareName: instance.softwareName,
|
||||
|
|
|
|||
|
|
@ -359,6 +359,78 @@ export class MiMeta {
|
|||
})
|
||||
public deeplIsPro: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public hfAuthKey: string | null;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public hfSpace: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public hfSpaceName: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public hfexampleAudioURL: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public hfexampleText: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
})
|
||||
public hfexampleLang: string | null;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
default: 'Slice once every 4 sentences',
|
||||
nullable: true,
|
||||
})
|
||||
public hfslice: string | null;
|
||||
|
||||
@Column('integer', {
|
||||
default: 15,
|
||||
})
|
||||
public hftopK: number;
|
||||
|
||||
@Column('integer', {
|
||||
default: 100,
|
||||
})
|
||||
public hftopP: number;
|
||||
|
||||
@Column('integer', {
|
||||
default: 100,
|
||||
})
|
||||
public hfTemperature: number;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public hfnrm: boolean;
|
||||
|
||||
@Column('integer', {
|
||||
default: 125,
|
||||
})
|
||||
public hfSpeedRate: number;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public hfdas: boolean;
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
nullable: true,
|
||||
|
|
|
|||
|
|
@ -83,6 +83,13 @@ type CondFormulaValueIsCat = {
|
|||
type: 'isCat';
|
||||
};
|
||||
|
||||
/**
|
||||
* Auto TTS
|
||||
*/
|
||||
type CondFormulaValueIsVI = {
|
||||
type: 'isVI';
|
||||
};
|
||||
|
||||
/**
|
||||
* 「ユーザを見つけやすくする」が有効なアカウントの場合のみ成立とする
|
||||
*/
|
||||
|
|
@ -164,6 +171,7 @@ export type RoleCondFormulaValue = { id: string } & (
|
|||
CondFormulaValueIsLocked |
|
||||
CondFormulaValueIsBot |
|
||||
CondFormulaValueIsCat |
|
||||
CondFormulaValueIsVI |
|
||||
CondFormulaValueIsExplorable |
|
||||
CondFormulaValueRoleAssignedTo |
|
||||
CondFormulaValueCreatedLessThan |
|
||||
|
|
|
|||
|
|
@ -184,6 +184,12 @@ export class MiUser {
|
|||
})
|
||||
public isCat: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
comment: 'Whether the User needs auto TTS.',
|
||||
})
|
||||
public isVI: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
comment: 'Whether the User is the root.',
|
||||
|
|
|
|||
|
|
@ -207,6 +207,10 @@ export const packedMetaLiteSchema = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
ttsAvailable: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
mediaProxy: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export const packedRoleCondFormulaValueUserSettingBooleanSchema = {
|
|||
type: {
|
||||
type: 'string',
|
||||
nullable: false, optional: false,
|
||||
enum: ['isSuspended', 'isLocked', 'isBot', 'isCat', 'isExplorable'],
|
||||
enum: ['isSuspended', 'isLocked', 'isBot', 'isCat', 'isVI', 'isExplorable'],
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
@ -216,6 +216,10 @@ export const packedRolePoliciesSchema = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canUseTTS: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
canHideAds: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,10 @@ export const packedUserLiteSchema = {
|
|||
type: 'boolean',
|
||||
nullable: false, optional: true,
|
||||
},
|
||||
isVI: {
|
||||
type: 'boolean',
|
||||
nullable: false, optional: true,
|
||||
},
|
||||
instance: {
|
||||
type: 'object',
|
||||
nullable: false, optional: true,
|
||||
|
|
|
|||
|
|
@ -305,6 +305,7 @@ import * as ep___notes_threadMuting_create from './endpoints/notes/thread-muting
|
|||
import * as ep___notes_threadMuting_delete from './endpoints/notes/thread-muting/delete.js';
|
||||
import * as ep___notes_timeline from './endpoints/notes/timeline.js';
|
||||
import * as ep___notes_translate from './endpoints/notes/translate.js';
|
||||
import * as ep___notes_tts from './endpoints/notes/tts.js';
|
||||
import * as ep___notes_unrenote from './endpoints/notes/unrenote.js';
|
||||
import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js';
|
||||
import * as ep___notifications_create from './endpoints/notifications/create.js';
|
||||
|
|
@ -692,6 +693,7 @@ const $notes_threadMuting_create: Provider = { provide: 'ep:notes/thread-muting/
|
|||
const $notes_threadMuting_delete: Provider = { provide: 'ep:notes/thread-muting/delete', useClass: ep___notes_threadMuting_delete.default };
|
||||
const $notes_timeline: Provider = { provide: 'ep:notes/timeline', useClass: ep___notes_timeline.default };
|
||||
const $notes_translate: Provider = { provide: 'ep:notes/translate', useClass: ep___notes_translate.default };
|
||||
const $notes_tts: Provider = { provide: 'ep:notes/tts', useClass: ep___notes_tts.default };
|
||||
const $notes_unrenote: Provider = { provide: 'ep:notes/unrenote', useClass: ep___notes_unrenote.default };
|
||||
const $notes_userListTimeline: Provider = { provide: 'ep:notes/user-list-timeline', useClass: ep___notes_userListTimeline.default };
|
||||
const $notifications_create: Provider = { provide: 'ep:notifications/create', useClass: ep___notifications_create.default };
|
||||
|
|
@ -1083,6 +1085,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
|||
$notes_threadMuting_delete,
|
||||
$notes_timeline,
|
||||
$notes_translate,
|
||||
$notes_tts,
|
||||
$notes_unrenote,
|
||||
$notes_userListTimeline,
|
||||
$notifications_create,
|
||||
|
|
@ -1468,6 +1471,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
|||
$notes_threadMuting_delete,
|
||||
$notes_timeline,
|
||||
$notes_translate,
|
||||
$notes_tts,
|
||||
$notes_unrenote,
|
||||
$notes_userListTimeline,
|
||||
$notifications_create,
|
||||
|
|
|
|||
|
|
@ -311,6 +311,7 @@ import * as ep___notes_threadMuting_create from './endpoints/notes/thread-muting
|
|||
import * as ep___notes_threadMuting_delete from './endpoints/notes/thread-muting/delete.js';
|
||||
import * as ep___notes_timeline from './endpoints/notes/timeline.js';
|
||||
import * as ep___notes_translate from './endpoints/notes/translate.js';
|
||||
import * as ep___notes_tts from './endpoints/notes/tts.js';
|
||||
import * as ep___notes_unrenote from './endpoints/notes/unrenote.js';
|
||||
import * as ep___notes_userListTimeline from './endpoints/notes/user-list-timeline.js';
|
||||
import * as ep___notifications_create from './endpoints/notifications/create.js';
|
||||
|
|
@ -696,6 +697,7 @@ const eps = [
|
|||
['notes/thread-muting/delete', ep___notes_threadMuting_delete],
|
||||
['notes/timeline', ep___notes_timeline],
|
||||
['notes/translate', ep___notes_translate],
|
||||
['notes/tts', ep___notes_tts],
|
||||
['notes/unrenote', ep___notes_unrenote],
|
||||
['notes/user-list-timeline', ep___notes_userListTimeline],
|
||||
['notifications/create', ep___notifications_create],
|
||||
|
|
|
|||
|
|
@ -122,6 +122,10 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
ttsAvailable: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
silencedHosts: {
|
||||
type: 'array',
|
||||
optional: true,
|
||||
|
|
@ -412,6 +416,58 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
hfAuthKey: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfSpace: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
hfSpaceName: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfexampleAudioURL: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfexampleText: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfexampleLang: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfslice: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hftopK: {
|
||||
type: 'number',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hftopP: {
|
||||
type: 'number',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfTemperature: {
|
||||
type: 'number',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfSpeedRate: {
|
||||
type: 'number',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
hfnrm: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
hfdas: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
defaultDarkTheme: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
|
|
@ -588,6 +644,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
enableEmail: instance.enableEmail,
|
||||
enableServiceWorker: instance.enableServiceWorker,
|
||||
translatorAvailable: instance.deeplAuthKey != null,
|
||||
ttsAvailable: instance.hfAuthKey != null,
|
||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
||||
pinnedUsers: instance.pinnedUsers,
|
||||
|
|
@ -630,6 +687,19 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
|
||||
deeplAuthKey: instance.deeplAuthKey,
|
||||
deeplIsPro: instance.deeplIsPro,
|
||||
hfAuthKey: instance.hfAuthKey,
|
||||
hfSpace: instance.hfSpace,
|
||||
hfSpaceName: instance.hfSpaceName,
|
||||
hfexampleAudioURL: instance.hfexampleAudioURL,
|
||||
hfexampleText: instance.hfexampleText,
|
||||
hfexampleLang: instance.hfexampleLang,
|
||||
hfslice: instance.hfslice,
|
||||
hftopK: instance.hftopK,
|
||||
hftopP: instance.hftopP,
|
||||
hfTemperature: instance.hfTemperature,
|
||||
hfSpeedRate: instance.hfSpeedRate,
|
||||
hfnrm: instance.hfnrm,
|
||||
hfdas: instance.hfdas,
|
||||
enableIpLogging: instance.enableIpLogging,
|
||||
enableActiveEmailValidation: instance.enableActiveEmailValidation,
|
||||
enableVerifymailApi: instance.enableVerifymailApi,
|
||||
|
|
|
|||
|
|
@ -98,6 +98,19 @@ export const paramDef = {
|
|||
},
|
||||
deeplAuthKey: { type: 'string', nullable: true },
|
||||
deeplIsPro: { type: 'boolean' },
|
||||
hfAuthKey: { type: 'string', nullable: true },
|
||||
hfSpace: { type: 'boolean', default: false },
|
||||
hfSpaceName: { type: 'string', nullable: true },
|
||||
hfexampleAudioURL: { type: 'string', nullable: true },
|
||||
hfexampleText: { type: 'string', nullable: true },
|
||||
hfexampleLang: { type: 'string', nullable: true },
|
||||
hfslice: { type: 'string', default: 'Slice once every 4 sentences', nullable: true },
|
||||
hftopK: { type: 'integer', default: 15 },
|
||||
hftopP: { type: 'integer', default: 100 },
|
||||
hfTemperature: { type: 'integer', default: 100 },
|
||||
hfnrm: { type: 'boolean', default: false },
|
||||
hfSpeedRate: { type: 'integer', default: 125 },
|
||||
hfdas: { type: 'boolean', default: false },
|
||||
enableEmail: { type: 'boolean' },
|
||||
email: { type: 'string', nullable: true },
|
||||
smtpSecure: { type: 'boolean' },
|
||||
|
|
@ -531,6 +544,82 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
set.deeplIsPro = ps.deeplIsPro;
|
||||
}
|
||||
|
||||
if (ps.hfAuthKey !== undefined) {
|
||||
if (ps.hfAuthKey === '') {
|
||||
set.hfAuthKey = null;
|
||||
} else {
|
||||
set.hfAuthKey = ps.hfAuthKey;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.hfSpace !== undefined) {
|
||||
set.hfSpace = ps.hfSpace;
|
||||
}
|
||||
|
||||
if (ps.hfSpaceName !== undefined) {
|
||||
if (ps.hfSpaceName === '') {
|
||||
set.hfSpaceName = null;
|
||||
} else {
|
||||
set.hfSpaceName = ps.hfSpaceName;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.hfexampleAudioURL !== undefined) {
|
||||
if (ps.hfexampleAudioURL === '') {
|
||||
set.hfexampleAudioURL = null;
|
||||
} else {
|
||||
set.hfexampleAudioURL = ps.hfexampleAudioURL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.hfexampleText !== undefined) {
|
||||
if (ps.hfexampleText === '') {
|
||||
set.hfexampleText = null;
|
||||
} else {
|
||||
set.hfexampleText = ps.hfexampleText;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.hfexampleLang !== undefined) {
|
||||
if (ps.hfexampleLang === '') {
|
||||
set.hfexampleLang = null;
|
||||
} else {
|
||||
set.hfexampleLang = ps.hfexampleLang;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.hfslice !== undefined) {
|
||||
if (ps.hfslice === '') {
|
||||
set.hfslice = null;
|
||||
} else {
|
||||
set.hfslice = ps.hfslice;
|
||||
}
|
||||
}
|
||||
|
||||
if (ps.hftopK !== undefined) {
|
||||
set.hftopK = ps.hftopK;
|
||||
}
|
||||
|
||||
if (ps.hftopP !== undefined) {
|
||||
set.hftopP = ps.hftopP;
|
||||
}
|
||||
|
||||
if (ps.hfTemperature !== undefined) {
|
||||
set.hfTemperature = ps.hfTemperature;
|
||||
}
|
||||
|
||||
if (ps.hfnrm !== undefined) {
|
||||
set.hfnrm = ps.hfnrm;
|
||||
}
|
||||
|
||||
if (ps.hfSpeedRate !== undefined) {
|
||||
set.hfSpeedRate = ps.hfSpeedRate;
|
||||
}
|
||||
|
||||
if (ps.hfdas !== undefined) {
|
||||
set.hfdas = ps.hfdas;
|
||||
}
|
||||
|
||||
if (ps.enableIpLogging !== undefined) {
|
||||
set.enableIpLogging = ps.enableIpLogging;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ export const paramDef = {
|
|||
preventAiLearning: { type: 'boolean' },
|
||||
isBot: { type: 'boolean' },
|
||||
isCat: { type: 'boolean' },
|
||||
isVI: { type: 'boolean' },
|
||||
injectFeaturedNote: { type: 'boolean' },
|
||||
receiveAnnouncementEmail: { type: 'boolean' },
|
||||
alwaysMarkNsfw: { type: 'boolean' },
|
||||
|
|
@ -335,6 +336,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle;
|
||||
if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning;
|
||||
if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat;
|
||||
if (typeof ps.isVI === 'boolean') updates.isVI = ps.isVI;
|
||||
if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote;
|
||||
if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail;
|
||||
if (typeof ps.alwaysMarkNsfw === 'boolean') {
|
||||
|
|
|
|||
197
packages/backend/src/server/api/endpoints/notes/tts.ts
Normal file
197
packages/backend/src/server/api/endpoints/notes/tts.ts
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Client } from "@gradio/client";
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { GetterService } from '@/server/api/GetterService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { ApiError } from '../../error.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['notes'],
|
||||
|
||||
requireCredential: true,
|
||||
kind: 'read:account',
|
||||
|
||||
res: {
|
||||
type: 'string',
|
||||
optional: true, nullable: false,
|
||||
contentMediaType: 'audio/flac',
|
||||
},
|
||||
|
||||
errors: {
|
||||
incorrectconfig: {
|
||||
message: 'Incorrect configuration.',
|
||||
code: 'INCORRECT_CONFIG',
|
||||
id: '8d171e60-83b8-11ef-b98c-a7506d6c1de4',
|
||||
},
|
||||
unavailable: {
|
||||
message: 'Convert of notes unavailable.',
|
||||
code: 'UNAVAILABLE',
|
||||
id: '97a0826c-6393-11ef-a650-67972d710975',
|
||||
},
|
||||
noSuchNote: {
|
||||
message: 'No such note.',
|
||||
code: 'NO_SUCH_NOTE',
|
||||
id: 'bea9b03f-36e0-49c5-a4db-627a029f8971',
|
||||
},
|
||||
cannotConvertInvisibleNote: {
|
||||
message: 'Cannot convert invisible note.',
|
||||
code: 'CANNOT_CONVERT_INVISIBLE_NOTE',
|
||||
id: 'f57caae0-6394-11ef-8e2a-d706932c1030',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
noteId: { type: 'string', format: 'misskey:id' },
|
||||
},
|
||||
required: ['noteId'],
|
||||
} as const;
|
||||
|
||||
@Injectable()
|
||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||
constructor(
|
||||
private noteEntityService: NoteEntityService,
|
||||
private getterService: GetterService,
|
||||
private metaService: MetaService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private roleService: RoleService,
|
||||
) {
|
||||
// @ts-expect-error: Functionality can be implemented here with minimal modifications.
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const policies = await this.roleService.getUserPolicies(me.id);
|
||||
if (!policies.canUseTTS) {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
|
||||
const note = await this.getterService.getNote(ps.noteId).catch(err => {
|
||||
if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||
throw err;
|
||||
});
|
||||
|
||||
if (!(await this.noteEntityService.isVisibleForMe(note, me.id))) {
|
||||
throw new ApiError(meta.errors.cannotConvertInvisibleNote);
|
||||
}
|
||||
|
||||
if (note.text == null) {
|
||||
throw new ApiError(meta.errors.cannotConvertInvisibleNote);
|
||||
}
|
||||
|
||||
const instance = await this.metaService.fetch();
|
||||
|
||||
if (instance.hfAuthKey == null) {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
|
||||
let outofQuota;
|
||||
|
||||
if (instance.hfSpace) {
|
||||
const langlist = ['Chinese', 'English', 'Japanese', 'Yue', 'Korean', 'Chinese-English Mixed', 'Japanese-English Mixed', 'Yue-English Mixed', 'Korean-English Mixed', 'Multilingual Mixed', 'Multilingual Mixed(Yue)'];
|
||||
const slicelist = ['No slice', 'Slice once every 4 sentences', 'Slice per 50 characters', 'Slice by Chinese punct', 'Slice by English punct', 'Slice by every punct'];
|
||||
let exampleAudio;
|
||||
let app;
|
||||
|
||||
try {
|
||||
const example = await fetch(instance.hfexampleAudioURL || '');
|
||||
exampleAudio = await example.blob();
|
||||
} catch (e) {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
|
||||
if (((!instance.hfnrm) && (!instance.hfexampleText)) || (!langlist.includes(instance.hfexampleLang || '')) || (!slicelist.includes(instance.hfslice || '')) || (!instance.hfSpaceName) || (!(instance.hfSpeedRate >= 60 && instance.hfSpeedRate <= 165)) || (!(instance.hfTemperature >= 0 && instance.hfTemperature <= 100)) || (!(instance.hftopK >= 0 && instance.hftopK <= 100)) || (!(instance.hftopP >= 0 && instance.hftopP <= 100))) {
|
||||
throw new ApiError(meta.errors.incorrectconfig);
|
||||
}
|
||||
|
||||
try {
|
||||
app = await Client.connect(instance.hfSpaceName, { hf_token: instance.hfAuthKey });
|
||||
} catch (e) {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
|
||||
let result;
|
||||
let notcontinue;
|
||||
|
||||
try {
|
||||
result = await app.predict("/get_tts_wav", [
|
||||
exampleAudio,
|
||||
instance.hfexampleText,
|
||||
instance.hfexampleLang,
|
||||
note.text,
|
||||
"Multilingual Mixed",
|
||||
instance.hfslice,
|
||||
instance.hftopK,
|
||||
instance.hftopP / 100,
|
||||
instance.hfTemperature / 100,
|
||||
instance.hfnrm,
|
||||
instance.hfSpeedRate / 100,
|
||||
instance.hfdas,
|
||||
]);
|
||||
} catch (e) {
|
||||
const responseMessage = (e as any).message || ((e as any).original_msg && (e as any).original_msg.message);
|
||||
|
||||
if (responseMessage && responseMessage.includes('You have exceeded your GPU quota')) {
|
||||
outofQuota = true;
|
||||
console.info("Fallback to Inference API");
|
||||
notcontinue = true;
|
||||
} else {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
}
|
||||
|
||||
if (!notcontinue) {
|
||||
const resurl = result.data[0].url;
|
||||
|
||||
const res = await this.httpRequestService.send(resurl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + instance.hfAuthKey,
|
||||
},
|
||||
timeout: 60000,
|
||||
});
|
||||
|
||||
const contentType = res.headers.get('Content-Type') || 'application/octet-stream';
|
||||
|
||||
if (contentType === 'audio/x-wav') {
|
||||
return res.body;
|
||||
} else {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!instance.hfSpace) || ((instance.hfSpace) && (outofQuota))) {
|
||||
const endpoint = 'https://api-inference.huggingface.co/models/suno/bark';
|
||||
|
||||
const res = await this.httpRequestService.send(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + instance.hfAuthKey,
|
||||
Accept: 'audio/flac, */*',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
inputs: note.text,
|
||||
}),
|
||||
timeout: 60000,
|
||||
});
|
||||
|
||||
const contentType = res.headers.get('Content-Type') || 'application/octet-stream';
|
||||
|
||||
if (contentType === 'audio/flac') {
|
||||
return res.body;
|
||||
} else {
|
||||
throw new ApiError(meta.errors.unavailable);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -87,6 +87,7 @@ export const ROLE_POLICIES = [
|
|||
'canManageAvatarDecorations',
|
||||
'canSearchNotes',
|
||||
'canUseTranslator',
|
||||
'canUseTTS',
|
||||
'canHideAds',
|
||||
'driveCapacityMb',
|
||||
'alwaysMarkNsfw',
|
||||
|
|
|
|||
|
|
@ -84,6 +84,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="converting || convert" :class="$style.translation">
|
||||
<MkLoading v-if="converting" mini/>
|
||||
<div v-else-if="converturl">
|
||||
<!--<b>{{ i18n.tsx.convertedFrom({ x: appearNote.id }) }}: </b>-->
|
||||
<b>{{ 'From ' + appearNote.id }} </b>
|
||||
<MkMediaAudio :audio="converturl"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="appearNote.files && appearNote.files.length > 0">
|
||||
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
||||
|
|
@ -167,7 +175,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, ref, shallowRef, Ref, watch, provide } from 'vue';
|
||||
import { computed, inject, onMounted, ref, shallowRef, Ref, watch, provide, onUnmounted } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { isLink } from '@@/js/is-link.js';
|
||||
|
|
@ -177,6 +185,7 @@ import type { MenuItem } from '@/types/menu.js';
|
|||
import MkNoteSub from '@/components/MkNoteSub.vue';
|
||||
import MkNoteHeader from '@/components/MkNoteHeader.vue';
|
||||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||
import MkMediaAudio from '@/components/MkMediaAudio.vue';
|
||||
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
||||
import MkReactionsViewerDetails from '@/components/MkReactionsViewer.details.vue';
|
||||
import MkMediaList from '@/components/MkMediaList.vue';
|
||||
|
|
@ -272,6 +281,9 @@ const muted = ref(checkMute(appearNote.value, $i?.mutedWords));
|
|||
const hardMuted = ref(props.withHardMute && checkMute(appearNote.value, $i?.hardMutedWords, true));
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const convert = ref<Blob | null>(null);
|
||||
const converting = ref(false);
|
||||
const converturl = ref<Misskey.entities.NotesTTSResponse | null>(null);
|
||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
const canRenote = computed(() => ['public', 'home'].includes(appearNote.value.visibility) || (appearNote.value.visibility === 'followers' && appearNote.value.userId === $i?.id));
|
||||
const renoteCollapsed = ref(
|
||||
|
|
@ -531,7 +543,7 @@ function showMenu(): void {
|
|||
return;
|
||||
}
|
||||
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted, currentClip: currentClip?.value });
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, convert, converting, isDeleted, currentClip: currentClip?.value });
|
||||
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
||||
}
|
||||
|
||||
|
|
@ -609,6 +621,24 @@ function emitUpdReaction(emoji: string, delta: number) {
|
|||
emit('reaction', emoji);
|
||||
}
|
||||
}
|
||||
|
||||
watch(convert, (newBlob) => {
|
||||
try {
|
||||
if (newBlob) {
|
||||
converturl.value = { url: newBlob };
|
||||
} else {
|
||||
converturl.value = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create URL:', error);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (converturl.value && converturl.value.url) {
|
||||
URL.revokeObjectURL(converturl.value.url);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
|||
|
|
@ -99,6 +99,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="converting || convert" :class="$style.translation">
|
||||
<MkLoading v-if="converting" mini/>
|
||||
<div v-else-if="converturl">
|
||||
<!--<b>{{ i18n.tsx.convertedFrom({ x: appearNote.id }) }}: </b>-->
|
||||
<b>{{ 'From ' + appearNote.id }} </b>
|
||||
<MkMediaAudio :audio="converturl"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="appearNote.files && appearNote.files.length > 0">
|
||||
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
|
||||
</div>
|
||||
|
|
@ -203,7 +211,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, provide, ref, shallowRef } from 'vue';
|
||||
import { computed, inject, onMounted, provide, ref, shallowRef, watch, onUnmounted } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { isLink } from '@@/js/is-link.js';
|
||||
|
|
@ -211,6 +219,7 @@ import MkNoteSub from '@/components/MkNoteSub.vue';
|
|||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
||||
import MkReactionsViewerDetails from '@/components/MkReactionsViewer.details.vue';
|
||||
import MkMediaAudio from '@/components/MkMediaAudio.vue';
|
||||
import MkMediaList from '@/components/MkMediaList.vue';
|
||||
import MkCwButton from '@/components/MkCwButton.vue';
|
||||
import MkPoll from '@/components/MkPoll.vue';
|
||||
|
|
@ -292,6 +301,9 @@ const isDeleted = ref(false);
|
|||
const muted = ref($i ? checkWordMute(appearNote.value, $i, $i.mutedWords) : false);
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | null>(null);
|
||||
const translating = ref(false);
|
||||
const convert = ref<Blob | null>(null);
|
||||
const converting = ref(false);
|
||||
const converturl = ref<Misskey.entities.NotesTTSResponse | null>(null);
|
||||
const parsed = appearNote.value.text ? mfm.parse(appearNote.value.text) : null;
|
||||
const urls = parsed ? extractUrlFromMfm(parsed).filter((url) => appearNote.value.renote?.url !== url && appearNote.value.renote?.uri !== url) : null;
|
||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
|
|
@ -483,13 +495,13 @@ function onContextmenu(ev: MouseEvent): void {
|
|||
ev.preventDefault();
|
||||
react();
|
||||
} else {
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, converting, convert, isDeleted });
|
||||
os.contextMenu(menu, ev).then(focus).finally(cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
function showMenu(): void {
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
|
||||
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, converting, convert, isDeleted });
|
||||
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
|
||||
}
|
||||
|
||||
|
|
@ -544,6 +556,24 @@ function loadConversation() {
|
|||
conversation.value = res.reverse();
|
||||
});
|
||||
}
|
||||
|
||||
watch(convert, (newBlob) => {
|
||||
try {
|
||||
if (newBlob) {
|
||||
converturl.value = { url: newBlob };
|
||||
} else {
|
||||
converturl.value = null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create URL:', error);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (converturl.value && converturl.value.url) {
|
||||
URL.revokeObjectURL(converturl.value.url);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ const exampleNote = reactive<Misskey.entities.Note>({
|
|||
avatarBlurhash: 'eiKmhHIByXxZ~qWXs:-pR*NbR*s:xuRjoL-oR*WCt6WWf6WVf6oeWB',
|
||||
isBot: false,
|
||||
isCat: true,
|
||||
isVI: false,
|
||||
emojis: {},
|
||||
onlineStatus: 'unknown',
|
||||
badgeRoles: [],
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<option value="isLocked">{{ i18n.ts._role._condition.isLocked }}</option>
|
||||
<option value="isBot">{{ i18n.ts._role._condition.isBot }}</option>
|
||||
<option value="isCat">{{ i18n.ts._role._condition.isCat }}</option>
|
||||
<option value="isVI">{{ i18n.ts._role._condition.isVI }}</option>
|
||||
<option value="isExplorable">{{ i18n.ts._role._condition.isExplorable }}</option>
|
||||
<option value="roleAssignedTo">{{ i18n.ts._role._condition.roleAssignedTo }}</option>
|
||||
<option value="createdLessThan">{{ i18n.ts._role._condition.createdLessThan }}</option>
|
||||
|
|
|
|||
|
|
@ -5,25 +5,99 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||
<FormSuspense :p="init">
|
||||
<MkFolder>
|
||||
<template #label>DeepL Translation</template>
|
||||
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||
<FormSuspense :p="init">
|
||||
<MkFolder>
|
||||
<template #label>DeepL Translation</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkInput v-model="deeplAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>DeepL Auth Key</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="deeplIsPro">
|
||||
<template #label>Pro account</template>
|
||||
</MkSwitch>
|
||||
<MkButton primary @click="save_deepl">Save</MkButton>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
<div class="_gaps_m">
|
||||
<MkInput v-model="deeplAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>DeepL Auth Key</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="deeplIsPro">
|
||||
<template #label>Pro account</template>
|
||||
</MkSwitch>
|
||||
<MkButton primary @click="save_deepl">Save</MkButton>
|
||||
</div>
|
||||
</MkFolder>
|
||||
<br />
|
||||
<MkFolder>
|
||||
<template #label>Text-To-Speech</template>
|
||||
<div class="_gaps_m">
|
||||
<MkInput v-model="hfAuthKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>HuggingFace Auth Key</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="hfSpace">
|
||||
<template #label>HuggingFace Space</template>
|
||||
</MkSwitch>
|
||||
<div v-if="hfSpace">
|
||||
<MkInput v-model="hfSpaceName">
|
||||
<template #label>Space Name</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="hfexampleAudioURL">
|
||||
<template #label>Example Audio URL</template>
|
||||
</MkInput>
|
||||
<br />
|
||||
<MkSwitch v-model="hfnrm">
|
||||
<template #label>Enable no reference mode</template>
|
||||
</MkSwitch>
|
||||
<br />
|
||||
<div v-if="!hfnrm">
|
||||
<MkInput v-model="hfexampleText">
|
||||
<template #label>Example Text</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
<MkSelect v-model="hfexampleLang">
|
||||
<template #label>Example Language</template>
|
||||
<option value="" disabled> </option>
|
||||
<option value="Chinese">中文</option>
|
||||
<option value="English">English</option>
|
||||
<option value="Japanese">日本語</option>
|
||||
<option value="Yue">中文 (粤语)</option>
|
||||
<option value="Korean">한국어</option>
|
||||
<option value="Chinese-English Mixed">中文 - English</option>
|
||||
<option value="Japanese-English Mixed">日本語 - English</option>
|
||||
<option value="Yue-English Mixed">中文 (粤语) - English</option>
|
||||
<option value="Korean-English Mixed">한국어 - English</option>
|
||||
<option value="Multilingual Mixed">Multilingual Mixed</option>
|
||||
<option value="Multilingual Mixed(Yue)">Multilingual Mixed (Yue)</option>
|
||||
</MkSelect>
|
||||
<br />
|
||||
<MkSwitch v-model="hfdas">
|
||||
<template #label>Whether to directly adjust the speech rate and timebre of the last synthesis result to prevent randomness</template>
|
||||
</MkSwitch>
|
||||
<br />
|
||||
<MkSelect v-model="hfslice">
|
||||
<template #label>Slice</template>
|
||||
<option value="" disabled> </option>
|
||||
<option value="No slice">No slice</option>
|
||||
<option value="Slice once every 4 sentences">Slice once every 4 sentences</option>
|
||||
<option value="Slice per 50 characters">Slice per 50 characters</option>
|
||||
<option value="Slice by Chinese punct">Slice by Chinese punct</option>
|
||||
<option value="Slice by English punct">Slice by English punct</option>
|
||||
<option value="Slice by every punct">Slice by every punct</option>
|
||||
</MkSelect>
|
||||
<MkInput v-model.number="hftopK" type="range" :min="0" :max="100" :step="1">
|
||||
<template #label>Set top_k Value: {{ hftopK }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model.number="hftopP" type="range" :min="0" :max="100" :step="5">
|
||||
<template #label>Set top_p Value: {{ hftopP }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model.number="hfTemperature" type="range" :min="0" :max="100" :step="5">
|
||||
<template #label>Set Temperature Value: {{ hfTemperature }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model.number="hfSpeedRate" type="range" :min="60" :max="165" :step="5">
|
||||
<template #label>Set Speed Rate Value: {{ hfSpeedRate }}</template>
|
||||
</MkInput>
|
||||
</div>
|
||||
<MkButton primary @click="save_tts">Save</MkButton>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</FormSuspense>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
|
|
@ -32,6 +106,7 @@ import { ref, computed } from 'vue';
|
|||
import XHeader from './_header_.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkSelect from '@/components/MkSelect.vue';
|
||||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import FormSuspense from '@/components/form/suspense.vue';
|
||||
import * as os from '@/os.js';
|
||||
|
|
@ -43,20 +118,66 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
|
||||
const deeplAuthKey = ref<string>('');
|
||||
const deeplIsPro = ref<boolean>(false);
|
||||
const hfAuthKey = ref<string>('');
|
||||
const hfSpace = ref<boolean>(false);
|
||||
const hfSpaceName = ref<string | null>(null);
|
||||
const hfexampleAudioURL = ref<string | null>(null);
|
||||
const hfexampleText = ref<string | null>(null);
|
||||
const hfexampleLang = ref<string | null>(null);
|
||||
const hfslice = ref<string | null>('Slice once every 4 sentences');
|
||||
const hftopK = ref<number>(15);
|
||||
const hftopP = ref<number>(100);
|
||||
const hfTemperature = ref<number>(100);
|
||||
const hfnrm = ref<boolean>(false);
|
||||
const hfSpeedRate = ref<number>(125);
|
||||
const hfdas = ref<boolean>(false);
|
||||
|
||||
async function init() {
|
||||
const meta = await misskeyApi('admin/meta');
|
||||
deeplAuthKey.value = meta.deeplAuthKey;
|
||||
deeplIsPro.value = meta.deeplIsPro;
|
||||
const meta = await misskeyApi('admin/meta');
|
||||
deeplAuthKey.value = meta.deeplAuthKey;
|
||||
deeplIsPro.value = meta.deeplIsPro;
|
||||
hfAuthKey.value = meta.hfAuthKey;
|
||||
hfSpace.value = meta.hfSpace;
|
||||
hfSpaceName.value = meta.hfSpaceName;
|
||||
hfexampleAudioURL.value = meta.hfexampleAudioURL;
|
||||
hfexampleText.value = meta.hfexampleText;
|
||||
hfexampleLang.value = meta.hfexampleLang;
|
||||
hfslice.value = meta.hfslice;
|
||||
hftopK.value = meta.hftopK;
|
||||
hftopP.value = meta.hftopP;
|
||||
hfTemperature.value = meta.hfTemperature;
|
||||
hfnrm.value = meta.hfnrm;
|
||||
hfSpeedRate.value = meta.hfSpeedRate;
|
||||
hfdas.value = meta.hfdas;
|
||||
}
|
||||
|
||||
function save_deepl() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
deeplAuthKey: deeplAuthKey.value,
|
||||
deeplIsPro: deeplIsPro.value,
|
||||
}).then(() => {
|
||||
fetchInstance(true);
|
||||
});
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
deeplAuthKey: deeplAuthKey.value,
|
||||
deeplIsPro: deeplIsPro.value,
|
||||
}).then(() => {
|
||||
fetchInstance(true);
|
||||
});
|
||||
}
|
||||
|
||||
function save_tts() {
|
||||
os.apiWithDialog('admin/update-meta', {
|
||||
hfAuthKey: hfAuthKey.value,
|
||||
hfSpace: hfSpace.value,
|
||||
hfSpaceName: hfSpaceName.value,
|
||||
hfexampleAudioURL: hfexampleAudioURL.value,
|
||||
hfexampleText: hfexampleText.value,
|
||||
hfexampleLang: hfexampleLang.value,
|
||||
hfslice: hfslice.value,
|
||||
hftopK: hftopK.value,
|
||||
hftopP: hftopP.value,
|
||||
hfTemperature: hfTemperature.value,
|
||||
hfnrm: hfnrm.value,
|
||||
hfSpeedRate: hfSpeedRate.value,
|
||||
hfdas: hfdas.value,
|
||||
}).then(() => {
|
||||
fetchInstance(true);
|
||||
});
|
||||
}
|
||||
|
||||
const headerActions = computed(() => []);
|
||||
|
|
@ -64,7 +185,7 @@ const headerActions = computed(() => []);
|
|||
const headerTabs = computed(() => []);
|
||||
|
||||
definePageMetadata(() => ({
|
||||
title: i18n.ts.externalServices,
|
||||
icon: 'ti ti-link',
|
||||
title: i18n.ts.externalServices,
|
||||
icon: 'ti ti-link',
|
||||
}));
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -338,6 +338,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTTS, 'canUseTTS'])">
|
||||
<template #label>{{ i18n.ts._role._options.canUseTTS }}</template>
|
||||
<template #suffix>
|
||||
<span v-if="role.policies.canUseTTS.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||
<span v-else>{{ role.policies.canUseTTS.value ? i18n.ts.yes : i18n.ts.no }}</span>
|
||||
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.canUseTTS)"></i></span>
|
||||
</template>
|
||||
<div class="_gaps">
|
||||
<MkSwitch v-model="role.policies.canUseTTS.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="role.policies.canUseTTS.value" :disabled="role.policies.canUseTTS.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-model="role.policies.canUseTTS.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||
</MkRange>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.driveCapacity, 'driveCapacityMb'])">
|
||||
<template #label>{{ i18n.ts._role._options.driveCapacity }}</template>
|
||||
<template #suffix>
|
||||
|
|
|
|||
|
|
@ -121,6 +121,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.canUseTTS, 'canSearchNotes'])">
|
||||
<template #label>{{ i18n.ts._role._options.canUseTTS }}</template>
|
||||
<template #suffix>{{ policies.canUseTTS ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
<MkSwitch v-model="policies.canUseTTS">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.driveCapacity, 'driveCapacityMb'])">
|
||||
<template #label>{{ i18n.ts._role._options.driveCapacity }}</template>
|
||||
<template #suffix>{{ policies.driveCapacityMb }}MB</template>
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div class="_gaps_m">
|
||||
<MkSwitch v-model="profile.isCat">{{ i18n.ts.flagAsCat }}<template #caption>{{ i18n.ts.flagAsCatDescription }}</template></MkSwitch>
|
||||
<MkSwitch v-model="profile.isBot">{{ i18n.ts.flagAsBot }}<template #caption>{{ i18n.ts.flagAsBotDescription }}</template></MkSwitch>
|
||||
<MkSwitch v-model="profile.isVI">{{ i18n.ts.flagAsVI }}<template #caption>{{ i18n.ts.flagAsVIDescription }}</template></MkSwitch>
|
||||
</div>
|
||||
</MkFolder>
|
||||
</div>
|
||||
|
|
@ -155,6 +156,7 @@ const profile = reactive({
|
|||
lang: assertVaildLang($i.lang) ? $i.lang : null,
|
||||
isBot: $i.isBot ?? false,
|
||||
isCat: $i.isCat ?? false,
|
||||
isVI: $i.isVI ?? false,
|
||||
});
|
||||
|
||||
watch(() => profile, () => {
|
||||
|
|
@ -206,6 +208,7 @@ function save() {
|
|||
lang: profile.lang || null,
|
||||
isBot: !!profile.isBot,
|
||||
isCat: !!profile.isCat,
|
||||
isVI: !!profile.isVI,
|
||||
}, undefined, {
|
||||
'0b3f9f6a-2f4d-4b1f-9fb4-49d3a2fd7191': {
|
||||
title: i18n.ts.yourNameContainsProhibitedWords,
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ export function getNoteMenu(props: {
|
|||
note: Misskey.entities.Note;
|
||||
translation: Ref<Misskey.entities.NotesTranslateResponse | null>;
|
||||
translating: Ref<boolean>;
|
||||
convert: Ref<string | null>;
|
||||
converting: Ref<boolean>;
|
||||
isDeleted: Ref<boolean>;
|
||||
currentClip?: Misskey.entities.Clip;
|
||||
}) {
|
||||
|
|
@ -294,6 +296,38 @@ export function getNoteMenu(props: {
|
|||
props.translation.value = res;
|
||||
}
|
||||
|
||||
async function convert(): Promise<void> {
|
||||
if (props.convert.value != null) return;
|
||||
props.converting.value = true;
|
||||
|
||||
const res = await misskeyApi('notes/tts', {
|
||||
noteId: appearNote.id,
|
||||
}, undefined, undefined, true);
|
||||
|
||||
try {
|
||||
if (res.body instanceof ReadableStream) {
|
||||
const reader = res.body.getReader();
|
||||
const chunks: Uint8Array[] = [];
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
chunks.push(value);
|
||||
}
|
||||
|
||||
const audioBlob = new Blob(chunks, { type: 'audio/flac' });
|
||||
|
||||
props.convert.value = URL.createObjectURL(audioBlob);
|
||||
} else {
|
||||
console.error('Response body is not a ReadableStream');
|
||||
}
|
||||
} catch (errors) {
|
||||
console.error('Failed to create Blob or Object URL:', e);
|
||||
}
|
||||
|
||||
props.converting.value = false;
|
||||
}
|
||||
|
||||
const menuItems: MenuItem[] = [];
|
||||
|
||||
if ($i) {
|
||||
|
|
@ -348,6 +382,14 @@ export function getNoteMenu(props: {
|
|||
});
|
||||
}
|
||||
|
||||
if ($i.policies.canUseTTS && instance.ttsAvailable) {
|
||||
menuItems.push({
|
||||
icon: 'ti ti-headphones',
|
||||
text: 'TTS',
|
||||
action: convert,
|
||||
});
|
||||
}
|
||||
|
||||
menuItems.push({ type: 'divider' });
|
||||
|
||||
menuItems.push(statePromise.then(state => state.isFavorited ? {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ export function misskeyApi<
|
|||
data: P = {} as any,
|
||||
token?: string | null | undefined,
|
||||
signal?: AbortSignal,
|
||||
): Promise<_ResT> {
|
||||
returnResponse: boolean = false
|
||||
): Promise<_ResT | Response> {
|
||||
if (endpoint.includes('://')) throw new Error('invalid endpoint');
|
||||
pendingApiRequestsCount.value++;
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ export function misskeyApi<
|
|||
pendingApiRequestsCount.value--;
|
||||
};
|
||||
|
||||
const promise = new Promise<_ResT>((resolve, reject) => {
|
||||
const promise = new Promise<_ResT | Response>((resolve, reject) => {
|
||||
// Append a credential
|
||||
if ($i) (data as any).i = $i.token;
|
||||
if (token !== undefined) (data as any).i = token;
|
||||
|
|
@ -44,14 +45,17 @@ export function misskeyApi<
|
|||
},
|
||||
signal,
|
||||
}).then(async (res) => {
|
||||
const body = res.status === 204 ? null : await res.json();
|
||||
|
||||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
} else if (res.status === 204) {
|
||||
resolve(undefined as _ResT); // void -> undefined
|
||||
if (returnResponse) {
|
||||
resolve(res);
|
||||
} else {
|
||||
reject(body.error);
|
||||
const body = res.status === 204 ? null : await res.json();
|
||||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
} else if (res.status === 204) {
|
||||
resolve(undefined as _ResT); // void -> undefined
|
||||
} else {
|
||||
reject(body.error);
|
||||
}
|
||||
}
|
||||
}).catch(reject);
|
||||
});
|
||||
|
|
@ -70,7 +74,8 @@ export function misskeyApiGet<
|
|||
>(
|
||||
endpoint: E,
|
||||
data: P = {} as any,
|
||||
): Promise<_ResT> {
|
||||
returnResponse: boolean = false
|
||||
): Promise<_ResT | Response> {
|
||||
pendingApiRequestsCount.value++;
|
||||
|
||||
const onFinally = () => {
|
||||
|
|
@ -79,21 +84,24 @@ export function misskeyApiGet<
|
|||
|
||||
const query = new URLSearchParams(data as any);
|
||||
|
||||
const promise = new Promise<_ResT>((resolve, reject) => {
|
||||
const promise = new Promise<_ResT | Response>((resolve, reject) => {
|
||||
// Send request
|
||||
window.fetch(`${apiUrl}/${endpoint}?${query}`, {
|
||||
method: 'GET',
|
||||
credentials: 'omit',
|
||||
cache: 'default',
|
||||
}).then(async (res) => {
|
||||
const body = res.status === 204 ? null : await res.json();
|
||||
|
||||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
} else if (res.status === 204) {
|
||||
resolve(undefined as _ResT); // void -> undefined
|
||||
if (returnResponse) {
|
||||
resolve(res);
|
||||
} else {
|
||||
reject(body.error);
|
||||
const body = res.status === 204 ? null : await res.json();
|
||||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
} else if (res.status === 204) {
|
||||
resolve(undefined as _ResT); // void -> undefined
|
||||
} else {
|
||||
reject(body.error);
|
||||
}
|
||||
}
|
||||
}).catch(reject);
|
||||
});
|
||||
|
|
@ -102,3 +110,4 @@ export function misskeyApiGet<
|
|||
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1671,6 +1671,8 @@ declare namespace entities {
|
|||
NotesTimelineResponse,
|
||||
NotesTranslateRequest,
|
||||
NotesTranslateResponse,
|
||||
NotesTtsRequest,
|
||||
NotesTtsResponse,
|
||||
NotesUnrenoteRequest,
|
||||
NotesUserListTimelineRequest,
|
||||
NotesUserListTimelineResponse,
|
||||
|
|
@ -2785,6 +2787,12 @@ type NotesTranslateRequest = operations['notes___translate']['requestBody']['con
|
|||
// @public (undocumented)
|
||||
type NotesTranslateResponse = operations['notes___translate']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type NotesTtsRequest = operations['notes___tts']['requestBody']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type NotesTtsResponse = operations['notes___tts']['responses']['200']['content']['application/json'];
|
||||
|
||||
// @public (undocumented)
|
||||
type NotesUnrenoteRequest = operations['notes___unrenote']['requestBody']['content']['application/json'];
|
||||
|
||||
|
|
|
|||
|
|
@ -3339,6 +3339,17 @@ declare module '../api.js' {
|
|||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:account*
|
||||
*/
|
||||
request<E extends 'notes/tts', P extends Endpoints[E]['req']>(
|
||||
endpoint: E,
|
||||
params: P,
|
||||
credential?: string | null,
|
||||
): Promise<SwitchCaseResponseType<E, P>>;
|
||||
|
||||
/**
|
||||
* No description provided.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -450,6 +450,8 @@ import type {
|
|||
NotesTimelineResponse,
|
||||
NotesTranslateRequest,
|
||||
NotesTranslateResponse,
|
||||
NotesTtsRequest,
|
||||
NotesTtsResponse,
|
||||
NotesUnrenoteRequest,
|
||||
NotesUserListTimelineRequest,
|
||||
NotesUserListTimelineResponse,
|
||||
|
|
@ -878,6 +880,7 @@ export type Endpoints = {
|
|||
'notes/thread-muting/delete': { req: NotesThreadMutingDeleteRequest; res: EmptyResponse };
|
||||
'notes/timeline': { req: NotesTimelineRequest; res: NotesTimelineResponse };
|
||||
'notes/translate': { req: NotesTranslateRequest; res: NotesTranslateResponse };
|
||||
'notes/tts': { req: NotesTtsRequest; res: NotesTtsResponse };
|
||||
'notes/unrenote': { req: NotesUnrenoteRequest; res: EmptyResponse };
|
||||
'notes/user-list-timeline': { req: NotesUserListTimelineRequest; res: NotesUserListTimelineResponse };
|
||||
'notifications/create': { req: NotificationsCreateRequest; res: EmptyResponse };
|
||||
|
|
|
|||
|
|
@ -453,6 +453,8 @@ export type NotesTimelineRequest = operations['notes___timeline']['requestBody']
|
|||
export type NotesTimelineResponse = operations['notes___timeline']['responses']['200']['content']['application/json'];
|
||||
export type NotesTranslateRequest = operations['notes___translate']['requestBody']['content']['application/json'];
|
||||
export type NotesTranslateResponse = operations['notes___translate']['responses']['200']['content']['application/json'];
|
||||
export type NotesTtsRequest = operations['notes___tts']['requestBody']['content']['application/json'];
|
||||
export type NotesTtsResponse = operations['notes___tts']['responses']['200']['content']['application/json'];
|
||||
export type NotesUnrenoteRequest = operations['notes___unrenote']['requestBody']['content']['application/json'];
|
||||
export type NotesUserListTimelineRequest = operations['notes___user-list-timeline']['requestBody']['content']['application/json'];
|
||||
export type NotesUserListTimelineResponse = operations['notes___user-list-timeline']['responses']['200']['content']['application/json'];
|
||||
|
|
|
|||
|
|
@ -2890,6 +2890,15 @@ export type paths = {
|
|||
*/
|
||||
post: operations['notes___translate'];
|
||||
};
|
||||
'/notes/tts': {
|
||||
/**
|
||||
* notes/tts
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:account*
|
||||
*/
|
||||
post: operations['notes___tts'];
|
||||
};
|
||||
'/notes/unrenote': {
|
||||
/**
|
||||
* notes/unrenote
|
||||
|
|
@ -3736,6 +3745,7 @@ export type components = {
|
|||
}[];
|
||||
isBot?: boolean;
|
||||
isCat?: boolean;
|
||||
isVI?: boolean;
|
||||
instance?: {
|
||||
name: string | null;
|
||||
softwareName: string | null;
|
||||
|
|
@ -4768,7 +4778,7 @@ export type components = {
|
|||
RoleCondFormulaValueUserSettingBooleanSchema: {
|
||||
id: string;
|
||||
/** @enum {string} */
|
||||
type: 'isSuspended' | 'isLocked' | 'isBot' | 'isCat' | 'isExplorable';
|
||||
type: 'isSuspended' | 'isLocked' | 'isBot' | 'isCat' | 'isVI' | 'isExplorable';
|
||||
};
|
||||
RoleCondFormulaValueAssignedRole: {
|
||||
id: string;
|
||||
|
|
@ -4850,6 +4860,7 @@ export type components = {
|
|||
canManageAvatarDecorations: boolean;
|
||||
canSearchNotes: boolean;
|
||||
canUseTranslator: boolean;
|
||||
canUseTTS: boolean;
|
||||
canHideAds: boolean;
|
||||
driveCapacityMb: number;
|
||||
alwaysMarkNsfw: boolean;
|
||||
|
|
@ -5001,6 +5012,7 @@ export type components = {
|
|||
enableEmail: boolean;
|
||||
enableServiceWorker: boolean;
|
||||
translatorAvailable: boolean;
|
||||
ttsAvailable: boolean;
|
||||
mediaProxy: string;
|
||||
enableUrlPreview: boolean;
|
||||
backgroundImageUrl: string | null;
|
||||
|
|
@ -5117,6 +5129,7 @@ export type operations = {
|
|||
enableEmail: boolean;
|
||||
enableServiceWorker: boolean;
|
||||
translatorAvailable: boolean;
|
||||
ttsAvailable: boolean;
|
||||
silencedHosts?: string[];
|
||||
mediaSilencedHosts: string[];
|
||||
pinnedUsers: string[];
|
||||
|
|
@ -5181,6 +5194,19 @@ export type operations = {
|
|||
backgroundImageUrl: string | null;
|
||||
deeplAuthKey: string | null;
|
||||
deeplIsPro: boolean;
|
||||
hfAuthKey: string | null;
|
||||
hfSpace: boolean;
|
||||
hfSpaceName: string | null;
|
||||
hfexampleAudioURL: string | null;
|
||||
hfexampleText: string | null;
|
||||
hfexampleLang: string | null;
|
||||
hfslice: string | null;
|
||||
hftopK: number | null;
|
||||
hftopP: number | null;
|
||||
hfTemperature: number | null;
|
||||
hfSpeedRate: number | null;
|
||||
hfnrm: boolean;
|
||||
hfdas: boolean;
|
||||
defaultDarkTheme: string | null;
|
||||
defaultLightTheme: string | null;
|
||||
description: string | null;
|
||||
|
|
@ -9510,6 +9536,27 @@ export type operations = {
|
|||
langs?: string[];
|
||||
deeplAuthKey?: string | null;
|
||||
deeplIsPro?: boolean;
|
||||
hfAuthKey?: string | null;
|
||||
/** @default false */
|
||||
hfSpace?: boolean;
|
||||
hfSpaceName?: string | null;
|
||||
hfexampleAudioURL?: string | null;
|
||||
hfexampleText?: string | null;
|
||||
hfexampleLang?: string | null;
|
||||
/** @default Slice once every 4 sentences */
|
||||
hfslice?: string | null;
|
||||
/** @default 15 */
|
||||
hftopK?: number;
|
||||
/** @default 100 */
|
||||
hftopP?: number;
|
||||
/** @default 100 */
|
||||
hfTemperature?: number;
|
||||
/** @default false */
|
||||
hfnrm?: boolean;
|
||||
/** @default 125 */
|
||||
hfSpeedRate?: number;
|
||||
/** @default false */
|
||||
hfdas?: boolean;
|
||||
enableEmail?: boolean;
|
||||
email?: string | null;
|
||||
smtpSecure?: boolean;
|
||||
|
|
@ -19846,6 +19893,7 @@ export type operations = {
|
|||
preventAiLearning?: boolean;
|
||||
isBot?: boolean;
|
||||
isCat?: boolean;
|
||||
isVI?: boolean;
|
||||
injectFeaturedNote?: boolean;
|
||||
receiveAnnouncementEmail?: boolean;
|
||||
alwaysMarkNsfw?: boolean;
|
||||
|
|
@ -23007,6 +23055,64 @@ export type operations = {
|
|||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* notes/tts
|
||||
* @description No description provided.
|
||||
*
|
||||
* **Credential required**: *Yes* / **Permission**: *read:account*
|
||||
*/
|
||||
notes___tts: {
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': {
|
||||
/** Format: misskey:id */
|
||||
noteId: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description OK (with results) */
|
||||
200: {
|
||||
content: {
|
||||
'application/json': string;
|
||||
};
|
||||
};
|
||||
/** @description OK (without any results) */
|
||||
204: {
|
||||
content: never;
|
||||
};
|
||||
/** @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'];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
/**
|
||||
* notes/unrenote
|
||||
* @description No description provided.
|
||||
|
|
|
|||
135
pnpm-lock.yaml
generated
135
pnpm-lock.yaml
generated
|
|
@ -125,6 +125,9 @@ importers:
|
|||
'@fastify/view':
|
||||
specifier: 10.0.1
|
||||
version: 10.0.1
|
||||
'@gradio/client':
|
||||
specifier: 1.6.0-beta.3
|
||||
version: 1.6.0-beta.3(utf-8-validate@6.0.3)
|
||||
'@misskey-dev/sharp-read-bmp':
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0
|
||||
|
|
@ -1163,7 +1166,7 @@ importers:
|
|||
version: 7.17.0(eslint@9.11.0)(typescript@5.6.2)
|
||||
'@vitest/coverage-v8':
|
||||
specifier: 1.6.0
|
||||
version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0))
|
||||
version: 1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0))
|
||||
'@vue/runtime-core':
|
||||
specifier: 3.5.11
|
||||
version: 3.5.11
|
||||
|
|
@ -2772,6 +2775,10 @@ packages:
|
|||
resolution: {integrity: sha512-XrftRn4z75SnaJOmZQbt7Mk+IIjqVHw+glDGOxuHwXkZBZh/MBoRS7MHjSZMDaLhT4RjN2VqiEU7EOYleuJWSQ==}
|
||||
hasBin: true
|
||||
|
||||
'@gradio/client@1.6.0-beta.3':
|
||||
resolution: {integrity: sha512-mJZVQ4UpfrSu71J4SkbSrpnbRotmB5ziy4fg7zqZhqXwXGZM3cHR9fUGkTFM0eXYnsaeBoiqn+1bcUh32Zcgkg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@hapi/boom@10.0.1':
|
||||
resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==}
|
||||
|
||||
|
|
@ -4633,6 +4640,9 @@ packages:
|
|||
'@types/estree@1.0.6':
|
||||
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
||||
|
||||
'@types/eventsource@1.1.15':
|
||||
resolution: {integrity: sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==}
|
||||
|
||||
'@types/express-serve-static-core@4.17.33':
|
||||
resolution: {integrity: sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==}
|
||||
|
||||
|
|
@ -6833,6 +6843,10 @@ packages:
|
|||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||
engines: {node: '>=0.8.x'}
|
||||
|
||||
eventsource@2.0.2:
|
||||
resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
execa@0.7.0:
|
||||
resolution: {integrity: sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==}
|
||||
engines: {node: '>=4'}
|
||||
|
|
@ -6975,6 +6989,9 @@ packages:
|
|||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||
engines: {node: ^12.20 || >= 14.13}
|
||||
|
||||
fetch-event-stream@0.1.5:
|
||||
resolution: {integrity: sha512-V1PWovkspxQfssq/NnxoEyQo1DV+MRK/laPuPblIZmSjMN8P5u46OhlFQznSr9p/t0Sp8Uc6SbM3yCMfr0KU8g==}
|
||||
|
||||
figures@3.2.0:
|
||||
resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -10236,6 +10253,10 @@ packages:
|
|||
seedrandom@3.0.5:
|
||||
resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
|
||||
|
||||
semiver@1.1.0:
|
||||
resolution: {integrity: sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
semver-regex@4.0.5:
|
||||
resolution: {integrity: sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -10806,6 +10827,9 @@ packages:
|
|||
textarea-caret@3.1.0:
|
||||
resolution: {integrity: sha512-cXAvzO9pP5CGa6NKx0WYHl+8CHKZs8byMkt3PCJBCmq2a34YA9pO1NrQET5pzeqnBjBdToF5No4rrmkDUgQC2Q==}
|
||||
|
||||
textlinestream@1.1.1:
|
||||
resolution: {integrity: sha512-iBHbi7BQxrFmwZUQJsT0SjNzlLLsXhvW/kg7EyOMVMBIrlnj/qYofwo1LVLZi+3GbUEo96Iu2eqToI2+lZoAEQ==}
|
||||
|
||||
thenify-all@1.6.0:
|
||||
resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
|
||||
engines: {node: '>=0.8'}
|
||||
|
|
@ -13245,6 +13269,20 @@ snapshots:
|
|||
|
||||
'@github/webauthn-json@2.1.1': {}
|
||||
|
||||
'@gradio/client@1.6.0-beta.3(utf-8-validate@6.0.3)':
|
||||
dependencies:
|
||||
'@types/eventsource': 1.1.15
|
||||
bufferutil: 4.0.7
|
||||
eventsource: 2.0.2
|
||||
fetch-event-stream: 0.1.5
|
||||
msw: 2.4.9(typescript@5.6.2)
|
||||
semiver: 1.1.0
|
||||
textlinestream: 1.1.1
|
||||
typescript: 5.6.2
|
||||
ws: 8.18.0(bufferutil@4.0.7)(utf-8-validate@6.0.3)
|
||||
transitivePeerDependencies:
|
||||
- utf-8-validate
|
||||
|
||||
'@hapi/boom@10.0.1':
|
||||
dependencies:
|
||||
'@hapi/hoek': 11.0.4
|
||||
|
|
@ -15573,6 +15611,8 @@ snapshots:
|
|||
|
||||
'@types/estree@1.0.6': {}
|
||||
|
||||
'@types/eventsource@1.1.15': {}
|
||||
|
||||
'@types/express-serve-static-core@4.17.33':
|
||||
dependencies:
|
||||
'@types/node': 20.14.12
|
||||
|
|
@ -15962,7 +16002,7 @@ snapshots:
|
|||
'@typescript-eslint/types': 7.17.0
|
||||
'@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4)
|
||||
'@typescript-eslint/visitor-keys': 7.17.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.11.0
|
||||
optionalDependencies:
|
||||
typescript: 5.5.4
|
||||
|
|
@ -15975,7 +16015,7 @@ snapshots:
|
|||
'@typescript-eslint/types': 7.17.0
|
||||
'@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2)
|
||||
'@typescript-eslint/visitor-keys': 7.17.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.11.0
|
||||
optionalDependencies:
|
||||
typescript: 5.6.2
|
||||
|
|
@ -15988,7 +16028,7 @@ snapshots:
|
|||
'@typescript-eslint/types': 7.17.0
|
||||
'@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2)
|
||||
'@typescript-eslint/visitor-keys': 7.17.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.8.0
|
||||
optionalDependencies:
|
||||
typescript: 5.6.2
|
||||
|
|
@ -16009,7 +16049,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.1.0(typescript@5.3.3)
|
||||
'@typescript-eslint/utils': 7.1.0(eslint@9.11.0)(typescript@5.3.3)
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.11.0
|
||||
ts-api-utils: 1.0.1(typescript@5.3.3)
|
||||
optionalDependencies:
|
||||
|
|
@ -16021,7 +16061,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.17.0(typescript@5.5.4)
|
||||
'@typescript-eslint/utils': 7.17.0(eslint@9.11.0)(typescript@5.5.4)
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.11.0
|
||||
ts-api-utils: 1.3.0(typescript@5.5.4)
|
||||
optionalDependencies:
|
||||
|
|
@ -16033,7 +16073,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2)
|
||||
'@typescript-eslint/utils': 7.17.0(eslint@9.11.0)(typescript@5.6.2)
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.11.0
|
||||
ts-api-utils: 1.3.0(typescript@5.6.2)
|
||||
optionalDependencies:
|
||||
|
|
@ -16045,7 +16085,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.17.0(typescript@5.6.2)
|
||||
'@typescript-eslint/utils': 7.17.0(eslint@9.8.0)(typescript@5.6.2)
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.8.0
|
||||
ts-api-utils: 1.3.0(typescript@5.6.2)
|
||||
optionalDependencies:
|
||||
|
|
@ -16061,7 +16101,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 7.1.0
|
||||
'@typescript-eslint/visitor-keys': 7.1.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.3
|
||||
|
|
@ -16076,7 +16116,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 7.17.0
|
||||
'@typescript-eslint/visitor-keys': 7.17.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.4
|
||||
|
|
@ -16091,7 +16131,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 7.17.0
|
||||
'@typescript-eslint/visitor-keys': 7.17.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.4
|
||||
|
|
@ -16175,7 +16215,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@ampproject/remapping': 2.2.1
|
||||
'@bcoe/v8-coverage': 0.2.3
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
istanbul-lib-source-maps: 5.0.4
|
||||
|
|
@ -16190,11 +16230,11 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0))':
|
||||
'@vitest/coverage-v8@1.6.0(vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0))':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.2.1
|
||||
'@bcoe/v8-coverage': 0.2.3
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
istanbul-lib-source-maps: 5.0.4
|
||||
|
|
@ -16205,7 +16245,7 @@ snapshots:
|
|||
std-env: 3.7.0
|
||||
strip-literal: 2.1.0
|
||||
test-exclude: 6.0.0
|
||||
vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0)
|
||||
vitest: 1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -16515,7 +16555,7 @@ snapshots:
|
|||
|
||||
agent-base@7.1.0:
|
||||
dependencies:
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -17001,7 +17041,6 @@ snapshots:
|
|||
bufferutil@4.0.7:
|
||||
dependencies:
|
||||
node-gyp-build: 4.6.0
|
||||
optional: true
|
||||
|
||||
bufferutil@4.0.8:
|
||||
dependencies:
|
||||
|
|
@ -18638,6 +18677,8 @@ snapshots:
|
|||
|
||||
events@3.3.0: {}
|
||||
|
||||
eventsource@2.0.2: {}
|
||||
|
||||
execa@0.7.0:
|
||||
dependencies:
|
||||
cross-spawn: 5.1.0
|
||||
|
|
@ -18885,6 +18926,8 @@ snapshots:
|
|||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 3.2.1
|
||||
|
||||
fetch-event-stream@0.1.5: {}
|
||||
|
||||
figures@3.2.0:
|
||||
dependencies:
|
||||
escape-string-regexp: 1.0.5
|
||||
|
|
@ -19487,7 +19530,7 @@ snapshots:
|
|||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -19526,7 +19569,7 @@ snapshots:
|
|||
https-proxy-agent@5.0.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
|
@ -19534,14 +19577,14 @@ snapshots:
|
|||
https-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
https-proxy-agent@7.0.5:
|
||||
dependencies:
|
||||
agent-base: 7.1.0
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -19914,7 +19957,7 @@ snapshots:
|
|||
istanbul-lib-source-maps@5.0.4:
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
|
@ -20315,6 +20358,35 @@ snapshots:
|
|||
|
||||
jsdoc-type-pratt-parser@4.1.0: {}
|
||||
|
||||
jsdom@24.1.1:
|
||||
dependencies:
|
||||
cssstyle: 4.0.1
|
||||
data-urls: 5.0.0
|
||||
decimal.js: 10.4.3
|
||||
form-data: 4.0.0
|
||||
html-encoding-sniffer: 4.0.0
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.5
|
||||
is-potential-custom-element-name: 1.0.1
|
||||
nwsapi: 2.2.12
|
||||
parse5: 7.1.2
|
||||
rrweb-cssom: 0.7.1
|
||||
saxes: 6.0.0
|
||||
symbol-tree: 3.2.4
|
||||
tough-cookie: 4.1.4
|
||||
w3c-xmlserializer: 5.0.0
|
||||
webidl-conversions: 7.0.0
|
||||
whatwg-encoding: 3.1.1
|
||||
whatwg-mimetype: 4.0.0
|
||||
whatwg-url: 14.0.0
|
||||
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
xml-name-validator: 5.0.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
optional: true
|
||||
|
||||
jsdom@24.1.1(bufferutil@4.0.7)(utf-8-validate@6.0.3):
|
||||
dependencies:
|
||||
cssstyle: 4.0.1
|
||||
|
|
@ -21361,8 +21433,7 @@ snapshots:
|
|||
node-gyp-build-optional-packages@5.0.7:
|
||||
optional: true
|
||||
|
||||
node-gyp-build@4.6.0:
|
||||
optional: true
|
||||
node-gyp-build@4.6.0: {}
|
||||
|
||||
node-gyp@10.2.0:
|
||||
dependencies:
|
||||
|
|
@ -22741,6 +22812,8 @@ snapshots:
|
|||
|
||||
seedrandom@3.0.5: {}
|
||||
|
||||
semiver@1.1.0: {}
|
||||
|
||||
semver-regex@4.0.5: {}
|
||||
|
||||
semver-truncate@2.0.0:
|
||||
|
|
@ -22889,7 +22962,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@hapi/hoek': 11.0.4
|
||||
'@hapi/wreck': 18.0.1
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
joi: 17.11.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
|
@ -23376,6 +23449,8 @@ snapshots:
|
|||
|
||||
textarea-caret@3.1.0: {}
|
||||
|
||||
textlinestream@1.1.1: {}
|
||||
|
||||
thenify-all@1.6.0:
|
||||
dependencies:
|
||||
thenify: 3.3.1
|
||||
|
|
@ -23849,7 +23924,7 @@ snapshots:
|
|||
vite-node@1.6.0(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.0.1
|
||||
vite: 5.4.8(@types/node@20.14.12)(sass@1.79.3)(terser@5.33.0)
|
||||
|
|
@ -23867,7 +23942,7 @@ snapshots:
|
|||
vite-node@1.6.0(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.0.1
|
||||
vite: 5.4.8(@types/node@20.14.12)(sass@1.79.4)(terser@5.33.0)
|
||||
|
|
@ -23949,7 +24024,7 @@ snapshots:
|
|||
- supports-color
|
||||
- terser
|
||||
|
||||
vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4))(sass@1.79.4)(terser@5.33.0):
|
||||
vitest@1.6.0(@types/node@20.14.12)(happy-dom@10.0.3)(jsdom@24.1.1)(sass@1.79.4)(terser@5.33.0):
|
||||
dependencies:
|
||||
'@vitest/expect': 1.6.0
|
||||
'@vitest/runner': 1.6.0
|
||||
|
|
@ -23974,7 +24049,7 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@types/node': 20.14.12
|
||||
happy-dom: 10.0.3
|
||||
jsdom: 24.1.1(bufferutil@4.0.8)(utf-8-validate@6.0.4)
|
||||
jsdom: 24.1.1
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
|
|
@ -24046,7 +24121,7 @@ snapshots:
|
|||
|
||||
vue-eslint-parser@9.4.3(eslint@9.11.0):
|
||||
dependencies:
|
||||
debug: 4.3.5(supports-color@5.5.0)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
eslint: 9.11.0
|
||||
eslint-scope: 7.2.2
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue