fix(desktop): serve local hermes-media ranges so chat video can seek

Electron's file:// loader ignores Range, so long clips stay unseekable even
though media-range.ts already landed. Wire fetchLocal through that helper.
This commit is contained in:
xxxigm
2026-09-11 22:08:28 +07:00
committed by brooklyn!
parent 3b45681c25
commit 73a2597c81
2 changed files with 22 additions and 7 deletions

View File

@@ -262,6 +262,7 @@ import {
} from './managed-ssh-update'
import { registerMcpOauthCallbackIpc } from './mcp-oauth-callback-ipc'
import { createMediaProtocolHandler, MEDIA_PROTOCOL } from './media-protocol'
import { fetchLocalMedia } from './media-range'
import { createNativeAccessTokenCoordinator, NativeAuthChangedError } from './native-access-token'
import { oauthSessionIsLive, resolveJsonBody, resolveReadinessProbeAuth } from './native-auth-decisions'
import {
@@ -1366,13 +1367,10 @@ protocol.registerSchemesAsPrivileged([
function registerMediaProtocol() {
const handler = createMediaProtocolHandler({
ensureRemoteBearer: baseUrl => ensureNativeAccessToken(baseUrl),
fetchLocal: (resolvedPath, headers, method) =>
electronNet.fetch(pathToFileURL(resolvedPath).toString(), {
bypassCustomProtocolHandlers: true,
credentials: 'omit',
headers,
method
}),
// Answer local files ourselves: Electron's file:// loader ignores Range and
// returns the whole body as 200 without Accept-Ranges, which makes <video>
// unseekable (seekable=[0,0]).
fetchLocal: fetchLocalMedia,
fetchRemote: (url, headers, method) =>
electronNet.fetch(url, {
bypassCustomProtocolHandlers: true,

View File

@@ -174,3 +174,20 @@ export async function buildLocalMediaResponse(
return new Response(stream({ end: range.end, start: range.start }), { headers, status: 206 })
}
/**
* Production `fetchLocal` for `hermes-media://stream/…`.
*
* Electron's `file://` loader ignores `Range` and answers `200` with the whole body, so Chromium
* reports `video.seekable` as `[0, 0]`. Pass this into the media-protocol handler instead.
*/
export function fetchLocalMedia(
resolvedPath: string,
headers: Headers,
method: string
): Promise<Response> {
return buildLocalMediaResponse(resolvedPath, {
method,
rangeHeader: headers.get('range')
})
}