<?php
 class vB_Api_Content_Video extends vB_Api_Content_Text { protected $contenttype = 'vBForum_Video'; protected $textRequired = false; const THUMBNAIL_TTL = 432000; protected function __construct() { parent::__construct(); $this->library = vB_Library::instance('Content_Video'); } public function add($data, $options = []) { vB_Api::instanceInternal('hv')->verifyToken($data['hvinput'] ?? null, 'post'); if ( (vB_Api::instanceInternal('node')->fetchAlbumChannel() == $data['parentid']) AND (!vB::getUserContext()->hasPermission('albumpermissions', 'picturefollowforummoderation')) ) { $data['approved'] = 0; $data['showapproved'] = 0; } return parent::add($data, $options); } public function getVideoFromUrl($url) { return $this->library->getVideoFromUrl($url); } public function getVideoFormat($provider) { return $this->library->getVideoFormat(strval($provider)); } public function getVideoThumbnailFromProvider($provider, $code, $url, $nodeid = false) { $nothumb = [ 'use_thumb' => false, 'url' => '', ]; $providers = vB::getDatastore()->getValue('video_providers'); $thumbinfo = $providers[$provider]['thumbnailinfo'] ?? null; if (!$thumbinfo) { return $nothumb; } $type = $thumbinfo['type']; if ($type == 'none') { return $nothumb; } $result = [ 'use_thumb' => true, 'url' => '', ]; if ($type == 'list') { $result['url'] = $this->getVideoThumbnailInternal( $url, $nodeid, function ($url) use ($thumbinfo, $code) {return $this->getThumbnailFromList($thumbinfo['urls'], $code);} ); return $result; } else if ($type == 'oembed') { $jsonurl = str_replace('{url}', urlencode($url), $thumbinfo['url']); $result['url'] = $this->getVideoThumbnailInternal( $jsonurl, $nodeid, function ($url) {return $this->getThumbnailFromJson($url, 'thumbnail_url');} ); return $result; } else if ($type == 'meta') { $result['url'] = $this->getVideoThumbnailInternal($url, $nodeid, $this->getThumbnailFromMeta(...)); return $result; } else { return $nothumb; } } private function getVideoThumbnailInternal($url, $nodeid, $callback) { $video = null; if ($nodeid) { $video = $this->getContent($nodeid); if ($video) { $video = reset($video); } } if (!$video) { $cacheKey = 'vB_Vid' . md5($url); $cache = vB_Cache::instance(vB_Cache::CACHE_LARGE); $thumbnail = $cache->read($cacheKey); if ($thumbnail) { return $thumbnail; } $video = $this->assertor->getRow('vBForum:video', ['url' => $url]); } $havevideothumbnail = ($video AND !empty($video['thumbnail'])); if ( $havevideothumbnail AND !empty($video['thumbnail_date']) AND ($video['thumbnail_date'] >= (vB::getRequest()->getTimeNow() - self::THUMBNAIL_TTL)) ) { return $video['thumbnail']; } $thumbnail = $callback($url); if ($thumbnail) { if (!empty($video)) { $this->assertor->update('vBForum:video', [ 'thumbnail' => $thumbnail, 'thumbnail_date' => vB::getRequest()->getTimeNow(), ], ['nodeid' => $video['nodeid']] ); vB_Cache::allCacheEvent('nodeChg_' . $video['nodeid']); } else { vB_Cache::instance(vB_Cache::CACHE_LARGE)->write($cacheKey, $thumbnail, self::THUMBNAIL_TTL); } return $thumbnail; } else if ($havevideothumbnail) { return $video['thumbnail']; } return false; } private function getThumbnailFromJson(string $url, string $path) : false | string { $vurl = vB::getUrlLoader(); $vurl->setOption(vB_Utility_Url::FOLLOWLOCATION, 1); $page = $vurl->get($url); if (!$page OR !$page['body']) { return false; } $thumbnail = json_decode($page['body'], true); if (!$thumbnail) { return false; } if ($path) { foreach (explode('.', $path) AS $segment) { if (!is_array($thumbnail)) { return false; } $thumbnail = $thumbnail[$segment] ?? false; } } if (is_array($thumbnail)) { return false; } return strval($thumbnail); } private function getThumbnailFromMeta($url) { $thumbnail = false; if (strpos($url, 'facebook.com') !== false) { preg_match("#^(?<url>(?:https?\:\/\/)?(?:www.)?facebook\.com\/[^\/]*\/videos\/[0-9]+\/?.*)$#", $url, $matches); if (!empty($matches['url'])) { $url = "https://www.facebook.com/plugins/video.php?href=" . urlencode($url); } } $data = vB_Api::instance('content_link')->parsePage($url); if (!empty($data['images'])) { $thumbnail = $data['images']; if (is_array($thumbnail)) { $thumbnail = $thumbnail[0]; } } return $thumbnail; } private function getThumbnailFromList(array $list, string $code) : string { $lasturl = array_pop($list); foreach ($list AS $url) { $url = str_replace('{code}', $code, $url); if ($this->isImageValid($url)) { return $url; } } return str_replace('{code}', $code, $lasturl); } private function isImageValid(string $url) : bool { $vurl = vB::getUrlLoader(); $vurl->setOption(vB_Utility_Url::FOLLOWLOCATION, 1); $vurl->setOption(vB_Utility_Url::HEADER, 1); $vurl->setOption(vB_Utility_Url::NOBODY, 1); $vurl->setOption(vB_Utility_Url::CLOSECONNECTION, 1); $result = $vurl->customRequest($url, 'HEAD'); return (($result['headers']['http-response']['statuscode'] ?? '') == '200'); } } 