From ffd179bb060cd274466ae698d63191bcfb78b6b2 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Sun, 30 Mar 2025 02:11:41 +0800 Subject: [PATCH] fix: TXT file correctly read and imported on desktop apps, closes #756 (#757) --- .../public/locales/ar/translation.json | 5 +++- .../public/locales/de/translation.json | 5 +++- .../public/locales/el/translation.json | 5 +++- .../public/locales/es/translation.json | 5 +++- .../public/locales/fr/translation.json | 5 +++- .../public/locales/hi/translation.json | 5 +++- .../public/locales/id/translation.json | 5 +++- .../public/locales/it/translation.json | 5 +++- .../public/locales/ja/translation.json | 5 +++- .../public/locales/ko/translation.json | 5 +++- .../public/locales/pl/translation.json | 5 +++- .../public/locales/pt/translation.json | 5 +++- .../public/locales/ru/translation.json | 5 +++- .../public/locales/tr/translation.json | 5 +++- .../public/locales/uk/translation.json | 5 +++- .../public/locales/vi/translation.json | 5 +++- .../public/locales/zh-CN/translation.json | 5 +++- .../public/locales/zh-TW/translation.json | 5 +++- apps/readest-app/src/app/library/page.tsx | 16 +++++++++-- .../app/reader/components/tts/TTSControl.tsx | 4 +-- apps/readest-app/src/components/Popup.tsx | 28 +++++++++---------- apps/readest-app/src/components/Toast.tsx | 7 ++++- apps/readest-app/src/utils/txt.ts | 14 ++-------- 23 files changed, 110 insertions(+), 49 deletions(-) diff --git a/apps/readest-app/public/locales/ar/translation.json b/apps/readest-app/public/locales/ar/translation.json index 1caa0334..2b9aa9ec 100644 --- a/apps/readest-app/public/locales/ar/translation.json +++ b/apps/readest-app/public/locales/ar/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "تصدير التعليقات", "Auto Import on File Open": "استيراد تلقائي عند فتح الملف", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "تبديل منطقة التقليب بالنقر" + "Swap Click-to-Flip Area": "تبديل منطقة التقليب بالنقر", + "No chapters detected.": "لم يتم التعرف على فصول.", + "Failed to parse the EPUB file.": "فشل في تحليل ملف EPUB.", + "This book format is not supported.": "هذا تنسيق الكتاب غير مدعوم." } diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 33bd5374..de530f33 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Anmerkungen exportieren", "Auto Import on File Open": "Automatischer Import beim Öffnen einer Datei", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Klick-zu-Blättern-Bereich tauschen" + "Swap Click-to-Flip Area": "Klick-zu-Blättern-Bereich tauschen", + "No chapters detected.": "Keine Kapitel erkannt.", + "Failed to parse the EPUB file.": "Fehler beim Parsen der EPUB-Datei.", + "This book format is not supported.": "Dieses Buchformat wird nicht unterstützt." } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index 20c43fd7..88b29338 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Εξαγωγή σχολιασμών", "Auto Import on File Open": "Αυτόματη εισαγωγή κατά το άνοιγμα αρχείου", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Ανταλλαγή περιοχής κλικ για γύρισμα σελίδας" + "Swap Click-to-Flip Area": "Ανταλλαγή περιοχής κλικ για γύρισμα σελίδας", + "No chapters detected.": "Δεν εντοπίστηκαν κεφάλαια.", + "Failed to parse the EPUB file.": "Αποτυχία ανάλυσης του αρχείου EPUB.", + "This book format is not supported.": "Αυτή η μορφή βιβλίου δεν υποστηρίζεται." } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index 3a120539..5b922ded 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Exportar anotaciones", "Auto Import on File Open": "Importación automática al abrir archivo", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Intercambiar área de clic para voltear" + "Swap Click-to-Flip Area": "Intercambiar área de clic para voltear", + "No chapters detected.": "No se detectaron capítulos.", + "Failed to parse the EPUB file.": "Error al analizar el archivo EPUB.", + "This book format is not supported.": "Este formato de libro no es compatible." } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 7c5802aa..4510cd98 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Exporter les annotations", "Auto Import on File Open": "Importation automatique à l'ouverture du fichier", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Échanger la zone de clic pour tourner" + "Swap Click-to-Flip Area": "Échanger la zone de clic pour tourner", + "No chapters detected.": "Aucun chapitre détecté.", + "Failed to parse the EPUB file.": "Échec de l'analyse du fichier EPUB.", + "This book format is not supported.": "Ce format de livre n'est pas pris en charge." } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 094b38c2..1b34d4e8 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "टिप्पणियाँ निर्यात करें", "Auto Import on File Open": "फ़ाइल खोलने पर स्वचालित आयात", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "क्लिक-टू-फ्लिप क्षेत्र स्वैप करें" + "Swap Click-to-Flip Area": "क्लिक-टू-फ्लिप क्षेत्र स्वैप करें", + "No chapters detected.": "कोई अध्याय नहीं मिला।", + "Failed to parse the EPUB file.": "EPUB फ़ाइल को पार्स करने में विफल।", + "This book format is not supported.": "यह पुस्तक प्रारूप समर्थित नहीं है।" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index fa5044b4..7bed02c4 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Ekspor Anotasi", "Auto Import on File Open": "Impor Otomatis saat File Dibuka", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Tukar Area Klik untuk Membalik" + "Swap Click-to-Flip Area": "Tukar Area Klik untuk Membalik", + "No chapters detected.": "Tidak ada bab yang terdeteksi.", + "Failed to parse the EPUB file.": "Gagal mengurai file EPUB.", + "This book format is not supported.": "Format buku ini tidak didukung." } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index f56b24ed..4d230306 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Esporta annotazioni", "Auto Import on File Open": "Importazione automatica all'apertura del file", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Scambia area click per voltare pagina" + "Swap Click-to-Flip Area": "Scambia area click per voltare pagina", + "No chapters detected.": "Nessun capitolo rilevato.", + "Failed to parse the EPUB file.": "Impossibile analizzare il file EPUB.", + "This book format is not supported.": "Questo formato di libro non è supportato." } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index ad45c401..212ea3c4 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "注釈をエクスポート", "Auto Import on File Open": "ファイルを開くと自動インポート", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "クリックめくりエリアを入れ替え" + "Swap Click-to-Flip Area": "クリックめくりエリアを入れ替え", + "No chapters detected.": "章が検出されません。", + "Failed to parse the EPUB file.": "EPUBファイルの解析に失敗しました。", + "This book format is not supported.": "この書籍形式はサポートされていません。" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index 1d4171c8..4d73f631 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "주석 내보내기", "Auto Import on File Open": "파일 열 때 자동 가져오기", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "클릭-뒤집기 영역 교환" + "Swap Click-to-Flip Area": "클릭-뒤집기 영역 교환", + "No chapters detected.": "장 발견되지 않음.", + "Failed to parse the EPUB file.": "EPUB 파일 구문 분석 실패.", + "This book format is not supported.": "이 책 형식은 지원되지 않습니다." } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index df880543..aa4cbe58 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Eksportuj adnotacje", "Auto Import on File Open": "Automatyczne importowanie przy otwieraniu pliku", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Zamień obszar kliknięcia na przewracanie" + "Swap Click-to-Flip Area": "Zamień obszar kliknięcia na przewracanie", + "No chapters detected.": "Nie wykryto rozdziałów.", + "Failed to parse the EPUB file.": "Nie udało się przeanalizować pliku EPUB.", + "This book format is not supported.": "Ten format książki nie jest obsługiwany." } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 010d61be..49c7eab6 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Exportar Anotações", "Auto Import on File Open": "Importação Automática ao Abrir Arquivo", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Trocar Área de Clique para Virar" + "Swap Click-to-Flip Area": "Trocar Área de Clique para Virar", + "No chapters detected.": "Nenhum capítulo detectado.", + "Failed to parse the EPUB file.": "Falha ao analisar o arquivo EPUB.", + "This book format is not supported.": "Este formato de livro não é suportado." } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 44d4d933..5873b5c3 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Экспортировать аннотации", "Auto Import on File Open": "Автоматический импорт при открытии файла", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Переключить область клика для переворота" + "Swap Click-to-Flip Area": "Переключить область клика для переворота", + "No chapters detected.": "Не обнаружено глав.", + "Failed to parse the EPUB file.": "Не удалось разобрать файл EPUB.", + "This book format is not supported.": "Этот формат книги не поддерживается." } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 05001204..6c636de1 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Notları Dışa Aktar", "Auto Import on File Open": "Dosya Açıldığında Otomatik İçe Aktar", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Tıkla-Çevir Alanını Değiştir" + "Swap Click-to-Flip Area": "Tıkla-Çevir Alanını Değiştir", + "No chapters detected.": "Bölüm bulunamadı.", + "Failed to parse the EPUB file.": "EPUB dosyası ayrıştırılamadı.", + "This book format is not supported.": "Bu kitap formatı desteklenmiyor." } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index d2c4432b..5c43e845 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Експортувати анотації", "Auto Import on File Open": "Автоматичний імпорт при відкритті файлу", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Поміняти місцями область кліку для перевороту" + "Swap Click-to-Flip Area": "Поміняти місцями область кліку для перевороту", + "No chapters detected.": "Не виявлено жодного розділу.", + "Failed to parse the EPUB file.": "Не вдалося розібрати файл EPUB.", + "This book format is not supported.": "Цей формат книги не підтримується." } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index b95bd6d3..fa5032fe 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "Xuất chú thích", "Auto Import on File Open": "Tự động nhập khi mở tệp", "LXGW WenKai GB Screen": "LXGW WenKai", - "Swap Click-to-Flip Area": "Hoán đổi khu vực nhấp để lật trang" + "Swap Click-to-Flip Area": "Hoán đổi khu vực nhấp để lật trang", + "No chapters detected.": "Không phát hiện thấy chương nào.", + "Failed to parse the EPUB file.": "Không thể phân tích tệp EPUB.", + "This book format is not supported.": "Định dạng sách này không được hỗ trợ." } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index c13189b3..3a300887 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "导出笔记", "Auto Import on File Open": "打开文件时自动导入", "LXGW WenKai GB Screen": "霞鹜文楷", - "Swap Click-to-Flip Area": "交换点击翻页区域" + "Swap Click-to-Flip Area": "交换点击翻页区域", + "No chapters detected.": "未检测到章节。", + "Failed to parse the EPUB file.": "无法解析 EPUB 文件。", + "This book format is not supported.": "不支持此书籍格式。" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index 8b6376c1..4541e156 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -261,5 +261,8 @@ "Export Annotations": "匯出筆記", "Auto Import on File Open": "打開文件時自動導入", "LXGW WenKai GB Screen": "霞鶩文楷", - "Swap Click-to-Flip Area": "交換點擊翻頁區域" + "Swap Click-to-Flip Area": "交換點擊翻頁區域", + "No chapters detected.": "未檢測到章節。", + "Failed to parse the EPUB file.": "無法解析 EPUB 文件。", + "This book format is not supported.": "不支援此書籍格式。" } diff --git a/apps/readest-app/src/app/library/page.tsx b/apps/readest-app/src/app/library/page.tsx index dce61c47..88ddf202 100644 --- a/apps/readest-app/src/app/library/page.tsx +++ b/apps/readest-app/src/app/library/page.tsx @@ -296,6 +296,11 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP const importBooks = async (files: (string | File)[]) => { setLoading(true); const failedFiles = []; + const errorMap: [string, string][] = [ + ['No chapters detected.', _('No chapters detected.')], + ['Failed to parse EPUB.', _('Failed to parse the EPUB file.')], + ['Unsupported format.', _('This book format is not supported.')], + ]; for (const file of files) { try { const book = await appService?.importBook(file, libraryBooks); @@ -308,10 +313,15 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP const filename = typeof file === 'string' ? file : file.name; const baseFilename = getBaseFilename(filename); failedFiles.push(baseFilename); + const errorMessage = + error instanceof Error + ? errorMap.find(([substring]) => error.message.includes(substring))?.[1] || '' + : ''; eventDispatcher.dispatch('toast', { - message: _('Failed to import book(s): {{filenames}}', { - filenames: listFormater(false).format(failedFiles), - }), + message: + _('Failed to import book(s): {{filenames}}', { + filenames: listFormater(false).format(failedFiles), + }) + (errorMessage ? `\n${errorMessage}` : ''), type: 'error', }); console.error('Failed to import book:', filename, error); diff --git a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx index 4e5c9d0a..1d415640 100644 --- a/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx +++ b/apps/readest-app/src/app/reader/components/tts/TTSControl.tsx @@ -277,8 +277,8 @@ const TTSControl = () => { className={clsx( 'fixed right-6 h-12 w-12', appService?.hasSafeAreaInset - ? 'bottom-[calc(env(safe-area-inset-bottom)+48px)]' - : 'bottom-12', + ? 'bottom-[calc(env(safe-area-inset-bottom)+70px)]' + : 'bottom-[70px] sm:bottom-14', )} > diff --git a/apps/readest-app/src/components/Popup.tsx b/apps/readest-app/src/components/Popup.tsx index 586d0724..6fd7ec89 100644 --- a/apps/readest-app/src/components/Popup.tsx +++ b/apps/readest-app/src/components/Popup.tsx @@ -21,7 +21,20 @@ const Popup = ({ }) => (
+
-
); diff --git a/apps/readest-app/src/components/Toast.tsx b/apps/readest-app/src/components/Toast.tsx index 241a1874..ecad6666 100644 --- a/apps/readest-app/src/components/Toast.tsx +++ b/apps/readest-app/src/components/Toast.tsx @@ -69,7 +69,12 @@ export const Toast = () => { messageClass.current, )} > - {toastMessage} + {toastMessage.split('\n').map((line, idx) => ( + + {line || <> } +
+
+ ))}
diff --git a/apps/readest-app/src/utils/txt.ts b/apps/readest-app/src/utils/txt.ts index b3b305d7..9b752773 100644 --- a/apps/readest-app/src/utils/txt.ts +++ b/apps/readest-app/src/utils/txt.ts @@ -1,3 +1,4 @@ +import { getBaseFilename } from './book'; import { partialMD5 } from './md5'; interface Metadata { @@ -38,12 +39,12 @@ export class TxtToEpubConverter { public async convert(options: Txt2EpubOptions): Promise { const { file: txtFile, author: providedAuthor, language: providedLanguage } = options; - const fileContent = await this.readFileAsArrayBuffer(txtFile); + const fileContent = await txtFile.arrayBuffer(); const detectedEncoding = this.detectEncoding(fileContent) || 'utf-8'; const decoder = new TextDecoder(detectedEncoding); const txtContent = decoder.decode(fileContent).trim(); - const bookTitle = this.extractBookTitle(txtFile.name); + const bookTitle = this.extractBookTitle(getBaseFilename(txtFile.name)); const fileName = `${bookTitle}.epub`; const fileHeader = txtContent.slice(0, 1024); @@ -358,15 +359,6 @@ export class TxtToEpubConverter { return 'en'; } - private readFileAsArrayBuffer(file: File): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = () => resolve(reader.result as ArrayBuffer); - reader.onerror = reject; - reader.readAsArrayBuffer(file); - }); - } - private extractBookTitle(filename: string): string { const match = filename.match(/《([^》]+)》/); return match ? match[1]! : filename.split('.')[0]!;