PluginProbe
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels / 1.6.3
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels v1.6.3
2.9.1 2.9.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 2.0.0 2.1.0 2.2.0 2.3.2 2.3.3 2.3.5 2.3.6 2.3.8 2.3.9 2.4.3 All 37 releases
automatic-youtube-gallery / includes / youtube-api.php

youtube-api.php in Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels 1.6.3, at includes/youtube-api.php

673 lines 17.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * A wrapper class for the Youtube Data API v3.
5 *
6 * @link https://plugins360.com
7 * @since 1.0.0
8 *
9 * @package Automatic_YouTube_Gallery
10 */
11
12 // Exit if accessed directly
13 if ( ! defined( 'WPINC' ) ) {
14 die;
15 }
16
17 /**
18 * AYG_YouTube_API class.
19 *
20 * @since 1.0.0
21 */
22 class AYG_YouTube_API {
23
24 /**
25 * The YouTube API Key.
26 *
27 * @since 1.0.0
28 * @access protected
29 * @var string
30 */
31 protected $api_key;
32
33 /**
34 * The YouTube API URLs.
35 *
36 * @since 1.0.0
37 * @access protected
38 * @var array
39 */
40 public $api_urls = array(
41 'playlistItems.list' => 'https://www.googleapis.com/youtube/v3/playlistItems',
42 'channels.list' => 'https://www.googleapis.com/youtube/v3/channels',
43 'search.list' => 'https://www.googleapis.com/youtube/v3/search',
44 'videos.list' => 'https://www.googleapis.com/youtube/v3/videos'
45 );
46
47 /**
48 * Get videos.
49 *
50 * @since 1.0.0
51 * @param array $params Array of query params.
52 * @return mixed
53 */
54 public function get_videos( $params = array() ) {
55 // Get YouTube API Key
56 $general_settings = get_option( 'ayg_general_settings' );
57
58 if ( empty( $general_settings['api_key'] ) ) {
59 return $this->get_error( __( 'YouTube API Key Missing.', 'automatic-youtube-gallery' ) . ' ' . sprintf( __( 'Follow <a href="%s" target="_blank">this guide</a> to get your own API key.', 'automatic-youtube-gallery' ), 'https://plugins360.com/automatic-youtube-gallery/how-to-get-youtube-api-key/' ) );
60 }
61
62 $this->api_key = $general_settings['api_key'];
63
64 // Process response
65 $response = array();
66
67 switch ( $params['type'] ) {
68 case 'playlist':
69 if ( empty( $params['id'] ) ) {
70 return $this->get_error( __( 'YouTube Playlist ID (or) URL is required.', 'automatic-youtube-gallery' ) );
71 }
72
73 $response = $this->request_api_playlist_items( $params );
74 break;
75
76 case 'channel':
77 if ( empty( $params['id'] ) ) {
78 return $this->get_error( __( 'YouTube Channel ID (or) URL is required.', 'automatic-youtube-gallery' ) );
79 }
80
81 // Find playlistId from the channel
82 $params['id'] = $this->parse_youtube_id_from_url( $params['id'], 'channel' );
83 $response = $this->request_api_channels( $params );
84
85 // Get videos using the playlistId
86 if ( ! isset( $response->error ) ) {
87
88 $params['id'] = $response->playlistId;
89 $response = $this->request_api_playlist_items( $params );
90
91 }
92 break;
93
94 case 'username':
95 if ( empty( $params['id'] ) ) {
96 return $this->get_error( __( 'YouTube Account Username is required.', 'automatic-youtube-gallery' ) );
97 }
98
99 // Find playlistId from the channel
100 $params['forUsername'] = $this->parse_youtube_id_from_url( $params['id'], 'username' );
101 unset( $params['id'] );
102
103 $response = $this->request_api_channels( $params );
104
105 // Get videos using the playlistId
106 if ( ! isset( $response->error ) ) {
107
108 $params['id'] = $response->playlistId;
109 $response = $this->request_api_playlist_items( $params );
110
111 }
112 break;
113
114 case 'search':
115 if ( empty( $params['id'] ) ) {
116 return $this->get_error( __( 'Cannot search an empty string. A search term is required.', 'automatic-youtube-gallery' ) );
117 }
118
119 $response = $this->request_api_search( $params );
120 break;
121
122 case 'videos':
123 if ( empty( $params['id'] ) ) {
124 return $this->get_error( __( 'Atleast one YouTube Video ID (or) URL is required.', 'automatic-youtube-gallery' ) );
125 }
126
127 $response = $this->request_api_videos( $params );
128 break;
129
130 default: // video
131 if ( empty( $params['id'] ) ) {
132 return $this->get_error( __( 'YouTube Video ID (or) URL is required.', 'automatic-youtube-gallery' ) );
133 }
134
135 $response = $this->request_api_video( $params );
136 break;
137 }
138
139 return $response;
140 }
141
142 /**
143 * Grab the playlist, channel or video ID using the YouTube URL given.
144 *
145 * @since 1.0.0
146 * @access private
147 * @param string $url YouTube URL.
148 * @param string $type Type of the URL (playlist|channel|video).
149 * @return mixed
150 */
151 private function parse_youtube_id_from_url( $url, $type = 'video' ) {
152 $id = $url;
153
154 switch ( $type ) {
155 case 'playlist':
156 if ( preg_match( '/list=(.*)&?\/?/', $url, $matches ) ) {
157 $id = $matches[1];
158 }
159 break;
160
161 case 'channel':
162 $url = parse_url( rtrim( $url, '/' ) );
163
164 if ( isset( $url['path'] ) && preg_match( '/^\/channel\/(([^\/])+?)$/', $url['path'], $matches ) ) {
165 $id = $matches[1];
166 }
167 break;
168
169 case 'username':
170 $url = parse_url( rtrim( $url, '/' ) );
171
172 if ( isset( $url['path'] ) && preg_match( '/^\/user\/(([^\/])+?)$/', $url['path'], $matches ) ) {
173 $id = $matches[1];
174 }
175 break;
176
177 default: // video
178 $url = parse_url( $url );
179
180 if ( array_key_exists( 'host', $url ) ) {
181 if ( 0 === strcasecmp( $url['host'], 'youtu.be' ) ) {
182 $id = substr( $url['path'], 1 );
183 } elseif ( 0 === strcasecmp( $url['host'], 'www.youtube.com' ) ) {
184 if ( isset( $url['query'] ) ) {
185 parse_str( $url['query'], $url['query'] );
186
187 if ( isset( $url['query']['v'] ) ) {
188 $id = $url['query']['v'];
189 }
190 }
191
192 if ( empty( $id ) ) {
193 $url['path'] = explode( '/', substr( $url['path'], 1 ) );
194
195 if ( in_array( $url['path'][0], array( 'e', 'embed', 'v' ) ) ) {
196 $id = $url['path'][1];
197 }
198 }
199 }
200 }
201 }
202
203 return $id;
204 }
205
206 /**
207 * Get videos using playlistItems API.
208 *
209 * @since 1.0.0
210 * @access private
211 * @param array $params Array of query params.
212 * @return stdClass
213 */
214 private function request_api_playlist_items( $params = array() ) {
215 $api_url = $this->get_api_url( 'playlistItems.list' );
216
217 $params['playlistId'] = $this->parse_youtube_id_from_url( $params['id'], 'playlist' );
218
219 $api_params = $this->safe_merge_params(
220 array(
221 'playlistId' => '',
222 'part' => 'id,snippet,contentDetails,status',
223 'maxResults' => 50,
224 'pageToken' => '',
225 'cache' => 0
226 ),
227 $params
228 );
229
230 $api_response = $this->request_api( $api_url, $api_params );
231 if ( isset( $api_response->error ) ) {
232 return $api_response;
233 }
234
235 $videos = $this->parse_videos( $api_response );
236 if ( isset( $videos->error ) ) {
237 return $videos;
238 }
239
240 // Process result
241 $response = new stdClass();
242 $response->page_info = $this->parse_page_info( $api_response );
243 $response->videos = $videos;
244
245 return $response;
246 }
247
248 /**
249 * Find playlistId using channels API.
250 *
251 * @since 1.0.0
252 * @access private
253 * @param array $params Array of query params.
254 * @return mixed
255 */
256 private function request_api_channels( $params = array() ) {
257 $api_url = $this->get_api_url( 'channels.list' );
258
259 $api_params = $this->safe_merge_params(
260 array(
261 'id' => '',
262 'forUsername' => '',
263 'part' => 'contentDetails',
264 'cache' => 0
265 ),
266 $params
267 );
268
269 $api_response = $this->request_api( $api_url, $api_params );
270 if ( isset( $api_response->error ) ) {
271 return $api_response;
272 }
273
274 $items = $api_response->items;
275 if ( ! is_array( $items ) || count( $items ) == 0 ) {
276 return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
277 }
278
279 // Process result
280 $response = new stdClass();
281 $response->playlistId = $items[0]->contentDetails->relatedPlaylists->uploads;
282
283 return $response;
284 }
285
286 /**
287 * Get videos using search API.
288 *
289 * @since 1.0.0
290 * @access private
291 * @param array $params Array of query params.
292 * @return stdClass
293 */
294 private function request_api_search( $params = array() ) {
295 $api_url = $this->get_api_url( 'search.list' );
296
297 $params['q'] = $params['id'];
298
299 if ( ! empty( $params['q'] ) ) {
300 $params['q'] = str_replace( '|', '%7C', $params['q'] );
301 }
302
303 $params['type'] = 'video'; // Overrides user defined type value 'search'
304
305 $api_params = $this->safe_merge_params(
306 array(
307 'q' => '',
308 'channelId' => '',
309 'type' => 'video',
310 'videoEmbeddable' => true,
311 'part' => 'id,snippet',
312 'order' => 'date',
313 'maxResults' => 50,
314 'pageToken' => '',
315 'cache' => 0
316 ),
317 $params
318 );
319
320 $api_response = $this->request_api( $api_url, $api_params );
321 if ( isset( $api_response->error ) ) {
322 return $api_response;
323 }
324
325 $videos = $this->parse_videos( $api_response );
326 if ( isset( $videos->error ) ) {
327 return $videos;
328 }
329
330 // Process result
331 $response = new stdClass();
332 $response->page_info = $this->parse_page_info( $api_response );
333 $response->videos = $videos;
334
335 return $response;
336 }
337
338 /**
339 * Get details of the given video IDs.
340 *
341 * @since 1.0.0
342 * @access private
343 * @param array $params Array of query params.
344 * @return stdClass
345 */
346 private function request_api_videos( $params = array() ) {
347 $api_url = $this->get_api_url( 'videos.list' );
348
349 $urls = str_replace( "\n\r", ',', $params['id'] );
350 $urls = str_replace( ' ', ',', $params['id'] );
351 $urls = explode( ',', $urls );
352 $urls = array_filter( $urls );
353
354 $all_ids = array();
355 foreach ( $urls as $url ) {
356 $all_ids[] = $this->parse_youtube_id_from_url( $url, 'video' );
357 }
358 $total_videos = count( $all_ids );
359 $total_pages = ceil( $total_videos / $params['maxResults'] );
360
361 $current_page = isset( $params['pageToken'] ) ? (int) $params['pageToken'] : 1;
362 $current_page = max( $current_page, 1 );
363 $current_page = min( $current_page, $total_pages );
364
365 $offset = ( $current_page - 1 ) * $params['maxResults'];
366 if ( $offset < 0 ) {
367 $offset = 0;
368 }
369
370 $current_ids = array_slice( $all_ids, $offset, $params['maxResults'] );
371 $params['id'] = implode( ',', $current_ids );
372
373 $api_params = $this->safe_merge_params(
374 array(
375 'id' => '',
376 'part' => 'id,snippet,contentDetails,statistics,status',
377 'cache' => 0
378 ),
379 $params
380 );
381
382 $api_response = $this->request_api( $api_url, $api_params );
383 if ( isset( $api_response->error ) ) {
384 return $api_response;
385 }
386
387 $videos = $this->parse_videos( $api_response );
388
389 // Process result
390 $response = new stdClass();
391 $response->videos = $videos;
392
393 $response->page_info = array(
394 'videos_found' => $total_videos
395 );
396
397 if ( $current_page > 1 ) {
398 $response->page_info['prev_page_token'] = $current_page - 1;
399 }
400
401 if ( $current_page < $total_pages ) {
402 $response->page_info['next_page_token'] = $current_page + 1;
403 }
404
405 return $response;
406 }
407
408 /**
409 * Get details of the given video ID.
410 *
411 * @since 1.0.0
412 * @access private
413 * @param array $params Array of query params.
414 * @return stdClass
415 */
416 private function request_api_video( $params = array() ) {
417 $api_url = $this->get_api_url( 'videos.list' );
418
419 $params['id'] = $this->parse_youtube_id_from_url( $params['id'], 'video' );
420
421 $api_params = $this->safe_merge_params(
422 array(
423 'id' => '',
424 'part' => 'id,snippet,contentDetails,statistics,status',
425 'cache' => 0
426 ),
427 $params
428 );
429
430 $api_response = $this->request_api( $api_url, $api_params );
431 if ( isset( $api_response->error ) ) {
432 return $api_response;
433 }
434
435 $videos = $this->parse_videos( $api_response );
436
437 // Process result
438 $response = new stdClass();
439 $response->videos = $videos;
440
441 return $response;
442 }
443
444 /**
445 * Get API URL by request.
446 *
447 * @since 1.0.0
448 * @access private
449 * @param array $name
450 * @return string
451 */
452 private function get_api_url( $name ) {
453 return $this->api_urls[ $name ];
454 }
455
456 /**
457 * Request data from the API server.
458 *
459 * @since 1.0.0
460 * @access private
461 * @param string $url YouTube API URL.
462 * @param array $params Array of query params.
463 * @return mixed
464 */
465 private function request_api( $url, $params ) {
466 $params['key'] = $this->api_key;
467
468 // Request data from transients
469 $transient_url = $url . ( strpos( $url, '?' ) === false ? '?' : '' ) . http_build_query( $params );
470 $transient_key = 'ayg_' . md5( $transient_url );
471 $transient_data = get_transient( $transient_key );
472
473 if ( ! empty( $transient_data ) ) {
474 return $transient_data;
475 }
476
477 $transient_expiration = 0;
478
479 if ( isset( $params['cache'] ) ) {
480 $transient_expiration = (int) $params['cache'];
481 unset( $params['cache'] );
482 }
483
484 // Request data from API server
485 $url = $url . ( strpos( $url, '?' ) === false ? '?' : '' ) . http_build_query( $params );
486
487 $request = wp_remote_get( $url, array(
488 'headers' => [ 'referer' => home_url() ],
489 ) );
490
491 if ( is_wp_error( $request ) ) {
492 return $this->get_error( $request->get_error_message() );
493 }
494
495 $body = wp_remote_retrieve_body( $request );
496
497 $data = json_decode( $body );
498
499 if ( isset( $data->error ) ) {
500 $message = "Error " . $data->error->code . " " . $data->error->message;
501
502 if ( isset( $data->error->errors[0] ) ) {
503 $message .= " : " . $data->error->errors[0]->reason;
504 }
505
506 return $this->get_error( $message );
507 }
508
509 // Store data in transients
510 if ( $transient_expiration > 0 ) {
511 set_transient( $transient_key, $data, $transient_expiration );
512
513 // Get the current list of transients
514 $transient_keys = get_option( 'ayg_transient_keys', array() );
515
516 // Append our new one
517 if ( ! in_array( $transient_key, $transient_keys ) ) {
518 $transient_keys[] = $transient_key;
519 }
520
521 // Save it to the DB
522 update_option( 'ayg_transient_keys', $transient_keys );
523 }
524
525 // Finally return the data
526 return $data;
527 }
528
529 /**
530 * Parse videos from the YouTube API response object.
531 *
532 * @since 1.0.0
533 * @access private
534 * @param object $data YouTube API response object.
535 * @return mixed
536 */
537 private function parse_videos( $data ) {
538 $items = $data->items;
539
540 if ( ! is_array( $items ) || 0 == count( $items ) ) {
541 return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
542 }
543
544 $videos = array();
545
546 foreach ( $items as $item ) {
547 $video = new stdClass();
548
549 // Video ID
550 $video->id = '';
551
552 if ( isset( $item->snippet->resourceId ) && isset( $item->snippet->resourceId->videoId ) ) {
553 $video->id = $item->snippet->resourceId->videoId;
554 } elseif ( isset( $item->contentDetails ) && isset( $item->contentDetails->videoId ) ) {
555 $video->id = $item->contentDetails->videoId;
556 } elseif ( isset( $item->id ) && isset( $item->id->videoId ) ) {
557 $video->id = $item->id->videoId;
558 } elseif ( isset( $item->id ) ) {
559 $video->id = $item->id;
560 }
561
562 // Video title
563 $video->title = $item->snippet->title;
564
565 // Video description
566 $video->description = $item->snippet->description;
567
568 // Video thumbnails
569 if ( isset( $item->snippet->thumbnails ) ) {
570 $video->thumbnails = $item->snippet->thumbnails;
571 }
572
573 // Video publish date
574 $video->published_at = $item->snippet->publishedAt;
575
576 // Push resulting object to the main array
577 $status = 'private';
578
579 if ( isset( $item->status ) && ( 'public' == $item->status->privacyStatus || 'unlisted' == $item->status->privacyStatus ) ) {
580 $status = 'public';
581 }
582
583 if ( isset( $item->snippet->status ) && ( 'public' == $item->snippet->status->privacyStatus || 'unlisted' == $item->snippet->status->privacyStatus ) ) {
584 $status = 'public';
585 }
586
587 if ( 'youtube#searchResult' == $item->kind ) {
588 $status = 'public';
589 }
590
591 if ( 'public' == $status ) {
592 $videos[] = $video;
593 }
594 }
595
596 return $videos;
597 }
598
599 /**
600 * Parse page info from the YouTube API response object.
601 *
602 * @since 1.0.0
603 * @access private
604 * @param object $data YouTube API response object.
605 * @return array
606 */
607 private function parse_page_info( $data ) {
608 $page_info = array();
609
610 // Total count of videos found
611 if ( isset( $data->pageInfo ) && isset( $data->pageInfo->totalResults ) ) {
612 $page_info['videos_found'] = $data->pageInfo->totalResults;
613 }
614
615 // Token for the previous page
616 if ( isset( $data->prevPageToken ) ) {
617 $page_info['prev_page_token'] = $data->prevPageToken;
618 }
619
620 // Token for the next page
621 if ( isset( $data->nextPageToken ) ) {
622 $page_info['next_page_token'] = $data->nextPageToken;
623 }
624
625 return $page_info;
626 }
627
628 /**
629 * Combine user params with known params and fill in defaults when needed.
630 *
631 * @since 1.0.0
632 * @access private
633 * @param array $pairs Entire list of supported params and their defaults.
634 * @param array $params User defined params.
635 * @return array $out Combined and filtered params array.
636 */
637 private function safe_merge_params( $pairs, $params ) {
638 $params = (array) $params;
639 $out = array();
640
641 foreach ( $pairs as $name => $default ) {
642 if ( array_key_exists( $name, $params ) ) {
643 $out[ $name ] = $params[ $name ];
644 } else {
645 $out[ $name ] = $default;
646 }
647
648 if ( empty( $out[ $name ] ) ) {
649 unset( $out[ $name ] );
650 }
651 }
652
653 return $out;
654 }
655
656 /**
657 * Build error object.
658 *
659 * @since 1.0.0
660 * @access private
661 * @param string $message Error message.
662 * @return object Error object.
663 */
664 private function get_error( $message ) {
665 $obj = new stdClass();
666 $obj->error = 1;
667 $obj->error_message = $message;
668
669 return $obj;
670 }
671
672 }
673