PluginProbe
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels / 2.6.4
Automatic YouTube Gallery – Embed Auto-Updating YouTube Video Galleries, Feeds, Playlists & Channels v2.6.4
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
← All changes | includes/youtube-api.php +194 -62 2.3.82.6.4 View file →
@@ -30,20 +30,15 @@
30 30 */
31 31 protected $api_key;
32 32
33 33 /**
34 - * The YouTube API URLs.
34 + * Array of query params.
35 35 *
36 - * @since 1.0.0
36 + * @since 2.5.7
37 37 * @access protected
38 38 * @var array
39 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 - );
40 + protected $params = array();
46 41
47 42 /**
48 43 * Is development mode enabled?
49 44 *
@@ -53,12 +48,26 @@
53 48 */
54 49 protected $is_development_mode = false;
55 50
56 51 /**
52 + * The YouTube API URLs.
53 + *
54 + * @since 1.0.0
55 + * @access protected
56 + * @var array
57 + */
58 + public $api_urls = array(
59 + 'playlistItems.list' => 'https://www.googleapis.com/youtube/v3/playlistItems',
60 + 'channels.list' => 'https://www.googleapis.com/youtube/v3/channels',
61 + 'search.list' => 'https://www.googleapis.com/youtube/v3/search',
62 + 'videos.list' => 'https://www.googleapis.com/youtube/v3/videos'
63 + );
64 +
65 + /**
57 66 * Get videos.
58 67 *
59 68 * @since 1.0.0
60 - * @param array $params Array of query params.
69 + * @param array $params Array of query params.
61 70 * @return mixed
62 71 */
63 72 public function query( $params = array() ) {
64 73 // Get YouTube API Key
@@ -64,12 +73,13 @@
64 73 // Get YouTube API Key
65 74 $general_settings = get_option( 'ayg_general_settings' );
66 75
67 76 if ( empty( $general_settings['api_key'] ) ) {
68 - return $this->get_error( __( 'YouTube API key not found.', 'automatic-youtube-gallery' ) . ' ' . sprintf( __( 'Kindly follow this URL <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/' ) );
77 + return $this->get_error( __( 'YouTube API key not found.', 'automatic-youtube-gallery' ) . ' ' . sprintf( __( 'Kindly follow this URL <a href="%s" target="_blank" rel="noopener noreferrer">this guide</a> to get your own API key.', 'automatic-youtube-gallery' ), 'https://plugins360.com/automatic-youtube-gallery/how-to-get-youtube-api-key/' ) );
69 78 }
70 79
71 80 $this->api_key = $general_settings['api_key'];
81 + $this->params = $params;
72 82
73 83 // Is development mode enabled?
74 84 if ( isset( $general_settings['development_mode'] ) && ! empty( $general_settings['development_mode'] ) ) {
75 85 $this->is_development_mode = true;
@@ -77,8 +87,13 @@
77 87
78 88 // Process output
79 89 $response = array();
80 90
91 + if ( ! empty( $params['searchTerm'] ) ) {
92 + $response = $this->get_videos_from_db( $params );
93 + return $response;
94 + }
95 +
81 96 switch ( $params['type'] ) {
82 97 case 'playlist':
83 98 if ( empty( $params['src'] ) ) {
84 99 return $this->get_error( __( 'YouTube Playlist ID (or) URL is required.', 'automatic-youtube-gallery' ) );
@@ -193,9 +208,9 @@
193 208 $id = $url;
194 209
195 210 switch ( $type ) {
196 211 case 'playlist':
197 - if ( preg_match( '/list=(.*)&?\/?/', $url, $matches ) ) {
212 + if ( preg_match( '/[?&]list=([^&]+)/', $url, $matches ) ) {
198 213 $id = $matches[1];
199 214 }
200 215 break;
201 216
@@ -219,14 +234,18 @@
219 234 }
220 235 break;
221 236
222 237 default: // video
238 + if ( wp_http_validate_url( $id ) ) {
239 + $id = '';
240 + }
241 +
223 242 $url = parse_url( $url );
224 243
225 244 if ( array_key_exists( 'host', $url ) ) {
226 245 if ( 0 === strcasecmp( $url['host'], 'youtu.be' ) ) {
227 246 $id = substr( $url['path'], 1 );
228 - } elseif ( 0 === strcasecmp( $url['host'], 'www.youtube.com' ) ) {
247 + } elseif ( 0 === strcasecmp( $url['host'], 'www.youtube.com' ) || 0 === strcasecmp( $url['host'], 'youtube.com' ) ) {
229 248 if ( isset( $url['query'] ) ) {
230 249 parse_str( $url['query'], $url['query'] );
231 250
232 251 if ( isset( $url['query']['v'] ) ) {
@@ -235,10 +254,9 @@
235 254 }
236 255
237 256 if ( empty( $id ) ) {
238 257 $url['path'] = explode( '/', substr( $url['path'], 1 ) );
239 -
240 - if ( in_array( $url['path'][0], array( 'e', 'embed', 'v' ) ) ) {
258 + if ( in_array( $url['path'][0], array( 'e', 'embed', 'v', 'shorts', 'live' ) ) ) {
241 259 $id = $url['path'][1];
242 260 }
243 261 }
244 262 }
@@ -496,9 +514,9 @@
496 514 ),
497 515 $params
498 516 );
499 517
500 - $api_response = $this->request_api( $api_url, $api_params );
518 + $api_response = $this->request_api( $api_url, $api_params, 'live' );
501 519 if ( isset( $api_response->error ) ) {
502 520 return $api_response;
503 521 }
504 522
@@ -580,12 +598,9 @@
580 598 $current_page = isset( $params['pageToken'] ) ? (int) $params['pageToken'] : 1;
581 599 $current_page = max( $current_page, 1 );
582 600 $current_page = min( $current_page, $total_pages );
583 601
584 - $offset = ( $current_page - 1 ) * $params['maxResults'];
585 - if ( $offset < 0 ) {
586 - $offset = 0;
587 - }
602 + $offset = max( 0, ( $current_page - 1 ) * $params['maxResults'] );
588 603
589 604 $current_ids = array_slice( $all_ids, $offset, $params['maxResults'] );
590 605 $params['id'] = implode( ',', $current_ids );
591 606
@@ -612,9 +627,11 @@
612 627 $response = new stdClass();
613 628 $response->videos = $videos;
614 629
615 630 $response->page_info = array(
616 - 'videos_found' => $total_videos
631 + 'videos_found' => $total_videos,
632 + 'total_pages' => $total_pages,
633 + 'paged' => $current_page
617 634 );
618 635
619 636 if ( $current_page > 1 ) {
620 637 $response->page_info['prev_page_token'] = $current_page - 1;
@@ -625,8 +642,96 @@
625 642 }
626 643
627 644 return $response;
628 645 }
646 +
647 + /**
648 + * Get videos from our custom database table "{$wpdb->prefix}ayg_videos".
649 + *
650 + * @since 2.5.7
651 + * @access private
652 + * @param array $params Array of query params.
653 + * @return stdClass
654 + */
655 + private function get_videos_from_db( $params = array() ) {
656 + global $wpdb;
657 +
658 + $videos_table = $wpdb->prefix . 'ayg_videos';
659 + $galleries_table = $wpdb->prefix . 'ayg_galleries';
660 +
661 + $search_term = '%' . $wpdb->esc_like( $params['searchTerm'] ) . '%';
662 + $gallery_id = $params['uid'];
663 +
664 + // Get Total Videos Count
665 + $total_query = $wpdb->prepare(
666 + "SELECT COUNT(*)
667 + FROM $videos_table AS v
668 + INNER JOIN $galleries_table AS g ON v.id = g.video_id
669 + WHERE g.gallery_id = %s
670 + AND (v.title LIKE %s OR v.description LIKE %s)",
671 + $gallery_id, $search_term, $search_term
672 + );
673 +
674 + $total_videos = $wpdb->get_var( $total_query );
675 +
676 + if ( empty( $total_videos ) ) {
677 + return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
678 + }
679 +
680 + // Fetch Paginated Videos
681 + $limit = $params['maxResults'];
682 +
683 + $total_pages = ceil( $total_videos / $limit );
684 +
685 + $current_page = isset( $params['pageToken'] ) ? (int) $params['pageToken'] : 1;
686 + $current_page = max( $current_page, 1 );
687 + $current_page = min( $current_page, $total_pages );
688 +
689 + $offset = max( 0, ( $current_page - 1 ) * $limit );
690 +
691 + $query = $wpdb->prepare(
692 + "SELECT v.*
693 + FROM $videos_table AS v
694 + INNER JOIN $galleries_table AS g ON v.id = g.video_id
695 + WHERE g.gallery_id = %s
696 + AND (v.title LIKE %s OR v.description LIKE %s)
697 + ORDER BY v.published_at_datetime DESC
698 + LIMIT %d OFFSET %d",
699 + $gallery_id, $search_term, $search_term, $limit, $offset
700 + );
701 +
702 + $videos = $wpdb->get_results( $query );
703 +
704 + if ( empty( $videos ) ) {
705 + return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
706 + }
707 +
708 + foreach ( $videos as $index => $video ) {
709 + if ( ! empty( $video->thumbnails ) ) {
710 + $videos[ $index ]->thumbnails = maybe_unserialize( $video->thumbnails );
711 + }
712 + }
713 +
714 + // Process output
715 + $response = new stdClass();
716 + $response->videos = $videos;
717 +
718 + $response->page_info = array(
719 + 'videos_found' => $total_videos,
720 + 'total_pages' => $total_pages,
721 + 'paged' => $current_page
722 + );
723 +
724 + if ( $current_page > 1 ) {
725 + $response->page_info['prev_page_token'] = $current_page - 1;
726 + }
727 +
728 + if ( $current_page < $total_pages ) {
729 + $response->page_info['next_page_token'] = $current_page + 1;
730 + }
731 +
732 + return $response;
733 + }
629 734
630 735 /**
631 736 * Get API URL by request.
632 737 *
@@ -645,31 +750,21 @@
645 750 * @since 1.0.0
646 751 * @access private
647 752 * @param string $url YouTube API URL.
648 753 * @param array $params Array of query params.
649 - * @param string $context "channel_id", "playlist_id", or "videos"
754 + * @param string $context "channel_id", "playlist_id", "videos", or "live"
650 755 * @return mixed
651 756 */
652 757 private function request_api( $url, $params, $context = 'videos' ) {
653 758 $params['key'] = $this->api_key;
654 -
655 - // Request from cache
656 - if ( ! $this->is_development_mode ) {
657 - $cache_url = $url . ( strpos( $url, '?' ) === false ? '?' : '' ) . http_build_query( $params );
658 - $cache_key = 'ayg_' . md5( $cache_url );
659 - $cache_data = get_transient( $cache_key );
660 -
661 - if ( ! empty( $cache_data ) ) {
662 - return $cache_data;
663 - }
664 - }
665 -
666 - // Request from API
759 +
760 + // Build API URL
667 761 $cache_duration = 0;
668 762 if ( isset( $params['cache'] ) ) {
669 763 $cache_duration = (int) $params['cache'];
670 764 unset( $params['cache'] );
671 765 }
766 + $cache_duration = min( $cache_duration, 2419200 ); // Max cache duration: 1 Month
672 767
673 768 $q = '';
674 769 if ( isset( $params['q'] ) ) {
675 770 $q = $params['q'];
@@ -675,15 +770,29 @@
675 770 $q = $params['q'];
676 771 unset( $params['q'] );
677 772 }
678 773
679 - $url = $url . ( strpos( $url, '?' ) === false ? '?' : '' ) . http_build_query( $params );
774 + $api_url = $url . ( strpos( $url, '?' ) === false ? '?' : '&' ) . http_build_query( $params );
680 775 if ( ! empty( $q ) ) {
681 - $url .= '&q=' . $q;
776 + $api_url .= '&q=' . $q;
682 777 }
683 778
684 - $request = wp_remote_get( $url, array(
779 + // Request from cache
780 + if ( ! $this->is_development_mode && $cache_duration > 0 ) {
781 + $cache_key = 'ayg_' . md5( $api_url );
782 + $cache_data = get_transient( $cache_key );
783 +
784 + if ( ! empty( $cache_data ) ) {
785 + return $cache_data;
786 + }
787 + }
788 +
789 + // Request from API
790 + $timeout = apply_filters( 'ayg_api_request_timeout', 15 );
791 +
792 + $request = wp_remote_get( $api_url, array(
685 793 'headers' => [ 'referer' => home_url() ],
794 + 'timeout' => $timeout, // Increase timeout if needed
686 795 ) );
687 796
688 797 if ( is_wp_error( $request ) ) {
689 798 return $this->get_error( $request->get_error_message() );
@@ -689,10 +798,13 @@
689 798 return $this->get_error( $request->get_error_message() );
690 799 }
691 800
692 801 $body = wp_remote_retrieve_body( $request );
802 + $data = json_decode( $body );
693 803
694 - $data = json_decode( $body );
804 + if ( empty( $data ) ) {
805 + return $this->get_error( __( 'Empty or invalid API response', 'automatic-youtube-gallery' ) );
806 + }
695 807
696 808 if ( isset( $data->error ) ) {
697 809 $message = "Error " . $data->error->code . " " . $data->error->message;
698 810
@@ -703,30 +815,42 @@
703 815 return $this->get_error( $message );
704 816 }
705 817
706 818 // Store in cache (transients)
707 - if ( ! $this->is_development_mode && 'videos' == $context && $cache_duration > 0 ) {
708 - if ( isset( $data->items ) && is_array( $data->items ) && count( $data->items ) > 0 ) {
709 - set_transient( $cache_key, $data, $cache_duration );
819 + $cache_enabled = false;
710 820
711 - // Get the current list of transients
712 - $cache_keys = get_option( 'ayg_transient_keys', array() );
713 - if ( ! is_array( $cache_keys ) ) {
714 - $cache_keys = (array) $cache_keys;
821 + if ( ! $this->is_development_mode && $cache_duration > 0 ) {
822 + if ( 'videos' === $context ) {
823 + if ( ! empty( $data->items ) && is_array( $data->items ) ) {
824 + $cache_enabled = true;
715 825 }
826 + }
716 827
717 - // Append our new one
718 - if ( ! in_array( $cache_key, $cache_keys ) ) {
719 - $cache_keys[] = $cache_key;
720 - }
828 + if ( 'live' === $context ) {
829 + $cache_enabled = true;
830 + }
831 + }
721 832
722 - // Save it to the DB
723 - update_option( 'ayg_transient_keys', $cache_keys );
833 + if ( $cache_enabled ) {
834 + set_transient( $cache_key, $data, $cache_duration );
835 +
836 + // Get the current list of transients
837 + $cache_keys = get_option( 'ayg_transient_keys', array() );
838 + if ( ! is_array( $cache_keys ) ) {
839 + $cache_keys = (array) $cache_keys;
724 840 }
841 +
842 + // Append our new one
843 + if ( ! in_array( $cache_key, $cache_keys ) ) {
844 + $cache_keys[] = $cache_key;
845 + }
846 +
847 + // Save it to the DB
848 + update_option( 'ayg_transient_keys', $cache_keys );
725 849 }
726 850
727 851 // Store videos in our custom database table "{$wpdb->prefix}ayg_videos"
728 - ayg_db_store_videos( $data );
852 + ayg_db_store_videos( $data, $this->params );
729 853
730 854 // Finally return the data
731 855 return $data;
732 856 }
@@ -739,17 +863,13 @@
739 863 * @param object $data YouTube API response object.
740 864 * @return mixed
741 865 */
742 866 private function parse_videos( $data ) {
743 - if ( ! isset( $data->items ) ) {
867 + if ( empty( $data->items ) || ! is_array( $data->items ) ) {
744 868 return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
745 869 }
746 870
747 - $items = $data->items;
748 - if ( ! is_array( $items ) || 0 == count( $items ) ) {
749 - return $this->get_error( __( 'No videos found matching your query.', 'automatic-youtube-gallery' ) );
750 - }
751 -
871 + $items = $data->items;
752 872 $videos = array();
753 873
754 874 foreach ( $items as $item ) {
755 875 $video = new stdClass();
@@ -823,14 +943,26 @@
823 943 * @param object $data YouTube API response object.
824 944 * @return array
825 945 */
826 946 private function parse_page_info( $data ) {
827 - $page_info = array();
947 + $page_info = array(
948 + 'videos_found' => 0
949 + );
828 950
829 - // Total count of videos found
951 + // Total number of videos found
830 952 if ( isset( $data->pageInfo ) && isset( $data->pageInfo->totalResults ) ) {
831 - $page_info['videos_found'] = $data->pageInfo->totalResults;
832 - }
953 + $page_info['videos_found'] = (int) $data->pageInfo->totalResults;
954 + }
955 +
956 + // Calculate total number of pages
957 + if ( $page_info['videos_found'] > 0 ) {
958 + if ( 'search' == $this->params['type'] ) {
959 + $limit = min( (int) $this->params['limit'], $page_info['videos_found'] );
960 + $page_info['total_pages'] = ceil( $limit / (int) $this->params['maxResults'] );
961 + } else {
962 + $page_info['total_pages'] = ceil( $page_info['videos_found'] / (int) $this->params['maxResults'] );
963 + }
964 + }
833 965
834 966 // Token for the previous page
835 967 if ( isset( $data->prevPageToken ) ) {
836 968 $page_info['prev_page_token'] = $data->prevPageToken;