*/
class syntax_plugin_vimeo extends DokuWiki_Syntax_Plugin
{
/**
* @return string Syntax mode type
*/
public function getType()
{
return 'substition';
}
/**
* @return string Paragraph type
*/
public function getPType()
{
return 'block';
}
/**
* @return int Sort order - Low numbers go before high numbers
*/
public function getSort()
{
return 100;
}
/**
* Connect lookup pattern to lexer.
*
* @param string $mode Parser mode
*/
public function connectTo($mode)
{
$this->Lexer->addSpecialPattern('{{vimeoAlbum>.+?}}', $mode, 'plugin_vimeo');
}
/**
* Handle matches of the vimeo syntax
*
* @param string $match The match of the syntax
* @param int $state The state of the handler
* @param int $pos The position in the document
* @param Doku_Handler $handler The handler
*
* @return array Data for the renderer
*/
public function handle($match, $state, $pos, Doku_Handler $handler)
{
$albumID = substr($match, strlen('{{vimeoAlbum>'), -2);
try {
$data = $this->getAlbumVideos($albumID);
} catch (Exception $e) {
$data = ['errors' => [$e->getMessage() . '; Code: ' . $e->getCode()]];
}
return $data;
}
/**
* Render xhtml output or metadata
*
* @param string $mode Renderer mode (supported modes: xhtml)
* @param Doku_Renderer $renderer The renderer
* @param array $data The data from the handler() function
*
* @return bool If rendering was successful.
*/
public function render($mode, Doku_Renderer $renderer, $data)
{
if ($mode !== 'xhtml') {
return false;
}
$renderer->doc .= '
';
if (!empty($data['errors'])) {
foreach ($data['errors'] as $error) {
msg('Vimeo Plugin Error: ' . hsc($error), -1);
}
}
if (!empty($data['videos'])) {
$videos = $data['videos'];
foreach ($videos as $video) {
$this->renderVideo($renderer, $video);
}
}
$renderer->doc .= '
';
return true;
}
/**
* Get all video data for the given album id
*
* The albumID must be owned be the user that provided the configured access token
*
* This also gets the paged videos in further requests if there are more than 100 videos
*
* @param string $albumID
*
* @return array data for the videos in the album
*/
protected function getAlbumVideos($albumID)
{
$accessToken = $this->getConf('accessToken');
if (empty($accessToken)) {
throw new RuntimeException('Vimeo access token not configured! Please see documentation.');
}
$fields = 'name,description,embed.html,pictures.sizes,privacy,release_time';
$endpoint = '/me/albums/' . $albumID . '/videos?sort=manual&per_page=100&fields=' . $fields;
$errors = [];
$respData = $this->sendVimeoRequest($accessToken, $endpoint, $errors);
$videos = $respData['data'];
if (!empty($respData['paging']['next'])) {
while (true) {
$respData = $this->sendVimeoRequest($accessToken, $respData['paging']['next'], $errors);
$videos = array_merge($videos, $respData['videos']);
if (empty($respData['paging']['next'])) {
break;
}
}
}
return [
'videos' => $videos,
'errors' => $errors,
];
}
/**
* Make a single request to Vimeo and return the parsed body
*
* @param string $accessToken The access token
* @param string $endpoint The endpoint to which to connect, must begin with a /
* @param array $errors If the rate-limit is hit, then an error-message is written in here
*
* @return mixed
*
* @throws RuntimeException If the server returns an error
*/
protected function sendVimeoRequest($accessToken, $endpoint, &$errors)
{
$http = new \DokuHTTPClient();
$http->headers['Authorization'] = 'Bearer ' . $accessToken;
$http->agent = 'DokuWiki HTTP Client (Vimeo Plugin)';
$http->keep_alive = false;
$base = 'https://api.vimeo.com';
$url = $base . $endpoint;
$http->sendRequest($url);
$body = $http->resp_body;
$respData = json_decode($body, true);
if (!empty($respData['error'])) {
dbglog($http->resp_headers, __FILE__ . ': ' . __LINE__);
throw new RuntimeException(
$respData['error'] . ' ' . $respData['developer_message'],
$respData['error_code']
);
}
$remainingRateLimit = $http->resp_headers['x-ratelimit-remaining'];
if ($remainingRateLimit < 10) {
dbglog($http->resp_headers, __FILE__ . ': ' . __LINE__);
$errors[] = 'The remaining Vimeo rate-limit is very low. Please check back in 15min or later';
}
return $respData;
}
/**
* Render a preview image and put the video iframe-html into a data attribute
*
* This offers all available images in a srcset, so the browser can decide which to load
*
* @param Doku_Renderer $renderer
* @param array $video The video data
*/
protected function renderVideo(Doku_Renderer $renderer, $video)
{
$title = hsc($video['name']);
if ($video['privacy']['embed'] === 'private') {
msg(sprintf($this->getLang('embed_deactivated'), $title), 2);
return;
}
$thumbnailWidthPercent = $this->getConf('thumbnailWidthPercent');
$widthAttr = 'style="width: ' . $thumbnailWidthPercent . '%;"';
$renderer->doc .= '