PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 3.7.1
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v3.7.1
4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.1.3 3.2.0 3.2.1 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.7.0 3.7.1 3.7.2 3.7.3 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.14 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.10 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.7 4.1.8 4.1.9 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.4.0 4.4.1 4.4.10 4.4.11 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5.0 4.5.1
embedpress / EmbedPress / Providers / Youtube.php
embedpress / EmbedPress / Providers Last commit date
Boomplay.php 5 years ago Giphy.php 5 years ago GoogleDocs.php 5 years ago GoogleDrive.php 3 years ago GoogleMaps.php 3 years ago OpenSea.php 3 years ago Twitch.php 5 years ago Youtube.php 3 years ago index.html 7 years ago
Youtube.php
929 lines
1 <?php
2
3 /**
4 * Youtube.php
5 *
6 * @package Embera
7 * @author Michael Pratt <yo@michael-pratt.com>
8 * @link http://www.michael-pratt.com/
9 *
10 * For the full copyright and license information, please view the LICENSE
11 * file that was distributed with this source code.
12 */
13
14 namespace EmbedPress\Providers;
15
16 use Embera\Provider\ProviderAdapter;
17 use Embera\Provider\ProviderInterface;
18 use Embera\Url;
19
20 /**
21 * youtube.com Provider
22 * @link https://youtube.com
23 * @link https://youtube-eng.googleblog.com/2009/10/oembed-support_9.html
24 */
25
26
27 class Youtube extends ProviderAdapter implements ProviderInterface {
28 /** inline {@inheritdoc} */
29 protected $shouldSendRequest = false;
30 public static $curltimeout = 30;
31 /** inline {@inheritdoc} */
32 protected $endpoint = 'https://www.youtube.com/oembed?format=json&scheme=https';
33 protected static $channel_endpoint = 'https://www.googleapis.com/youtube/v3/';
34 /** @var array Array with allowed params for the current Provider */
35 protected $allowedParams = [ 'maxwidth', 'maxheight', 'pagesize', 'thumbnail', 'gallery', 'hideprivate', 'columns', 'ispagination', 'gapbetweenvideos' ];
36
37 /** inline {@inheritdoc} */
38 protected static $hosts = [
39 'm.youtube.com', 'youtube.com', 'youtu.be',
40 ];
41
42 /** inline {@inheritdoc} */
43 protected $httpsSupport = true;
44
45 public function getAllowedParams(){
46 return $this->allowedParams;
47 }
48
49 /** inline {@inheritdoc} */
50 public function validateUrl(Url $url) {
51 return (bool) (preg_match('~\/channel\/|\/c\/|\/user\/|\/@\w+|(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(\w+)[^?\/]*$~i', (string) $url));
52 }
53
54 public function validateTYLiveUrl($url) {
55 return (bool) (preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/(?:channel|c|user)\/\w+\/live|@\w+\/live)~i', (string) $url));
56 }
57
58 /** inline {@inheritdoc} */
59 public function normalizeUrl(Url $url) {
60 return $url;
61 }
62
63 public function isChannel($url = null) {
64 if (empty($url)) {
65 $url = $this->url;
66 }
67 $channel = $this->getChannel($url);
68 return !empty($channel['id']);
69 }
70
71 public function getChannel($url = null) {
72 if (empty($url)) {
73 $url = $this->url;
74 }
75 preg_match('~\/(channel|c|user)\/(.+)~i', (string) $url, $matches);
76 if(empty($matches[1])){
77 preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(\w+)[^?\/]*$~i', (string) $url, $matches);
78 if(!empty($matches[1])){
79 return [
80 "type" => 'user',
81 "id" => $matches[1],
82 ];
83 }
84 }
85 if(empty($matches[1])){
86 preg_match('~\/(@)(\w+)~i', (string) $url, $matches);
87 if(!empty($matches[1])){
88 return [
89 "type" => 'user',
90 "id" => $matches[2],
91 ];
92 }
93 }
94 return [
95 "type" => isset($matches[1]) ? $matches[1] : '',
96 "id" => isset($matches[2]) ? $matches[2] : '',
97 ];
98 }
99
100 /** inline {@inheritdoc} */
101 public function getEndpoint() {
102 if ($this->isChannel()) {
103 $apiEndpoint = 'https://www.googleapis.com/youtube/v3/channels';
104 return $apiEndpoint;
105 }
106 return (string) $this->endpoint;
107 }
108
109 protected static function get_api_key() {
110 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
111 return !empty($settings['api_key']) ? $settings['api_key'] : '';
112 }
113
114 protected static function get_pagesize() {
115 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
116 return !empty($settings['pagesize']) ? $settings['pagesize'] : '';
117 }
118
119 /** inline {@inheritdoc} */
120 public function getParams() {
121 $params = parent::getParams();
122 if ($this->isChannel() && self::get_api_key()) {
123 $channel = $this->getChannel();
124 $params['part'] = 'contentDetails,snippet';
125 $params['key'] = self::get_api_key();
126 if ($channel['type'] == 'c') {
127 $params['forUsername'] = $channel['id'];
128 } else {
129 $params['id'] = $channel['id'];
130 }
131 unset($params['url']);
132 }
133 return $params;
134 }
135
136 /**
137 * Builds a valid Oembed query string based on the given parameters,
138 * Since this method uses the http_build_query function, there is no
139 * need to pass urlencoded parameters, http_build_query already does
140 * this for us.
141 *
142 * @param string $endpoint The Url to the Oembed endpoint
143 * @param array $params Parameters for the query string
144 * @return string
145 */
146
147 protected function constructUrl($endpoint, array $params = array())
148 {
149 $endpoint = self::$channel_endpoint . $endpoint;
150
151 return $endpoint . ((strpos($endpoint, '?') === false) ? '?' : '&') . http_build_query(array_filter($params));
152 }
153
154 public function getStaticResponse() {
155 $results = [
156 "title" => "",
157 "type" => "video",
158 'provider_name' => $this->getProviderName(),
159 "provider_url" => "https://www.youtube.com/",
160 'html' => '',
161 ];
162
163 $params = $this->getParams();
164
165 if (preg_match("/^https?:\/\/(?:www\.)?youtube\.com\/channel\/([\w-]+)\/live$/", $this->url, $matches) || $this->validateTYLiveUrl($this->url)) {
166
167 if(!empty($matches[1])){
168 $channelId = $matches[1];
169 }
170
171
172 if(!empty($this->get_youtube_handler($this->url))){
173 if(!empty($this->get_channel_id_by_handler($this->get_youtube_handler($this->url)))){
174 $channelId = $this->get_channel_id_by_handler($this->get_youtube_handler($this->url));
175 }
176 }
177
178 $embedUrl = 'https://www.youtube.com/embed/live_stream?channel='.$channelId.'&feature=oembed';
179
180 $attr = [];
181 $attr[] = 'width="'.$params['maxheight'].'"';
182 $attr[] = 'height="'.$params['maxheight'].'";';
183 $attr[] = 'src="' . $embedUrl . '"';
184 $attr[] = 'frameborder="0"';
185 $attr[] = 'allow="accelerometer; encrypted-media; gyroscope; picture-in-picture"';
186 $attr[] = 'allowfullscreen';
187
188 $results['html'] = '<iframe ' . implode(' ', $attr) . '></iframe>';
189 }
190 else if($this->isChannel()){
191 $channel = $this->getChannelGallery();
192 $results = array_merge($results, $channel);
193 }
194 return $results;
195 }
196
197 public function getChannelPlaylist(){
198 $result = [
199 "playlistID" => '',
200 "title" => '',
201 ];
202 $channel = $this->getChannel();
203 $channel_url = $this->constructUrl('channels', $this->getParams());
204 $transient_key = 'ep_embed_youtube_channel_playlist_id_' . md5($channel_url);
205 $jsonResult = get_transient($transient_key);
206
207 if(!empty($jsonResult)){
208 return $jsonResult;
209 }
210
211 if($channel['type'] == 'user' || $channel['type'] == 'c'){
212 $this->getChannelIDbyUsername();
213 $channel_url = $this->constructUrl('channels', $this->getParams());
214 }
215
216 if (empty(self::get_api_key())) {
217 $result['error'] = true;
218 $result['html'] = self::get_api_key_error_message();
219 return $result;
220 }
221
222 $apiResult = wp_remote_get($channel_url, array('timeout' => self::$curltimeout));
223 if (is_wp_error($apiResult)) {
224 $result['error'] = true;
225 $result['html'] = self::clean_api_error_html($apiResult->get_error_message(), true);
226 set_transient($transient_key, $result, 10);
227 return $result;
228 }
229 $jsonResult = json_decode($apiResult['body']);
230
231
232 if (isset($jsonResult->error)) {
233 $result['error'] = true;
234 if (isset($jsonResult->error->message)) {
235 $result['html'] = self::clean_api_error_html($jsonResult->error->message, true);
236 }
237 else{
238 $result['html'] = self::clean_api_error_html(__('Sorry, there may be an issue with your YouTube API key.', 'embedpress'));
239 }
240 set_transient($transient_key, $result, MINUTE_IN_SECONDS);
241 return $result;
242 }
243 elseif(!empty($jsonResult->items[0]->contentDetails->relatedPlaylists->uploads)){
244 $result['playlistID'] = $jsonResult->items[0]->contentDetails->relatedPlaylists->uploads;
245 $result['title'] = isset($jsonResult->items[0]->snippet->title) ? $jsonResult->items[0]->snippet->title : '';
246 set_transient($transient_key, $result, DAY_IN_SECONDS);
247 }
248
249 return $result;
250 }
251
252 public function get_youtube_handler($url){
253 preg_match('/^https:\/\/www.youtube.com\/@(.+)\/live$/i', $url, $matches);
254
255 $handle_name = '';
256 if(!empty($matches[1])){
257 $handle_name = $matches[1];
258 }
259
260 return $handle_name;
261 }
262
263 public function getChannelIDbyUsername(){
264 $url = $this->getUrl();
265 $apiResult = wp_remote_get($url, array('timeout' => self::$curltimeout));
266
267 if (!is_wp_error($apiResult)) {
268 $channel_html = $apiResult['body'];
269 preg_match("/<meta\s+itemprop=[\"']channelId[\"']\s+content=[\"'](.*?)[\"']\/?>/", $channel_html, $matches);
270 if(!empty($matches[1])){
271 $url = "https://www.youtube.com/channel/{$matches[1]}";
272 $this->url = $this->normalizeUrl(new Url($url));
273 }
274 }
275 }
276
277 public function get_channel_id_by_handler($handler){
278 $api_key = self::get_api_key();
279 $username = $handler;
280
281 // Check if the transient exists
282 $transient_name = 'channel_id_' . $handler;
283 $channel_id = get_transient( $transient_name );
284 if ( $channel_id ) {
285 // If the transient exists, return the channel ID
286 return $channel_id;
287 }
288
289 $url = "https://www.googleapis.com/youtube/v3/search?part=id&type=channel&q={$username}&key={$api_key}";
290
291 $response = wp_remote_get($url);
292 if ( is_wp_error( $response ) ) {
293 return false;
294 }
295
296 $json_response = json_decode(wp_remote_retrieve_body($response), true);
297
298 if(isset($json_response['error'])) {
299 return false;
300 } else {
301 $channel_id = $json_response['items'][0]['id']['channelId'];
302
303 // Set the transient for 1 day (86400 seconds)
304 set_transient( $transient_name, $channel_id, 86400 );
305
306 return $channel_id;
307 }
308 }
309
310 /** inline {@inheritdoc} */
311 public function getChannelGallery() {
312 $response = [];
313 $channel = $this->getChannelPlaylist();
314 if(!empty($channel['error'])){
315 return $channel;
316 }
317 if (!empty($channel["playlistID"])) {
318 $params = $this->getParams();
319 $the_playlist_id = $channel["playlistID"];
320 $rel = 'https://www.youtube.com/embed?listType=playlist&list=' . esc_attr($the_playlist_id);
321 $title = $channel['title'];
322 $main_iframe = "";
323 $gallery_args = [
324 'playlistId' => $the_playlist_id,
325 ];
326 if(!empty($params['pagesize'])){
327 $gallery_args['pagesize'] = $params['pagesize'];
328 }
329 $gallery = self::get_gallery_page($gallery_args);
330
331 if (!empty($gallery->first_vid)) {
332 $rel = "https://www.youtube.com/embed/{$gallery->first_vid}?feature=oembed";
333 $main_iframe = "<div class='ep-first-video'><iframe width='{$params['maxwidth']}' height='{$params['maxheight']}' src='$rel' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen title='{$title}'></iframe></div>";
334 }
335 if($gallery->html && $this->validateTYLiveUrl($this->getUrl())){
336 $styles = self::styles($params, $this->getUrl());
337 return [
338 "title" => $title,
339 "html" => "<div class='ep-player-wrap'>$main_iframe $styles</div>",
340 ];
341 }
342 if($gallery->html){
343 $styles = self::styles($params, $this->getUrl());
344 return [
345 "title" => $title,
346 "html" => "<div class='ep-player-wrap'>$main_iframe {$gallery->html} $styles</div>",
347 ];
348 }
349 }
350 elseif ($this->isChannel() && empty(self::get_api_key()) && current_user_can('manage_options')) {
351 return [
352 "html" => "<div class='ep-player-wrap'>" . __('Please enter your YouTube API key to embed YouTube Channel.', 'embedpress') . "</div>",
353 ];
354 }
355
356 return $response;
357 }
358
359 /**
360 * Undocumented function
361 *
362 * @param array $options
363 * @return object
364 */
365 public static function get_gallery_page($options) {
366 $nextPageToken = '';
367 $prevPageToken = '';
368 $gallobj = new \stdClass();
369 $options = wp_parse_args($options, [
370 'playlistId' => '',
371 'pageToken' => '',
372 'pagesize' => self::get_pagesize() ? self::get_pagesize() : 6,
373 'currentpage' => '',
374 'columns' => 3,
375 'thumbnail' => 'medium',
376 'gallery' => true,
377 'autonext' => true,
378 'thumbplay' => true,
379 'apiKey' => self::get_api_key(),
380 'hideprivate' => '',
381 ]);
382 $options['pagesize'] = $options['pagesize'] > 50 ? 50 : $options['pagesize'];
383 $options['pagesize'] = $options['pagesize'] < 1 ? 1 : $options['pagesize'];
384
385 if (empty($options['apiKey'])) {
386 $gallobj->html = self::get_api_key_error_message();
387 return $gallobj;
388 }
389
390 $apiEndpoint = 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet,status&playlistId=' . $options['playlistId']
391 . '&maxResults=' . $options['pagesize']
392 . '&key=' . $options['apiKey'];
393 if ($options['pageToken'] != null) {
394 $apiEndpoint .= '&pageToken=' . $options['pageToken'];
395 }
396
397 $transient_key = 'ep_embed_youtube_channel_' . md5($apiEndpoint);
398 $gallobj->transient_key = $transient_key;
399 $jsonResult = get_transient($transient_key);
400 if (empty($jsonResult)) {
401 $apiResult = wp_remote_get($apiEndpoint, array('timeout' => self::$curltimeout));
402 if (is_wp_error($apiResult)) {
403 $gallobj->html = self::clean_api_error_html($apiResult->get_error_message(), true);
404 return $gallobj;
405 }
406 $jsonResult = json_decode($apiResult['body']);
407 if (empty($jsonResult->error)) {
408 set_transient($transient_key, $jsonResult, MINUTE_IN_SECONDS * 20);
409 }
410 else{
411 set_transient($transient_key, $jsonResult, 10);
412 }
413 }
414
415
416 if (isset($jsonResult->error)) {
417 if(!empty($jsonResult->error->errors[0]->reason) && $jsonResult->error->errors[0]->reason == 'playlistNotFound'){
418 $gallobj->html = self::clean_api_error_html(__('There is nothing on the playlist.', 'embedpress'));
419 return $gallobj;
420 }
421 if (isset($jsonResult->error->message)) {
422 $gallobj->html = self::clean_api_error_html($jsonResult->error->message);
423 return $gallobj;
424 }
425 $gallobj->html = self::clean_api_error_html(__('Sorry, there may be an issue with your YouTube API key.', 'embedpress'));
426 return $gallobj;
427 }
428
429
430
431 $resultsPerPage = $jsonResult->pageInfo->resultsPerPage;
432 $totalResults = $jsonResult->pageInfo->totalResults;
433 $totalPages = ceil($totalResults / $resultsPerPage);
434 if (isset($jsonResult->nextPageToken)) {
435 $nextPageToken = $jsonResult->nextPageToken;
436 }
437
438 if (isset($jsonResult->prevPageToken)) {
439 $prevPageToken = $jsonResult->prevPageToken;
440 }
441
442
443 if (!empty($jsonResult->items) && is_array($jsonResult->items)) :
444 if($options['gallery'] === "false"){
445 $gallobj->html = "";
446 if(count($jsonResult->items) === 1){
447 $gallobj->first_vid = self::get_id($jsonResult->items[0]);
448 }
449 return $gallobj;
450 }
451
452 if(count($jsonResult->items) === 1 && empty($nextPageToken) && empty($prevPageToken)){
453 $gallobj->first_vid = self::get_id($jsonResult->items[0]);
454 $gallobj->html = "";
455 return $gallobj;
456 }
457
458 if (strpos($options['playlistId'], 'UU') === 0) {
459 // sort only channels
460 usort($jsonResult->items, array(get_class(), 'compare_vid_date')); // sorts in place
461 }
462
463 ob_start();
464 ?>
465 <div class="ep-youtube__content__block" data-unique-id="<?php echo wp_rand(); ?>">
466 <div class="youtube__content__body">
467 <div class="content__wrap">
468 <?php foreach ($jsonResult->items as $item) : ?>
469 <?php
470 $privacyStatus = isset($item->status->privacyStatus) ? $item->status->privacyStatus : null;
471 $thumbnail = self::get_thumbnail_url($item, $options['thumbnail'], $privacyStatus);
472 $vid = self::get_id($item);
473 if (empty($gallobj->first_vid)) {
474 $gallobj->first_vid = $vid;
475 }
476 if ($privacyStatus == 'private' && $options['hideprivate']) {
477 continue;
478 }
479 ?>
480 <div class="item" data-vid="<?php echo $vid; ?>">
481 <div class="thumb" style="background: <?php echo "url({$thumbnail}) no-repeat center"; ?>">
482 <div class="play-icon">
483 <img src="<?php echo EMBEDPRESS_URL_ASSETS . 'images/youtube/youtube-play.png'; ?>" alt="">
484 </div>
485 </div>
486 <div class="body">
487 <p><?php echo $item->snippet->title; ?></p>
488 </div>
489 </div>
490
491 <?php endforeach; ?>
492 <div class="item" style="height: 0"></div>
493 </div>
494
495
496 <?php if ($totalPages > 1) : ?>
497 <div class="ep-youtube__content__pagination <?php echo (empty($prevPageToken) && empty($nextPageToken)) ? ' hide ' : ''; ?>">
498 <div
499 class="ep-prev" <?php echo empty($prevPageToken) ? ' style="display:none" ' : ''; ?>
500 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
501 data-pagetoken="<?php echo esc_attr($prevPageToken) ?>"
502 data-pagesize="<?php echo intval($options['pagesize']) ?>"
503 >
504 <span><?php _e("Prev", "embedpress"); ?></span>
505 </div>
506 <div class="is_desktop_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
507 <?php
508
509 $numOfPages = $totalPages;
510 $renderedEllipses = false;
511
512 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
513
514 for($i = 1; $i<=$numOfPages; $i++)
515 {
516 //render pages 1 - 3
517 if($i < 4) {
518 //render link
519 $is_current = $i == (int)$currentPage? "active__current_page" : "";
520
521 echo wp_kses_post("<span class='page-number $is_current' data-page='$i'>$i</span>");
522
523 }
524
525 //render current page number
526 else if($i == (int)$currentPage) {
527 //render link
528 echo wp_kses_post('<span class="page-number active__current_page" data-page="'.$i.'">'.$i.'</span>');
529 //reset ellipses
530 $renderedEllipses = false;
531 }
532
533 //last page number
534 else if ($i >= $numOfPages - 1) {
535 //render link
536 echo wp_kses_post('<span class="page-number" data-page="'.$i.'">'.$i.'</span>');
537 }
538
539 //make sure you only do this once per ellipses group
540 else {
541 if (!$renderedEllipses){
542 print("...");
543 $renderedEllipses = true;
544 }
545 }
546 }
547 ?>
548
549 </div>
550
551 <div class="is_mobile_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
552 <?php
553
554 $numOfPages = $totalPages;
555 $renderedEllipses = false;
556
557 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
558
559 for($i = 1; $i<=$numOfPages; $i++)
560 {
561
562 //render current page number
563 if($i == (int)$currentPage) {
564 //render link
565 echo wp_kses_post('<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
566 //reset ellipses
567 $renderedEllipses = false;
568 }
569
570 //last page number
571 else if ($i >= $numOfPages ) {
572 //render link
573 echo wp_kses_post('...<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
574 }
575 }
576 ?>
577
578 </div>
579
580
581 <div
582 class="ep-next " <?php echo empty($nextPageToken) ? ' style="display:none" ' : ''; ?>
583 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
584 data-pagetoken="<?php echo esc_attr($nextPageToken) ?>"
585 data-pagesize="<?php echo intval($options['pagesize']) ?>"
586 >
587 <span><?php _e("Next ", "embedpress"); ?> </span>
588 </div>
589 </div>
590 <?php endif; ?>
591
592 <div class="ep-loader-wrap">
593 <div class="ep-loader"><img alt="loading" src="<?php echo EMBEDPRESS_URL_ASSETS . 'images/youtube/spin.gif'; ?>"></div>
594 </div>
595
596 </div>
597 </div>
598 <?php
599 $gallobj->html = ob_get_clean();
600 else:
601 $gallobj->html = self::clean_api_error_html(__("There is nothing on the playlist.", 'embedpress'));
602 endif;
603
604 return $gallobj;
605 }
606
607 public static function get_api_key_error_message(){
608 return '<div>' . sprintf(__("EmbedPress: Please enter your YouTube API key at <a class='ep-link' href='%s' target='_blank' style='color: #5b4e96; text-decoration: none'>EmbedPress > Platforms > YouTube</a> to embed YouTube Channel.", "embedpress"), admin_url('?page=embedpress&page_type=youtube#api_key')) . '</div>';
609 }
610
611 public static function get_id($item){
612 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
613 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
614 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
615 return $vid;
616 }
617 public static function get_thumbnail_url($item, $quality, $privacyStatus) {
618 $url = "";
619 if ($privacyStatus == 'private') {
620 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/private.png';
621 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
622 $url = $item->snippet->thumbnails->{$quality}->url;
623 } elseif (isset($item->snippet->thumbnails->medium->url)) {
624 $url = $item->snippet->thumbnails->medium->url;
625 } elseif (isset($item->snippet->thumbnails->default->url)) {
626 $url = $item->snippet->thumbnails->default->url;
627 } elseif (isset($item->snippet->thumbnails->high->url)) {
628 $url = $item->snippet->thumbnails->high->url;
629 } else {
630 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/deleted-video-thumb.png';
631 }
632 return $url;
633 }
634
635 public static function compare_vid_date($a, $b) {
636 if ($a->snippet->publishedAt == $b->snippet->publishedAt) {
637 return 0;
638 }
639 return ($a->snippet->publishedAt > $b->snippet->publishedAt) ? -1 : 1;
640 }
641
642 public static function clean_api_error($raw_message) {
643 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
644 }
645
646 public static function clean_api_error_html($raw_message) {
647 $clean_html = '';
648 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
649 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . self::clean_api_error($raw_message) . '</div>';
650 }
651 return $clean_html;
652 }
653
654 /** inline {@inheritdoc} */
655 public function getFakeResponse() {
656 preg_match('~v=([a-z0-9_\-]+)~i', (string) $this->url, $matches);
657
658 $embedUrl = 'https://www.youtube.com/embed/' . $matches['1'] . '?feature=oembed';
659
660 $attr = [];
661 $attr[] = 'width="{width}"';
662 $attr[] = 'height="{height}"';
663 $attr[] = 'src="' . $embedUrl . '"';
664 $attr[] = 'frameborder="0"';
665 $attr[] = 'allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"';
666 $attr[] = 'allowfullscreen';
667
668 return [
669 'type' => 'video',
670 'provider_name' => 'Youtube',
671 'provider_url' => 'https://www.youtube.com',
672 'title' => 'Unknown title',
673 'html' => '<iframe ' . implode(' ', $attr) . '></iframe>',
674 ];
675 }
676
677 // public static $num = 0;
678
679
680
681 public static $x = 0;
682
683 public static function styles($params, $url){
684
685 $uniqid = '.ose-youtube.ose-uid-'.md5($url);
686
687 ob_start();
688 ?>
689 <style>
690 html {
691 scroll-behavior: smooth;
692 }
693 .ep-player-wrap .hide {
694 display: none;
695 }
696
697 .ep-gdrp-content {
698 background: #222;
699 padding: 50px 30px;
700 color: #fff;
701 }
702
703 .ep-gdrp-content a {
704 color: #fff;
705 }
706
707 .ep-youtube__content__pagination {
708 display: flex;
709 justify-content: center;
710 align-items: center;
711 margin-top: 30px;
712 gap: 10px;
713 }
714 .ep-loader-wrap {
715 margin-top: 30px;
716 display: flex;
717 justify-content: center;
718 }
719
720 .ep-youtube__content__pagination .ep-prev,
721 .ep-youtube__content__pagination .ep-next {
722 cursor: pointer;
723 border: 1px solid rgba(0, 0, 0, .1);
724 border-radius: 30px;
725 padding: 0 20px;
726 height: 40px;
727 transition: .3s;
728 display: flex;
729 align-items: center;
730 }
731 .ep-youtube__content__pagination .ep-prev:hover,
732 .ep-youtube__content__pagination .ep-next:hover{
733 background-color: #5B4E96;
734 color: #fff;
735 }
736 .ep-youtube__content__pagination .ep-page-numbers {
737 display: flex;
738 align-items: center;
739 gap: 10px;
740 flex-wrap: wrap;
741 }
742 .ep-youtube__content__pagination .ep-page-numbers > span {
743 border: 1px solid rgba(0, 0, 0, .1);
744 border-radius: 30px;
745 display: inline-block;
746 width: 45px;
747 height: 45px;
748 display: flex;
749 align-items: center;
750 justify-content: center;
751 }
752 .active__current_page{
753 background: #5B4E96;
754 color: #fff;
755 }
756
757 .ep-youtube__content__block .youtube__content__body .content__wrap {
758 margin-top: 30px;
759 display: grid;
760 grid-template-columns:repeat(auto-fit, minmax(250px, 1fr));
761 gap: 30px;
762 }
763
764 .ep-youtube__content__block .item {
765 cursor: pointer;
766 white-space: initial;
767 }
768
769 .ep-youtube__content__block .item:hover .thumb .play-icon {
770 opacity: 1;
771 top: 50%;
772 }
773
774 .ep-youtube__content__block .item:hover .thumb:after {
775 opacity: .4;
776 z-index: 0;
777 }
778
779 .ep-youtube__content__block .thumb {
780 padding-top: 56.25%;
781 margin-bottom: 5px;
782 position: relative;
783 background: #222;
784 background-size: contain !important;
785 }
786
787 .ep-youtube__content__block .thumb:after {
788 position: absolute;
789 top: 0;
790 left: 0;
791 height: 100%;
792 width: 100%;
793 content: '';
794 background: #000;
795 opacity: 0;
796 transition: opacity .3s ease;
797 }
798
799 .ep-youtube__content__block .thumb:before {
800 position: absolute;
801 top: 0;
802 left: 0;
803 height: 100%;
804 width: 100%;
805 content: '';
806 background: #222;
807 z-index: -1;
808 }
809
810 .ep-youtube__content__block .thumb img {
811 width: 100%;
812 height: 100%;
813 object-fit: cover;
814 }
815
816 .ep-youtube__content__block .thumb .play-icon {
817 width: 50px;
818 height: auto;
819 position: absolute;
820 top: 40%;
821 left: 50%;
822 transform: translate(-50%, -50%);
823 opacity: 0;
824 transition: all .3s ease;
825 z-index: 2;
826 }
827
828 .ep-youtube__content__block .thumb .play-icon img {
829 width: 100;
830 }
831
832 .ep-youtube__content__block .body p {
833 margin-bottom: 0;
834 font-size: 15px;
835 text-align: left;
836 line-height: 1.5;
837 font-weight: 400;
838 }
839 .ep-youtube__content__block.loading .ep-youtube__content__pagination {
840 display: none;
841 }
842
843 .ep-youtube__content__block .ep-loader {
844 display: none;
845 }
846
847 .ep-youtube__content__block.loading .ep-loader {
848 display: block;
849 }
850 .ep-loader img {
851 width: 20px;
852 }
853 .is_mobile_device{
854 display: none!important;
855 }
856
857
858 .is_mobile_devic.ep-page-numbers {
859 gap: 5px;
860 }
861
862 @media only screen and (max-width: 480px) {
863 .is_desktop_device{
864 display: none!important;
865 }
866 .ep-youtube__content__pagination .ep-page-numbers > span {
867 width: 35px;
868 height: 35px;
869 }
870 .ep-youtube__content__pagination .ep-prev, .ep-youtube__content__pagination .ep-next{
871 height: 35px;
872 }
873 .is_mobile_device{
874 display: flex!important;;
875 }
876 .ep-youtube__content__pagination .ep-page-numbers {
877 gap: 5px;
878 }
879 }
880 <?php
881 $attributes_data = $params;
882
883 $is_pagination = 'flex';
884
885 $gap = '30';
886 $columns = '';
887
888 if (isset($attributes_data['ispagination']) && $attributes_data['ispagination']) {
889 $is_pagination = 'none';
890 }
891 if(isset($attributes_data['gapbetweenvideos'])){
892 $gap = $attributes_data['gapbetweenvideos'];
893 }
894 if(isset($attributes_data['columns'])){
895 $columns = $attributes_data['columns'];
896 }
897
898
899 if(!empty($columns) && (int) $columns > 0){
900 $repeatCol = 'repeat(auto-fit, minmax('.esc_html('calc('.(100 / (int) $columns).'% - '.$gap.'px)').', 1fr))';
901 }
902 else{
903 $repeatCol = 'repeat(auto-fit, minmax(calc(250px - '.$gap.'px), 1fr))';
904 }
905
906 ?>
907 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap {
908 gap: <?php echo esc_html($gap); ?>px !important;
909 margin-top: <?php echo esc_html($gap); ?>px !important;
910 grid-template-columns: <?php echo $repeatCol; ?>;
911 }
912 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .ep-youtube__content__pagination {
913 display: <?php echo esc_html($is_pagination); ?>!important;
914 }
915
916 <?php
917 if($is_pagination){
918 echo esc_attr($uniqid) ?> {
919 height: 100%!important;
920 }
921 <?php
922 }
923 ?>
924 </style>
925 <?php
926 return ob_get_clean();
927 }
928 }
929