diff --git a/enjoy/src/main/db/models/audio.ts b/enjoy/src/main/db/models/audio.ts index 07973f0d..e240ce1e 100644 --- a/enjoy/src/main/db/models/audio.ts +++ b/enjoy/src/main/db/models/audio.ts @@ -25,13 +25,20 @@ import mainWindow from "@main/window"; import log from "electron-log/main"; import storage from "@main/storage"; import Ffmpeg from "@main/ffmpeg"; -import webApi from "@main/web-api"; +import { Client } from "@/api"; +import { WEB_API_URL } from "@/constants"; import { startCase } from "lodash"; import { v5 as uuidv5 } from "uuid"; const SIZE_LIMIT = 1024 * 1024 * 50; // 50MB const logger = log.scope("db/models/audio"); + +const webApi = new Client({ + baseUrl: process.env.WEB_API_URL || WEB_API_URL, + accessToken: settings.getSync("user.accessToken") as string, +}); + @Table({ modelName: "Audio", tableName: "audios", diff --git a/enjoy/src/main/db/models/pronunciation-assessment.ts b/enjoy/src/main/db/models/pronunciation-assessment.ts index 26d6132a..7794476e 100644 --- a/enjoy/src/main/db/models/pronunciation-assessment.ts +++ b/enjoy/src/main/db/models/pronunciation-assessment.ts @@ -14,7 +14,15 @@ import { } from "sequelize-typescript"; import mainWindow from "@main/window"; import { Recording } from "@main/db/models"; -import webApi from "@main/web-api"; +import { Client } from "@/api"; +import { WEB_API_URL } from "@/constants"; +import settings from "@main/settings"; + +const webApi = new Client({ + baseUrl: process.env.WEB_API_URL || WEB_API_URL, + accessToken: settings.getSync("user.accessToken") as string, +}); + @Table({ modelName: "PronunciationAssessment", diff --git a/enjoy/src/main/db/models/recording.ts b/enjoy/src/main/db/models/recording.ts index af7e313b..1b4dfe3c 100644 --- a/enjoy/src/main/db/models/recording.ts +++ b/enjoy/src/main/db/models/recording.ts @@ -23,12 +23,18 @@ import { hashFile } from "@/utils"; import log from "electron-log/main"; import storage from "@main/storage"; import Ffmpeg from "@main/ffmpeg"; -import webApi from "@main/web-api"; +import { Client } from "@/api"; +import { WEB_API_URL } from "@/constants"; import { AzureSpeechSdk } from "@main/azure-speech-sdk"; import camelcaseKeys from "camelcase-keys"; const logger = log.scope("db/models/recording"); +const webApi = new Client({ + baseUrl: process.env.WEB_API_URL || WEB_API_URL, + accessToken: settings.getSync("user.accessToken") as string, +}); + @Table({ modelName: "Recording", tableName: "recordings", @@ -36,7 +42,7 @@ const logger = log.scope("db/models/recording"); timestamps: true, }) export class Recording extends Model { - @IsUUID('all') + @IsUUID("all") @Default(DataType.UUIDV4) @Column({ primaryKey: true, type: DataType.UUID }) id: string; diff --git a/enjoy/src/main/db/models/transcription.ts b/enjoy/src/main/db/models/transcription.ts index 7bd82582..2a51f225 100644 --- a/enjoy/src/main/db/models/transcription.ts +++ b/enjoy/src/main/db/models/transcription.ts @@ -15,9 +15,16 @@ import { Audio, Video } from "@main/db/models"; import whisper from "@main/whisper"; import mainWindow from "@main/window"; import log from "electron-log/main"; -import webApi from "@main/web-api"; +import { Client } from "@/api"; +import { WEB_API_URL } from "@/constants"; +import settings from "@main/settings"; const logger = log.scope("db/models/transcription"); +const webApi = new Client({ + baseUrl: process.env.WEB_API_URL || WEB_API_URL, + accessToken: settings.getSync("user.accessToken") as string, +}); + @Table({ modelName: "Transcription", tableName: "transcriptions", @@ -25,7 +32,7 @@ const logger = log.scope("db/models/transcription"); timestamps: true, }) export class Transcription extends Model { - @IsUUID('all') + @IsUUID("all") @Default(DataType.UUIDV4) @Column({ primaryKey: true, type: DataType.UUID }) id: string; diff --git a/enjoy/src/main/db/models/video.ts b/enjoy/src/main/db/models/video.ts index c2899a7a..90e0fe81 100644 --- a/enjoy/src/main/db/models/video.ts +++ b/enjoy/src/main/db/models/video.ts @@ -25,13 +25,20 @@ import mainWindow from "@main/window"; import log from "electron-log/main"; import storage from "@main/storage"; import Ffmpeg from "@main/ffmpeg"; -import webApi from "@main/web-api"; +import { Client } from "@/api"; +import { WEB_API_URL } from "@/constants"; import { startCase } from "lodash"; import { v5 as uuidv5 } from "uuid"; const SIZE_LIMIT = 1024 * 1024 * 100; // 100MB const logger = log.scope("db/models/video"); + +const webApi = new Client({ + baseUrl: process.env.WEB_API_URL || WEB_API_URL, + accessToken: settings.getSync("user.accessToken") as string, +}); + @Table({ modelName: "Video", tableName: "videos", diff --git a/enjoy/src/main/web-api.ts b/enjoy/src/main/web-api.ts deleted file mode 100644 index dc274736..00000000 --- a/enjoy/src/main/web-api.ts +++ /dev/null @@ -1,480 +0,0 @@ -import { ipcMain } from "electron"; -import axios, { AxiosInstance } from "axios"; -import { WEB_API_URL } from "@/constants"; -import settings from "@main/settings"; -import log from "electron-log/main"; -import decamelizeKeys from "decamelize-keys"; -import camelcaseKeys from "camelcase-keys"; - -const logger = log.scope("web-api"); -const ONE_MINUTE = 1000 * 60; // 1 minute -class WebApi { - public api: AxiosInstance; - - constructor() { - this.api = axios.create({ - baseURL: process.env.WEB_API_URL || WEB_API_URL, - timeout: ONE_MINUTE, - headers: { - "Content-Type": "application/json", - }, - }); - this.api.interceptors.request.use((config) => { - config.headers.Authorization = `Bearer ${settings.getSync( - "user.accessToken" - )}`; - - logger.info( - config.method.toUpperCase(), - config.baseURL + config.url, - config.data, - config.params - ); - return config; - }); - this.api.interceptors.response.use( - (response) => { - logger.info( - response.status, - response.config.method.toUpperCase(), - response.config.baseURL + response.config.url - ); - return camelcaseKeys(response.data, { deep: true }); - }, - (err) => { - if (err.response) { - logger.error( - err.response.status, - err.response.config.method.toUpperCase(), - err.response.config.baseURL + err.response.config.url - ); - logger.error(err.response.data); - return Promise.reject(err.response.data); - } - - if (err.request) { - logger.error(err.request); - } else { - logger.error(err.message); - } - - return Promise.reject(err); - } - ); - } - - auth(params: { provider: string; code: string }): Promise { - return this.api.post("/api/sessions", decamelizeKeys(params)); - } - - me() { - return this.api.get("/api/me"); - } - - rankings(range: "day" | "week" | "month" | "year" | "all" = "day"): Promise<{ - rankings: UserType[]; - range: string; - }> { - return this.api.get("/api/users/rankings", { params: { range } }); - } - - posts(params?: { page?: number; items?: number }): Promise< - { - posts: PostType[]; - } & PagyResponseType - > { - return this.api.get("/api/posts", { params: decamelizeKeys(params) }); - } - - post(id: string): Promise { - return this.api.get(`/api/posts/${id}`); - } - - createPost(params: { content: string }): Promise { - return this.api.post("/api/posts", decamelizeKeys(params)); - } - - updatePost(id: string, params: { content: string }): Promise { - return this.api.put(`/api/posts/${id}`, decamelizeKeys(params)); - } - - deletePost(id: string): Promise { - return this.api.delete(`/api/posts/${id}`); - } - - syncAudio(audio: Partial) { - return this.api.post("/api/mine/audios", decamelizeKeys(audio)); - } - - syncVideo(video: Partial) { - return this.api.post("/api/mine/videos", decamelizeKeys(video)); - } - - syncTranscription(transcription: Partial) { - return this.api.post("/api/transcriptions", decamelizeKeys(transcription)); - } - - syncRecording(recording: Partial) { - if (!recording) return; - - return this.api.post("/api/mine/recordings", decamelizeKeys(recording)); - } - - generateSpeechToken(): Promise<{ token: string; region: string }> { - return this.api.post("/api/speech/tokens"); - } - - syncPronunciationAssessment( - pronunciationAssessment: Partial - ) { - if (!pronunciationAssessment) return; - - return this.api.post( - "/api/mine/pronunciation_assessments", - decamelizeKeys(pronunciationAssessment) - ); - } - - recordingAssessment(id: string) { - return this.api.get(`/api/mine/recordings/${id}/assessment`); - } - - lookup(params: { - word: string; - context: string; - sourceId?: string; - sourceType?: string; - }): Promise { - return this.api.post("/api/lookups", decamelizeKeys(params)); - } - - lookupInBatch( - lookups: { - word: string; - context: string; - sourceId?: string; - sourceType?: string; - }[] - ): Promise<{ successCount: number; total: number }> { - return this.api.post("/api/lookups/batch", { - lookups: decamelizeKeys(lookups, { deep: true }), - }); - } - - extractVocabularyFromStory(storyId: string): Promise { - return this.api.post(`/api/stories/${storyId}/extract_vocabulary`); - } - - storyMeanings( - storyId: string, - params?: { - page?: number; - items?: number; - storyId?: string; - } - ): Promise< - { - meanings: MeaningType[]; - } & PagyResponseType - > { - return this.api.get(`/api/stories/${storyId}/meanings`, { - params: decamelizeKeys(params), - }); - } - - mineMeanings(params?: { - page?: number; - items?: number; - sourceId?: string; - sourceType?: string; - status?: string; - }): Promise< - { - meanings: MeaningType[]; - } & PagyResponseType - > { - return this.api.get("/api/mine/meanings", { - params: decamelizeKeys(params), - }); - } - - createStory(params: CreateStoryParamsType): Promise { - return this.api.post("/api/stories", decamelizeKeys(params)); - } - - story(id: string): Promise { - return this.api.get(`/api/stories/${id}`); - } - - stories(params?: { page: number }): Promise< - { - stories: StoryType[]; - } & PagyResponseType - > { - return this.api.get("/api/stories", { params: decamelizeKeys(params) }); - } - - mineStories(params?: { page: number }): Promise< - { - stories: StoryType[]; - } & PagyResponseType - > { - return this.api.get("/api/mine/stories", { - params: decamelizeKeys(params), - }); - } - - starStory(storyId: string) { - return this.api.post(`/api/mine/stories`, decamelizeKeys({ storyId })); - } - - unstarStory(storyId: string) { - return this.api.delete(`/api/mine/stories/${storyId}`); - } - - registerIpcHandlers() { - ipcMain.handle("web-api-auth", async (event, params) => { - return this.auth(params) - .then((user) => { - return user; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-me", async (event) => { - return this.me() - .then((user) => { - return user; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-rankings", async (event, range) => { - return this.rankings(range) - .then((response) => { - return response; - }) - .catch((error) => { - logger.error(error); - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-posts", async (event, params) => { - return this.posts(params) - .then((response) => { - return response; - }) - .catch((error) => { - logger.error(error); - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-post", async (event, id) => { - return this.post(id) - .then((response) => { - return response; - }) - .catch((error) => { - logger.error(error); - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-create-post", async (event, params) => { - return this.createPost(params) - .then((response) => { - return response; - }) - .catch((error) => { - logger.error(error); - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-delete-post", async (event, id) => { - return this.deletePost(id) - .then((response) => { - return response; - }) - .catch((error) => { - logger.error(error); - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-lookup", async (event, params) => { - return this.lookup(params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-lookup-in-batch", async (event, params) => { - return this.lookupInBatch(params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-mine-meanings", async (event, params) => { - return this.mineMeanings(params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-create-story", async (event, params) => { - return this.createStory(params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle( - "web-api-extract-vocabulary-from-story", - async (event, storyId) => { - return this.extractVocabularyFromStory(storyId) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - } - ); - - ipcMain.handle("web-api-story-meanings", async (event, storyId, params) => { - return this.storyMeanings(storyId, params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-stories", async (event, params) => { - return this.stories(params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-story", async (event, id) => { - return this.story(id) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-mine-stories", async (event, params) => { - return this.mineStories(params) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-star-story", async (event, id) => { - return this.starStory(id) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - - ipcMain.handle("web-api-unstar-story", async (event, id) => { - return this.unstarStory(id) - .then((response) => { - return response; - }) - .catch((error) => { - event.sender.send("on-notification", { - type: "error", - message: error.message, - }); - }); - }); - } -} - -export default new WebApi(); diff --git a/enjoy/src/main/window.ts b/enjoy/src/main/window.ts index c802f85d..5d82cf9c 100644 --- a/enjoy/src/main/window.ts +++ b/enjoy/src/main/window.ts @@ -14,7 +14,6 @@ import downloader from "@main/downloader"; import whisper from "@main/whisper"; import fs from "fs-extra"; import "@main/i18n"; -import webApi from "@main/web-api"; import log from "electron-log/main"; import { WEB_API_URL } from "@/constants"; import { AudibleProvider, TedProvider } from "@main/providers"; @@ -38,8 +37,6 @@ main.init = () => { return; } - webApi.registerIpcHandlers(); - // Prepare local database db.registerIpcHandlers();