forked from akai/readest
fix: save custom cover images in apps (#1588)
This commit is contained in:
@@ -464,5 +464,6 @@
|
||||
"Keep manual input": "الاحتفاظ بالإدخال اليدوي",
|
||||
"Google Books": "كتب جوجل",
|
||||
"Open Library": "المكتبة المفتوحة",
|
||||
"Fiction, Science, History": "خيال، علوم، تاريخ"
|
||||
"Fiction, Science, History": "خيال، علوم، تاريخ",
|
||||
"Select Cover Image": "اختر صورة الغلاف"
|
||||
}
|
||||
|
||||
@@ -448,5 +448,6 @@
|
||||
"Keep manual input": "Manuelle Eingabe beibehalten",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Belletristik, Wissenschaft, Geschichte"
|
||||
"Fiction, Science, History": "Belletristik, Wissenschaft, Geschichte",
|
||||
"Select Cover Image": "Coverbild auswählen"
|
||||
}
|
||||
|
||||
@@ -448,5 +448,6 @@
|
||||
"Keep manual input": "Διατήρηση χειροκίνητης εισαγωγής",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Μυθοπλασία, Επιστήμη, Ιστορία"
|
||||
"Fiction, Science, History": "Μυθοπλασία, Επιστήμη, Ιστορία",
|
||||
"Select Cover Image": "Επιλέξτε εικόνα εξωφύλλου"
|
||||
}
|
||||
|
||||
@@ -452,5 +452,6 @@
|
||||
"Keep manual input": "Mantener entrada manual",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Ficción, Ciencia, Historia"
|
||||
"Fiction, Science, History": "Ficción, Ciencia, Historia",
|
||||
"Select Cover Image": "Seleccionar imagen de portada"
|
||||
}
|
||||
|
||||
@@ -452,5 +452,6 @@
|
||||
"Keep manual input": "Conserver la saisie manuelle",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Fiction, Science, Histoire"
|
||||
"Fiction, Science, History": "Fiction, Science, Histoire",
|
||||
"Select Cover Image": "Sélectionner l'image de couverture"
|
||||
}
|
||||
|
||||
@@ -448,5 +448,6 @@
|
||||
"Keep manual input": "मैन्युअल इनपुट रखें",
|
||||
"Google Books": "गूगल बुक्स",
|
||||
"Open Library": "ओपन लाइब्रेरी",
|
||||
"Fiction, Science, History": "काल्पनिक, विज्ञान, इतिहास"
|
||||
"Fiction, Science, History": "काल्पनिक, विज्ञान, इतिहास",
|
||||
"Select Cover Image": "कवर इमेज चुनें"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "Pertahankan input manual",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Fiksi, Sains, Sejarah"
|
||||
"Fiction, Science, History": "Fiksi, Sains, Sejarah",
|
||||
"Select Cover Image": "Pilihan Gambar Sampul"
|
||||
}
|
||||
|
||||
@@ -452,5 +452,6 @@
|
||||
"Keep manual input": "Mantieni input manuale",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Narrativa, Scienza, Storia"
|
||||
"Fiction, Science, History": "Narrativa, Scienza, Storia",
|
||||
"Select Cover Image": "Seleziona immagine di copertina"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "手動入力を保持",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "小説、科学、歴史"
|
||||
"Fiction, Science, History": "小説、科学、歴史",
|
||||
"Select Cover Image": "表紙画像を選択"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "수동 입력 유지",
|
||||
"Google Books": "구글 북스",
|
||||
"Open Library": "오픈 라이브러리",
|
||||
"Fiction, Science, History": "소설, 과학, 역사"
|
||||
"Fiction, Science, History": "소설, 과학, 역사",
|
||||
"Select Cover Image": "표지 이미지 선택"
|
||||
}
|
||||
|
||||
@@ -448,5 +448,6 @@
|
||||
"Keep manual input": "Handmatige invoer behouden",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Fictie, Wetenschap, Geschiedenis"
|
||||
"Fiction, Science, History": "Fictie, Wetenschap, Geschiedenis",
|
||||
"Select Cover Image": "Selecteer omslagafbeelding"
|
||||
}
|
||||
|
||||
@@ -456,5 +456,6 @@
|
||||
"Keep manual input": "Zachowaj wprowadzenie ręczne",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Beletrystyka, Nauka, Historia"
|
||||
"Fiction, Science, History": "Beletrystyka, Nauka, Historia",
|
||||
"Select Cover Image": "Zaznacz obraz okładki"
|
||||
}
|
||||
|
||||
@@ -452,5 +452,6 @@
|
||||
"Keep manual input": "Manter entrada manual",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Ficção, Ciência, História"
|
||||
"Fiction, Science, History": "Ficção, Ciência, História",
|
||||
"Select Cover Image": "Selecionar imagem da capa"
|
||||
}
|
||||
|
||||
@@ -456,5 +456,6 @@
|
||||
"Keep manual input": "Сохранить ручной ввод",
|
||||
"Google Books": "Google Книги",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Художественная литература, Наука, История"
|
||||
"Fiction, Science, History": "Художественная литература, Наука, История",
|
||||
"Select Cover Image": "Выбрать изображение обложки"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "เก็บข้อมูลที่ป้อนด้วยตนเอง",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "นิยาย, วิทยาศาสตร์, ประวัติศาสตร์"
|
||||
"Fiction, Science, History": "นิยาย, วิทยาศาสตร์, ประวัติศาสตร์",
|
||||
"Select Cover Image": "เลือกภาพปก"
|
||||
}
|
||||
|
||||
@@ -448,5 +448,6 @@
|
||||
"Keep manual input": "Manuel girişi koru",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Kurgu, Bilim, Tarih"
|
||||
"Fiction, Science, History": "Kurgu, Bilim, Tarih",
|
||||
"Select Cover Image": "Kapak Resmi Seç"
|
||||
}
|
||||
|
||||
@@ -456,5 +456,6 @@
|
||||
"Keep manual input": "Зберегти ручне введення",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Художня література, Наука, Історія"
|
||||
"Fiction, Science, History": "Художня література, Наука, Історія",
|
||||
"Select Cover Image": "Оберіть зображення обкладинки"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "Giữ nhập liệu thủ công",
|
||||
"Google Books": "Google Books",
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Tiểu thuyết, Khoa học, Lịch sử"
|
||||
"Fiction, Science, History": "Tiểu thuyết, Khoa học, Lịch sử",
|
||||
"Select Cover Image": "Chọn ảnh bìa"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "保留手动输入",
|
||||
"Google Books": "谷歌图书",
|
||||
"Open Library": "开放图书馆",
|
||||
"Fiction, Science, History": "小说,科学,历史"
|
||||
"Fiction, Science, History": "小说,科学,历史",
|
||||
"Select Cover Image": "选择封面图片"
|
||||
}
|
||||
|
||||
@@ -444,5 +444,6 @@
|
||||
"Keep manual input": "保留手動輸入",
|
||||
"Google Books": "Google 圖書",
|
||||
"Open Library": "開放圖書館",
|
||||
"Fiction, Science, History": "小說,科學,歷史"
|
||||
"Fiction, Science, History": "小說,科學,歷史",
|
||||
"Select Cover Image": "選擇封面圖片"
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import { eventDispatcher } from '@/utils/event';
|
||||
import { ProgressPayload } from '@/utils/transfer';
|
||||
import { throttle } from '@/utils/throttle';
|
||||
import { parseOpenWithFiles } from '@/helpers/openWith';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
import { isTauriAppPlatform, isWebAppPlatform } from '@/services/environment';
|
||||
import { checkForAppUpdates, checkAppReleaseNotes } from '@/helpers/updater';
|
||||
import { FILE_ACCEPT_FORMATS, SUPPORTED_FILE_EXTS } from '@/services/constants';
|
||||
import { impactFeedback } from '@tauri-apps/plugin-haptics';
|
||||
@@ -565,17 +565,29 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
||||
book.title = formatTitle(metadata.title);
|
||||
book.author = formatAuthors(metadata.author);
|
||||
book.primaryLanguage = getPrimaryLanguage(metadata.language);
|
||||
if (metadata.coverImageBlobUrl || metadata.coverImageUrl) {
|
||||
book.updatedAt = Date.now();
|
||||
if (metadata.coverImageBlobUrl || metadata.coverImageUrl || metadata.coverImageFile) {
|
||||
book.coverImageUrl = metadata.coverImageBlobUrl || metadata.coverImageUrl;
|
||||
try {
|
||||
appService?.updateCoverImage(
|
||||
await appService?.updateCoverImage(
|
||||
book,
|
||||
(metadata.coverImageBlobUrl || metadata.coverImageUrl) as string,
|
||||
metadata.coverImageBlobUrl || metadata.coverImageUrl,
|
||||
metadata.coverImageFile,
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn('Failed to update cover image:', error);
|
||||
}
|
||||
}
|
||||
if (isWebAppPlatform()) {
|
||||
// Clear HTTP cover image URL if cover is updated with a local file
|
||||
if (metadata.coverImageBlobUrl) {
|
||||
metadata.coverImageUrl = undefined;
|
||||
}
|
||||
} else {
|
||||
metadata.coverImageUrl = undefined;
|
||||
}
|
||||
metadata.coverImageBlobUrl = undefined;
|
||||
metadata.coverImageFile = undefined;
|
||||
await updateBook(envConfig, book);
|
||||
};
|
||||
|
||||
@@ -585,9 +597,9 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
|
||||
let files;
|
||||
|
||||
if (isTauriAppPlatform()) {
|
||||
files = (await selectFilesTauri()) as [string];
|
||||
files = (await selectFilesTauri()) as string[];
|
||||
} else {
|
||||
files = (await selectFilesWeb()) as [File];
|
||||
files = (await selectFilesWeb()) as File[];
|
||||
}
|
||||
importBooks(files);
|
||||
};
|
||||
|
||||
@@ -37,9 +37,7 @@ const BookCover: React.FC<BookCoverProps> = ({
|
||||
<div className={clsx('book-cover-container relative flex h-full w-full', className)}>
|
||||
{coverFit === 'crop' ? (
|
||||
<Image
|
||||
src={
|
||||
book.metadata?.coverImageUrl || book.metadata?.coverImageBlobUrl || book.coverImageUrl!
|
||||
}
|
||||
src={book.metadata?.coverImageUrl || book.coverImageUrl!}
|
||||
alt={book.title}
|
||||
fill={true}
|
||||
className={clsx('crop-cover-img object-cover', imageClassName)}
|
||||
@@ -53,7 +51,7 @@ const BookCover: React.FC<BookCoverProps> = ({
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
src={book.coverImageUrl!}
|
||||
src={book.metadata?.coverImageUrl || book.coverImageUrl!}
|
||||
alt={book.title}
|
||||
width={0}
|
||||
height={0}
|
||||
|
||||
@@ -4,9 +4,12 @@ import { MdEdit, MdLock, MdLockOpen, MdOutlineSearch } from 'react-icons/md';
|
||||
|
||||
import { Book } from '@/types/book';
|
||||
import { BookMetadata } from '@/libs/document';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { formatAuthors, formatTitle } from '@/utils/book';
|
||||
import { FormField } from './FormField';
|
||||
import { IMAGE_ACCEPT_FORMATS, SUPPORTED_IMAGE_EXTS } from '@/services/constants';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
import BookCover from '@/components/BookCover';
|
||||
|
||||
interface BookDetailEditProps {
|
||||
@@ -43,20 +46,18 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
onSave,
|
||||
}) => {
|
||||
const _ = useTranslation();
|
||||
const { appService } = useEnv();
|
||||
|
||||
const hasLockedFields = Object.values(lockedFields).some((locked) => locked);
|
||||
const allFieldsLocked = Object.values(lockedFields).every((locked) => locked);
|
||||
const isCoverLocked = lockedFields['coverImageUrl'] || false;
|
||||
const [coverImageUpdated, setCoverImageUpdated] = useState(false);
|
||||
const [newCoverImageUrl, setNewCoverImageUrl] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (metadata.coverImageUrl) {
|
||||
if (book.metadata) {
|
||||
book.metadata.coverImageUrl = metadata.coverImageUrl;
|
||||
}
|
||||
setCoverImageUpdated(true);
|
||||
setNewCoverImageUrl(metadata.coverImageUrl);
|
||||
}
|
||||
}, [book.metadata, metadata.coverImageUrl]);
|
||||
}, [metadata.coverImageUrl]);
|
||||
|
||||
const titleAuthorFields = [
|
||||
{
|
||||
@@ -147,12 +148,11 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
},
|
||||
];
|
||||
|
||||
const selectImageFile = () => {
|
||||
if (coverImageUpdated) setCoverImageUpdated(false);
|
||||
const selectImageFileWeb = () => {
|
||||
return new Promise((resolve) => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.png, .jpg, .jpeg';
|
||||
fileInput.accept = IMAGE_ACCEPT_FORMATS;
|
||||
fileInput.multiple = false;
|
||||
fileInput.click();
|
||||
|
||||
@@ -162,27 +162,50 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
});
|
||||
};
|
||||
|
||||
const selectImageFileTauri = async () => {
|
||||
const exts = appService?.isMobileApp ? [] : SUPPORTED_IMAGE_EXTS;
|
||||
const files = (await appService?.selectFiles(_('Select Cover Image'), exts)) || [];
|
||||
if (appService?.isIOSApp) {
|
||||
return files.filter((file) => {
|
||||
const fileExt = file.split('.').pop()?.toLowerCase() || 'unknown';
|
||||
return SUPPORTED_IMAGE_EXTS.includes(fileExt);
|
||||
});
|
||||
}
|
||||
return files;
|
||||
};
|
||||
|
||||
const handleSelectLocalImage = async () => {
|
||||
const files = (await selectImageFile()) as [File];
|
||||
if (files && files.length > 0) {
|
||||
const file = files[0];
|
||||
metadata.coverImageBlobUrl = URL.createObjectURL(file);
|
||||
setCoverImageUpdated(true);
|
||||
let files;
|
||||
if (isTauriAppPlatform()) {
|
||||
files = (await selectImageFileTauri()) as string[];
|
||||
if (files.length > 0) {
|
||||
metadata.coverImageFile = files[0]!;
|
||||
metadata.coverImageUrl = appService?.fs.getURL(files[0]!);
|
||||
setNewCoverImageUrl(metadata.coverImageUrl!);
|
||||
}
|
||||
} else {
|
||||
files = (await selectImageFileWeb()) as File[];
|
||||
if (files.length > 0) {
|
||||
metadata.coverImageBlobUrl = URL.createObjectURL(files[0]!);
|
||||
setNewCoverImageUrl(metadata.coverImageBlobUrl!);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='bg-base-100 relative w-full rounded-lg'>
|
||||
<div className='mb-6 flex items-start gap-4'>
|
||||
<div className='flex w-[40%] max-w-36 flex-col gap-2'>
|
||||
<div className='flex w-[30%] max-w-32 flex-col gap-2'>
|
||||
<div className='aspect-[28/41] h-full shadow-md'>
|
||||
<BookCover
|
||||
mode='list'
|
||||
book={{
|
||||
...book,
|
||||
...(metadata.coverImageUrl || metadata.coverImageBlobUrl
|
||||
? { coverImageUrl: metadata.coverImageUrl || metadata.coverImageBlobUrl }
|
||||
: {}),
|
||||
metadata: {
|
||||
...metadata,
|
||||
coverImageUrl: newCoverImageUrl || metadata.coverImageUrl,
|
||||
},
|
||||
...(newCoverImageUrl ? { coverImageUrl: newCoverImageUrl } : {}),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -191,14 +214,15 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
onClick={handleSelectLocalImage}
|
||||
disabled={isCoverLocked}
|
||||
className={clsx(
|
||||
'flex flex-1 items-center justify-center gap-1 rounded px-2 py-1 text-xs',
|
||||
'flex flex-1 items-center justify-center gap-1 rounded px-2 py-1',
|
||||
'border border-gray-300 bg-white hover:bg-gray-50',
|
||||
'disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'text-sm sm:text-xs',
|
||||
isCoverLocked && '!text-base-content !bg-base-200',
|
||||
)}
|
||||
title={_('Change cover image')}
|
||||
>
|
||||
<MdEdit className='h-3 w-3' />
|
||||
<MdEdit className='h-5 w-5 sm:h-4 sm:w-4' />
|
||||
<span className='hidden sm:inline'>{_('Replace')}</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
|
||||
|
||||
const handleSaveMetadata = () => {
|
||||
if (editedMeta && handleBookMetadataUpdate) {
|
||||
setBookMeta(editedMeta);
|
||||
setBookMeta({ ...editedMeta });
|
||||
handleBookMetadataUpdate(book, editedMeta);
|
||||
setEditMode(false);
|
||||
}
|
||||
|
||||
@@ -48,15 +48,7 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
<div className='relative w-full rounded-lg'>
|
||||
<div className='mb-6 me-4 flex h-32 items-start'>
|
||||
<div className='me-10 aspect-[28/41] h-32 shadow-lg'>
|
||||
<BookCover
|
||||
mode='list'
|
||||
book={{
|
||||
...book,
|
||||
...(metadata.coverImageUrl || metadata.coverImageBlobUrl
|
||||
? { coverImageUrl: metadata.coverImageUrl || metadata.coverImageBlobUrl }
|
||||
: {}),
|
||||
}}
|
||||
/>
|
||||
<BookCover mode='list' book={book} />
|
||||
</div>
|
||||
<div className='title-author flex h-32 flex-col justify-between'>
|
||||
<div>
|
||||
|
||||
@@ -39,7 +39,6 @@ export const useMetadataEdit = (metadata: BookMetadata | null) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (metadata) {
|
||||
console.log('initial metadata:', metadata);
|
||||
setEditedMeta({ ...metadata });
|
||||
}
|
||||
}, [metadata]);
|
||||
|
||||
@@ -75,6 +75,8 @@ export type BookMetadata = {
|
||||
series?: string;
|
||||
seriesIndex?: number;
|
||||
seriesTotal?: number;
|
||||
|
||||
coverImageFile?: string;
|
||||
coverImageUrl?: string;
|
||||
coverImageBlobUrl?: string;
|
||||
};
|
||||
|
||||
@@ -539,26 +539,36 @@ export abstract class BaseAppService implements AppService {
|
||||
await this.fs.writeFile(getLibraryFilename(), 'Books', JSON.stringify(libraryBooks));
|
||||
}
|
||||
|
||||
private imageToArrayBuffer(imageUrl: string): Promise<ArrayBuffer> {
|
||||
private imageToArrayBuffer(imageUrl?: string, imageFile?: string): Promise<ArrayBuffer> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (imageUrl.startsWith('blob:')) {
|
||||
if (!imageUrl && !imageFile) {
|
||||
reject(new Error('No image URL or file provided'));
|
||||
return;
|
||||
}
|
||||
if (this.appPlatform === 'web' && imageUrl && imageUrl.startsWith('blob:')) {
|
||||
fetch(imageUrl)
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then((buffer) => resolve(buffer))
|
||||
.catch((error) => reject(error));
|
||||
} else if (this.appPlatform === 'web') {
|
||||
reject(new Error('Skip non-blob URL'));
|
||||
} else if (this.appPlatform === 'tauri') {
|
||||
} else if (this.appPlatform === 'tauri' && imageFile) {
|
||||
this.fs
|
||||
.openFile(imageFile, 'None')
|
||||
.then((file) => file.arrayBuffer())
|
||||
.then((buffer) => resolve(buffer))
|
||||
.catch((error) => reject(error));
|
||||
} else if (this.appPlatform === 'tauri' && imageUrl) {
|
||||
tauriFetch(imageUrl, { method: 'GET' })
|
||||
.then((response) => response.arrayBuffer())
|
||||
.then((buffer) => resolve(buffer))
|
||||
.catch((error) => reject(error));
|
||||
} else {
|
||||
reject(new Error('Unsupported platform or missing image data'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async updateCoverImage(book: Book, imageUrl: string): Promise<void> {
|
||||
const arrayBuffer = await this.imageToArrayBuffer(imageUrl);
|
||||
async updateCoverImage(book: Book, imageUrl?: string, imageFile?: string): Promise<void> {
|
||||
const arrayBuffer = await this.imageToArrayBuffer(imageUrl, imageFile);
|
||||
await this.fs.writeFile(getCoverFilename(book), 'Books', arrayBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ export const FILE_ACCEPT_FORMATS = SUPPORTED_FILE_EXTS.map((ext) => `.${ext}`).j
|
||||
export const BOOK_UNGROUPED_NAME = '';
|
||||
export const BOOK_UNGROUPED_ID = '';
|
||||
|
||||
export const SUPPORTED_IMAGE_EXTS = ['png', 'jpg', 'jpeg'];
|
||||
export const IMAGE_ACCEPT_FORMATS = SUPPORTED_IMAGE_EXTS.map((ext) => `.${ext}`).join(', ');
|
||||
|
||||
export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
|
||||
keepLogin: false,
|
||||
autoUpload: true,
|
||||
|
||||
@@ -71,5 +71,5 @@ export interface AppService {
|
||||
getCoverImageUrl(book: Book): string;
|
||||
getCoverImageBlobUrl(book: Book): Promise<string>;
|
||||
generateCoverImageUrl(book: Book): Promise<string>;
|
||||
updateCoverImage(book: Book, imageUrl: string): Promise<void>;
|
||||
updateCoverImage(book: Book, imageUrl?: string, imageFile?: string): Promise<void>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user