1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-07-06 23:56:13 +02:00

Windows: Fix PDF, video, and audio rendering (#10881)

This commit is contained in:
Henry Heino
2024-08-17 04:22:03 -07:00
committed by GitHub
parent b94cf5a107
commit eb53c7e3b9
12 changed files with 220 additions and 18 deletions

View File

@ -6,7 +6,6 @@ import resolvePathWithinDir from '@joplin/lib/utils/resolvePathWithinDir';
import { LoggerWrapper } from '@joplin/utils/Logger';
import * as fs from 'fs-extra';
import { createReadStream } from 'fs';
import { Readable } from 'stream';
import { fromFilename } from '@joplin/lib/mime-utils';
export interface CustomProtocolHandler {
@ -14,6 +13,62 @@ export interface CustomProtocolHandler {
allowReadAccessToFile(path: string): { remove(): void };
}
// In some cases, the NodeJS built-in adapter (Readable.toWeb) closes its controller twice,
// leading to an error dialog. See:
// - https://github.com/nodejs/node/blob/e578c0b1e8d3dd817e692a0c5df1b97580bc7c7f/lib/internal/webstreams/adapters.js#L454
// - https://github.com/nodejs/node/issues/54205
// We work around this by creating a more-error-tolerant custom adapter.
const nodeStreamToWeb = (resultStream: fs.ReadStream) => {
resultStream.pause();
let closed = false;
return new ReadableStream({
start: (controller) => {
resultStream.on('data', (chunk) => {
if (closed) {
return;
}
if (Buffer.isBuffer(chunk)) {
controller.enqueue(new Uint8Array(chunk));
} else {
controller.enqueue(chunk);
}
if (controller.desiredSize <= 0) {
resultStream.pause();
}
});
resultStream.on('error', (error) => {
controller.error(error);
});
resultStream.on('end', () => {
if (!closed) {
closed = true;
controller.close();
}
});
},
pull: (_controller) => {
if (closed) {
return;
}
resultStream.resume();
},
cancel: () => {
if (!closed) {
closed = true;
resultStream.close();
}
},
}, { highWaterMark: resultStream.readableHighWaterMark });
};
// Allows seeking videos.
// See https://github.com/electron/electron/issues/38749 for why this is necessary.
const handleRangeRequest = async (request: Request, targetPath: string) => {
@ -42,7 +97,7 @@ const handleRangeRequest = async (request: Request, targetPath: string) => {
}
// Note: end is inclusive.
const resultStream = Readable.toWeb(createReadStream(targetPath, { start: startByte, end: endByte }));
const resultStream = createReadStream(targetPath, { start: startByte, end: endByte });
// See the HTTP range requests guide: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
const headers = new Headers([
@ -52,10 +107,9 @@ const handleRangeRequest = async (request: Request, targetPath: string) => {
['Content-Range', `bytes ${startByte}-${endByte}/${stat.size}`],
]);
return new Response(
// This cast is necessary -- .toWeb produces a different type
// from the global ReadableStream.
resultStream as ReadableStream,
nodeStreamToWeb(resultStream),
{ headers, status: 206 },
);
};