shoud use something else in production such as a redis
} else {
if(is_file($storage)){
$_SESSION=json_decode(file_get_contents($storage),true);
}
register_shutdown_function(function(){// otherwise session_write_close
global $storage;
if ($_SESSION) file_put_contents($storage, json_encode($_SESSION));
});
}
// '1: If token and channel are ok Query first folder: root and get it identifier') {
if ('log to the api with your credentials once => put theses values on your code' and !isset($_SESSION['apiToken']) and !isset($_SESSION['channel'])) {
if (isset($_POST['apiToken']) and isset($_POST['channel']) and 'Step 1: validate token and channel against channel root folder') {
$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . $_POST['channel'] . '/folder/root?with=encodings,effective_encodings', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $_POST['apiToken']]];
// quickCurl($apiUrl . $_POST['channel'] . '/folder/root?with=encodings,effective_encodings')
$contents = json_decode(curlRequest($options), true);
if ($contents['data']['id']) {
$ok = true;
ss('apiToken',$_POST['apiToken']);
ss('channel',$_POST['channel']);
ss('encoding',$contents['data']['encodings'][0]['id']);
ss('rootFolderId',$contents['data']['id']);
}
}
if (!$ok) {// Token and channel not correct ? Still diplay the form in order to check your parameters are correct
?>
['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/viewers/medias?from=' . $statsFrom . '&medias=' . $_POST['mediaStats']]);
die($a);
}
if (isset($_POST['getToken4share'])) {
$now = time();
if (!isset($_POST['uniqid']) or !isset($_POST['hash']) or !in_array($_POST['hash'], $innerHashes) or !isset($_SESSION['uniqid']) or !isset($_SESSION['expires']) or ($_SESSION['expires'] < $now) or $_POST['uniqid'] != $_SESSION['uniqid']) {
die('{"error":"not allowed"}');
}
// nb: shall use redis or memcach instead
$requestsPerIp = (is_file($ip . '.requests') ? json_decode(file_get_contents($ip . '.requests'), true) : []);
$min = $now - $maxTokensTimeLimit;
foreach ($requestsPerIp as $k => &$v) {
if ($k < $min) $v = null;// ne plus prendre en compte les hits < 1 heure
}
unset($v);
$requestsPerIp = array_filter($requestsPerIp);
$nbHits = array_sum($requestsPerIp);
if ($nbHits > $limitTokensPerHour) die('{"toomuchtokenrequests":1}');
if (!isset($requestsPerIp[$now])) $requestsPerIp[$now] = 0;
$requestsPerIp[$now]++;
file_put_contents($ip . '.requests', json_encode($requestsPerIp));
$post =
[
'window' => 3600// validity in seconds : 1 hour, default is 1800
, 'strategy' => 'SINGLE'// strategy:DASH|HLS|BEST|SINGLE => single for /_single_/ links, hls for /_hls_/ manifest links ... default is HLS
/*
, 'allowed_domains' => ['https://infomaniak.ch', 'http://other.ch']
, 'restricted_domains' => ['http://win.ch', 'http://orange.ch']
,'attempts' => 5 // Number of allowed hits until token expires
, 'ip'=>'127.0.0.1'// v4 adress, but one day its going to be ipv6, so you'll have to catch your user ipv4 or ipv6 using ajax requests : https://ipv4.infomaniak.com/ip.php , https://www.infomaniak.com/ip.php might return ipv6 if available , if both respond ipv4 its safe , yet the server only resolves as ipv4, but might resolve adresses as ipv6 in the future
// validity here starts in the future, for 12 hours
,'start_time'=>date('Y-m-d H:i:s',strtotime('12 hours')), 'end_time'=>date('Y-m-d H:i:s',strtotime('24 hours'))//will be valid for 1 hour once consumed starting in 12 hours and ending in 24 hours in theses domains
*/
];
$post = [];// default parameters
$options = [CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/share/' . $_POST['getToken4share'] . '/token', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => json_encode($post)];
die('{"token":"' . json_decode(curlRequest($options), true)['data'] . '"}');
}
}
/**
* THIS MECANIC IS FOR INNER CSRF TOKEN DISTRIBUTION EVEN BEFORE OPENING API CALLS TO REAL VIDEO TOKEN GENERATION IN ORDER TO AVOID ANY USER POSSIBLE EXPLOIT OF THE FEATURE, PLEASE NOTE IT ALSO EXPIRES ...
*/
if ('refresh page token used for throttling token api queries, only for legitimate users') {
if (!isset($_SESSION['expires']) or $_SESSION['expires'] < (time() + ($crsfTokenTimeout / 2))) {
ss('expires', time() + $crsfTokenTimeout);
ss('uniqid',\uniqid());// refresh token : add complexity
}
if (isset($_GET['refreshToken'])) {// async ajax refreshToken action
if (!isset($_POST['hash']) or !in_array($_POST['hash'], $innerHashes)) {
die('{"error":"not allowed 2"}');
}
die('{"uniqid":"' . $_SESSION['uniqid'] . '"}');
}
}
if (!$player and '2:list available players - get first one available - in order to publish shares foreach found media') {
$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/player', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken]];
$contents = json_decode(curlRequest($options), true);
$player = $contents['data'][0]['id'];ss('player',$player);
}
if (0 and !$autoPlayliste and '3 : list all playlists, then returns the share with the auto playlist videos') {
$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/playlist?with=shares', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken]];
$contents = json_decode(curlRequest($options), true);
$autoPlaylisteShare = '';ss('autoPlaylisteShare','');
$playlists = $contents['data'];
ss('playlists',$playlists);
foreach ($contents['data'] as $playlist) {
if ($playlist['type'] == 'dynamic' and $playlist['name'] == 'autodyn') {
if (isset($playlist['shares'][0])) {
$_SESSION['autoPlaylisteShare'] = $autoPlaylisteShare = $playlist['shares'][0]['links']['embed']['html']['url'];//Skip
}
$_SESSION['autoPlayliste'] = $autoPlayliste = $contents['data'];
break;
}
}
if (!isset($_SESSION['autoPlayliste']) and 'create autodyn playlist with all previous folders') {
if (!$folders and '3A : list all folders --> create an automated playlist with all channel contents') {
$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/folder', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken]];
$contents = json_decode(curlRequest($options), true);
foreach ($contents['data'] as $folder) {
$folders[] = $folder['id'];
}
$_SESSION['folders'] = $folders;
}
if ('3B : creates automatic channel contents playlist') {
$post = ['name' => 'autodyn', 'type' => 'dynamic'];
$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/playlist', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'Content-Type: application/json'], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => json_encode($post)];
$contents = json_decode(curlRequest($options), true);
$_SESSION['autoPlayliste'] = $autoPlayliste = $contents['data']['id'];
}
if ('3C : attach folders / medias to playlist') {
$post = ['items' => implode(',', $folders)];
$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/playlist/' . $autoPlayliste . '/attach', CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'Content-Type: application/json'], CURLOPT_POST => 1, CURLOPT_POSTFIELDS => json_encode($post)];
$contents = json_decode(curlRequest($options), true);
}
if ('3D : get playlist share') {
$post = json_encode(['target' => $autoPlayliste, 'player' => $player, 'encoding' => $encoding]);
$options = [CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/share', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post];
$contents = json_decode(curlRequest($options), true);
$_SESSION['autoPlaylisteShare'] = $autoPlaylisteShare = $contents['data']['links']['embed']['html']['url'];
}
}
}
if (!$medias and '4 : list all media --> get thumbnails, creates shares if non existing with the first encoding found, then create foreach 1 token based on ip') {
/***
* state: 192 - media encoded and ready to play
* validated : true -- so any share could playback the media like : aka public vs private
* effective_encodings : different video qualities associated with the media
*/
$options = [CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/media?per_page='.$perPage.'&page=1&order_by=created_at&order=desc&with=encodings,effective_encodings,shares,thumbnail,sample,playbacks'];//,thumbstrip,preview,sample,,scenes,encodings,progress,state -> might consider loading less data in order to get a faster response
// &filter[]=published:0&order_by=name&order=desc
$contents = json_decode(curlRequest($options), true);
//shares
$medias = $contents['data'];
foreach ($medias as &$media) {
if (!$media['playbacks']) {// or $media['streams'] == [0 => 'audio']
continue;// or !$media['encodings'] Cant share a media which has non encodings ..
}
if ($media['shares']) {// Filter deleted or time expiration shares
$media['shares'] = array_values(array_filter(array_map(function($a){if($a['validity'] or $a['deleted_at'] or $a['valid_until']){return null;}return $a;}, $media['shares'])));
}
if (!$media['shares'] or $media['shares'][0]['validity'] or $media['shares'][0]['deleted_at']) {//
if ('4B: create a share of the uploaded media') {
// $post = json_encode(['validity' => 0, 'target' => $media['id'], 'player' => $player, 'encoding' => $media['encodings'][0]['id']]);
$post = json_encode(['validity' => 0/* never expires, if >0, will expire in that much seconds */, 'target' => $media['id'], 'player' => $player, 'encoding' => array_keys($media['playbacks'])[0]]);
$options = [CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/share', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post];
// {"validity":0,"target":"1jhvl2uqe6vo2","player":"1jhvl2upwockr","encoding":"1jhvl2uq8p2rs"} {target: "1jhvl2uqbdrgq", encoding: "1jhvl2uq8p2rn"}
$c1 = json_decode(curlRequest($options), true);
$media['shares'] = [$c1['data']];
$shares[] = $share = $c1['data']['id'];
}
} else {
$share = $media['shares'][0]['id'];
}
}
unset($media);
$_SESSION['medias'] = $medias;// = $contents['data'];
}
if ('5:display') {
header('Content-Type: text/html; charset=utf-8');
echo 'Infomaniak Vod Api
'.((isset($autoPlaylisteShare) && $autoPlaylisteShare)?' - Dynamic Channel Playlist with all medias':'').' - Rafraichir les résultats';
foreach ($medias as $mk => &$media) {
if (!is_array($media)) {
$uuidOnly = 'mauvaise formation du cache';$_SESSION=[];continue;
}
$protected = false;
$share = (isset($media['shares']) && isset($media['shares'][0])) ? $media['shares'][0]['id'] : 0;
if (is_array($media) && isset($media['key_restricted'])) {
$protected = $media['key_restricted'];
}
if (0 and 'perform check if Media has one encoding and is ready to play ?') {
$isReadyToPlay = false;
$encodings = $media['encodings'];
$progress = $media['progress'];
$state = $media['state'];
$readyForPlayback = ($state >= 64 && (($state & 64) === 64)) || ($state >= 128 && (($state & 128) === 128));
/* state is bitwise of IDLE = 1; DELETED = 2; TRANSFERRING = 4; INITIALIZING = 8; AWAIT_ENCODING = 16; ENCODING = 32; AVAILABLE = 64; READY = 128; E_TRANSIENT = 256; E_FATAL = 512; */
if ($progress == 100 and count($encodings) and $readyForPlayback) {
$isReadyToPlay = true;
}
}
$tnFile = (isset($media['thumbnail']['url'])) ? $media['thumbnail']['url'] : '';
$previewFile = (isset($media['preview'])) ? $media['preview']['video']['url'] : '';
$thumbstrip = $thumbstripFile = (isset($media['thumbstrip'])) ? 'http://api.vod2.infomaniak.com/res/thumb/' . $media['thumbstrip']['id'] : '';
if ($cacheThumbnails and 'put thumbnails into local file cache ( faster display )') {
if (!is_dir($thumbnailsDir)) {
mkdir($thumbnailsDir);
}
if (!isset($multi)) {
$multi = curl_multi_init();
}
$thumbnail = $tnFile;
if ($thumbnail) {
$found = false;
$end = explode('/', $thumbnail);
$media['thumbnail'] = $tnFile = $thumbnailsDir . '/' . end($end) . '.jpg';
if ($resize) {
$wp = $tnFile . '-' . $resize[0] . '-' . $resize[1] . '.webp';
$jpg = $tnFile . '-' . $resize[0] . '-' . $resize[1] . '.jpg';
if (is_file($wp)) {
$found = true;
$media['thumbnail'] = $tnFile = $wp;
} elseif (is_file($jpg)) {
$found = true;
$media['thumbnail'] = $tnFile = $jpg;
}
}
if (!$found && !is_file($tnFile)) {
$lastCurl = $multiCh[] = curl_init($thumbnail);
$resId = (int)$lastCurl;
$files[$resId] = $tnFile;
$res2mk[$resId] = $mk;
$fileHandles[$resId] = $fh = fopen($tnFile, 'w');
if (!$fh) {
throw new Exception('Cant write file:' . __line__);
}
curl_setopt_array($lastCurl, [CURLOPT_URL => $thumbnail . '?id=' . $resId, CURLOPT_HEADER => false, CURLINFO_HEADER_OUT => false, CURLOPT_VERBOSE => false, CURLOPT_FILE => $fh, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_NOPROGRESS => 0, CURLOPT_BUFFERSIZE => CURL_MAX_READ_SIZE, CURLOPT_TIMEOUT => 9999]);//CURLOPT_PROGRESSFUNCTION => 'progress',
curl_multi_add_handle($multi, $lastCurl);
}
}
if (isset($media['sample']['video']['url']) and $media['sample']['video']['url']) {
$url = $media['sample']['video']['url'];
$end = explode('/', $media['sample']['video']['url']);
$media['sample'] = $tnFile = $thumbnailsDir . '/' . end($end) . '.jpg';
if (!is_file($tnFile)) {
$lastCurl = $multiCh[] = curl_init($url);
$resId = (int)$lastCurl;
$files[$resId] = $tnFile;
$res2mk[$resId] = $mk;
$fileHandles[$resId] = $fh = fopen($tnFile, 'w');
if (!$fh) {
throw new Exception('Cant write file:' . __line__);
}
curl_setopt_array($lastCurl, [CURLOPT_URL => $url . '?id=' . $resId, CURLOPT_HEADER => false, CURLINFO_HEADER_OUT => false, CURLOPT_VERBOSE => false, CURLOPT_FILE => $fh, CURLOPT_FOLLOWLOCATION => 1, CURLOPT_NOPROGRESS => 0, CURLOPT_BUFFERSIZE => CURL_MAX_READ_SIZE, CURLOPT_TIMEOUT => 9999]);//CURLOPT_PROGRESSFUNCTION => 'progress',
curl_multi_add_handle($multi, $lastCurl);
}
}
} else {//no thumbnail caching
$media['thumbnail'] = (isset($media['thumbnail']['url'])) ? $media['thumbnail']['url'] : '';
$media['sample'] = (isset($media['sample']['url'])) ? $media['sample']['video']['url'] : '';
}
}
unset($media);
if (isset($multi)) {
do {
$r = curl_multi_exec($multi, $active);
if (\curl_multi_select($multi) == -1) {
usleep(100000);
} else {
$ir = \curl_multi_info_read($multi);
if ($ir) {//msg:1,result:3
$resId = intval($ir['handle']);
$info = curl_getinfo($ir['handle']);
if ($info['http_code'] == 200) {
fclose($fileHandles[$resId]);
$quality = 70;
if ($resize && 'want to resize the thumbnail to specific dimensions ?' && function_exists('imagecreatefromjpeg')) {
$path = $files[$resId] . '-' . $resize[0] . '-' . $resize[1];
[$w, $h, $mime] = getimagesize($files[$resId]);
if (!$w or !$h) {
continue;// error with downloading the image
}
if ($mime == 2) {
$image = imagecreatefromjpeg($files[$resId]);
} elseif ($mime == 4) {
$image = imagecreatefrompng($files[$resId]);
} elseif ($mime == 32) {
$image = imagecreatefromwebp($files[$resId]);
} else {
$a = 1;
}
$tmp = imagecreatetruecolor($resize[0], $resize[1]);
imagecopyresampled($tmp, $image, 0, 0, 0, 0, $resize[0], $resize[1], $w, $h);
if (function_exists('imagewebp')) {// faster, better than jpeg
$path .= '.webp';
imagewebp($tmp, $path, $quality);
} else {
$path .= '.jpg';
imagejpeg($tmp, $path, $quality);
}
if (isset($res2mk[$resId])) {
$mk = $res2mk[$resId];
$media[$mk]['thumbnail'] = $path;
}
}
} elseif ('cant download thumbnail file: 404 error') {
fclose($fileHandles[$resId]);
touch($files[$resId]);
// put file 404.png instead, let them anyways
}
unset($fileHandles[$resId], $files[$resId]);
curl_multi_remove_handle($multi, $ir['handle']);
}
}
} while ($r == CURLM_CALL_MULTI_PERFORM || $active);
curl_multi_close($multi);
foreach ($fileHandles as $fileHandle) {
fclose($fileHandle);
}
if (0 and $r != CURLM_OK) {
throw new Exception("Curl multi read error $r");
}
}
if ('print html for display') {
foreach ($medias as $media) {
$tnFile = $media['thumbnail'] ?? '';
$previewFile = $media['preview'] ?? '';
$protected = $media['key_restricted'] ?? '';
$share = $media['shares'][0] ?? '';
if (!isset($share['id'])) {
continue;// Anomalie
$a = 1;
} else {
$link = $share['links']['embed']['html']['url'];
}
if (isset($media['sample']['audio']['url'])) {//is audio, no previews
$media['sample'] = '';
}
if ($protected) {
$requestToken[$media['id']] = $share['id'];
}
$mediasUuids[]=$media['id'];
if(is_array($media['sample']))$media['sample']='';
echo "\n\t
";
}
}
echo "
";
}
?>
';
if (0 and 'other usefull ( yet disabled in this script ) functions') {
if ('6 : search for a media by name') {
$options = [CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/browse?page=1&per_page='.$perPage.'&with=shares,thumbnail&search=' . $searchFor];
$searchResults = json_decode(curlRequest($options), true)['data'];
$sharesForMedias = [];
foreach ($searchResults as $searchResult) {
/* other with : thumbnail,sample,preview,thumbstrip,manifests */
$options = [CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/media/' . $searchResult['id'] . '?with=shares'];
$res = json_decode(curlRequest($options), true)['data'];
if (isset($res['shares']) and $res['shares']) {
foreach ($res['shares'] as $share) {
$sharesForMedias[$searchResult['id']] = 'https://player.vod2.infomaniak.com/embed/' . $share['id'];
}
}
}
print_r(compact('searchResults', 'sharesForMedias'));
}
if ('7: query video statistics') {
if ('viewing') {
$stats['viewing'] = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/media/' . $mediaId . '/viewing?from=' . $statsFrom]), true)['data']['value'];
}
if ('viewers') {
$stats['viewers'] = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/media/' . $mediaId . '/viewers?from=' . $statsFrom]), true)['data']['value'];
}
if ('unique viewers') {
$stats['unique_viewers'] = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/media/' . $mediaId . '/viewers/uniques?from=' . $statsFrom]), true)['data']['value'];
}
if ('average viewing time on channel') {
$res = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/avg_time?from=' . $statsFrom]))['data'];
$stats['number_ips'] = $res['number_ips'];
$stats['average_time'] = $res['average_time'];
}
if ('countries in csv format') {
$stats['countries:csv'] = curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/geolocation/countries?from=' . $statsFrom.'&format=csv'])['data'];
}
if ('cities') {
$stats['cities:json'] = curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/geolocation/cities?from=' . $statsFrom])['data'];
}
if ('location : lat, lon clusters') {
$stats['latLonClusters'] = curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/geolocation/clusters?from=' . $statsFrom])['data'];
}
if ('location : lat, lon clusters, groupés par pays') {
$stats['latLonByCountry'] = curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/geolocation/clusterspercountry?from=' . $statsFrom])['data'];
}
//$mediasUuids
if ('bulk : multiple medias viewers') {
$stats['viewers'] = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/statistics/viewers/medias?from=' . $statsFrom . '&medias=' . implode(',', $mediasUuids)]), true)['data'];
}
}
print_r($stats);
$videoFileName = '';
$file2uploadLocalPath = '';
$videoUrl = 'https://www.youtube.com/watch?v=uSce2_Te6Dc';
if ('8: upload media into this folder' && is_file($file2uploadLocalPath)) {
$sha256=hash_file('sha256',$file2uploadLocalPath);// is optional
$post = ['folder' => $folder, 'name' => 'videoName', 'file' => new \CURLFile($file2uploadLocalPath, '', $videoFileName)];
$contents = json_decode(curlRequest([CURLOPT_TIMEOUT => 36000/* large timeout for large files */, CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'User-Agent: client', 'Content-Type: multipart/form-data','Digest: sha256='.$sha256], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/upload', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post]),true);
$uploadedMediaId = $contents['data']['id'];
echo "\nUploaded media id: " . $uploadedMediaId;
}
if ('9: upload a distant media ( by url ) into this folder') {
$sha256='sha256oftheGivenUrl';// is optional, but permit detection of non fully transferred files
$post = ['folder' => $folder, 'filename' => 'videoName', 'url' => $videoUrl];
$contents = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'User-Agent: client', 'Content-Type: multipart/form-data','Digest: sha256='.$sha256], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/upload', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post]),true);
$uploadedMediaId = $contents['data']['id'];
echo "\nUploaded media id: " . $uploadedMediaId;
}
if ("10: change media thumbnail (have to wait both preview and poster are generated .. otherwise they'll be overriden") {
$thumbnail='1jhvl2uqgbuon.jpg.jpg';
$post = [ 'file' => new \CURLFile($thumbnail, '', $thumbnail)];
$contents = json_decode(quickCurl($apiUrl . '/media/'.$medias[0]['id'].'/thumbnail',[CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post],['Content-Type: multipart/form-data']));
//{"result":"success","data":{"id":"1jhvl2uqi21qz","created_at":"1678438327","updated_at":"1678438327","deleted_at":null,"link":{"url":"https:\/\/res.vod2.infomaniak.com\/1\/vod\/thumbnail\/1jhvl2uqi21qz.jpg","mimetype":"image\/jpeg","size":635266,"size_human_readable":"635.27kB","data":{"manual":true}},"manual":true}}
}
if ('11: set a callback if none present') {
$callbacks = json_decode(quickCurl($apiUrl . '/callback',[CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $post],['Content-Type: application/json']));
if (!$callbacks or !$callbacks['data']) {
$contents = json_decode(curlRequest([CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiToken, 'User-Agent: client', 'Content-Type: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_URL => $apiUrl . '/callback', CURLOPT_POST => 1, CURLOPT_POSTFIELDS => '{"name":"callback","events": ["media_ready","encoding_finished"],"url":"http://yourdomain.com/callbackHandler.php","response":"json","auth":"none","active": true}']),true);
}
echo "\nCallback id: " . $contents['data']['id'];
}
if ('12: Subtitles : create and publish, then edit, then toggle published / unpublished') {
$lang = 'fr';
$uuidMedia = reset($mediasUuids);
$post=['name'=>'soustitre','published'=>true,'lines'=>[
['start'=>'0.000','end'=>'2.000','text'=>'soustitre deux premières secondes']
,['start'=>'2.000','end'=>'4.000','text'=>'soustitre deux à 4']]
];
$uuidSubtitle = json_decode(quickCurl($apiUrl . '/media/' . $uuidMedia . '/subtitle/' . $lang, [CURLOPT_POST => 1, CURLOPT_POSTFIELDS =>json_encode($post)], ['Content-Type: application/json']))['data']['id'];
echo "\nSubtitle id: " . $uuidSubtitle;
$post=['name'=>'soustitre2','published'=>false,'lines'=>[
['start'=>'0.000','end'=>'2.000','text'=>'soustitre deux premières secondes']
,['start'=>'4.000','end'=>'6.000','text'=>'soustitre 4 à 6']]
];
$modifiedSubtitleUnpublished = json_decode(quickCurl($apiUrl . '/media/' . $uuidMedia . '/subtitle/' . $uuidSubtitle, [CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => json_encode($post)], ['Content-Type: application/json']));
$post=['subtitles'=>[$uuidSubtitle],'published'=>true];
$batchPublishingSubtitles = json_decode(quickCurl($apiUrl . '/media/' . $uuidMedia . '/subtitle', [CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => json_encode($post)], ['Content-Type: application/json']));
}
}
$a=1;
} catch (\Throwable $e) {
echo "Error: " . $e->getMessage() . ':' . $e->getLine();// . ':' . json_encode($e);
}
function curlRequest($options)
{
$ch = curl_init();
curl_setopt_array($ch, [CURLOPT_TIMEOUT => 3600] + $options);
$res = curl_exec($ch);
$i = curl_getinfo($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
$bt = debug_backtrace(-2)[0]['line'];
throw new Exception('Error on line ' . $bt . ':' . json_encode($error));
}
if (strpos($res, '"error":')) {
$json = json_decode($res, true);
//if (isset($json['result']) and $json['result'] == 'error') {
if (isset($json['error'])) {
$bt = debug_backtrace(-2)[0]['line'];
if ($json['error']['code'] == 'vod_not_authorized') {
$json['error'] = 'bad token,vod_not_authorized';
}// {"validity":0,"target":"1jhvl2uqe6vo2","player":"1jhvl2upwockr","encoding":"1jhvl2uq8p2rn"}
throw new Exception('Error on line ' . $bt . ':' . json_encode($json['error'])." with payload \n\n".$options[CURLOPT_URL]."\n\n".$options[CURLOPT_POSTFIELDS]);
}
}
if ($i['http_code'] == 404) {
$res = json_encode(['error' => '404 response for ' . $options[CURLOPT_URL]]);
}
if (substr($i['http_code'], 0, 1) == 5) {// bad gateway or timeout
$bt = debug_backtrace(-2)[0]['line'];
throw new Exception('Bad response: ' . $i['http_code'] . ' : ' . $bt . ':' . json_encode($json['error']) . " with payload \n\n" . $options[CURLOPT_URL] . "\n\n" . $options[CURLOPT_POSTFIELDS]);
}
return $res;
}
function curlHeaders($headers)
{
global $apiToken;
return ['Authorization: Bearer ' . $apiToken, 'User-Agent: api'] + $headers;
}
function quickCurl($url, $options = [], $headers = [])
{
return curlRequest([CURLOPT_TIMEOUT => 3600, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => curlHeaders($headers), CURLOPT_URL => $url] + $options);
}
function ss($k, $v)
{
$_SESSION[$k] = $v;
}
?>
curl -ks -H 'Content-Type: multipart/form-data' -H "Authorization: Bearer $token" 1/channel/xXx/media/xXx/thumbnail -X POST -F 'file=@thumbnail.jpg';
curl -ks -H "Authorization: Bearer $token" -H "Content-type: application/json" 1/channel/xXx/browse/update -X PUT --data '{ "targets": ["1jhvl2uqh41ll","1jhvl2uqh3yl8"], "published": true, "validated": true }';
curl -ks -H "Authorization: Bearer $token" -H "Content-type: application/json" 1/channel/xXx/browse/trash -X DELETE --data '{"targets": ["1jhvl2xxx4wzm"]}'; # permanently delete file from trash
curl -ks -H "Authorization: Bearer $token" -H "Content-type: application/json" 1/channel/XxX/player/1jhvlxXxf5inu -X PUT --data '{"name":"name","slug":"slut"}';# etc pour tous les attributs
curl -ks -H "Authorization: Bearer $token" 1/channel/XxX/media/YyY/chapter/ZzZ
POST /channel/xxx/browse/move --data '{targets: ["1jhvl2uqhksoy"], destination: "1jhvl2uq8p2r0"}';# medias Uuid to folder, caution, it deletes previous shares
POST : /channel/{channel}/browse/copy --data '{name: "mediaNameInFolder", destination: "1jhvl2uq8p2r0"}'
if ('apiv3 routes : in progress, those are the fastest ones ') {/* /([2-9]|[0-9]{2,})
HOST : https://api.vod2.infomaniak.com/2/vod/
GET|HEAD accounts/{account}/channels
GET|HEAD browse/{folder}
GET|HEAD browse/{folder}/breadcrumb
GET|HEAD browse/{folder}/tree
GET|HEAD channels/{channel}
GET|HEAD channels/{channel}/browse
GET|HEAD channels/{channel}/browse/breadcrumb
GET|HEAD channels/{channel}/browse/trash
GET|HEAD channels/{channel}/browse/tree
GET|HEAD channels/{channel}/encodings
GET|HEAD channels/{channel}/folders
GET|HEAD channels/{channel}/media
GET|HEAD channels/{channel}/players
GET|HEAD chapters/{chapter}
GET|HEAD chapters/{chapter}.{format}
GET|HEAD encodings/p
GET|HEAD encodings/p/{profile}
GET|HEAD encodings/{encoding}
GET|HEAD folders/{folder}
GET|HEAD lang
GET|HEAD lang/{lang}
GET|HEAD media/{media}
GET|HEAD media/{media}/chapters
GET|HEAD media/{media}/chapters.{format}
GET|HEAD media/{media}/subtitles
GET|HEAD media/{media}/thumbnails
GET|HEAD players/{player}
GET|HEAD players/{player}.{image}.{format}
GET|HEAD subtitles/{subtitle}
GET|HEAD subtitles/{subtitle}.{format}
GET|HEAD thumbnails/{thumbnail}
GET|HEAD thumbnails/{thumbnail}.{format}
GET|HEAD api/pub/v1/channel/{channel}/media/{media}/subtitle
PUT|PATCH api/pub/v1/channel/{channel}/media/{media}/subtitle
DELETE api/pub/v1/channel/{channel}/media/{media}/subtitle
POST api/pub/v1/channel/{channel}/media/{media}/subtitle/{language}
POST api/pub/v1/channel/{channel}/media/{media}/subtitle/{language}/import
GET|HEAD api/pub/v1/channel/{channel}/media/{media}/subtitle/{subtitle}
PUT|PATCH api/pub/v1/channel/{channel}/media/{media}/subtitle/{subtitle}
DELETE api/pub/v1/channel/{channel}/media/{media}/subtitle/{subtitle
PUT api/pub/v1/channel/{channel}/media/{media}/subtitle/{subtitle}/default
*/
}