diff --git a/enjoy/src/main/downloader.ts b/enjoy/src/main/downloader.ts index 584217ef..f9fbea30 100644 --- a/enjoy/src/main/downloader.ts +++ b/enjoy/src/main/downloader.ts @@ -1,4 +1,4 @@ -import { ipcMain, app } from "electron"; +import { ipcMain, app, BrowserWindow } from "electron"; import path from "path"; import fs from "fs"; import mainWin from "@main/window"; @@ -77,6 +77,44 @@ class Downloader { }); } + prinfAsPDF(content: string, savePath: string) { + let pdfWin: BrowserWindow | null = null; + + return new Promise((resolve, reject) => { + pdfWin = new BrowserWindow({ + webPreferences: { + nodeIntegration: true, + webSecurity: false, + }, + show: false, + width: 800, + height: 600, + fullscreenable: false, + minimizable: false, + }); + + pdfWin.loadURL(`data:text/html;charset=utf-8,${encodeURI(content)}`); + + pdfWin.webContents.on("did-finish-load", () => { + pdfWin.webContents + .printToPDF({ printBackground: true }) + .then((data) => { + fs.writeFile(savePath, data, (error) => { + if (error) throw error; + + resolve(savePath); + + pdfWin.close(); + pdfWin = null; + }); + }) + .catch((error) => { + reject(error); + }); + }); + }); + } + cancel(filename: string) { logger.debug("dashboard", this.dashboard()); this.tasks @@ -125,6 +163,9 @@ class Downloader { ipcMain.handle("download-dashboard", () => { return this.dashboard(); }); + ipcMain.handle("print-as-pdf", (_event, content, savePath) => { + return this.prinfAsPDF(content, savePath); + }); } } diff --git a/enjoy/src/preload.ts b/enjoy/src/preload.ts index 3e685b9e..f616440a 100644 --- a/enjoy/src/preload.ts +++ b/enjoy/src/preload.ts @@ -497,6 +497,9 @@ contextBridge.exposeInMainWorld("__ENJOY_APP__", { start: (url: string, savePath?: string) => { return ipcRenderer.invoke("download-start", url, savePath); }, + printAsPdf: (content: string, savePath: string) => { + return ipcRenderer.invoke("print-as-pdf", content, savePath); + }, cancel: (filename: string) => { ipcRenderer.invoke("download-cancel", filename); }, diff --git a/enjoy/src/renderer/components/medias/index.ts b/enjoy/src/renderer/components/medias/index.ts index 3f2a514f..a99b6b46 100644 --- a/enjoy/src/renderer/components/medias/index.ts +++ b/enjoy/src/renderer/components/medias/index.ts @@ -12,3 +12,4 @@ export * from "./media-provider"; export * from "./media-tabs"; export * from "./media-loading-modal"; export * from "./add-media-button"; +export * from "./media-transcription-download"; diff --git a/enjoy/src/renderer/components/medias/media-transcription-download.tsx b/enjoy/src/renderer/components/medias/media-transcription-download.tsx new file mode 100644 index 00000000..970ab998 --- /dev/null +++ b/enjoy/src/renderer/components/medias/media-transcription-download.tsx @@ -0,0 +1,81 @@ +import { useContext } from "react"; +import { Button, toast } from "@renderer/components/ui"; +import { t } from "i18next"; +import { + MediaPlayerProviderContext, + AppSettingsProviderContext, +} from "@/renderer/context"; +import { AlignmentResult } from "echogarden/dist/api/API.d.js"; +import { convertWordIpaToNormal } from "@/utils"; +import template from "./transcription.template.html?raw"; + +export const MediaTranscriptionDownload = () => { + const { media, transcription } = useContext(MediaPlayerProviderContext); + const { EnjoyApp, learningLanguage, ipaMappings } = useContext( + AppSettingsProviderContext + ); + + function generateContent() { + const language = transcription.language || learningLanguage; + const sentences = transcription.result as AlignmentResult; + + const contents = sentences.timeline.map((sentence) => { + let words = sentence.text.split(" "); + + const ipas = sentence.timeline.map((w) => + w.timeline.map((t) => + language.startsWith("en") + ? convertWordIpaToNormal( + t.timeline.map((s) => s.text), + { mappings: ipaMappings } + ).join("") + : t.text + ) + ); + + if (words.length !== sentence.timeline.length) { + words = sentence.timeline.map((w) => w.text); + } + + return ` +