fix: resolve various tracked exceptions in ph (#3584)
* fix: handle synced bookmarks without cfi * chore: clean up some exceptions in ph
This commit is contained in:
@@ -3,7 +3,7 @@ PDFJS_FONTS_PATH=../../packages/foliate-js/node_modules/pdfjs-dist
|
||||
PDFJS_STYLE_PATH=../../packages/foliate-js/vendor/pdfjs
|
||||
|
||||
NEXT_PUBLIC_DEFAULT_POSTHOG_URL_BASE64="aHR0cHM6Ly91cy5pLnBvc3Rob2cuY29t"
|
||||
NEXT_PUBLIC_DEFAULT_POSTHOG_KEY_BASE64="cGhjX2ViNXowbVRxWm8yZm5YYnZGNmE3bFh5TThpTmRSNTNsR1A3VFM3VGh4S08="
|
||||
NEXT_PUBLIC_DEFAULT_POSTHOG_KEY_BASE64="cGhjX0x3ekhZRWtsZUVub3ZSc05ZQlRpTVRTV2MyS1NUOFdZMzBIWWFhN0ZPa1IK"
|
||||
|
||||
NEXT_PUBLIC_DEFAULT_SUPABASE_URL_BASE64="aHR0cHM6Ly9yZWFkZXN0LnN1cGFiYXNlLmNv"
|
||||
NEXT_PUBLIC_DEFAULT_SUPABASE_KEY_BASE64="ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKemRYQmhZbUZ6WlNJc0luSmxaaUk2SW5aaWMzbDRablZ6YW1weFpIaHJhbkZzZVhOaklpd2ljbTlzWlNJNkltRnViMjRpTENKcFlYUWlPakUzTXpReE1qTTJOekVzSW1WNGNDSTZNakEwT1RZNU9UWTNNWDAuM1U1VXFhb3VfMVNnclZlMWVvOXJBcGMwdUtqcWhwUWRVWGh2d1VIbVVmZw=="
|
||||
|
||||
@@ -18,6 +18,12 @@ describe('isCfiInLocation', () => {
|
||||
expect(isCfiInLocation('epubcfi(/6/6)', null)).toBe(false);
|
||||
expect(isCfiInLocation('epubcfi(/6/6)', undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for null/undefined/empty cfi', () => {
|
||||
expect(isCfiInLocation(null as unknown as string, 'epubcfi(/6/6)')).toBe(false);
|
||||
expect(isCfiInLocation(undefined as unknown as string, 'epubcfi(/6/6)')).toBe(false);
|
||||
expect(isCfiInLocation('', 'epubcfi(/6/6)')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findNearestCfi', () => {
|
||||
|
||||
@@ -264,7 +264,13 @@ const FoliateViewer: React.FC<{
|
||||
item.style &&
|
||||
getIndexFromCfi(item.cfi) === sectionIndex,
|
||||
)
|
||||
.forEach((annotation) => viewRef.current?.addAnnotation(annotation));
|
||||
.map((annotation) => {
|
||||
try {
|
||||
viewRef.current?.addAnnotation(annotation);
|
||||
} catch (err) {
|
||||
console.warn('Failed to add annotation', { annotation, error: err });
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
|
||||
if (!detail.doc.isEventListenersAdded) {
|
||||
|
||||
@@ -54,10 +54,9 @@ const ProgressBar: React.FC<ProgressBarProps> = ({
|
||||
const progressInfo = formatProgress(pageInfo?.current, pageInfo?.total, template, localize, lang);
|
||||
|
||||
const { page: current = 0, pages: total = 0 } = view?.renderer || {};
|
||||
const pagesLeft = Math.min(
|
||||
Math.max(total - current, 1),
|
||||
pageInfo ? pageInfo.total - pageInfo.current : total,
|
||||
);
|
||||
const pagesLeft = bookData?.isFixedLayout
|
||||
? 1
|
||||
: Math.min(Math.max(total - current, 1), pageInfo ? pageInfo.total - pageInfo.current : total);
|
||||
const showPagesLeft = total > 0 || bookData?.isFixedLayout;
|
||||
const timeLeftStr = showPagesLeft
|
||||
? _('{{time}} min left in chapter', {
|
||||
|
||||
@@ -333,7 +333,11 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
getIndexFromCfi(booknote.cfi) === detail.index,
|
||||
)
|
||||
.map((annotation) => {
|
||||
view?.addAnnotation(annotation);
|
||||
try {
|
||||
view?.addAnnotation(annotation);
|
||||
} catch (err) {
|
||||
console.warn('Failed to add annotation', { annotation, error: err });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ export const useProgressAutoSave = (bookKey: string) => {
|
||||
const saveBookConfig = useCallback(
|
||||
debounce(() => {
|
||||
setTimeout(async () => {
|
||||
const config = getConfig(bookKey)!;
|
||||
const config = getConfig(bookKey);
|
||||
if (!config) return;
|
||||
const settings = useSettingsStore.getState().settings;
|
||||
await saveConfig(envConfig, bookKey, config, settings);
|
||||
}, 500);
|
||||
|
||||
@@ -23,6 +23,7 @@ if (typeof window !== 'undefined' && process.env['NODE_ENV'] === 'production' &&
|
||||
posthog.init(posthogKey, {
|
||||
api_host: posthogUrl,
|
||||
person_profiles: 'always',
|
||||
autocapture: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
|
||||
openLastBooks: false,
|
||||
lastOpenBooks: [],
|
||||
autoImportBooksOnOpen: false,
|
||||
telemetryEnabled: false,
|
||||
telemetryEnabled: true,
|
||||
discordRichPresenceEnabled: false,
|
||||
libraryViewMode: 'grid',
|
||||
librarySortBy: LibrarySortByType.Updated,
|
||||
|
||||
@@ -181,7 +181,7 @@ export class NativeTTSClient implements TTSClient {
|
||||
const { marks } = parseSSMLMarks(ssml, this.#primaryLang);
|
||||
|
||||
for (const mark of marks) {
|
||||
this.controller?.dispatchSpeakMark(mark);
|
||||
if (!preload) this.controller?.dispatchSpeakMark(mark);
|
||||
for await (const ev of this.speakMark(mark, preload, signal)) {
|
||||
if (signal.aborted) {
|
||||
yield { code: 'error', message: 'Aborted' } as TTSMessageEvent;
|
||||
|
||||
@@ -32,7 +32,7 @@ export class TTSController extends EventTarget {
|
||||
#nossmlCnt: number = 0;
|
||||
#currentSpeakAbortController: AbortController | null = null;
|
||||
#currentSpeakPromise: Promise<void> | null = null;
|
||||
#isPreloading: boolean = false;
|
||||
|
||||
#ttsSectionIndex: number = -1;
|
||||
|
||||
state: TTSState = 'stopped';
|
||||
@@ -261,7 +261,6 @@ export class TTSController extends EventTarget {
|
||||
const tts = this.view.tts;
|
||||
if (!tts) return;
|
||||
|
||||
this.#isPreloading = true;
|
||||
const ssmls: string[] = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
const ssml = await this.#preprocessSSML(tts.next());
|
||||
@@ -271,7 +270,6 @@ export class TTSController extends EventTarget {
|
||||
for (let i = 0; i < ssmls.length; i++) {
|
||||
tts.prev();
|
||||
}
|
||||
this.#isPreloading = false;
|
||||
await Promise.all(ssmls.map((ssml) => this.preloadSSML(ssml, new AbortController().signal)));
|
||||
}
|
||||
|
||||
@@ -533,15 +531,11 @@ export class TTSController extends EventTarget {
|
||||
dispatchSpeakMark(mark?: TTSMark) {
|
||||
this.dispatchEvent(new CustomEvent('tts-speak-mark', { detail: mark || { text: '' } }));
|
||||
if (mark && mark.name !== '-1') {
|
||||
if (this.#isPreloading) {
|
||||
setTimeout(() => this.dispatchSpeakMark(mark), 500);
|
||||
} else {
|
||||
try {
|
||||
const range = this.view.tts?.setMark(mark.name);
|
||||
try {
|
||||
const cfi = this.view.getCFI(this.#ttsSectionIndex, range);
|
||||
this.dispatchEvent(new CustomEvent('tts-highlight-mark', { detail: { cfi } }));
|
||||
} catch {}
|
||||
}
|
||||
const cfi = this.view.getCFI(this.#ttsSectionIndex, range);
|
||||
this.dispatchEvent(new CustomEvent('tts-highlight-mark', { detail: { cfi } }));
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,6 +179,8 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
|
||||
}
|
||||
}
|
||||
}
|
||||
// Filter out invalid booknotes
|
||||
config.booknotes = config.booknotes?.filter((booknote) => booknote.cfi) ?? [];
|
||||
await updateToc(
|
||||
bookDoc,
|
||||
config.viewSettings?.sortedTOC ?? false,
|
||||
|
||||
@@ -6,14 +6,19 @@ const unwrapCfi = (cfi: string): string => {
|
||||
};
|
||||
|
||||
export function isCfiInLocation(cfi: string, location: string | null | undefined): boolean {
|
||||
if (!location) return false;
|
||||
if (!cfi || !location) return false;
|
||||
if (cfi === location) return true;
|
||||
if (cfi && unwrapCfi(cfi).startsWith(unwrapCfi(location))) return true;
|
||||
|
||||
const start = CFI.collapse(location);
|
||||
const end = CFI.collapse(location, true);
|
||||
|
||||
return CFI.compare(cfi, start) >= 0 && CFI.compare(cfi, end) <= 0;
|
||||
try {
|
||||
return CFI.compare(cfi, start) >= 0 && CFI.compare(cfi, end) <= 0;
|
||||
} catch (err) {
|
||||
console.warn('Failed to compare CFIs', { cfi, location, error: err });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ export const findParentPath = (toc: TOCItem[], href: string): TOCItem[] => {
|
||||
};
|
||||
|
||||
export const findTocItemBS = (toc: TOCItem[], cfi: string): TOCItem | null => {
|
||||
if (!cfi) return null;
|
||||
let left = 0;
|
||||
let right = toc.length - 1;
|
||||
let result: TOCItem | null = null;
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: 57e35351b1...ae94dce261
Reference in New Issue
Block a user