diff --git a/assets/api.ts b/assets/api.ts index 1140647..957914c 100644 --- a/assets/api.ts +++ b/assets/api.ts @@ -19,7 +19,7 @@ export interface IUserSettings extends IUserLocalSettings { level: number } -export interface IEntry { +export interface IDictionaryLookup { id: string list: string[] reading: string[] @@ -31,6 +31,25 @@ export interface IEntry { type: IType description: string tag: string[] + level?: number +} + +export interface IEntryLookup { + entry: string + sub: string[] + sup: string[] + variant: string[] + visual: { + entry: string + }[] + amalgamation: { + entry: string + type?: IType + }[] + component: { + entry: string + type?: IType + }[] } export interface ILibrary { @@ -197,16 +216,16 @@ class Api { return await this.axios .get('/api/extra/q', { params }) - .then((r) => r.data as ILookupResult) + .then((r) => r.data as ILookupResult) } - async extra_create(payload: Omit) { + async extra_create(payload: Omit) { return await this.axios .put('/api/extra', payload) .then((r) => r.data as { id: string }) } - async extra_update(payload: IEntry) { + async extra_update(payload: IDictionaryLookup) { return await this.axios.patch('/api/extra', payload, { params: { id: payload.id }, }) @@ -226,7 +245,7 @@ class Api { return await this.axios .get('/api/character/vocabulary', { params }) - .then((r) => r.data as ILookupResult) + .then((r) => r.data as ILookupResult) } async character_getSentence( @@ -237,7 +256,18 @@ class Api { return await this.axios .get('/api/character/sentence', { params }) - .then((r) => r.data as ILookupResult) + .then((r) => r.data as ILookupResult) + } + + async vocabulary_getVocabulary( + params: ILookup<{ entry: string; distinct?: 'id' }> + ) { + params.offset = params.offset || 0 + params.limit = params.limit || 5 + + return await this.axios + .get('/api/vocabulary/vocabulary', { params }) + .then((r) => r.data as ILookupResult) } async vocabulary_getSentence( @@ -248,7 +278,7 @@ class Api { return await this.axios .get('/api/vocabulary/sentence', { params }) - .then((r) => r.data as ILookupResult) + .then((r) => r.data as ILookupResult) } async all_getRandom(params: { type: IType }) { @@ -261,7 +291,9 @@ class Api { ) } - async all_getQuery(params: ILookup<{ q: string }>) { + async all_getQuery( + params: ILookup<{ q: string; type?: IType; distinct?: 'id' }> + ) { params.offset = params.offset || 0 params.limit = params.limit || 5 @@ -284,38 +316,13 @@ class Api { .get('/api/all', { params, }) - .then( - (r) => - r.data as ILookupResult< - IEntry & { - level?: number - } - > - ) + .then((r) => r.data as ILookupResult) } async all_getComponent(params: { entry: string; type: IType }) { return await this.axios .get('/api/all/components', { params }) - .then( - (r) => - r.data as { - sub: string[] - sup: string[] - variant: string[] - visual: { - entry: string - }[] - amalgamation: { - entry: string - type?: IType - }[] - component: { - entry: string - type?: IType - }[] - } - ) + .then((r) => r.data as IEntryLookup) .catch(() => null) } diff --git a/assets/speak.ts b/assets/speak.ts index df6b9ca..f5240f0 100644 --- a/assets/speak.ts +++ b/assets/speak.ts @@ -17,13 +17,15 @@ export async function speak( opts: { lang?: string forceOffline?: boolean + url?: string } = {} ) { if (!opts.forceOffline) { const audio = new Audio( - `/api/tts?q=${encodeURIComponent(s)}&lang=${encodeURIComponent( - opts.lang || 'ja' - )}` + opts.url || + `/api/tts?q=${encodeURIComponent(s)}&lang=${encodeURIComponent( + opts.lang || 'ja' + )}` ) await audio.play().catch(() => speak(s, { @@ -73,7 +75,6 @@ window.addEventListener('keydown', (ev) => { } if (ev.key === 's') { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const s = window.getSelection()!.toString() if (s) { speak(s) diff --git a/components/ContextMenu.vue b/components/ContextMenu.vue index 0997d4c..d1c33e9 100644 --- a/components/ContextMenu.vue +++ b/components/ContextMenu.vue @@ -102,6 +102,10 @@ import { api, IType } from '~/assets/api' export default class ContextMenu extends Vue { @Prop() id?: string @Prop() entry?: string + @Prop() audio?: { + mimetype?: string + url: string + }[] @Prop() list?: string[] @Prop() type?: IType @Prop() source?: string @@ -176,7 +180,7 @@ export default class ContextMenu extends Vue { async doSpeak() { if (this.entry) { - await speak(this.entry) + await speak(this.entry, { url: this.audio?.[0]?.url }) } } diff --git a/components/cards/LibraryCard.vue b/components/cards/LibraryCard.vue index c376122..ce17a38 100644 --- a/components/cards/LibraryCard.vue +++ b/components/cards/LibraryCard.vue @@ -149,11 +149,11 @@