aws-sdk getSignedUrl for videos in Safari or IOS does not work

Viewed 581

My issue is that Safari (and it seems like all browsers on IOS) does not show a video when i pipe the response to the frontend. The videos are however shown on Android and win/linux Desktops on all browsers.

Note, i believe the videos were shown previously in IOS and Safari, this could have been a recent bug or new change to IOS/Safari policy?

My backend looks something like:

...
const aws = require('aws-sdk');

aws.config.update({
  accessKeyId: process.env.ACCESS,
  secretAccessKey: process.env.SECRET,
  region: process.env.S3_REGION
});

const s3 = new aws.S3();

function getS3Url(filename) {
  var params = { Bucket: process.env.BUCKET, Key: filename };
  return new Promise((resolve, reject) => {
    if (filename) {
      s3.getSignedUrl('getObject', params, function(err, url) {
        if (err) {
          reject(err.message ? err.message : err);
        }
        resolve(url);
      });
    } else {
      resolve('/none.png');
    }
  });
}

// Return file
router.get('/file/:filename', (req, res) => {
  const { filename = '' } = req.params;

  getS3Url(filename).then((url) => {
    request(url).pipe(res);
  }).catch((err) => {
    return res.status(codeToInt(err.code, 404)).send(err.message ? err.message : err);
  });
});

I also save the mediaType "video/mp4" which is used in the source tag. The resulting file-url in my frontend will be something like: src="www.myhost.com/api/file/123" type="video/mp4"

The media before beeing uploaded to S3 can be viewed in Safari, so it must be the way I pipe the response with getSignedUrl?

1 Answers

Good solution

The solution was to add Cloudfront to AWS. I did not need to implement my own streaming service, instead i returned the signed urls to the frontend, which also solves another issue i had with using my server as a middleman when sending images/videos


"Almost" solution

My issue seems to be that IOS/Safari only supports streamed videos

I implemented a streaming response if the client is IOS/Safari:

function getS3StreamUrl(filename) {
  var params = { Bucket: process.env.AWS_BUCKET, Key: filename };
  return s3.getObject(params).createReadStream();
}

const isAnnoyingClient = isIOS || isSafari;

if (isAnnoyingClient) {
  getS3StreamUrl(filename).pipe(res);
} else {
  getS3Url(filename).then((url) => {
    request(url).pipe(res);
  }).catch((err) => {
    return res.status(codeToInt(err.code, 404)).send(err.message ? err.message : err);
  });
}

But now, my new issue is that videos in IOS/Safari will not loop, they will only play once..

Related