forked from akai/readest
fix: bot-review robustness fixes (TTS sync, updater, nightly, a11y) (#4659)
Cherry-picked and re-verified the applicable subset of julianshen/readest@fa1b74a0 (its "address PR #15 bot reviews" commit). The fork-only AI-annotation-tool change was dropped — readest has no 'ai' toolbar tool. Each logic fix is covered by a failing-first test. - TTS position sequence is now an app-wide monotonic counter, so a fresh TTSController (constructed per `tts-speak`) isn't dropped by consumers holding `lastSequenceSeen` from a prior session. - share.ts only swallows AbortError (user cancel); other failures — e.g. NotAllowedError when a quick action fires without a user gesture — fall back to the clipboard so the text still reaches the user. - document.isTxt tolerates MIME params (text/plain;charset=utf-8), uppercase extensions (BOOK.TXT), and a nameless Blob, so a TXT can't slip onto the non-text path and yield a null book. - updater getNightlyPlatformKey matches x86_64/aarch64 explicitly; a 32-bit or otherwise unknown arch yields no nightly instead of mis-routing to aarch64. - UpdaterWindow downloadWithProgress resolves on tauriDownload completion even when Content-Length is absent (no more hang on portable/AppImage/Android). - nightly_update.rs uses async tokio::fs::read in the async command. - nightly.yml: serialize runs via a concurrency group (no cancel) and persist-credentials:false on checkouts. - edge TTS route only emits the word-boundary header when it fits under ~8KB; oversized values get dropped by proxies, and the client falls back to []. - RSVPOverlay drops the contradictory aria-disabled on the functional rate button (it opens the pace picker). - nightly verify harness handles artifact stream errors instead of crashing. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -186,40 +186,33 @@ export const UpdaterContent = ({
|
||||
} as GenericUpdate);
|
||||
}
|
||||
};
|
||||
const downloadWithProgress = (
|
||||
const downloadWithProgress = async (
|
||||
downloadUrl: string,
|
||||
filePath: string,
|
||||
onEvent?: (progress: DownloadEvent) => void,
|
||||
): Promise<void> => {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
let downloaded = 0;
|
||||
let total = 0;
|
||||
await tauriDownload(downloadUrl, filePath, (progress) => {
|
||||
if (!onEvent) return;
|
||||
if (!total && progress.total) {
|
||||
total = progress.total;
|
||||
onEvent({
|
||||
event: 'Started',
|
||||
data: { contentLength: total },
|
||||
});
|
||||
} else if (downloaded > 0 && progress.progress === progress.total) {
|
||||
console.log('File downloaded to', filePath);
|
||||
onEvent?.({ event: 'Finished' });
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
onEvent({
|
||||
event: 'Progress',
|
||||
data: { chunkLength: progress.progress - downloaded },
|
||||
});
|
||||
downloaded = progress.progress;
|
||||
}).catch((error) => {
|
||||
console.error('Download failed:', error);
|
||||
reject(error);
|
||||
});
|
||||
let downloaded = 0;
|
||||
let total = 0;
|
||||
let finished = false;
|
||||
// Resolve when tauriDownload itself completes — NOT only when a progress
|
||||
// tick reports progress === total. Servers that omit Content-Length leave
|
||||
// total at 0, so that tick never fires and the await would hang forever
|
||||
// after the file is fully written (nightly portable/AppImage/Android).
|
||||
await tauriDownload(downloadUrl, filePath, (progress) => {
|
||||
if (!onEvent) return;
|
||||
if (!total && progress.total) {
|
||||
total = progress.total;
|
||||
onEvent({ event: 'Started', data: { contentLength: total } });
|
||||
}
|
||||
onEvent({ event: 'Progress', data: { chunkLength: progress.progress - downloaded } });
|
||||
downloaded = progress.progress;
|
||||
if (progress.total && progress.progress === progress.total && !finished) {
|
||||
finished = true;
|
||||
onEvent({ event: 'Finished' });
|
||||
}
|
||||
});
|
||||
console.log('File downloaded to', filePath);
|
||||
if (onEvent && !finished) onEvent({ event: 'Finished' });
|
||||
};
|
||||
const checkWindowsPortableUpdate = async () => {
|
||||
if (!appService) return;
|
||||
|
||||
Reference in New Issue
Block a user