can't seek html5 video or audio in chrome can't seek html5 video or audio in chrome google-chrome google-chrome

can't seek html5 video or audio in chrome


I found the reason why it's not working on this question:

HTML5 video will not loop

Our server doesn't understand partial content right now. As a result chrome is sending requests for content that doesn't get answered which in turn makes our video's and audio unseekable (and unloopable).


You must handle req.headers['range'] which Chrome will send to your streaming server.

Please refer to my codes below. It worked well on Chrome, Firefox, Edge and IE. I haven't test it on Safari but hopefully it also can work.

I used Sails/Nodejs backend and gridFS/mongodb database for storing Videos files as Chunks.

try {        let foundMetaFile = await GridFS.findOne({id: fileId});        if (!foundMetaFile) return res.status(400).json(Res.error(undefined, {message: `invalid ${fileId} file`}));        let fileLength  = foundMetaFile['length'];        let contentType = foundMetaFile['contentType'];        // let chunkSize   = foundMetaFile['chunkSize'];        if(req.headers['range']) {            // Range request, partialle stream the file            console.log('Range Reuqest');            var parts = req.headers['range'].replace(/bytes=/, "").split("-");            var partialStart = parts[0];            var partialEnd = parts[1];            var start = parseInt(partialStart, 10);            var end = partialEnd ? parseInt(partialEnd, 10) : fileLength - 1;            var chunkSize = (end - start) + 1;            console.log('Range ', start, '-', end);            res.writeHead(206, {                'Content-Range': 'bytes ' + start + '-' + end + '/' + fileLength,                'Accept-Ranges': 'bytes',                'Content-Length': chunkSize,                'Content-Type': contentType            });        }        let { mongodbConnection } = global;        let bucket = new GridFSBucket(mongodbConnection, { bucketName: 'fs' });        return new Promise ((resolve, reject) => {            let downloadStream  = bucket.openDownloadStream(fileId);            downloadStream.on('error', (err) => {                console.log("Received Error stream")                res.end();                reject(err);            })            downloadStream.on('end', () => {                console.log("Received End stream");                res.end();                resolve(true);            })            console.log("start streaming");            downloadStream.pipe(res);        })    } catch (error) {        switch (error.name) {            case 'UsageError':                return res.status(400).json(Res.error(undefined, {message: 'invalid Input'}));            case 'AdapterError':                return res.status(400).json(Res.error(undefined, {message: 'adapter Error'}));            default:                return res.serverError(error);        }