Skip to content

Instantly share code, notes, and snippets.

@ToshY
Last active July 17, 2023 04:44
Show Gist options
  • Select an option

  • Save ToshY/0b1b818b080bf9528dfbcc375b937a08 to your computer and use it in GitHub Desktop.

Select an option

Save ToshY/0b1b818b080bf9528dfbcc375b937a08 to your computer and use it in GitHub Desktop.
BunnyCDN VOD HLS Token Authentication V2 with directory tokens
<?php
/*
VOD HLS streaming for BunnyCDN with Token authentication V2
NOTES:
> Credits to Dejan from BunnyCDN Support for the function for token authentication V2
> I've created this snippet to show how to use HLS streaming with the directory tokens.
This is a workaround which works by appending the token query string for every request to the TS segments (see JS below)
> Please add the appropriate CORS headers if enabled in the BunnyCDN panel (for HLS add 'm3u8, ts')
> Chromecast with HLS streaming and the usage of directory tokens will not.
If you really want to have it work with Chromecast, I suggest using MP4 instead and use the option "Optimize for video delivery"
in BunnyCDN's control panel. Especially if you have high bitrate videos or segments (>15 Mbps), the Chromecast (V3) is able to
handle MP4 much better than TS (hanging).
> Tested with VideoJS 7.5.5 (19-6-2020 working)
*/
function sign_bcdn_url($url, $securityKey, $expiration_time = 3600, $user_ip = NULL, $path_allowed = NULL, $countries_allowed = NULL, $countries_blocked = NULL)
{
if(!is_null($countries_allowed))
{
$url .= (parse_url($url, PHP_URL_QUERY) == "") ? "?" : "&";
$url .= "token_countries={$countries_allowed}";
}
if(!is_null($countries_blocked))
{
$url .= (parse_url($url, PHP_URL_QUERY) == "") ? "?" : "&";
$url .= "token_countries_blocked={$countries_blocked}";
}
$url_scheme = parse_url($url, PHP_URL_SCHEME);
$url_host = parse_url($url, PHP_URL_HOST);
$url_path = parse_url($url, PHP_URL_PATH);
$url_query = parse_url($url, PHP_URL_QUERY);
$parameters = array();
parse_str($url_query, $parameters);
// Check if the path is specified and ovewrite the default
$signature_path = $url_path;
if(!is_null($path_allowed))
{
$signature_path = $path_allowed;
$parameters["token_path"] = $signature_path;
}
// Expiration time
$expires = time() + $expiration_time;
// Construct the parameter data
ksort($parameters); // Sort alphabetically, very important
$parameter_data = "";
$parameter_data_url = "";
if(sizeof($parameters) > 0)
{
foreach ($parameters as $key => $value)
{
if(strlen($parameter_data) > 0)
$parameter_data .= "&";
$parameter_data_url .= "&";
$parameter_data .= "{$key}=" . $value;
$parameter_data_url .= "{$key}=" . $value;
}
}
// Generate the toke
$hashableBase = $securityKey.$signature_path.$expires.$parameter_data;
// If using IP validation
if(!is_null($user_ip))
{
$hashableBase .= $user_ip;
}
// Generate the token
$token = hash('sha256', $hashableBase, true);
$token = base64_encode($token);
$token = strtr($token, '+/', '-_');
$token = str_replace('=', '', $token);
//$url_path = str_replace("%2F", "/", urlencode($url_path)); // URL encode everything but slashes for the URL data
$query_string = "?token={$token}{$parameter_data_url}&expires={$expires}&token_ver=2";
return [$query_string, "{$url_scheme}://{$url_host}{$url_path}{$query_string}"];
}
list($query_string, $secure_url) = sign_bcdn_url("https://mydomain.b-cdn.net/test/bigbuck.m3u8", "a1b2c3d4-e5f6-g7h8-i9j1-k2l3m4n5o6p7", 3600, NULL, "/test/");
?>
<html>
<head>
<link href="https://vjs.zencdn.net/7.5.5/video-js.css" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/@silvermine/videojs-quality-selector@1.2.4/dist/css/quality-selector.css" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/@silvermine/videojs-chromecast@1.2.1/dist/silvermine-videojs-chromecast.css" rel="stylesheet" type="text/css">
</head>
<body>
<video
id="MyPlayer"
class="video-js vjs-16-9 vjs-big-play-centered"
controls
preload="auto"
poster=""
data-title=""
data-poster=""
>
<source src="<?php echo $secure_url; ?>" type="application/x-mpegURL" label="" />
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank"
>supports HTML5 video</a
>
</p>
</video>
</body>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
<script src="https://vjs.zencdn.net/7.5.5/video.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@silvermine/videojs-quality-selector@1.2.4/dist/js/silvermine-videojs-quality-selector.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@silvermine/videojs-chromecast@1.2.1/dist/silvermine-videojs-chromecast.js"></script>
<script>
// current source
csource = $('#MyPlayer source').attr('src')
titles = {
csource: $('#MyPlayer').attr('data-title')
}
// options for chromecast
options = {
controls: true,
techOrder: [ 'chromecast', 'html5' ],
chromecast: {
requestTitleFn: function(source) {
return titles[csource.url];
}
},
plugins: {
chromecast: {}
}
};
// append the token query string to the TS segments
videojs.Hls.xhr.beforeRequest = function(options) {
if(options.uri.includes('.ts')) options.uri += '<?php echo $query_string; ?>';
return options;
};
var vjplayer = videojs("MyPlayer", options);
</script>
</html>
@saturngod
Copy link

Finally I got support from bunny.

I forked your code and edit it.

Thanks for your support.

https://gist.github.com/saturngod/01ca507ee0134c38f85874cc4061b320

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