Skip to content

[Feature Request] Implement Range Requests for <video> / <audio> #19

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bogeychan opened this issue Nov 10, 2023 · 6 comments · May be fixed by #31
Closed

[Feature Request] Implement Range Requests for <video> / <audio> #19

bogeychan opened this issue Nov 10, 2023 · 6 comments · May be fixed by #31

Comments

@bogeychan
Copy link
Collaborator

bogeychan commented Nov 10, 2023

Due to the current implementation, the frontend must download the entire file, which in turn prevents buffering ("the frontend has to download the whole file first") in the video / audio control:

new Response(Bun.file(file), {

Bun supports Streaming files:

You can send part of a file using the slice(start, end) method on the Bun.file object. This automatically sets the Content-Range and Content-Length headers on the Response object.

However this behavior doesn't allow seeking ("jumping to a timestamp") because the actual size is not set in the Content-Range header:

  • Bun: bytes 0-10/*
  • Required: bytes 0-10/20

manually setting the header works but it ends up twice in the response (with [email protected] - due to slice(start, end))

new Response(Bun.file(filename).slice(start, end), {
  status: 206,
  headers: {
    'Content-Range': `bytes ${start}-${end - 1}/${size}`
  }
});

HTTP range requests

@libersoft-org
Copy link

Is this Elysia or Bun bug?

@libersoft-org
Copy link

I've just found a walkaround:

 async getDownload(req) {
  if (!req.params.hash || !req.params.name) return this.getIndex(req);
  const file = Bun.file(path.join(Common.settings.storage.download, req.params.hash));
  if (!await file.exists()) return this.getIndex(req);
  if (req.headers.range) {
   const chunk = Common.settings.storage.chunk_download;
   let [start = 0, end = Infinity] = req.headers.range.split('=').at(-1).split('-').map(Number);
   if (end == 0) end = start + chunk < file.size ? start + chunk : file.size;
   return new Response(file.slice(start, start + chunk), {
    status: 206,
    headers: { 'Content-Range': 'bytes ' + start + '-' + end + '/' + file.size }
   });
  } else {
   return new Response(file, {
    headers: {
     'Content-Type': 'application/octet-stream',
     'Content-Disposition': 'attachment; filename="' + req.params.name + '"'
    }
   });
  }

@libersoft-org
Copy link

I've just found a walkaround:

 async getDownload(req) {
  if (!req.params.hash || !req.params.name) return this.getIndex(req);
  const file = Bun.file(path.join(Common.settings.storage.download, req.params.hash));
  if (!await file.exists()) return this.getIndex(req);
  if (req.headers.range) {
   const chunk = Common.settings.storage.chunk_download;
   let [start = 0, end = Infinity] = req.headers.range.split('=').at(-1).split('-').map(Number);
   if (end == 0) end = start + chunk < file.size ? start + chunk : file.size;
   return new Response(file.slice(start, start + chunk), {
    status: 206,
    headers: { 'Content-Range': 'bytes ' + start + '-' + end + '/' + file.size }
   });
  } else {
   return new Response(file, {
    headers: {
     'Content-Type': 'application/octet-stream',
     'Content-Disposition': 'attachment; filename="' + req.params.name + '"'
    }
   });
  }

Hmm, this walkaround seems to be working in Firefox only, not in Chrome. The problem is that the header range is present twice :(

@bogeychan
Copy link
Collaborator Author

blocked by oven-sh/bun#7051

@hckhanh
Copy link

hckhanh commented Jan 30, 2024

oven-sh/bun#7051 is closed

@SaltyAom
Copy link
Member

Should have been fixed by 4ba3e85 published under 0.8.0.

Feel free to reopen the issue if the problem still persists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants