PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more / 3.9.15
EmbedPress – PDF Embedder, Embed PDF viewer, YouTube Videos, 3D FlipBook, Social feeds & more v3.9.15
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 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 Youtube.php 2 years ago index.html 7 years ago
Youtube.php
949 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(get_class(), 'compare_vid_date')); // sorts in place
481 }
482
483 ob_start();
484 ?>
485 <div class="ep-youtube__content__block" data-unique-id="<?php echo wp_rand(); ?>">
486 <div class="youtube__content__body">
487 <div class="content__wrap">
488 <?php foreach ($jsonResult->items as $item) : ?>
489 <?php
490 $privacyStatus = isset($item->status->privacyStatus) ? $item->status->privacyStatus : null;
491 $thumbnail = self::get_thumbnail_url($item, $options['thumbnail'], $privacyStatus);
492 $vid = self::get_id($item);
493 if (empty($gallobj->first_vid)) {
494 $gallobj->first_vid = $vid;
495 }
496 if ($privacyStatus == 'private' && $options['hideprivate']) {
497 continue;
498 }
499 ?>
500 <div class="item" data-vid="<?php echo $vid; ?>">
501 <div class="thumb" style="background: <?php echo "url({$thumbnail}) no-repeat center"; ?>">
502 <div class="play-icon">
503 <img src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS . 'images/youtube/youtube-play.png'); ?>" alt="">
504 </div>
505 </div>
506 <div class="body">
507 <p><?php echo $item->snippet->title; ?></p>
508 </div>
509 </div>
510
511 <?php endforeach; ?>
512 <div class="item" style="height: 0"></div>
513 </div>
514
515
516 <?php if ($totalPages > 1) : ?>
517 <div class="ep-youtube__content__pagination <?php echo (empty($prevPageToken) && empty($nextPageToken)) ? ' hide ' : ''; ?>">
518 <div
519 class="ep-prev" <?php echo empty($prevPageToken) ? ' style="display:none" ' : ''; ?>
520 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
521 data-pagetoken="<?php echo esc_attr($prevPageToken) ?>"
522 data-pagesize="<?php echo intval($options['pagesize']) ?>"
523 >
524 <span><?php _e("Prev", "embedpress"); ?></span>
525 </div>
526 <div class="is_desktop_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
527 <?php
528
529 $numOfPages = $totalPages;
530 $renderedEllipses = false;
531
532 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
533
534 for($i = 1; $i<=$numOfPages; $i++)
535 {
536 //render pages 1 - 3
537 if($i < 4) {
538 //render link
539 $is_current = $i == (int)$currentPage? "active__current_page" : "";
540
541 echo wp_kses_post("<span class='page-number $is_current' data-page='$i'>$i</span>");
542
543 }
544
545 //render current page number
546 else if($i == (int)$currentPage) {
547 //render link
548 echo wp_kses_post('<span class="page-number active__current_page" data-page="'.$i.'">'.$i.'</span>');
549 //reset ellipses
550 $renderedEllipses = false;
551 }
552
553 //last page number
554 else if ($i >= $numOfPages - 1) {
555 //render link
556 echo wp_kses_post('<span class="page-number" data-page="'.$i.'">'.$i.'</span>');
557 }
558
559 //make sure you only do this once per ellipses group
560 else {
561 if (!$renderedEllipses){
562 print("...");
563 $renderedEllipses = true;
564 }
565 }
566 }
567 ?>
568
569 </div>
570
571 <div class="is_mobile_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
572 <?php
573
574 $numOfPages = $totalPages;
575 $renderedEllipses = false;
576
577 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
578
579 for($i = 1; $i<=$numOfPages; $i++)
580 {
581
582 //render current page number
583 if($i == (int)$currentPage) {
584 //render link
585 echo wp_kses_post('<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
586 //reset ellipses
587 $renderedEllipses = false;
588 }
589
590 //last page number
591 else if ($i >= $numOfPages ) {
592 //render link
593 echo wp_kses_post('...<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
594 }
595 }
596 ?>
597
598 </div>
599
600
601 <div
602 class="ep-next " <?php echo empty($nextPageToken) ? ' style="display:none" ' : ''; ?>
603 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
604 data-pagetoken="<?php echo esc_attr($nextPageToken) ?>"
605 data-pagesize="<?php echo intval($options['pagesize']) ?>"
606 >
607 <span><?php _e("Next ", "embedpress"); ?> </span>
608 </div>
609 </div>
610 <?php endif; ?>
611
612 <div class="ep-loader-wrap">
613 <div class="ep-loader"><img alt="loading" src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS . 'images/youtube/spin.gif'); ?>"></div>
614 </div>
615
616 </div>
617 </div>
618 <?php
619 $gallobj->html = ob_get_clean();
620 else:
621 $gallobj->html = self::clean_api_error_html(__("There is nothing on the playlist.", 'embedpress'));
622 endif;
623
624 return $gallobj;
625 }
626
627 public static function get_api_key_error_message(){
628 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>';
629 }
630
631 public static function get_id($item){
632 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
633 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
634 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
635 return $vid;
636 }
637 public static function get_thumbnail_url($item, $quality, $privacyStatus) {
638 $url = "";
639 if ($privacyStatus == 'private') {
640 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/private.png';
641 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
642 $url = $item->snippet->thumbnails->{$quality}->url;
643 } elseif (isset($item->snippet->thumbnails->medium->url)) {
644 $url = $item->snippet->thumbnails->medium->url;
645 } elseif (isset($item->snippet->thumbnails->default->url)) {
646 $url = $item->snippet->thumbnails->default->url;
647 } elseif (isset($item->snippet->thumbnails->high->url)) {
648 $url = $item->snippet->thumbnails->high->url;
649 } else {
650 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/deleted-video-thumb.png';
651 }
652 return $url;
653 }
654
655 public static function compare_vid_date($a, $b) {
656 if ($a->snippet->publishedAt == $b->snippet->publishedAt) {
657 return 0;
658 }
659 return ($a->snippet->publishedAt > $b->snippet->publishedAt) ? -1 : 1;
660 }
661
662 public static function clean_api_error($raw_message) {
663 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
664 }
665
666 public static function clean_api_error_html($raw_message) {
667 $clean_html = '';
668 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
669 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . self::clean_api_error($raw_message) . '</div>';
670 }
671 return $clean_html;
672 }
673
674 /** inline {@inheritdoc} */
675 public function getFakeResponse() {
676 preg_match('~v=([a-z0-9_\-]+)~i', (string) $this->url, $matches);
677
678 $embedUrl = 'https://www.youtube.com/embed/' . $matches['1'] . '?feature=oembed';
679
680 $attr = [];
681 $attr[] = 'width="{width}"';
682 $attr[] = 'height="{height}"';
683 $attr[] = 'src="' . esc_url($embedUrl) . '"';
684 $attr[] = 'frameborder="0"';
685 $attr[] = 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"';
686 $attr[] = 'allowfullscreen';
687
688 return [
689 'type' => 'video',
690 'provider_name' => 'Youtube',
691 'provider_url' => 'https://www.youtube.com',
692 'title' => 'Unknown title',
693 'html' => '<iframe ' . implode(' ', $attr) . '></iframe>',
694 ];
695 }
696
697 // public static $num = 0;
698
699
700
701 public static $x = 0;
702
703 public static function styles($params, $url){
704
705 $uniqid = '.ose-youtube.ose-uid-'.md5($url);
706
707 ob_start();
708 ?>
709 <style>
710 html {
711 scroll-behavior: smooth;
712 }
713 .ep-player-wrap .hide {
714 display: none;
715 }
716
717 .ep-gdrp-content {
718 background: #222;
719 padding: 50px 30px;
720 color: #fff;
721 }
722
723 .ep-gdrp-content a {
724 color: #fff;
725 }
726
727 .ep-youtube__content__pagination {
728 display: flex;
729 justify-content: center;
730 align-items: center;
731 margin-top: 30px;
732 gap: 10px;
733 }
734 .ep-loader-wrap {
735 margin-top: 30px;
736 display: flex;
737 justify-content: center;
738 }
739
740 .ep-youtube__content__pagination .ep-prev,
741 .ep-youtube__content__pagination .ep-next {
742 cursor: pointer;
743 border: 1px solid rgba(0, 0, 0, .1);
744 border-radius: 30px;
745 padding: 0 20px;
746 height: 40px;
747 transition: .3s;
748 display: flex;
749 align-items: center;
750 }
751 .ep-youtube__content__pagination .ep-prev:hover,
752 .ep-youtube__content__pagination .ep-next:hover{
753 background-color: #5B4E96;
754 color: #fff;
755 }
756 .ep-youtube__content__pagination .ep-page-numbers {
757 display: flex;
758 align-items: center;
759 gap: 10px;
760 flex-wrap: wrap;
761 }
762 .ep-youtube__content__pagination .ep-page-numbers > span {
763 border: 1px solid rgba(0, 0, 0, .1);
764 border-radius: 30px;
765 display: inline-block;
766 width: 45px;
767 height: 45px;
768 display: flex;
769 align-items: center;
770 justify-content: center;
771 }
772 .active__current_page{
773 background: #5B4E96;
774 color: #fff;
775 }
776
777 .ep-youtube__content__block .youtube__content__body .content__wrap {
778 margin-top: 30px;
779 display: grid;
780 grid-template-columns:repeat(auto-fit, minmax(250px, 1fr));
781 gap: 30px;
782 }
783
784 .ep-youtube__content__block .item {
785 cursor: pointer;
786 white-space: initial;
787 }
788
789 .ep-youtube__content__block .item:hover .thumb .play-icon {
790 opacity: 1;
791 top: 50%;
792 }
793
794 .ep-youtube__content__block .item:hover .thumb:after {
795 opacity: .4;
796 z-index: 0;
797 }
798
799 .ep-youtube__content__block .thumb {
800 padding-top: 56.25%;
801 margin-bottom: 5px;
802 position: relative;
803 background: #222;
804 background-size: contain !important;
805 }
806
807 .ep-youtube__content__block .thumb:after {
808 position: absolute;
809 top: 0;
810 left: 0;
811 height: 100%;
812 width: 100%;
813 content: '';
814 background: #000;
815 opacity: 0;
816 transition: opacity .3s ease;
817 }
818
819 .ep-youtube__content__block .thumb:before {
820 position: absolute;
821 top: 0;
822 left: 0;
823 height: 100%;
824 width: 100%;
825 content: '';
826 background: #222;
827 z-index: -1;
828 }
829
830 .ep-youtube__content__block .thumb img {
831 width: 100%;
832 height: 100%;
833 object-fit: cover;
834 }
835
836 .ep-youtube__content__block .thumb .play-icon {
837 width: 50px;
838 height: auto;
839 position: absolute;
840 top: 40%;
841 left: 50%;
842 transform: translate(-50%, -50%);
843 opacity: 0;
844 transition: all .3s ease;
845 z-index: 2;
846 }
847
848 .ep-youtube__content__block .thumb .play-icon img {
849 width: 100;
850 }
851
852 .ep-youtube__content__block .body p {
853 margin-bottom: 0;
854 font-size: 15px;
855 text-align: left;
856 line-height: 1.5;
857 font-weight: 400;
858 }
859 .ep-youtube__content__block.loading .ep-youtube__content__pagination {
860 display: none;
861 }
862
863 .ep-youtube__content__block .ep-loader {
864 display: none;
865 }
866
867 .ep-youtube__content__block.loading .ep-loader {
868 display: block;
869 }
870 .ep-loader img {
871 width: 20px;
872 }
873 .is_mobile_device{
874 display: none!important;
875 }
876
877
878 .is_mobile_devic.ep-page-numbers {
879 gap: 5px;
880 }
881
882 @media only screen and (max-width: 480px) {
883 .is_desktop_device{
884 display: none!important;
885 }
886 .ep-youtube__content__pagination .ep-page-numbers > span {
887 width: 35px;
888 height: 35px;
889 }
890 .ep-youtube__content__pagination .ep-prev, .ep-youtube__content__pagination .ep-next{
891 height: 35px;
892 }
893 .is_mobile_device{
894 display: flex!important;;
895 }
896 .ep-youtube__content__pagination .ep-page-numbers {
897 gap: 5px;
898 }
899 }
900 <?php
901 $attributes_data = $params;
902
903 $is_pagination = 'flex';
904
905 $gap = '30';
906 $columns = '';
907
908 if (isset($attributes_data['ispagination']) && $attributes_data['ispagination']) {
909 $is_pagination = 'none';
910 }
911 if(isset($attributes_data['gapbetweenvideos'])){
912 $gap = $attributes_data['gapbetweenvideos'];
913 }
914 if(isset($attributes_data['columns'])){
915 $columns = $attributes_data['columns'];
916 }
917
918
919 if(!empty($columns) && (int) $columns > 0){
920 $repeatCol = 'repeat(auto-fit, minmax('.esc_html('calc('.(100 / (int) $columns).'% - '.$gap.'px)').', 1fr))';
921 }
922 else{
923 $repeatCol = 'repeat(auto-fit, minmax(calc(250px - '.$gap.'px), 1fr))';
924 }
925
926 ?>
927 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap {
928 gap: <?php echo esc_html($gap); ?>px !important;
929 margin-top: <?php echo esc_html($gap); ?>px !important;
930 grid-template-columns: <?php echo $repeatCol; ?>;
931 }
932 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .ep-youtube__content__pagination {
933 display: <?php echo esc_html($is_pagination); ?>!important;
934 }
935
936 <?php
937 if($is_pagination){
938 echo esc_attr($uniqid) ?> {
939 height: 100%!important;
940 }
941 <?php
942 }
943 ?>
944 </style>
945 <?php
946 return ob_get_clean();
947 }
948 }
949