Skip to content

Instantly share code, notes, and snippets.

@renalpha
Created August 19, 2023 13:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save renalpha/a4092c7fd205dfb13f84c70edb079663 to your computer and use it in GitHub Desktop.
Save renalpha/a4092c7fd205dfb13f84c70edb079663 to your computer and use it in GitHub Desktop.
Ionic Capacitor <video> remote URL IOS Android
<?php
return [
/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'paths' => ['api/*', 'sanctum/csrf-cookie', 'video/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => false,
'max_age' => false,
'supports_credentials' => false,
];
<video autoplay loop muted playsinline preload="metadata" webkit-playsinline="webkit-playsinline">
<source src="https://yoururl.test/video/smallerbg-te.mp4" type="video/mp4"/>
</video>
Route::get('/video/{video}', function (Request $request, $video) {
$fileName = storage_path('video/' . $video);
$contentType = mime_content_type($fileName);
$fileTitle = basename($fileName);
if (!file_exists($fileName)) {
throw new \Exception(sprintf('File not found: %s', $fileName));
}
if (!is_readable($fileName)) {
throw new \Exception(sprintf('File not readable: %s', $fileName));
}
### Remove headers that might unnecessarily clutter up the output
header_remove('Cache-Control');
header_remove('Pragma');
### Default to send entire file
$byteOffset = 0;
$byteLength = $fileSize = filesize($fileName);
header('Accept-Ranges: bytes', true);
header(sprintf('Content-Type: %s', $contentType), true);
if ($fileTitle) {
header(sprintf('Content-Disposition: attachment; filename="%s"', $fileTitle));
}
### Parse Content-Range header for byte offsets, looks like "bytes=11525-" OR "bytes=11525-12451"
if (isset($_SERVER['HTTP_RANGE']) && preg_match('%bytes=(\d+)-(\d+)?%i', $_SERVER['HTTP_RANGE'], $match)) {
### Offset signifies where we should begin to read the file
$byteOffset = (int)$match[1];
### Length is for how long we should read the file according to the browser, and can never go beyond the file size
if (isset($match[2])) {
$finishBytes = (int)$match[2];
$byteLength = $finishBytes + 1;
} else {
$finishBytes = $fileSize - 1;
}
$cr_header = sprintf('Content-Range: bytes %d-%d/%d', $byteOffset, $finishBytes, $fileSize);
header("HTTP/1.1 206 Partial content");
header($cr_header); ### Decrease by 1 on byte-length since this definition is zero-based index of bytes being sent
}
$byteRange = $byteLength - $byteOffset;
header(sprintf('Content-Length: %d', $byteRange));
header(sprintf('Expires: %s', date('D, d M Y H:i:s', time() + 60 * 60 * 24 * 90) . ' GMT'));
$buffer = ''; ### Variable containing the buffer
$bufferSize = 512 * 16; ### Just a reasonable buffer size
$bytePool = $byteRange; ### Contains how much is left to read of the byteRange
if (!$handle = fopen($fileName, 'r')) {
throw new \Exception(sprintf("Could not get handle for file %s", $fileName));
}
if (fseek($handle, $byteOffset, SEEK_SET) == -1) {
throw new \Exception(sprintf("Could not seek to byte offset %d", $byteOffset));
}
while ($bytePool > 0) {
$chunkSizeRequested = min($bufferSize, $bytePool); ### How many bytes we request on this iteration
### Try readin $chunkSizeRequested bytes from $handle and put data in $buffer
$buffer = fread($handle, $chunkSizeRequested);
### Store how many bytes were actually read
$chunkSizeActual = strlen($buffer);
### If we didn't get any bytes that means something unexpected has happened since $bytePool should be zero already
if ($chunkSizeActual == 0) {
### For production servers this should go in your php error log, since it will break the output
trigger_error(sprintf("Chunksize became 0 in %s with byteOffset %s, byteRange %s, byteLength %s", $fileName, $byteOffset, $byteRange, $byteLength), E_USER_WARNING);
break;
}
### Decrease byte pool with amount of bytes that were read during this iteration
$bytePool -= $chunkSizeActual;
### Write the buffer to output
print $buffer;
### Try to output the data to the client immediately
flush();
}
exit();
})->where('video', '.*.mp4$');
@renalpha
Copy link
Author

The reason why this doesnt work out of the box is because of PartialContent.

You should first test your URL endpoint through Safari.

This took me days to fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment