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