75 lines
2.1 KiB
JavaScript
75 lines
2.1 KiB
JavaScript
|
|
/**
|
||
|
|
* API client for the F1 Streams backend.
|
||
|
|
* All endpoints are on the same origin, so no CORS issues.
|
||
|
|
*/
|
||
|
|
|
||
|
|
const API_BASE = '';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fetch the F1 race schedule with session statuses.
|
||
|
|
* @returns {Promise<{season: string, fetched_at: string, races: Array}>}
|
||
|
|
*/
|
||
|
|
export async function fetchSchedule() {
|
||
|
|
const res = await fetch(`${API_BASE}/schedule`);
|
||
|
|
if (!res.ok) throw new Error(`Schedule fetch failed: ${res.status}`);
|
||
|
|
return res.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fetch available live streams.
|
||
|
|
* @returns {Promise<{streams: Array, count: number}>}
|
||
|
|
*/
|
||
|
|
export async function fetchStreams() {
|
||
|
|
const res = await fetch(`${API_BASE}/streams`);
|
||
|
|
if (!res.ok) throw new Error(`Streams fetch failed: ${res.status}`);
|
||
|
|
return res.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Encode a URL to base64url for the proxy endpoint.
|
||
|
|
* @param {string} rawUrl - The original m3u8 URL
|
||
|
|
* @returns {string} base64url-encoded string
|
||
|
|
*/
|
||
|
|
function toBase64Url(rawUrl) {
|
||
|
|
return btoa(rawUrl).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the proxied m3u8 URL for HLS playback.
|
||
|
|
* @param {string} m3u8Url - The original m3u8 URL
|
||
|
|
* @returns {string} The proxy URL
|
||
|
|
*/
|
||
|
|
export function getProxyUrl(m3u8Url) {
|
||
|
|
const encoded = toBase64Url(m3u8Url);
|
||
|
|
return `${API_BASE}/proxy?url=${encoded}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Mark a stream as actively being watched (enables token refresh).
|
||
|
|
* @param {string} url - The stream URL
|
||
|
|
* @param {string} [siteKey] - Optional site key
|
||
|
|
*/
|
||
|
|
export async function activateStream(url, siteKey = '') {
|
||
|
|
const res = await fetch(`${API_BASE}/streams/activate`, {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({ url, site_key: siteKey })
|
||
|
|
});
|
||
|
|
if (!res.ok) throw new Error(`Activate failed: ${res.status}`);
|
||
|
|
return res.json();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Mark a stream as no longer being watched.
|
||
|
|
* @param {string} url - The stream URL
|
||
|
|
*/
|
||
|
|
export async function deactivateStream(url) {
|
||
|
|
const res = await fetch(`${API_BASE}/streams/deactivate`, {
|
||
|
|
method: 'POST',
|
||
|
|
headers: { 'Content-Type': 'application/json' },
|
||
|
|
body: JSON.stringify({ url })
|
||
|
|
});
|
||
|
|
if (!res.ok) throw new Error(`Deactivate failed: ${res.status}`);
|
||
|
|
return res.json();
|
||
|
|
}
|