PluginProbe
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels / 1.5.0
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels v1.5.0
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.5.0, at includes/youtube-api.php

665 lines 16.7 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 'part' => 'id,snippet',
311 'order' => 'date',
312 'maxResults' => 50,
313 'pageToken' => '',
314 'cache' => 0
315 ),
316 $params
317 );
318
319 $api_response = $this->request_api( $api_url, $api_params );
320 if ( isset( $api_response->error ) ) {
321 return $api_response;
322 }
323
324 $videos = $this->parse_videos( $api_response );
325 if ( isset( $videos->error ) ) {
326 return $videos;
327 }
328
329 // Process result
330 $response = new stdClass();
331 $response->page_info = $this->parse_page_info( $api_response );
332 $response->videos = $videos;
333
334 return $response;
335 }
336
337 /**
338 * Get details of the given video IDs.
339 *
340 * @since 1.0.0
341 * @access private
342 * @param array $params Array of query params.
343 * @return stdClass
344 */
345 private function request_api_videos( $params = array() ) {
346 $api_url = $this->get_api_url( 'videos.list' );
347
348 $urls = str_replace( "\n\r", ',', $params['id'] );
349 $urls = str_replace( ' ', ',', $params['id'] );
350 $urls = explode( ',', $urls );
351 $urls = array_filter( $urls );
352
353 $all_ids = array();
354 foreach ( $urls as $url ) {
355 $all_ids[] = $this->parse_youtube_id_from_url( $url, 'video' );
356 }
357 $total_videos = count( $all_ids );
358 $total_pages = ceil( $total_videos / $params['maxResults'] );
359
360 $current_page = isset( $params['pageToken'] ) ? (int) $params['pageToken'] : 1;
361 $current_page = max( $current_page, 1 );
362 $current_page = min( $current_page, $total_pages );
363
364 $offset = ( $current_page - 1 ) * $params['maxResults'];
365 if ( $offset < 0 ) {
366 $offset = 0;
367 }
368
369 $current_ids = array_slice( $all_ids, $offset, $params['maxResults'] );
370 $params['id'] = implode( ',', $current_ids );
371
372 $api_params = $this->safe_merge_params(
373 array(
374 'id' => '',
375 'part' => 'id,snippet,contentDetails,statistics,status',
376 'cache' => 0
377 ),
378 $params
379 );
380
381 $api_response = $this->request_api( $api_url, $api_params );
382 if ( isset( $api_response->error ) ) {
383 return $api_response;
384 }
385
386 $videos = $this->parse_videos( $api_response );
387
388 // Process result
389 $response = new stdClass();
390 $response->videos = $videos;
391
392 $response->page_info = array(
393 'videos_found' => $total_videos
394 );
395
396 if ( $current_page > 1 ) {
397 $response->page_info['prev_page_token'] = $current_page - 1;
398 }
399
400 if ( $current_page < $total_pages ) {
401 $response->page_info['next_page_token'] = $current_page + 1;
402 }
403
404 return $response;
405 }
406
407 /**
408 * Get details of the given video ID.
409 *
410 * @since 1.0.0
411 * @access private
412 * @param array $params Array of query params.
413 * @return stdClass
414 */
415 private function request_api_video( $params = array() ) {
416 $api_url = $this->get_api_url( 'videos.list' );
417
418 $params['id'] = $this->parse_youtube_id_from_url( $params['id'], 'video' );
419
420 $api_params = $this->safe_merge_params(
421 array(
422 'id' => '',
423 'part' => 'id,snippet,contentDetails,statistics,status',
424 'cache' => 0
425 ),
426 $params
427 );
428
429 $api_response = $this->request_api( $api_url, $api_params );
430 if ( isset( $api_response->error ) ) {
431 return $api_response;
432 }
433
434 $videos = $this->parse_videos( $api_response );
435
436 // Process result
437 $response = new stdClass();
438 $response->videos = $videos;
439
440 return $response;
441 }
442
443 /**
444 * Get API URL by request.
445 *
446 * @since 1.0.0
447 * @access private
448 * @param array $name
449 * @return string
450 */
451 private function get_api_url( $name ) {
452 return $this->api_urls[ $name ];
453 }
454
455 /**
456 * Request data from the API server.
457 *
458 * @since 1.0.0
459 * @access private
460 * @param string $url YouTube API URL.
461 * @param array $params Array of query params.
462 * @return mixed
463 */
464 private function request_api( $url, $params ) {
465 $params['key'] = $this->api_key;
466
467 // Request data from transients
468 $transient_url = $url . ( strpos( $url, '?' ) === false ? '?' : '' ) . http_build_query( $params );
469 $transient_key = 'ayg_' . md5( $transient_url );
470 $transient_data = get_transient( $transient_key );
471
472 if ( ! empty( $transient_data ) ) {
473 return $transient_data;
474 }
475
476 $transient_expiration = 0;
477
478 if ( isset( $params['cache'] ) ) {
479 $transient_expiration = (int) $params['cache'];
480 unset( $params['cache'] );
481 }
482
483 // Request data from API server
484 $url = $url . ( strpos( $url, '?' ) === false ? '?' : '' ) . http_build_query( $params );
485
486 $request = wp_remote_get( $url, array(
487 'headers' => [ 'referer' => home_url() ],
488 ) );
489
490 if ( is_wp_error( $request ) ) {
491 return $this->get_error( $request->get_error_message() );
492 }
493
494 $body = wp_remote_retrieve_body( $request );
495
496 $data = json_decode( $body );
497
498 if ( isset( $data->error ) ) {
499 $message = "Error " . $data->error->code . " " . $data->error->message;
500
501 if ( isset( $data->error->errors[0] ) ) {
502 $message .= " : " . $data->error->errors[0]->reason;
503 }
504
505 return $this->get_error( $message );
506 }
507
508 // Store data in transients
509 if ( $transient_expiration > 0 ) {
510 set_transient( $transient_key, $data, $transient_expiration );
511
512 // Get the current list of transients
513 $transient_keys = get_option( 'ayg_transient_keys', array() );
514
515 // Append our new one
516 if ( ! in_array( $transient_key, $transient_keys ) ) {
517 $transient_keys[] = $transient_key;
518 }
519
520 // Save it to the DB
521 update_option( 'ayg_transient_keys', $transient_keys );
522 }
523
524 // Finally return the data
525 return $data;
526 }
527
528 /**
529 * Parse videos from the YouTube API response object.
530 *
531 * @since 1.0.0
532 * @access private
533 * @param object $data YouTube API response object.
534 * @return mixed
535 */
536 private function parse_videos( $data ) {
537 $items = $data->items;
538
539 if ( ! is_array( $items ) || 0 == count( $items ) ) {
540 return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
541 }
542
543 $videos = array();
544
545 foreach ( $items as $item ) {
546 $video = new stdClass();
547
548 // Video ID
549 $video->id = '';
550
551 if ( isset( $item->snippet->resourceId ) && isset( $item->snippet->resourceId->videoId ) ) {
552 $video->id = $item->snippet->resourceId->videoId;
553 } elseif ( isset( $item->contentDetails ) && isset( $item->contentDetails->videoId ) ) {
554 $video->id = $item->contentDetails->videoId;
555 } elseif ( isset( $item->id ) && isset( $item->id->videoId ) ) {
556 $video->id = $item->id->videoId;
557 } elseif ( isset( $item->id ) ) {
558 $video->id = $item->id;
559 }
560
561 // Video title
562 $video->title = $item->snippet->title;
563
564 // Video description
565 $video->description = $item->snippet->description;
566
567 // Video thumbnails
568 if ( isset( $item->snippet->thumbnails ) ) {
569 $video->thumbnails = $item->snippet->thumbnails;
570 }
571
572 // Video publish date
573 $video->published_at = $item->snippet->publishedAt;
574
575 // Is video private?
576 $video->is_private = 0;
577
578 if ( ! isset( $item->snippet->thumbnails ) || ( isset( $item->snippet->status ) && 'private' == $item->snippet->status->privacyStatus ) ) {
579 $video->is_private = 1;
580 }
581
582 // Push resulting object to the main array
583 if ( ! $video->is_private ) {
584 $videos[] = $video;
585 }
586 }
587
588 return $videos;
589 }
590
591 /**
592 * Parse page info from the YouTube API response object.
593 *
594 * @since 1.0.0
595 * @access private
596 * @param object $data YouTube API response object.
597 * @return array
598 */
599 private function parse_page_info( $data ) {
600 $page_info = array();
601
602 // Total count of videos found
603 if ( isset( $data->pageInfo ) && isset( $data->pageInfo->totalResults ) ) {
604 $page_info['videos_found'] = $data->pageInfo->totalResults;
605 }
606
607 // Token for the previous page
608 if ( isset( $data->prevPageToken ) ) {
609 $page_info['prev_page_token'] = $data->prevPageToken;
610 }
611
612 // Token for the next page
613 if ( isset( $data->nextPageToken ) ) {
614 $page_info['next_page_token'] = $data->nextPageToken;
615 }
616
617 return $page_info;
618 }
619
620 /**
621 * Combine user params with known params and fill in defaults when needed.
622 *
623 * @since 1.0.0
624 * @access private
625 * @param array $pairs Entire list of supported params and their defaults.
626 * @param array $params User defined params.
627 * @return array $out Combined and filtered params array.
628 */
629 private function safe_merge_params( $pairs, $params ) {
630 $params = (array) $params;
631 $out = array();
632
633 foreach ( $pairs as $name => $default ) {
634 if ( array_key_exists( $name, $params ) ) {
635 $out[ $name ] = $params[ $name ];
636 } else {
637 $out[ $name ] = $default;
638 }
639
640 if ( empty( $out[ $name ] ) ) {
641 unset( $out[ $name ] );
642 }
643 }
644
645 return $out;
646 }
647
648 /**
649 * Build error object.
650 *
651 * @since 1.0.0
652 * @access private
653 * @param string $message Error message.
654 * @return object Error object.
655 */
656 private function get_error( $message ) {
657 $obj = new stdClass();
658 $obj->error = 1;
659 $obj->error_message = $message;
660
661 return $obj;
662 }
663
664 }
665