Files
szkoleniauryzaj.pl/wp-content/plugins/youtube-feed-pro/inc/Pro/SBY_Live_Streams.php
2026-04-26 23:47:49 +02:00

364 lines
9.2 KiB
PHP

<?php
/**
* SBY_Live_Streams.
*
* Live streamed videos are stored in a cache due to there being no
* reliable way to retrieve then using an API key and a standard API endpoint.
* The RSS feed for the channel is used to get the latest 15 published videos
* and this class can be used tp store all of the ones that are scheduled
* live streams.
*
* @since 1.3
*/
namespace SmashBalloon\YouTubeFeed\Pro;
use SmashBalloon\YouTubeFeed\SBY_Parse;
use SmashBalloon\YouTubeFeed\SBY_RSS_Connect;
class SBY_Live_Streams {
/**
* @var string
*/
private $channel;
/**
* @var int
*/
private $feed_id;
/**
* @var string
*/
private $cache_name;
/**
* @var array
*/
private $video_cache;
/**
* SBY_Live_Streams constructor.
*
* @param $channel string
*
* @since 1.3
*/
public function __construct( $channel, $feed_id ) {
$this->channel = $channel;
$this->feed_id = $feed_id;
$this->cache_name = 'sby_livestreams_' . $channel;
$this->video_cache = get_option( $this->cache_name, array() );
}
/**
* Cached video api data
*
* @return array
*
* @since 1.3
*/
public function get_video_cache() {
return $this->video_cache;
}
/**
* Get latest 15 videos from RSS and return only
* live streams. Use the video IDs to retrieve details
* using the "single" video API endpoint. Update or add
* to the cache based on results.
*
* @return array
*
* @since 1.3
*/
public function add_remote_posts() {
$api_videos = $this->fetch_via_api();
if(empty($api_videos)) {
$api_videos = $this->fetch_rss();
}
$live_streams = $this->fetch_singles( $api_videos );
$this->update_or_add( $live_streams );
return $live_streams;
}
/**
* Refresh the API data for the most recent 40
* videos in the cache. Can exclude videos if they
* were just updated from another process.
*
* @param $exclude array
*
* @since 1.3
*/
public function update_cached_video_details( $exclude ) {
$to_check = array_slice( $this->video_cache, 0, 40 + count( $exclude ) );
$to_update = array();
foreach ( $to_check as $vid_id => $post ) {
// $exclude set as an associative array with the video ID
// as the index.
if ( ! isset( $exclude[ $vid_id ] )
&& count( $to_update ) < 40 ) {
$to_update[] = $vid_id;
}
}
if ( ! empty( $to_update ) ) {
$live_streams = $this->fetch_singles( $to_update );
$this->update_or_add( $live_streams, $to_update );
}
}
/**
* The RSS feed contains live stream videos.
*
* @return array
*
* @since 1.3
*/
public function fetch_rss() {
$params = array(
'channel_id' => $this->channel,
'livestream' => '1'
);
$connection = new SBY_RSS_Connect( 'playlistItems', $params );
$connection->connect();
$data = $connection->get_data();
$ids = array();
if ( is_array( $data ) ) {
foreach ( $data as $post ) {
$vid_id = SBY_Parse::get_video_id( $post );
$ids[] = $vid_id;
}
}
return $ids;
}
/**
* Retrieves the video IDs of live stream feeds for a specific event type.
*
* @param string $event_type The type of event for which to fetch live stream video IDs.
* This parameter determines the category or type of live streams to query.
* @param string $page_token (Optional) The token to retrieve the next page of results, if available.
* Default is an empty string, which fetches the first page.
*
* @return array An associative array containing the video IDs of the live streams and any
*
* @since 1.3
*
*/
public function get_live_stream_feed_video_ids($event_type, $page_token = '') {
$ids = [];
$page_token = '';
$params = array(
'channel_id' => $this->channel,
'event_type' => $event_type,
);
if( !empty($page_token) ) {
$params['page_token'] = $page_token;
}
$connection = new SBY_API_Connect_Pro(sby_get_first_connected_account(), 'livestream', $params);
$connection->connect();
if ( ! $connection->is_youtube_error() ) {
$items = !empty( $connection->get_data()['items'] ) ? $connection->get_data()['items'] : '';
$page_token = !empty( $connection->get_data()['nextPageToken'] ) ? $connection->get_data()['nextPageToken'] : '';
if( !empty($items)) {
foreach ( $items as $single ) {
$videoId = isset($single['id']['videoId']) ? $single['id']['videoId'] : '';
$ids[] = $videoId;
}
}
}
return [
'ids' => $ids,
'page_token' => $page_token
];
}
/**
* Get livestream feed using api.
*
* @return array
*
* @since 1.3
*/
public function fetch_via_api() {
$atts = ['feed' => (int)$this->feed_id];
$database_settings = sby_get_database_settings();
$youtube_feed_settings = new SBY_Settings_Pro($atts, $database_settings);
if (empty($database_settings['connected_accounts']) && empty($database_settings['api_key'])) {
wp_send_json_error('Error: No connected account');
}
$settings = $youtube_feed_settings->get_settings();
$data = [];
$event_types = ['upcoming','live'];
$page_token = '';
$archive_page_count = !empty($settings['showpast'] )? apply_filters( 'sby_past_live_stream_num_pages', 1 ) : 0;
// For adding more past live streams in the future.
if ($archive_page_count > 0) {
$event_types[] = 'completed';
}
foreach ($event_types as $single) {
$page_token = ''; // Initialize the page token for each event type.
$current_page = 0; // Track the current page for "completed" events.
do {
// Fetch data with or without a page token.
if ('completed' === $single && !empty($page_token)) {
$response = self::get_live_stream_feed_video_ids($single, $page_token);
} else {
$response = self::get_live_stream_feed_video_ids($single);
}
if (!empty($response)) {
// Add video IDs to the data array.
$ids = !empty($response['ids']) ? $response['ids'] : [];
array_push($data, ...$ids);
// Update the page token for the next loop iteration.
$page_token = !empty($response['page_token']) ? $response['page_token'] : '';
// Increment the page counter for "completed" events.
if ('completed' === $single) {
$current_page++;
}
} else {
// Exit the loop if no response or no more pages.
$page_token = '';
}
} while (!empty($page_token) && $current_page < $archive_page_count); // Limit pages based on $archive_page_count.
}
return $data;
}
/**
* Divides an array of items into smaller batches of a specified size.
*
* @param array $items The array of items to be divided into batches.
* @param int $batchSize The maximum number of items per batch.
* @return array An array of batches, with each batch being a sub-array of items.
*/
public function slice_into_batches($items, $batchSize) {
return array_chunk($items, $batchSize);
}
/**
* Uses the "single" API endpoint to get video details and
* returns only those that appear to be live streams.
*
* @param $vid_ids array
*
* @return array
*
* @since 1.3
*/
public function fetch_singles( $vid_ids ) {
if( empty($vid_ids) ) {
return [];
}
$batches = self::slice_into_batches($vid_ids, SBY_MAX_SINGLE_PAGE);
$live_streamed_videos = array();
foreach ($batches as $batch) {
$params['video_ids'] = $batch;
$connected_account = sby_get_first_connected_account();
$video_connection = new SBY_API_Connect_Pro( $connected_account, 'single', $params );
$video_connection->connect();
$potential_live_streams = $video_connection->get_data();
if ( is_array( $potential_live_streams['items'] ) ) {
foreach ( $potential_live_streams['items'] as $post ) {
if ( ! empty( $post['liveStreamingDetails']['scheduledStartTime'] )
|| ! empty( $post['liveStreamingDetails']['actualStartTime'] ) ) {
$vid_id = SBY_Parse::get_video_id( $post );
$live_streamed_videos[ $vid_id ] = $post;
}
}
}
}
return $live_streamed_videos;
}
/**
* Updates or adds to video cache stored as an associative array with
* the video ID as the index.
*
* @param $live_streams array
* @param $update_attempted array
*
* @since 1.3
*/
public function update_or_add( $live_streams, $update_attempted = array() ) {
$actually_retrieved = array();
foreach ( $live_streams as $vid_id => $live_stream ) {
$actually_retrieved[] = $vid_id;
$this->video_cache[ $vid_id ] = $live_stream;
}
// If a video ID is attempted to be retrieve but nothing is returned for it
// It's likely that it was removed so we should remove it from the cache
$no_longer_exist = array_diff( $update_attempted, $actually_retrieved );
if ( ! empty( $no_longer_exist ) ) {
foreach ( $no_longer_exist as $vid_id ) {
if ( isset( $this->video_cache[ $vid_id ] ) ) {
unset( $this->video_cache[ $vid_id ] );
}
}
}
}
/**
* Orders videos by schedules start date or actual start date
* when available starting with the most recent.
*
* @since 1.3
*/
public function sort() {
$post_set = $this->video_cache;
uasort($post_set, 'sby_scheduled_start_sort' );
$this->video_cache = $post_set;
}
/**
* Save most recent 200 videos in cache.
*
* @since 1.3
*/
public function update_cache() {
$to_cache = array_slice( $this->video_cache, 0, 200 );
update_option( $this->cache_name, $to_cache, false );
}
}