@@ -1,157 +1,155 @@
<?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)
> 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
*/
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 )
/*
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 ))
{
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 ;
$ 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 }" ];
}
// 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/ " );
?>
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="./videojs-7.5.5.css" rel="stylesheet" type="text/css">
<link href="./videojs-quality-selector.css" rel="stylesheet" type="text/css">
<link href="./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
<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=""
>
</p>
</video>
</body>
<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="./videojs- 7.5.5.js"></script>
<script src="./ videojs-quality-selector.min .js"></script>
<script src="./ videojs-chromecast.min. js"></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[source .url];
return titles[csource .url];
}
},
plugins: {
chromecast: {}
}
};
// append the token query string to the TS segments
videojs.Hls.xhr.beforeRequest = function(options) {
if(segment.uri.includes('.ts')){
segment.uri += '<?php echo $ secure_query ; ?> ';
segment.resolvedUri += '<?php echo $ secure_query ; ?> ';
};
if(options.uri.includes('.ts')) options.uri += '<?php echo $ query_string ; ?> ';
return options;
};
var vjplayer = videojs("MyPlayer", options);
</script>
</html>