Download static/reader/core/reader-document-loader.mjs from VoiceOfML/Search: direct link, hf CLI and curl.
- Browser
- Download file 6.53 kB
-
https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/static/reader/core/reader-document-loader.mjs
- Command line
-
hf download hf://spaces/VoiceOfML/Search/static/reader/core/reader-document-loader.mjs
-
curl -L -o reader-document-loader.mjs https://huggingface.co/spaces/VoiceOfML/Search/resolve/main/static/reader/core/reader-document-loader.mjs
6.53 kB
| export function createReaderDocumentLoader(readerContext) { | |
| function loadScript(url) { | |
| readerContext.assertReaderActive(); | |
| return new Promise((resolve, reject) => { | |
| const script = document.createElement("script"); | |
| let settled = false, timeout = 0, untrack = () => {}; | |
| const finish = (error) => { | |
| if (settled) return; | |
| settled = true; | |
| clearTimeout(timeout); | |
| untrack(); | |
| script.onload = script.onerror = null; | |
| if (error) { | |
| script.remove(); | |
| reject(error); | |
| } else resolve(); | |
| }; | |
| const networkError = () => Object.assign( | |
| new Error("阅读组件下载失败,请检查网络后重试加载,或下载原文件。"), | |
| { code: "READER_ENGINE_NETWORK" } | |
| ); | |
| untrack = readerContext.trackReaderResource(() => finish(readerContext.readerAbortError())); | |
| // Download sibling engines concurrently, execute in dependency order. | |
| script.async = false; | |
| script.src = url; | |
| script.onload = () => finish(); | |
| script.onerror = () => finish(networkError()); | |
| timeout = setTimeout(() => finish(networkError()), 20000); | |
| document.head.appendChild(script); | |
| }); | |
| } | |
| function fetchWithReaderTimeout(url, timeoutMs = readerContext.READER_PROXY_TIMEOUT_MS, requestInit = {}) { | |
| return readerContext.readerRequestManager.request(url, timeoutMs, requestInit); | |
| } | |
| function retryableReaderProxyError(error) { | |
| return [408, 429, 500, 502, 503, 504].includes(error?.status) || | |
| ["TypeError", "TimeoutError"].includes(error?.name) || | |
| /failed to fetch|network|timeout|HTTP\s*(?:408|429|5\d\d)|server response\s*\((?:408|429|5\d\d)\)/i.test(error?.message || ""); | |
| } | |
| async function retryReaderProxy(open) { | |
| for (let attempt = 0; ; attempt++) { | |
| readerContext.assertReaderActive(); | |
| try { | |
| return await open(); | |
| } catch (error) { | |
| if (attempt >= 2 || !readerContext.retryableReaderProxyError(error)) throw error; | |
| await readerContext.waitForReader(350 * (attempt + 1)); | |
| } | |
| } | |
| } | |
| function fetchReaderUrl(rawUrl, requestInit = {}) { | |
| if (String(rawUrl).includes("/api/reader-bucket-resource?")) | |
| return readerContext.fetchWithReaderTimeout(rawUrl, readerContext.READER_PROXY_TIMEOUT_MS, requestInit); | |
| const proxyUrl = readerContext.readerContentUrl(rawUrl); | |
| return readerContext.retryReaderProxy(async () => { | |
| const response = await readerContext.fetchWithReaderTimeout(proxyUrl, readerContext.READER_PROXY_TIMEOUT_MS, requestInit); | |
| if (response.ok) return response; | |
| await response.body?.cancel(); | |
| throw Object.assign(new Error(`HTTP ${response.status}`), { status: response.status }); | |
| }).catch((error) => { | |
| readerContext.assertReaderActive(); | |
| requestInit.signal?.throwIfAborted(); | |
| if (readerContext.retryableReaderProxyError(error)) throw error; | |
| return readerContext.fetchWithReaderTimeout(rawUrl, readerContext.READER_PROXY_TIMEOUT_MS, requestInit); | |
| }); | |
| } | |
| function fetchReaderResponse() { | |
| const early = window.__VOICE_PDF_PRELOAD__; | |
| if (early?.manifest && early.manifestUrl === new URL(readerContext.sourceUrl, location.href).href) { | |
| const pending = early.manifest; | |
| early.manifest = null; | |
| return pending.then( | |
| (response) => (response?.ok ? response : readerContext.fetchReaderUrl(readerContext.sourceUrl)), | |
| () => readerContext.fetchReaderUrl(readerContext.sourceUrl) | |
| ); | |
| } | |
| return readerContext.fetchReaderUrl(readerContext.sourceUrl); | |
| } | |
| function prepareReaderDocument(engineTasks) { | |
| const engines = Promise.all(engineTasks); | |
| const response = Promise.race([readerContext.fetchReaderResponse(), engines.then(() => new Promise(() => {}))]); | |
| // Rendering owns both promises; early rejection must not become unhandled. | |
| response.catch(() => {}); | |
| engines.catch(() => {}); | |
| return {response, engines}; | |
| } | |
| function readPreparedBytes(response, engines, limit = VoiceOfMLReaderSecurity.LIMITS.documentBytes) { | |
| return Promise.all([Promise.resolve(response).then(response => { | |
| if (!response.ok) throw new Error(`HTTP ${response.status}`); | |
| return VoiceOfMLReaderSecurity.readBytes(response,limit); | |
| }), engines]).then(([bytes]) => bytes); | |
| } | |
| function loadTextDocument() { | |
| return readerContext.fetchReaderResponse().then((response) => ({ response })); | |
| } | |
| function loadMarkdownDocument() { | |
| return readerContext.prepareReaderDocument([readerContext.loadScript(readerContext.MARKED_URL), readerContext.loadScript(readerContext.PURIFY_URL)]); | |
| } | |
| function loadHtmlDocument() { | |
| const {response, engines} = readerContext.prepareReaderDocument([readerContext.loadScript(readerContext.PURIFY_URL)]); | |
| return {response, engine:engines}; | |
| } | |
| function loadMediaDocument() { | |
| return Promise.resolve(null); | |
| } | |
| async function loadImageDocument(target = readerContext.sourceUrl) { | |
| const deadline = performance.now() + readerContext.READER_PROXY_TIMEOUT_MS; | |
| const image = new Image(); | |
| image.className = "reader-image"; | |
| image.alt = readerContext.documentState.title; | |
| image.decoding = "async"; | |
| try { | |
| return await readerContext.imageLoader.load(image, readerContext.readerContentUrl(target), readerContext.readerAbortController.signal, deadline); | |
| } catch (error) { | |
| readerContext.assertReaderActive(); | |
| if (error?.code === "READER_RESOURCE_LIMIT") throw error; | |
| return readerContext.imageLoader.load(image, target, readerContext.readerAbortController.signal, deadline); | |
| } | |
| } | |
| function loadChapterManifestDocument() { | |
| const target = readerContext.chapterManifestUrl || readerContext.sourceUrl, early = window.__VOICE_READER_CHAPTER_PRELOAD__; | |
| if (early?.manifest && early.manifestUrl === new URL(target, location.href).href) { | |
| const pending = early.manifest; | |
| early.manifest = null; | |
| return pending.then(response => response.ok ? response : readerContext.fetchReaderUrl(target), () => readerContext.fetchReaderUrl(target)); | |
| } | |
| return readerContext.fetchReaderUrl(target); | |
| } | |
| return { | |
| loadScript, | |
| fetchWithReaderTimeout, | |
| retryableReaderProxyError, | |
| retryReaderProxy, | |
| fetchReaderUrl, | |
| fetchReaderResponse, | |
| prepareReaderDocument, | |
| readPreparedBytes, | |
| loadTextDocument, | |
| loadMarkdownDocument, | |
| loadHtmlDocument, | |
| loadMediaDocument, | |
| loadImageDocument, | |
| loadChapterManifestDocument | |
| }; | |
| } | |