/**
* Get RacingTodayZA YouTube videos for a specific date.
*
* Example:
*
* /wp-json/racing/v1/youtube-videos?date=2026-08-25
*
* Returns JSON:
*
* {
* "success": true,
* "date": "2026-08-25",
* "count": 5,
* "videos": [
* {
* "video_id": "...",
* "title": "...",
* "url": "...",
* "date": "..."
* }
* ]
* }
*/
function get_racing_today_youtube_videos( $requested_date = null ) {
/*
* ---------------------------------------------------------
* SETTINGS
* ---------------------------------------------------------
*/
$api_key = 'AIzaSyC7nYG2Prf6vx70n2fAjT7JS4tJxgkmjac';
$handle = '@RacingTodayZA';
/*
* ---------------------------------------------------------
* WORDPRESS TIMEZONE
* ---------------------------------------------------------
*/
$timezone = wp_timezone();
/*
* ---------------------------------------------------------
* DATE
*
* If no date is supplied, use today.
*
* Expected format:
* YYYY-MM-DD
* ---------------------------------------------------------
*/
if ( empty( $requested_date ) ) {
$requested_date = current_time( 'Y-m-d' );
}
/*
* Validate date.
*/
$date_object = DateTime::createFromFormat(
'Y-m-d',
$requested_date,
$timezone
);
if (
!$date_object ||
$date_object->format( 'Y-m-d' ) !== $requested_date
) {
return array(
'success' => false,
'error' => 'Invalid date. Use YYYY-MM-DD.',
);
}
/*
* ---------------------------------------------------------
* CREATE DATE RANGE
*
* Example:
*
* date = 2026-08-25
*
* We want:
*
* 2026-08-25 00:00:00
* through
* 2026-08-26 00:00:00
*
* We convert these to UTC because YouTube API expects
* RFC 3339 timestamps.
* ---------------------------------------------------------
*/
$start = clone $date_object;
$end = clone $date_object;
$end->modify( '+1 day' );
/*
* Convert to UTC.
*/
$utc_timezone = new DateTimeZone( 'UTC' );
$start->setTimezone( $utc_timezone );
$end->setTimezone( $utc_timezone );
/*
* RFC 3339 format.
*/
$published_after =
$start->format( 'Y-m-d\TH:i:s\Z' );
$published_before =
$end->format( 'Y-m-d\TH:i:s\Z' );
/*
* ---------------------------------------------------------
* STEP 1
*
* Find the channel ID from @RacingTodayZA
* ---------------------------------------------------------
*/
$channel_url = add_query_arg(
array(
'part' => 'id,snippet',
'forHandle' => $handle,
'key' => $api_key,
),
'https://www.googleapis.com/youtube/v3/channels'
);
$response = wp_remote_get(
$channel_url,
array(
'timeout' => 30,
)
);
if ( is_wp_error( $response ) ) {
return array(
'success' => false,
'error' => $response->get_error_message(),
);
}
/*
* HTTP status.
*/
$http_code = wp_remote_retrieve_response_code(
$response
);
$body = wp_remote_retrieve_body(
$response
);
$data = json_decode(
$body,
true
);
/*
* API error.
*/
if ( $http_code < 200 || $http_code >= 300 ) {
return array(
'success' => false,
'error' => 'YouTube channel API request failed.',
'http_code' => $http_code,
'api_response' => $data,
);
}
/*
* Channel not found.
*/
if (
empty( $data['items'] ) ||
empty( $data['items'][0]['id'] )
) {
return array(
'success' => false,
'error' => 'YouTube channel not found.',
'api_response' => $data,
);
}
$channel_id =
$data['items'][0]['id'];
$channel_name =
$data['items'][0]['snippet']['title']
?? '';
/*
* ---------------------------------------------------------
* STEP 2
*
* Search for videos published on requested date.
* ---------------------------------------------------------
*/
$videos = array();
$page_token = '';
do {
$params = array(
/*
* Search resource only needs snippet.
*/
'part' => 'snippet',
/*
* Only this channel.
*/
'channelId' => $channel_id,
/*
* Only videos.
*/
'type' => 'video',
/*
* Requested date range.
*/
'publishedAfter' =>
$published_after,
'publishedBefore' =>
$published_before,
/*
* Newest first.
*/
'order' => 'date',
/*
* Maximum allowed.
*/
'maxResults' => 50,
/*
* API key.
*/
'key' => $api_key,
);
/*
* Pagination.
*/
if ( !empty( $page_token ) ) {
$params['pageToken'] =
$page_token;
}
/*
* Build API URL.
*/
$search_url = add_query_arg(
$params,
'https://www.googleapis.com/youtube/v3/search'
);
/*
* Request.
*/
$response = wp_remote_get(
$search_url,
array(
'timeout' => 30,
)
);
if ( is_wp_error( $response ) ) {
return array(
'success' => false,
'error' => $response->get_error_message(),
);
}
/*
* HTTP status.
*/
$http_code =
wp_remote_retrieve_response_code(
$response
);
$body =
wp_remote_retrieve_body(
$response
);
$data =
json_decode(
$body,
true
);
/*
* API error.
*/
if (
$http_code < 200 ||
$http_code >= 300
) {
return array(
'success' => false,
'error' => 'YouTube search API request failed.',
'http_code' => $http_code,
'api_response' => $data,
);
}
/*
* YouTube API error.
*/
if ( !empty( $data['error'] ) ) {
return array(
'success' => false,
'error' => 'YouTube API error.',
'api_response' => $data['error'],
);
}
/*
* -----------------------------------------------------
* PROCESS RESULTS
* -----------------------------------------------------
*/
if ( !empty( $data['items'] ) ) {
foreach ( $data['items'] as $item ) {
/*
* Make sure this is a video.
*/
if (
empty(
$item['id']['videoId']
)
) {
continue;
}
$video_id =
$item['id']['videoId'];
$title =
$item['snippet']['title']
?? '';
$published_at =
$item['snippet']['publishedAt']
?? '';
/*
* -------------------------------------------------
* Add video.
* -------------------------------------------------
*/
$videos[] = array(
'video_id' =>
$video_id,
'title' =>
$title,
'url' =>
'https://www.youtube.com/watch?v=' .
$video_id,
'date' =>
$published_at,
'date_local' =>
!empty( $published_at )
? (
new DateTime(
$published_at,
new DateTimeZone( 'UTC' )
)
)->setTimezone( $timezone )->format(
'Y-m-d H:i:s'
)
: '',
);
}
}
/*
* -----------------------------------------------------
* NEXT PAGE
* -----------------------------------------------------
*/
$page_token =
$data['nextPageToken']
?? '';
} while ( !empty( $page_token ) );
/*
* ---------------------------------------------------------
* RETURN
* ---------------------------------------------------------
*/
return array(
'success' => true,
'channel' => array(
'id' =>
$channel_id,
'name' =>
$channel_name,
'handle' =>
$handle,
),
'date' =>
$requested_date,
'timezone' =>
$timezone->getName(),
'published_after' =>
$published_after,
'published_before' =>
$published_before,
'count' =>
count( $videos ),
'videos' =>
$videos,
);
}
/*
* =============================================================
* WORDPRESS REST API ENDPOINT
* =============================================================
*/
add_action(
'rest_api_init',
function () {
register_rest_route(
'api/v1',
'/get_yt_links',
array(
'methods' => 'GET',
'callback' => function ( WP_REST_Request $request ) {
/*
* Get ?date=YYYY-MM-DD
*/
$date = $request->get_param('date');
/*
* If no date is supplied,
* use today's WordPress date.
*/
if ( empty($date) ) {
$date = current_time('Y-m-d');
}
/*
* Get YouTube videos.
*/
return get_racing_today_youtube_videos($date);
},
/*
* -------------------------------------------------
* API KEY AUTHENTICATION
* -------------------------------------------------
*/
'permission_callback' => function ( WP_REST_Request $request ) {
$provided_key =
$request->get_header('x-api-key');
/*
* No API key supplied.
*/
if ( empty($provided_key) ) {
return new WP_Error(
'missing_api_key',
'API key is required.',
array(
'status' => 401
)
);
}
/*
* Invalid API key.
*
* hash_equals() prevents timing attacks.
*/
if (
!defined('REPLAYS_API_KEY') ||
!hash_equals(
REPLAYS_API_KEY,
$provided_key
)
) {
return new WP_Error(
'invalid_api_key',
'Invalid API key.',
array(
'status' => 403
)
);
}
/*
* API key is valid.
*/
return true;
},
)
);
}
);
法国赛事分析 (尚蒂伊) – 星期五 6月19日 - iRace
法国赛事分析:尚蒂伊@2026.06.19

第1场
赛事预览: 巴尔雄志 5月9日于 高滨 一场2400米未夺标马赛事中获得亚军,近四仗皆争得相同名次,其中两仗为本场同程,现已蓄势待发,可力争首胜。巴希马 第二仗即于3月 24日在 圣格卢 一场2400米未夺标马赛事中获得第4,今可有显著提升。凡德罗赫 5月22日首战于 圣格卢 一场2000米未夺标马赛事中获得第4,今增程作战甚合蹄,值得留意。 关怀之道 5月5日于 圣格卢 一场2400米让磅赛中,仅以微差名列第4,于让磅赛级别表现不俗,今重返未夺标马赛,可构成强力威胁。
第2场
赛事预览: 阿玛丽斯 5月7日于 巴黎隆尚 一场2000米表列赛中获得第7,近两仗皆名次, 今补报参赛,具备一定的竞争力。梅努拉 5月28日于 巴黎隆尚 一场 1800 米未夺标马赛事 中仅获得第5,表现欠佳,其实力远高于此,可有一番大作为。瓦德拉玛 5月25日首战于 高滨 一场 2000 米条件赛中以 2.75 个马位不敌对手,最终获得季军,表现可圈可点,今由 骑师德姆洛执缰,不容小觑。南希乐地 5月15日于 圣格卢 一场 2400 米条件赛中,以微差 屈居季军,并于该仗击败“阿马迪欧”。后驹其后成功获胜,使战绩更具含金量,值得尊敬。
第3场
赛事预览: 优丽名 5月22日于 圣格卢 一场1200米条件赛中获得第7,曾迎战较强对手,此次降级作战,胜利在望。乔治先生 5月21日于 巴黎隆尚 一场1400米让磅赛中名列第12,表现令人失望,今缩程作战且为直道赛事,形势有利。金色雌鹿 6月6日于 迪耶普 一场1100米未夺标马赛中获得第4,目前状态可取,并由默契十足的骑师执缰,可争得一席之位。 雏菊 6月6日复出于 迪耶普 一场1100米让磅赛中获得第7,表现可圈可点,可跻身前列。
第4场
赛事预览: 大富豪人 父系 No Nay Never、母系 Nazuna 的初出2岁雄马,其母曾在一场 1400 米的二级赛中获得名次,其首度出战可力争到底。苏菲娜 5月19日首战于此地一场 1200 米未夺标马赛事,于该仗未能适应湿软场地,但仍跑获第4,今可有良多进展。月影舞姿 5月29日于 圣格卢 一场 1200 米赛事中获得亚军,于该仗不敌强敌,表现情有可原,可再有一番大作为。晨曦风暴 5月29日于 圣格卢 一场 1200 米赛事中获得季军,仅以 0.75个马位不敌“月影舞姿”,今占减磅优势,有望争得一席之位。
第5场
赛事预览: 瓦基尔斯 5月22日于维沃一场1500米第3级让磅赛中获得季军,今可力撼群驹。贪吃 6月8日于勒阿弗一场1400米第4级赛事中获得第4,可争得一席之位。弗兰卡诺 近三仗表现欠佳,5月28日于图尔一场1000米第3级让磅赛中名列第7,有望扭转局势。皓月 近期 均未有作为,包括5月17日于特鲁瓦一场1100米第4级让磅赛中,现评分下调,可扳回一城。
第6场
赛事预览: 加里安 上仗于5月14日一场1600米第3级让磅赛中获得第6,今可扮演争胜主角。最终罪孽 近期状态欠佳,前四仗皆未能有作为,包括6月4日于克朗一场2400米第4级让磅赛,今驮重占优,若状态返勇,有望力争到底。尼布查 5月19日于此地一场1800米第4级 让磅赛中获得第4,今可跻身前列。银色奇诺 5月13日于 维希 一场1600米第4级让磅赛中获得第5,表现已有所提升,具备一定的竞争力。
第7场
赛事预览: 拉奇布 5月24日于哈拉斯杜平一场2200米第4级赛事中获得亚军,今可重返胜轨。伊扣 5月28日于巴黎隆尚一场2400米第3级赛事中获得季军,今返战胶沙地,可扮演争胜 主角。收藏家 近两仗皆争得位置,包括5月19日于此地一场1800米第3级让磅赛中获得季军,可跻身三甲。谢瓦多 上仗于5月24日一场2000米条件赛中获胜,有望争得一席之位。
第8场
赛事预览: 双倍效果 3月3日于尚蒂伊一场1800米第3级让磅赛中获得第5,表现不俗,擅长于草地作战,今可扮演争胜主角。凯瑟琳 近两仗皆争得位置,包括6月5日于勒利翁当热一场第4级让磅赛中获得季军,可与群驹一斗。加勒斯帝 3月20日于勒克瓦塞拉罗西一场1800米第4级赛事中获胜,此后两仗皆未能有作为,可拼入榜内。糖果雪莉 5月25日于 沙隆普温一场2000米第4级让磅赛中获胜,有望跻身前列。