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

663 lines 16.6 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 );
487
488 if ( is_wp_error( $request ) ) {
489 return $this->get_error( $request->get_error_message() );
490 }
491
492 $body = wp_remote_retrieve_body( $request );
493
494 $data = json_decode( $body );
495
496 if ( isset( $data->error ) ) {
497 $message = "Error " . $data->error->code . " " . $data->error->message;
498
499 if ( isset( $data->error->errors[0] ) ) {
500 $message .= " : " . $data->error->errors[0]->reason;
501 }
502
503 return $this->get_error( $message );
504 }
505
506 // Store data in transients
507 if ( $transient_expiration > 0 ) {
508 set_transient( $transient_key, $data, $transient_expiration );
509
510 // Get the current list of transients
511 $transient_keys = get_option( 'ayg_transient_keys', array() );
512
513 // Append our new one
514 if ( ! in_array( $transient_key, $transient_keys ) ) {
515 $transient_keys[] = $transient_key;
516 }
517
518 // Save it to the DB
519 update_option( 'ayg_transient_keys', $transient_keys );
520 }
521
522 // Finally return the data
523 return $data;
524 }
525
526 /**
527 * Parse videos from the YouTube API response object.
528 *
529 * @since 1.0.0
530 * @access private
531 * @param object $data YouTube API response object.
532 * @return mixed
533 */
534 private function parse_videos( $data ) {
535 $items = $data->items;
536
537 if ( ! is_array( $items ) || 0 == count( $items ) ) {
538 return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
539 }
540
541 $videos = array();
542
543 foreach ( $items as $item ) {
544 $video = new stdClass();
545
546 // Video ID
547 $video->id = '';
548
549 if ( isset( $item->snippet->resourceId ) && isset( $item->snippet->resourceId->videoId ) ) {
550 $video->id = $item->snippet->resourceId->videoId;
551 } elseif ( isset( $item->contentDetails ) && isset( $item->contentDetails->videoId ) ) {
552 $video->id = $item->contentDetails->videoId;
553 } elseif ( isset( $item->id ) && isset( $item->id->videoId ) ) {
554 $video->id = $item->id->videoId;
555 } elseif ( isset( $item->id ) ) {
556 $video->id = $item->id;
557 }
558
559 // Video title
560 $video->title = $item->snippet->title;
561
562 // Video description
563 $video->description = $item->snippet->description;
564
565 // Video thumbnails
566 if ( isset( $item->snippet->thumbnails ) ) {
567 $video->thumbnails = $item->snippet->thumbnails;
568 }
569
570 // Video publish date
571 $video->published_at = $item->snippet->publishedAt;
572
573 // Is video private?
574 $video->is_private = 0;
575
576 if ( ! isset( $item->snippet->thumbnails ) || ( isset( $item->snippet->status ) && 'private' == $item->snippet->status->privacyStatus ) ) {
577 $video->is_private = 1;
578 }
579
580 // Push resulting object to the main array
581 if ( ! $video->is_private ) {
582 $videos[] = $video;
583 }
584 }
585
586 return $videos;
587 }
588
589 /**
590 * Parse page info from the YouTube API response object.
591 *
592 * @since 1.0.0
593 * @access private
594 * @param object $data YouTube API response object.
595 * @return array
596 */
597 private function parse_page_info( $data ) {
598 $page_info = array();
599
600 // Total count of videos found
601 if ( isset( $data->pageInfo ) && isset( $data->pageInfo->totalResults ) ) {
602 $page_info['videos_found'] = $data->pageInfo->totalResults;
603 }
604
605 // Token for the previous page
606 if ( isset( $data->prevPageToken ) ) {
607 $page_info['prev_page_token'] = $data->prevPageToken;
608 }
609
610 // Token for the next page
611 if ( isset( $data->nextPageToken ) ) {
612 $page_info['next_page_token'] = $data->nextPageToken;
613 }
614
615 return $page_info;
616 }
617
618 /**
619 * Combine user params with known params and fill in defaults when needed.
620 *
621 * @since 1.0.0
622 * @access private
623 * @param array $pairs Entire list of supported params and their defaults.
624 * @param array $params User defined params.
625 * @return array $out Combined and filtered params array.
626 */
627 private function safe_merge_params( $pairs, $params ) {
628 $params = (array) $params;
629 $out = array();
630
631 foreach ( $pairs as $name => $default ) {
632 if ( array_key_exists( $name, $params ) ) {
633 $out[ $name ] = $params[ $name ];
634 } else {
635 $out[ $name ] = $default;
636 }
637
638 if ( empty( $out[ $name ] ) ) {
639 unset( $out[ $name ] );
640 }
641 }
642
643 return $out;
644 }
645
646 /**
647 * Build error object.
648 *
649 * @since 1.0.0
650 * @access private
651 * @param string $message Error message.
652 * @return object Error object.
653 */
654 private function get_error( $message ) {
655 $obj = new stdClass();
656 $obj->error = 1;
657 $obj->error_message = $message;
658
659 return $obj;
660 }
661
662 }
663