PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.0.5
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.0.5
4.6.0 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 2 years ago Calendly.php 2 years ago Giphy.php 2 years ago GitHub.php 3 years ago GoogleDocs.php 2 years ago GoogleDrive.php 2 years ago GoogleMaps.php 2 years ago Gumroad.php 2 years ago InstagramFeed.php 2 years ago LinkedIn.php 2 years ago NRKRadio.php 2 years ago OpenSea.php 2 years ago SelfHosted.php 2 years ago TikTok.php 2 years ago Twitch.php 2 years ago Wrapper.php 3 years ago X.php 2 years ago Youtube.php 2 years ago index.html 7 years ago
Youtube.php
950 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 $channelId = 'unknown_id'; // temporarily assigned a placeholder value for demonstration purposes
73
74 if (empty($url)) {
75 $url = $this->url;
76 }
77 preg_match('~\/(channel|c|user)\/(.+)~i', (string) $url, $matches);
78 if(empty($matches[1])){
79 preg_match('~(?:https?:\/\/)?(?:www\.)?(?:youtube.com\/)(\w+)[^?\/]*$~i', (string) $url, $matches);
80 if(!empty($matches[1])){
81 return [
82 "type" => 'user',
83 "id" => $matches[1],
84 ];
85 }
86 }
87
88 // $channel___id = $this->get_channel_id_by_handler('adin');
89
90 // echo 'akash';
91 // print_r($channel___id); die;
92
93 if(empty($matches[1])){
94 preg_match('~\/(@)(\w+)~i', (string) $url, $matches);
95 if(!empty($matches[1])){
96 if(!empty($this->get_youtube_handler($this->url))){
97 if(!empty($this->get_channel_id_by_handler($this->get_youtube_handler($this->url)))){
98 $channelId = $this->get_channel_id_by_handler($this->get_youtube_handler($this->url));
99 }
100 }
101 return [
102 "type" => 'user',
103 "id" => $channelId,
104 ];
105 }
106 }
107 return [
108 "type" => isset($matches[1]) ? $matches[1] : '',
109 "id" => isset($matches[2]) ? $matches[2] : '',
110 ];
111 }
112
113 /** inline {@inheritdoc} */
114 public function getEndpoint() {
115 if ($this->isChannel()) {
116 $apiEndpoint = 'https://www.googleapis.com/youtube/v3/channels';
117 return $apiEndpoint;
118 }
119 return (string) $this->endpoint;
120 }
121
122 protected static function get_api_key() {
123 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
124 return !empty($settings['api_key']) ? $settings['api_key'] : '';
125 }
126
127 protected static function get_pagesize() {
128 $settings = (array) get_option(EMBEDPRESS_PLG_NAME . ':youtube', []);
129 return !empty($settings['pagesize']) ? $settings['pagesize'] : '';
130 }
131
132 /** inline {@inheritdoc} */
133 public function getParams() {
134 $params = parent::getParams();
135 if ($this->isChannel() && self::get_api_key()) {
136 $channel = $this->getChannel();
137 $params['part'] = 'contentDetails,snippet';
138 $params['key'] = self::get_api_key();
139 if ($channel['type'] == 'c') {
140 $params['forUsername'] = $channel['id'];
141 } else {
142 $params['id'] = $channel['id'];
143 }
144 unset($params['url']);
145 }
146 return $params;
147 }
148
149 /**
150 * Builds a valid Oembed query string based on the given parameters,
151 * Since this method uses the http_build_query function, there is no
152 * need to pass urlencoded parameters, http_build_query already does
153 * this for us.
154 *
155 * @param string $endpoint The Url to the Oembed endpoint
156 * @param array $params Parameters for the query string
157 * @return string
158 */
159
160 protected function constructUrl($endpoint, array $params = array())
161 {
162 $endpoint = self::$channel_endpoint . $endpoint;
163
164 return $endpoint . ((strpos($endpoint, '?') === false) ? '?' : '&') . http_build_query(array_filter($params));
165 }
166
167 public function getStaticResponse() {
168 $results = [
169 "title" => "",
170 "type" => "video",
171 'provider_name' => $this->getProviderName(),
172 "provider_url" => "https://www.youtube.com/",
173 'html' => '',
174 ];
175
176 $params = $this->getParams();
177
178 if (preg_match("/^https?:\/\/(?:www\.)?youtube\.com\/channel\/([\w-]+)\/live$/", $this->url, $matches) || $this->validateTYLiveUrl($this->url)) {
179
180 if(!empty($matches[1])){
181 $channelId = $matches[1];
182 }
183
184 if(!empty($this->get_youtube_handler($this->url))){
185 if(!empty($this->get_channel_id_by_handler($this->get_youtube_handler($this->url)))){
186 $channelId = $this->get_channel_id_by_handler($this->get_youtube_handler($this->url));
187 }
188 }
189
190
191
192 $embedUrl = 'https://www.youtube.com/embed/live_stream?channel='.$channelId.'&feature=oembed';
193
194 $attr = [];
195 $attr[] = 'width="'.esc_attr($params['maxheight']).'"';
196 $attr[] = 'height="'.esc_attr($params['maxheight']).'";';
197 $attr[] = 'src="' . esc_url($embedUrl) . '"';
198 $attr[] = 'frameborder="0"';
199 $attr[] = 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"';
200 $attr[] = 'allowfullscreen';
201
202 $results['html'] = '<iframe ' . implode(' ', $attr) . '></iframe>';
203 }
204 else if($this->isChannel()){
205 $channel = $this->getChannelGallery();
206 $results = array_merge($results, $channel);
207 }
208 return $results;
209 }
210
211 public function getChannelPlaylist(){
212 $result = [
213 "playlistID" => '',
214 "title" => '',
215 ];
216 $channel = $this->getChannel();
217 $channel_url = $this->constructUrl('channels', $this->getParams());
218 $transient_key = 'ep_embed_youtube_channel_playlist_id_' . md5($channel_url);
219 $jsonResult = get_transient($transient_key);
220
221 if(!empty($jsonResult)){
222 return $jsonResult;
223 }
224
225 if($channel['type'] == 'user' || $channel['type'] == 'c'){
226 $this->getChannelIDbyUsername();
227 $channel_url = $this->constructUrl('channels', $this->getParams());
228 }
229
230 if (empty(self::get_api_key())) {
231 $result['error'] = true;
232 $result['html'] = self::get_api_key_error_message();
233 return $result;
234 }
235
236 $apiResult = wp_remote_get($channel_url, array('timeout' => self::$curltimeout));
237 if (is_wp_error($apiResult)) {
238 $result['error'] = true;
239 $result['html'] = self::clean_api_error_html($apiResult->get_error_message(), true);
240 set_transient($transient_key, $result, 10);
241 return $result;
242 }
243 $jsonResult = json_decode($apiResult['body']);
244
245
246 if (isset($jsonResult->error)) {
247 $result['error'] = true;
248 if (isset($jsonResult->error->message)) {
249 $result['html'] = self::clean_api_error_html($jsonResult->error->message, true);
250 }
251 else{
252 $result['html'] = self::clean_api_error_html(__('Sorry, there may be an issue with your YouTube API key.', 'embedpress'));
253 }
254 set_transient($transient_key, $result, MINUTE_IN_SECONDS);
255 return $result;
256 }
257 elseif(!empty($jsonResult->items[0]->contentDetails->relatedPlaylists->uploads)){
258 $result['playlistID'] = $jsonResult->items[0]->contentDetails->relatedPlaylists->uploads;
259 $result['title'] = isset($jsonResult->items[0]->snippet->title) ? $jsonResult->items[0]->snippet->title : '';
260 set_transient($transient_key, $result, DAY_IN_SECONDS);
261 }
262
263 return $result;
264 }
265
266 public function get_youtube_handler($url){
267 // preg_match('/^https:\/\/www.youtube.com\/@(.+)\/live$/i', $url, $matches);
268 preg_match('/^https:\/\/www.youtube.com\/@([^\/?]+)/i', $url, $matches);
269
270
271 $handle_name = '';
272 if(!empty($matches[1])){
273 $handle_name = $matches[1];
274 }
275
276 return $handle_name;
277 }
278
279 public function getChannelIDbyUsername(){
280 $url = $this->getUrl();
281 $apiResult = wp_remote_get($url, array('timeout' => self::$curltimeout));
282
283 if (!is_wp_error($apiResult)) {
284 $channel_html = $apiResult['body'];
285 preg_match("/<meta\s+itemprop=[\"']channelId[\"']\s+content=[\"'](.*?)[\"']\/?>/", $channel_html, $matches);
286 if(!empty($matches[1])){
287 $url = "https://www.youtube.com/channel/{$matches[1]}";
288 $this->url = $this->normalizeUrl(new Url($url));
289 }
290 }
291 }
292
293
294 public function get_channel_id_by_handler($handle)
295 {
296 $transient_key = 'channel_id_' . md5($handle);
297 $channel_id = get_transient($transient_key);
298
299 if (false === $channel_id) {
300 $ch = curl_init();
301
302 $channel_handle = "https://www.youtube.com/@{$handle}";
303
304 curl_setopt($ch, CURLOPT_URL, $channel_handle);
305 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
306
307 $response = curl_exec($ch);
308
309 if (curl_errno($ch)) {
310 return 'cURL error: ' . curl_error($ch);
311 }
312
313 curl_close($ch);
314
315 $pattern = '/(<link rel="canonical" href="https:\/\/www\.youtube\.com\/channel\/)(.{1,50})(">)/';
316 if (preg_match($pattern, $response, $matches)) {
317 $channel_id = $matches[2];
318 set_transient($transient_key, $channel_id, 30 * DAY_IN_SECONDS);
319
320 return $channel_id;
321 } else {
322 return "Not a channel URL";
323 }
324 } else {
325 return $channel_id;
326 }
327 }
328
329
330 /** inline {@inheritdoc} */
331 public function getChannelGallery() {
332 $response = [];
333 $channel = $this->getChannelPlaylist();
334 if(!empty($channel['error'])){
335 return $channel;
336 }
337 if (!empty($channel["playlistID"])) {
338 $params = $this->getParams();
339 $the_playlist_id = $channel["playlistID"];
340 $rel = 'https://www.youtube.com/embed?listType=playlist&list=' . esc_attr($the_playlist_id);
341 $title = $channel['title'];
342 $main_iframe = "";
343 $gallery_args = [
344 'playlistId' => $the_playlist_id,
345 ];
346 if(!empty($params['pagesize'])){
347 $gallery_args['pagesize'] = $params['pagesize'];
348 }
349 $gallery = self::get_gallery_page($gallery_args);
350
351 if (!empty($gallery->first_vid)) {
352 $rel = "https://www.youtube.com/embed/{$gallery->first_vid}?feature=oembed";
353 $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>";
354 }
355 if($gallery->html && $this->validateTYLiveUrl($this->getUrl())){
356 $styles = self::styles($params, $this->getUrl());
357 return [
358 "title" => $title,
359 "html" => "<div class='ep-player-wrap'>$main_iframe $styles</div>",
360 ];
361 }
362 if($gallery->html){
363 $styles = self::styles($params, $this->getUrl());
364 return [
365 "title" => $title,
366 "html" => "<div class='ep-player-wrap'>$main_iframe {$gallery->html} $styles</div>",
367 ];
368 }
369 }
370 elseif ($this->isChannel() && empty(self::get_api_key()) && current_user_can('manage_options')) {
371 return [
372 "html" => "<div class='ep-player-wrap'>" . __('Please enter your YouTube API key to embed YouTube Channel.', 'embedpress') . "</div>",
373 ];
374 }
375
376 return $response;
377 }
378
379 /**
380 * Undocumented function
381 *
382 * @param array $options
383 * @return object
384 */
385 public static function get_gallery_page($options) {
386 $nextPageToken = '';
387 $prevPageToken = '';
388 $gallobj = new \stdClass();
389 $options = wp_parse_args($options, [
390 'playlistId' => '',
391 'pageToken' => '',
392 'pagesize' => self::get_pagesize() ? self::get_pagesize() : 6,
393 'currentpage' => '',
394 'columns' => 3,
395 'thumbnail' => 'medium',
396 'gallery' => true,
397 'autonext' => true,
398 'thumbplay' => true,
399 'apiKey' => self::get_api_key(),
400 'hideprivate' => '',
401 ]);
402 $options['pagesize'] = $options['pagesize'] > 50 ? 50 : $options['pagesize'];
403 $options['pagesize'] = $options['pagesize'] < 1 ? 1 : $options['pagesize'];
404
405 if (empty($options['apiKey'])) {
406 $gallobj->html = self::get_api_key_error_message();
407 return $gallobj;
408 }
409
410 $apiEndpoint = 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet,status&playlistId=' . $options['playlistId']
411 . '&maxResults=' . $options['pagesize']
412 . '&key=' . $options['apiKey'];
413 if ($options['pageToken'] != null) {
414 $apiEndpoint .= '&pageToken=' . $options['pageToken'];
415 }
416
417 $transient_key = 'ep_embed_youtube_channel_' . md5($apiEndpoint);
418 $gallobj->transient_key = $transient_key;
419 $jsonResult = get_transient($transient_key);
420 if (empty($jsonResult)) {
421 $apiResult = wp_remote_get($apiEndpoint, array('timeout' => self::$curltimeout));
422 if (is_wp_error($apiResult)) {
423 $gallobj->html = self::clean_api_error_html($apiResult->get_error_message(), true);
424 return $gallobj;
425 }
426 $jsonResult = json_decode($apiResult['body']);
427 if (empty($jsonResult->error)) {
428 set_transient($transient_key, $jsonResult, MINUTE_IN_SECONDS * 20);
429 }
430 else{
431 set_transient($transient_key, $jsonResult, 10);
432 }
433 }
434
435
436 if (isset($jsonResult->error)) {
437 if(!empty($jsonResult->error->errors[0]->reason) && $jsonResult->error->errors[0]->reason == 'playlistNotFound'){
438 $gallobj->html = self::clean_api_error_html(__('There is nothing on the playlist.', 'embedpress'));
439 return $gallobj;
440 }
441 if (isset($jsonResult->error->message)) {
442 $gallobj->html = self::clean_api_error_html($jsonResult->error->message);
443 return $gallobj;
444 }
445 $gallobj->html = self::clean_api_error_html(__('Sorry, there may be an issue with your YouTube API key.', 'embedpress'));
446 return $gallobj;
447 }
448
449
450
451 $resultsPerPage = $jsonResult->pageInfo->resultsPerPage;
452 $totalResults = $jsonResult->pageInfo->totalResults;
453 $totalPages = ceil($totalResults / $resultsPerPage);
454 if (isset($jsonResult->nextPageToken)) {
455 $nextPageToken = $jsonResult->nextPageToken;
456 }
457
458 if (isset($jsonResult->prevPageToken)) {
459 $prevPageToken = $jsonResult->prevPageToken;
460 }
461
462
463 if (!empty($jsonResult->items) && is_array($jsonResult->items)) :
464 if($options['gallery'] === "false"){
465 $gallobj->html = "";
466 if(count($jsonResult->items) === 1){
467 $gallobj->first_vid = self::get_id($jsonResult->items[0]);
468 }
469 return $gallobj;
470 }
471
472 if(count($jsonResult->items) === 1 && empty($nextPageToken) && empty($prevPageToken)){
473 $gallobj->first_vid = self::get_id($jsonResult->items[0]);
474 $gallobj->html = "";
475 return $gallobj;
476 }
477
478 if (strpos($options['playlistId'], 'UU') === 0) {
479 // sort only channels
480 usort($jsonResult->items, array(self::class, 'compare_vid_date')); // sorts in place
481 }
482
483
484 ob_start();
485 ?>
486 <div class="ep-youtube__content__block" data-unique-id="<?php echo wp_rand(); ?>">
487 <div class="youtube__content__body">
488 <div class="content__wrap">
489 <?php foreach ($jsonResult->items as $item) : ?>
490 <?php
491 $privacyStatus = isset($item->status->privacyStatus) ? $item->status->privacyStatus : null;
492 $thumbnail = self::get_thumbnail_url($item, $options['thumbnail'], $privacyStatus);
493 $vid = self::get_id($item);
494 if (empty($gallobj->first_vid)) {
495 $gallobj->first_vid = $vid;
496 }
497 if ($privacyStatus == 'private' && $options['hideprivate']) {
498 continue;
499 }
500 ?>
501 <div class="item" data-vid="<?php echo $vid; ?>">
502 <div class="thumb" style="background: <?php echo "url({$thumbnail}) no-repeat center"; ?>">
503 <div class="play-icon">
504 <img src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS . 'images/youtube/youtube-play.png'); ?>" alt="">
505 </div>
506 </div>
507 <div class="body">
508 <p><?php echo $item->snippet->title; ?></p>
509 </div>
510 </div>
511
512 <?php endforeach; ?>
513 <div class="item" style="height: 0"></div>
514 </div>
515
516
517 <?php if ($totalPages > 1) : ?>
518 <div class="ep-youtube__content__pagination <?php echo (empty($prevPageToken) && empty($nextPageToken)) ? ' hide ' : ''; ?>">
519 <div
520 class="ep-prev" <?php echo empty($prevPageToken) ? ' style="display:none" ' : ''; ?>
521 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
522 data-pagetoken="<?php echo esc_attr($prevPageToken) ?>"
523 data-pagesize="<?php echo intval($options['pagesize']) ?>"
524 >
525 <span><?php _e("Prev", "embedpress"); ?></span>
526 </div>
527 <div class="is_desktop_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
528 <?php
529
530 $numOfPages = $totalPages;
531 $renderedEllipses = false;
532
533 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
534
535 for($i = 1; $i<=$numOfPages; $i++)
536 {
537 //render pages 1 - 3
538 if($i < 4) {
539 //render link
540 $is_current = $i == (int)$currentPage? "active__current_page" : "";
541
542 echo wp_kses_post("<span class='page-number $is_current' data-page='$i'>$i</span>");
543
544 }
545
546 //render current page number
547 else if($i == (int)$currentPage) {
548 //render link
549 echo wp_kses_post('<span class="page-number active__current_page" data-page="'.$i.'">'.$i.'</span>');
550 //reset ellipses
551 $renderedEllipses = false;
552 }
553
554 //last page number
555 else if ($i >= $numOfPages - 1) {
556 //render link
557 echo wp_kses_post('<span class="page-number" data-page="'.$i.'">'.$i.'</span>');
558 }
559
560 //make sure you only do this once per ellipses group
561 else {
562 if (!$renderedEllipses){
563 print("...");
564 $renderedEllipses = true;
565 }
566 }
567 }
568 ?>
569
570 </div>
571
572 <div class="is_mobile_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
573 <?php
574
575 $numOfPages = $totalPages;
576 $renderedEllipses = false;
577
578 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
579
580 for($i = 1; $i<=$numOfPages; $i++)
581 {
582
583 //render current page number
584 if($i == (int)$currentPage) {
585 //render link
586 echo wp_kses_post('<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
587 //reset ellipses
588 $renderedEllipses = false;
589 }
590
591 //last page number
592 else if ($i >= $numOfPages ) {
593 //render link
594 echo wp_kses_post('...<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
595 }
596 }
597 ?>
598
599 </div>
600
601
602 <div
603 class="ep-next " <?php echo empty($nextPageToken) ? ' style="display:none" ' : ''; ?>
604 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
605 data-pagetoken="<?php echo esc_attr($nextPageToken) ?>"
606 data-pagesize="<?php echo intval($options['pagesize']) ?>"
607 >
608 <span><?php _e("Next ", "embedpress"); ?> </span>
609 </div>
610 </div>
611 <?php endif; ?>
612
613 <div class="ep-loader-wrap">
614 <div class="ep-loader"><img alt="loading" src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS . 'images/youtube/spin.gif'); ?>"></div>
615 </div>
616
617 </div>
618 </div>
619 <?php
620 $gallobj->html = ob_get_clean();
621 else:
622 $gallobj->html = self::clean_api_error_html(__("There is nothing on the playlist.", 'embedpress'));
623 endif;
624
625 return $gallobj;
626 }
627
628 public static function get_api_key_error_message(){
629 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>';
630 }
631
632 public static function get_id($item){
633 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
634 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
635 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
636 return $vid;
637 }
638 public static function get_thumbnail_url($item, $quality, $privacyStatus) {
639 $url = "";
640 if ($privacyStatus == 'private') {
641 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/private.png';
642 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
643 $url = $item->snippet->thumbnails->{$quality}->url;
644 } elseif (isset($item->snippet->thumbnails->medium->url)) {
645 $url = $item->snippet->thumbnails->medium->url;
646 } elseif (isset($item->snippet->thumbnails->default->url)) {
647 $url = $item->snippet->thumbnails->default->url;
648 } elseif (isset($item->snippet->thumbnails->high->url)) {
649 $url = $item->snippet->thumbnails->high->url;
650 } else {
651 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/deleted-video-thumb.png';
652 }
653 return $url;
654 }
655
656 public static function compare_vid_date($a, $b) {
657 if ($a->snippet->publishedAt == $b->snippet->publishedAt) {
658 return 0;
659 }
660 return ($a->snippet->publishedAt > $b->snippet->publishedAt) ? -1 : 1;
661 }
662
663 public static function clean_api_error($raw_message) {
664 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
665 }
666
667 public static function clean_api_error_html($raw_message) {
668 $clean_html = '';
669 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
670 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . self::clean_api_error($raw_message) . '</div>';
671 }
672 return $clean_html;
673 }
674
675 /** inline {@inheritdoc} */
676 public function getFakeResponse() {
677 preg_match('~v=([a-z0-9_\-]+)~i', (string) $this->url, $matches);
678
679 $embedUrl = 'https://www.youtube.com/embed/' . $matches['1'] . '?feature=oembed';
680
681 $attr = [];
682 $attr[] = 'width="{width}"';
683 $attr[] = 'height="{height}"';
684 $attr[] = 'src="' . esc_url($embedUrl) . '"';
685 $attr[] = 'frameborder="0"';
686 $attr[] = 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"';
687 $attr[] = 'allowfullscreen';
688
689 return [
690 'type' => 'video',
691 'provider_name' => 'Youtube',
692 'provider_url' => 'https://www.youtube.com',
693 'title' => 'Unknown title',
694 'html' => '<iframe ' . implode(' ', $attr) . '></iframe>',
695 ];
696 }
697
698 // public static $num = 0;
699
700
701
702 public static $x = 0;
703
704 public static function styles($params, $url){
705
706 $uniqid = '.ose-youtube.ose-uid-'.md5($url);
707
708 ob_start();
709 ?>
710 <style>
711 html {
712 scroll-behavior: smooth;
713 }
714 .ep-player-wrap .hide {
715 display: none;
716 }
717
718 .ep-gdrp-content {
719 background: #222;
720 padding: 50px 30px;
721 color: #fff;
722 }
723
724 .ep-gdrp-content a {
725 color: #fff;
726 }
727
728 .ep-youtube__content__pagination {
729 display: flex;
730 justify-content: center;
731 align-items: center;
732 margin-top: 30px;
733 gap: 10px;
734 }
735 .ep-loader-wrap {
736 margin-top: 30px;
737 display: flex;
738 justify-content: center;
739 }
740
741 .ep-youtube__content__pagination .ep-prev,
742 .ep-youtube__content__pagination .ep-next {
743 cursor: pointer;
744 border: 1px solid rgba(0, 0, 0, .1);
745 border-radius: 30px;
746 padding: 0 20px;
747 height: 40px;
748 transition: .3s;
749 display: flex;
750 align-items: center;
751 }
752 .ep-youtube__content__pagination .ep-prev:hover,
753 .ep-youtube__content__pagination .ep-next:hover{
754 background-color: #5B4E96;
755 color: #fff;
756 }
757 .ep-youtube__content__pagination .ep-page-numbers {
758 display: flex;
759 align-items: center;
760 gap: 10px;
761 flex-wrap: wrap;
762 }
763 .ep-youtube__content__pagination .ep-page-numbers > span {
764 border: 1px solid rgba(0, 0, 0, .1);
765 border-radius: 30px;
766 display: inline-block;
767 width: 45px;
768 height: 45px;
769 display: flex;
770 align-items: center;
771 justify-content: center;
772 }
773 .active__current_page{
774 background: #5B4E96;
775 color: #fff;
776 }
777
778 .ep-youtube__content__block .youtube__content__body .content__wrap {
779 margin-top: 30px;
780 display: grid;
781 grid-template-columns:repeat(auto-fit, minmax(250px, 1fr));
782 gap: 30px;
783 }
784
785 .ep-youtube__content__block .item {
786 cursor: pointer;
787 white-space: initial;
788 }
789
790 .ep-youtube__content__block .item:hover .thumb .play-icon {
791 opacity: 1;
792 top: 50%;
793 }
794
795 .ep-youtube__content__block .item:hover .thumb:after {
796 opacity: .4;
797 z-index: 0;
798 }
799
800 .ep-youtube__content__block .thumb {
801 padding-top: 56.25%;
802 margin-bottom: 5px;
803 position: relative;
804 background: #222;
805 background-size: contain !important;
806 }
807
808 .ep-youtube__content__block .thumb:after {
809 position: absolute;
810 top: 0;
811 left: 0;
812 height: 100%;
813 width: 100%;
814 content: '';
815 background: #000;
816 opacity: 0;
817 transition: opacity .3s ease;
818 }
819
820 .ep-youtube__content__block .thumb:before {
821 position: absolute;
822 top: 0;
823 left: 0;
824 height: 100%;
825 width: 100%;
826 content: '';
827 background: #222;
828 z-index: -1;
829 }
830
831 .ep-youtube__content__block .thumb img {
832 width: 100%;
833 height: 100%;
834 object-fit: cover;
835 }
836
837 .ep-youtube__content__block .thumb .play-icon {
838 width: 50px;
839 height: auto;
840 position: absolute;
841 top: 40%;
842 left: 50%;
843 transform: translate(-50%, -50%);
844 opacity: 0;
845 transition: all .3s ease;
846 z-index: 2;
847 }
848
849 .ep-youtube__content__block .thumb .play-icon img {
850 width: 100;
851 }
852
853 .ep-youtube__content__block .body p {
854 margin-bottom: 0;
855 font-size: 15px;
856 text-align: left;
857 line-height: 1.5;
858 font-weight: 400;
859 }
860 .ep-youtube__content__block.loading .ep-youtube__content__pagination {
861 display: none;
862 }
863
864 .ep-youtube__content__block .ep-loader {
865 display: none;
866 }
867
868 .ep-youtube__content__block.loading .ep-loader {
869 display: block;
870 }
871 .ep-loader img {
872 width: 20px;
873 }
874 .is_mobile_device{
875 display: none!important;
876 }
877
878
879 .is_mobile_devic.ep-page-numbers {
880 gap: 5px;
881 }
882
883 @media only screen and (max-width: 480px) {
884 .is_desktop_device{
885 display: none!important;
886 }
887 .ep-youtube__content__pagination .ep-page-numbers > span {
888 width: 35px;
889 height: 35px;
890 }
891 .ep-youtube__content__pagination .ep-prev, .ep-youtube__content__pagination .ep-next{
892 height: 35px;
893 }
894 .is_mobile_device{
895 display: flex!important;;
896 }
897 .ep-youtube__content__pagination .ep-page-numbers {
898 gap: 5px;
899 }
900 }
901 <?php
902 $attributes_data = $params;
903
904 $is_pagination = 'flex';
905
906 $gap = '30';
907 $columns = '';
908
909 if (isset($attributes_data['ispagination']) && $attributes_data['ispagination']) {
910 $is_pagination = 'none';
911 }
912 if(isset($attributes_data['gapbetweenvideos'])){
913 $gap = $attributes_data['gapbetweenvideos'];
914 }
915 if(isset($attributes_data['columns'])){
916 $columns = $attributes_data['columns'];
917 }
918
919
920 if(!empty($columns) && (int) $columns > 0){
921 $repeatCol = 'repeat(auto-fit, minmax('.esc_html('calc('.(100 / (int) $columns).'% - '.$gap.'px)').', 1fr))';
922 }
923 else{
924 $repeatCol = 'repeat(auto-fit, minmax(calc(250px - '.$gap.'px), 1fr))';
925 }
926
927 ?>
928 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap {
929 gap: <?php echo esc_html($gap); ?>px !important;
930 margin-top: <?php echo esc_html($gap); ?>px !important;
931 grid-template-columns: <?php echo $repeatCol; ?>;
932 }
933 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .ep-youtube__content__pagination {
934 display: <?php echo esc_html($is_pagination); ?>!important;
935 }
936
937 <?php
938 if($is_pagination){
939 echo esc_attr($uniqid) ?> {
940 height: 100%!important;
941 }
942 <?php
943 }
944 ?>
945 </style>
946 <?php
947 return ob_get_clean();
948 }
949 }
950