PluginProbe ʕ •ᴥ•ʔ
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents / 4.0.12
EmbedPress – PDF Embedder, 3D PDF FlipBook, Google Reviews, YouTube Videos, Upload & Embed PDF documents v4.0.12
4.6.5 4.6.4 4.6.3 4.6.2 4.6.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 2 years ago 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
936 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 (!is_embedpress_pro_active() && 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 // echo '<pre>';
619 // print_r($options);
620
621
622 $channelTitle = isset($channel_info['snippet']['title']) ? $channel_info['snippet']['title'] : null;
623 $channelThumb = isset($channel_info['snippet']['thumbnails']['high']['url']) ? $channel_info['snippet']['thumbnails']['high']['url'] : null;
624 $layout = $this->get_layout();
625
626 // echo '<pre>';
627 // print_r($channelTitle);
628 // print_r($channelTitle);
629
630 if($layout === 'gallery'){
631 echo YoutubeLayout::create_gallery_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
632 }
633 else if($layout === 'grid'){
634 echo YoutubeLayout::create_grid_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
635 }
636 else if($layout === 'list'){
637 echo YoutubeLayout::create_list_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
638 }
639 else if($layout === 'carousel'){
640 echo YoutubeLayout::create_carousel_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
641 }
642 else{
643 echo YoutubeLayout::create_grid_layout($jsonResult, $gallobj, $options, $data, $channelTitle, $channelThumb);
644
645 }
646
647 ?>
648 <!--
649 <?php foreach ($jsonResult->items as $item) : ?>
650 <?php
651 $privacyStatus = isset($item->status->privacyStatus) ? $item->status->privacyStatus : null;
652 $thumbnail = $this->get_thumbnail_url($item, $options['thumbnail'], $privacyStatus);
653 $vid = $this->get_id($item);
654 if (empty($gallobj->first_vid)) {
655 $gallobj->first_vid = $vid;
656 }
657 if ($privacyStatus == 'private' && $options['hideprivate']) {
658 continue;
659 }
660 ?>
661 <div class="item" data-vid="<?php echo $vid; ?>">
662 <div class="thumb" style="background: <?php echo "url({$thumbnail}) no-repeat center"; ?>">
663 <div class="play-icon">
664 <img src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS . 'images/youtube/youtube-play.png'); ?>" alt="">
665 </div>
666 </div>
667 <div class="body">
668 <p><?php echo $item->snippet->title; ?></p>
669 </div>
670 </div>
671
672 <?php endforeach; ?> -->
673
674 <div class="item" style="height: 0"></div>
675 </div>
676
677
678 <?php
679 $layout = $this->get_layout();
680
681 if ($totalPages > 1 && $layout !== 'carousel') : ?>
682 <div class="ep-youtube__content__pagination <?php echo (empty($prevPageToken) && empty($nextPageToken)) ? ' hide ' : ''; ?>">
683 <div
684 class="ep-prev" <?php echo empty($prevPageToken) ? ' style="display:none" ' : ''; ?>
685 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
686 data-pagetoken="<?php echo esc_attr($prevPageToken) ?>"
687 data-pagesize="<?php echo intval($options['pagesize']) ?>"
688 >
689 <span><?php _e("Prev", "embedpress"); ?></span>
690 </div>
691 <div class="is_desktop_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
692 <?php
693
694 $numOfPages = $totalPages;
695 $renderedEllipses = false;
696
697 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
698
699 for($i = 1; $i<=$numOfPages; $i++)
700 {
701 //render pages 1 - 3
702 if($i < 4) {
703 //render link
704 $is_current = $i == (int)$currentPage? "active__current_page" : "";
705
706 echo wp_kses_post("<span class='page-number $is_current' data-page='$i'>$i</span>");
707
708 }
709
710 //render current page number
711 else if($i == (int)$currentPage) {
712 //render link
713 echo wp_kses_post('<span class="page-number active__current_page" data-page="'.$i.'">'.$i.'</span>');
714 //reset ellipses
715 $renderedEllipses = false;
716 }
717
718 //last page number
719 else if ($i >= $numOfPages - 1) {
720 //render link
721 echo wp_kses_post('<span class="page-number" data-page="'.$i.'">'.$i.'</span>');
722 }
723
724 //make sure you only do this once per ellipses group
725 else {
726 if (!$renderedEllipses){
727 print("...");
728 $renderedEllipses = true;
729 }
730 }
731 }
732 ?>
733
734 </div>
735
736 <div class="is_mobile_device ep-page-numbers <?php echo $totalPages > 1 ? '' : 'hide'; ?>">
737 <?php
738
739 $numOfPages = $totalPages;
740 $renderedEllipses = false;
741
742 $currentPage = !empty($options['currentpage'])?$options['currentpage'] : 1;
743
744 for($i = 1; $i<=$numOfPages; $i++)
745 {
746
747 //render current page number
748 if($i == (int)$currentPage) {
749 //render link
750 echo wp_kses_post('<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
751 //reset ellipses
752 $renderedEllipses = false;
753 }
754
755 //last page number
756 else if ($i >= $numOfPages ) {
757 //render link
758 echo wp_kses_post('...<span class="page-number-mobile" data-page="'.$i.'">'.$i.'</span>');
759 }
760 }
761 ?>
762
763 </div>
764
765
766 <div
767 class="ep-next " <?php echo empty($nextPageToken) ? ' style="display:none" ' : ''; ?>
768 data-playlistid="<?php echo esc_attr($options['playlistId']) ?>"
769 data-pagetoken="<?php echo esc_attr($nextPageToken) ?>"
770 data-pagesize="<?php echo intval($options['pagesize']) ?>"
771 >
772 <span><?php _e("Next ", "embedpress"); ?> </span>
773 </div>
774 </div>
775 <?php endif; ?>
776
777 <div class="ep-loader-wrap">
778 <div class="ep-loader"><img alt="loading" src="<?php echo esc_url(EMBEDPRESS_URL_ASSETS . 'images/youtube/spin.gif'); ?>"></div>
779 </div>
780
781 </div>
782 </div>
783
784 <?php
785 $gallobj->html = ob_get_clean();
786 else:
787 $gallobj->html = $this->clean_api_error_html(__("There is nothing on the playlist.", 'embedpress'));
788 endif;
789
790 return $gallobj;
791 }
792
793 public function get_api_key_error_message(){
794 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>';
795 }
796
797 public function get_id($item){
798 $vid = isset($item->snippet->resourceId->videoId) ? $item->snippet->resourceId->videoId : null;
799 $vid = $vid ? $vid : (isset($item->id->videoId) ? $item->id->videoId : null);
800 $vid = $vid ? $vid : (isset($item->id) ? $item->id : null);
801 return $vid;
802 }
803 public function get_thumbnail_url($item, $quality, $privacyStatus) {
804 $url = "";
805 if ($privacyStatus == 'private') {
806 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/private.png';
807 } elseif (isset($item->snippet->thumbnails->{$quality}->url)) {
808 $url = $item->snippet->thumbnails->{$quality}->url;
809 } elseif (isset($item->snippet->thumbnails->medium->url)) {
810 $url = $item->snippet->thumbnails->medium->url;
811 } elseif (isset($item->snippet->thumbnails->default->url)) {
812 $url = $item->snippet->thumbnails->default->url;
813 } elseif (isset($item->snippet->thumbnails->high->url)) {
814 $url = $item->snippet->thumbnails->high->url;
815 } else {
816 $url = EMBEDPRESS_URL_ASSETS . 'images/youtube/deleted-video-thumb.png';
817 }
818 return $url;
819 }
820
821 public function compare_vid_date($a, $b) {
822 if ($a->snippet->publishedAt == $b->snippet->publishedAt) {
823 return 0;
824 }
825 return ($a->snippet->publishedAt > $b->snippet->publishedAt) ? -1 : 1;
826 }
827
828 public function clean_api_error($raw_message) {
829 return htmlspecialchars(strip_tags(preg_replace('@&key=[^& ]+@i', '&key=*******', $raw_message)));
830 }
831
832 public function clean_api_error_html($raw_message) {
833 $clean_html = '';
834 if ((defined('REST_REQUEST') && REST_REQUEST) || current_user_can('manage_options')) {
835 $clean_html = '<div>' . __('EmbedPress: ', 'embedpress') . $this->clean_api_error($raw_message) . '</div>';
836 }
837 return $clean_html;
838 }
839
840 /** inline {@inheritdoc} */
841 public function getFakeResponse() {
842 preg_match('~v=([a-z0-9_\-]+)~i', (string) $this->url, $matches);
843
844 $embedUrl = 'https://www.youtube.com/embed/' . $matches['1'] . '?feature=oembed';
845
846 $attr = [];
847 $attr[] = 'width="{width}"';
848 $attr[] = 'height="{height}"';
849 $attr[] = 'src="' . esc_url($embedUrl) . '"';
850 $attr[] = 'frameborder="0"';
851 $attr[] = 'allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"';
852 $attr[] = 'allowfullscreen';
853
854 return [
855 'type' => 'video',
856 'provider_name' => 'Youtube',
857 'provider_url' => 'https://www.youtube.com',
858 'title' => 'Unknown title',
859 'html' => '<iframe ' . implode(' ', $attr) . '></iframe>',
860 ];
861 }
862
863 // public $num = 0;
864
865
866
867 public $x = 0;
868
869 public function styles($params, $url){
870
871 $uniqid = '.ose-youtube.ose-uid-'.md5($url);
872
873 ob_start();
874 ?>
875 <style>
876
877 <?php
878 $attributes_data = $params;
879
880 $is_pagination = 'flex';
881
882 $gap = '30';
883 $columns = '';
884
885 if (isset($attributes_data['ispagination']) && $attributes_data['ispagination']) {
886 $is_pagination = 'none';
887 }
888 if(isset($attributes_data['gapbetweenvideos'])){
889 $gap = $attributes_data['gapbetweenvideos'];
890 }
891 if(isset($attributes_data['columns'])){
892 $columns = $attributes_data['columns'];
893 }
894
895
896 if(!empty($columns) && (int) $columns > 0){
897 $repeatCol = 'repeat(auto-fit, minmax('.esc_html('calc('.(100 / (int) $columns).'% - '.$gap.'px)').', 1fr))';
898 }
899 else{
900 $repeatCol = 'repeat(auto-fit, minmax(calc(250px - '.$gap.'px), 1fr))';
901 }
902
903 ?>
904 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap:not(.youtube-carousel) {
905 gap: <?php echo esc_html($gap); ?>px !important;
906 margin-top: <?php echo esc_html($gap); ?>px !important;
907 grid-template-columns: <?php echo $repeatCol; ?>;
908 }
909 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .ep-youtube__content__pagination {
910 display: <?php echo esc_html($is_pagination); ?>!important;
911 }
912
913 <?php echo esc_attr($uniqid); ?> .layout-list .ep-youtube__content__block .youtube__content__body .content__wrap{
914 grid-template-columns: repeat(auto-fit, minmax(calc(100% - 30px), 1fr))!important;
915 }
916
917 @media (max-width: 420px) {
918 <?php echo esc_attr($uniqid); ?> .ep-youtube__content__block .youtube__content__body .content__wrap:not(.youtube-carousel) {
919 gap: 30px !important;
920 }
921 }
922
923 <?php
924 if($is_pagination){
925 echo esc_attr($uniqid) ?> {
926 height: 100%!important;
927 }
928 <?php
929 }
930 ?>
931 </style>
932 <?php
933 return ob_get_clean();
934 }
935 }
936