139 lines
3.6 KiB
TypeScript
139 lines
3.6 KiB
TypeScript
import { Channel, Playlist, Video, Config, SchedulerStatus } from '../types';
|
|
|
|
const API_BASE = '/api';
|
|
|
|
async function fetchJSON<T>(url: string, options?: RequestInit): Promise<T> {
|
|
const response = await fetch(url, {
|
|
...options,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...options?.headers,
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const error = await response.json().catch(() => ({ error: 'Request failed' }));
|
|
throw new Error(error.error || `HTTP ${response.status}`);
|
|
}
|
|
|
|
if (response.status === 204) {
|
|
return {} as T;
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
// Channels API
|
|
export const channelsAPI = {
|
|
getAll: () => fetchJSON<Channel[]>(`${API_BASE}/channels`),
|
|
|
|
getById: (id: number) => fetchJSON<Channel>(`${API_BASE}/channels/${id}`),
|
|
|
|
getVideos: (id: number) => fetchJSON<Video[]>(`${API_BASE}/channels/${id}/videos`),
|
|
|
|
create: (url: string) =>
|
|
fetchJSON<Channel>(`${API_BASE}/channels`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ url }),
|
|
}),
|
|
|
|
update: (id: number, active: boolean) =>
|
|
fetchJSON<Channel>(`${API_BASE}/channels/${id}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ active }),
|
|
}),
|
|
|
|
delete: (id: number) =>
|
|
fetchJSON<void>(`${API_BASE}/channels/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
|
|
refresh: (id: number) =>
|
|
fetchJSON<{ message: string }>(`${API_BASE}/channels/${id}/refresh`, {
|
|
method: 'POST',
|
|
}),
|
|
};
|
|
|
|
// Playlists API
|
|
export const playlistsAPI = {
|
|
getAll: () => fetchJSON<Playlist[]>(`${API_BASE}/playlists`),
|
|
|
|
getById: (id: number) => fetchJSON<Playlist>(`${API_BASE}/playlists/${id}`),
|
|
|
|
getVideos: (id: number) => fetchJSON<Video[]>(`${API_BASE}/playlists/${id}/videos`),
|
|
|
|
create: (url: string) =>
|
|
fetchJSON<Playlist>(`${API_BASE}/playlists`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ url }),
|
|
}),
|
|
|
|
update: (id: number, active: boolean) =>
|
|
fetchJSON<Playlist>(`${API_BASE}/playlists/${id}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ active }),
|
|
}),
|
|
|
|
delete: (id: number) =>
|
|
fetchJSON<void>(`${API_BASE}/playlists/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
|
|
refresh: (id: number) =>
|
|
fetchJSON<{ message: string }>(`${API_BASE}/playlists/${id}/refresh`, {
|
|
method: 'POST',
|
|
}),
|
|
};
|
|
|
|
// Videos API
|
|
export const videosAPI = {
|
|
getAll: (status?: string, search?: string) => {
|
|
const params = new URLSearchParams();
|
|
if (status) params.append('status', status);
|
|
if (search) params.append('search', search);
|
|
|
|
const queryString = params.toString();
|
|
const url = queryString
|
|
? `${API_BASE}/videos?${queryString}`
|
|
: `${API_BASE}/videos`;
|
|
return fetchJSON<Video[]>(url);
|
|
},
|
|
|
|
getById: (id: number) => fetchJSON<Video>(`${API_BASE}/videos/${id}`),
|
|
|
|
create: (url: string) =>
|
|
fetchJSON<Video>(`${API_BASE}/videos`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({ url }),
|
|
}),
|
|
|
|
delete: (id: number) =>
|
|
fetchJSON<void>(`${API_BASE}/videos/${id}`, {
|
|
method: 'DELETE',
|
|
}),
|
|
|
|
retry: (id: number) =>
|
|
fetchJSON<Video>(`${API_BASE}/videos/${id}/retry`, {
|
|
method: 'POST',
|
|
}),
|
|
|
|
downloadNow: (id: number) =>
|
|
fetchJSON<{ message: string; videoId: string }>(`${API_BASE}/videos/${id}/download`, {
|
|
method: 'POST',
|
|
}),
|
|
};
|
|
|
|
// Config API
|
|
export const configAPI = {
|
|
get: () => fetchJSON<Config>(`${API_BASE}/config`),
|
|
|
|
update: (config: Partial<Config>) =>
|
|
fetchJSON<Config>(`${API_BASE}/config`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(config),
|
|
}),
|
|
|
|
getSchedulerStatus: () =>
|
|
fetchJSON<SchedulerStatus>(`${API_BASE}/config/scheduler/status`),
|
|
};
|