Video Seek Functionality Not Working with Upload Field #11152
Replies: 4 comments
-
Hi @peterkunsay - thanks for opening this issue and providing a reproduction! Can you explain what you mean by
|
Beta Was this translation helpful? Give feedback.
-
Hello @JessChowdhury, thanks for the reply! By "serialize it in some way," I meant using the video from the Upload Field via the payload-provided URL at the frontend. Here's what I did:
and
Please note that the issue is not related to serialization. Even if we copy the video URL and use it directly inside the source tag of the video element like: I suspect there is an issue with the upload mechanism itself. Probably releated to metadata? Video demonstrating the issue: Desktop.2025.02.12.-.20.02.48.03.mp4 |
Beta Was this translation helpful? Give feedback.
-
Thanks @peterkunsay for your detailed reply - I completely see what you are describing now. At the moment, Payload uses I'm going to convert this to a feature request for now so we can plan it in accordingly. Thanks again for raising this! |
Beta Was this translation helpful? Give feedback.
-
@peterkunsay I've got a Payload app that relies on "streaming" of video files and have had similar issues. I ended up writing a custom Next endpoint to grab the file from the upload directory and send a streaming response to the client. I've got the following in a import { getSession } from "@/src/common/core/get-session";
import fs from "fs";
import { readFile } from "fs/promises";
import mime from "mime-types";
import { notFound } from "next/navigation";
type Args = {
params: Promise<{
filename?: string
}>
}
export async function GET(
request: Request,
{ params }: Args
) {
const { filename } = await params;
if (!filename) notFound();
const nextAuthSession = await getSession();
if (!nextAuthSession) {
return new Response("Unauthorized", { status: 401 });
}
const uploadDir = process.env.PAYLOAD_UPLOADS_DIR || "./public";
const filePath = `${uploadDir}/${filename}`;
if (!fs.existsSync(filePath)) {
return new Response("File not found", { status: 404 });
}
const bytes = await readFile(filePath);
const mimeType = mime.lookup(filePath) || "application/octet-stream";
// if it's a video, and the client has requested a range, return a partial response
const range = request.headers.get("range");
if (range && mimeType.startsWith("video")) {
// Validate range header format
const parts = range.replace(/bytes=/, "").split("-");
if (parts.length !== 2) {
return new Response("Invalid range header", { status: 400 });
}
const [start, end] = parts;
const fileSize = bytes.length;
// Convert and validate start position
const nStart = Number(start);
if (isNaN(nStart) || nStart < 0 || nStart >= fileSize) {
return new Response("Invalid range", { status: 416 });
}
// Convert and validate end position
let nEnd = end ? Number(end) : Math.min(nStart + (10 ** 6), fileSize - 1);
if (isNaN(nEnd) || nEnd >= fileSize) {
nEnd = fileSize - 1;
}
// Ensure start is before end
if (nStart > nEnd) {
return new Response("Invalid range", { status: 416 });
}
const chunksize = (nEnd - nStart) + 1;
return new Response(bytes.slice(nStart, nEnd + 1), {
status: 206,
headers: {
"Content-Range": `bytes ${nStart}-${nEnd}/${fileSize}`,
"Accept-Ranges": "bytes",
"Content-Length": chunksize.toString(),
"Content-Type": mimeType,
},
});
}
return new Response(bytes, {
headers: {
"Content-Type": mimeType,
"Accept-Ranges": "bytes",
"Content-Length": bytes.byteLength.toString()
},
});
} I've got an added auth layer in this code that you can either remove or swap out. |
Beta Was this translation helpful? Give feedback.
-
Describe the Bug
Hello,
First of all, thank you for Payload 3. It's a very nice update!
Unfortunately, I encountered a bug with the Upload Field when using it for videos. When a video is serialized (e.g., inside rich text via custom converter), the video is displayed correctly on the website; however, the seek functionality is broken. Whenever you try to jump to a different timestamp in the video, it always jumps back to the current playback location. This occurs with the vanilla video player, and I also experienced the same issue with next-video.
I suspect there might be an issue with the upload itself, possibly related to metadata?
This issue has already been discussed on Payload's Discord:
https://discord.com/channels/967097582721572934/1302281442465939477
The reproduction repo I included clearly demonstrates the issue.
Keep up the good work!
Link to the code that reproduces this issue
https://github.com/peterkunsay/payload-video-upload-seek-bug-reproduction/tree/main
Reproduction Steps
Which area(s) are affected? (Select all that apply)
plugin: richtext-lexical, plugin: other
Environment Info
Beta Was this translation helpful? Give feedback.
All reactions