- "frontend/src/pages/ChapterReview.tsx" - "frontend/src/pages/ChapterReview.module.css" - "frontend/src/api/videos.ts" - "frontend/src/App.tsx" GSD-Task: S06/T02
110 lines
3.3 KiB
TypeScript
110 lines
3.3 KiB
TypeScript
import { request, BASE } from "./client";
|
|
|
|
// ── Types ────────────────────────────────────────────────────────────────────
|
|
|
|
export interface VideoDetail {
|
|
id: string;
|
|
filename: string;
|
|
file_path: string;
|
|
duration_seconds: number | null;
|
|
content_type: string;
|
|
creator_id: string;
|
|
creator_name: string;
|
|
creator_slug: string;
|
|
video_url: string | null;
|
|
processing_status: string;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface TranscriptSegment {
|
|
id: string;
|
|
source_video_id: string;
|
|
start_time: number;
|
|
end_time: number;
|
|
text: string;
|
|
segment_index: number;
|
|
topic_label: string | null;
|
|
}
|
|
|
|
export interface TranscriptResponse {
|
|
video_id: string;
|
|
segments: TranscriptSegment[];
|
|
total: number;
|
|
}
|
|
|
|
// ── API functions ────────────────────────────────────────────────────────────
|
|
|
|
export function fetchVideo(id: string): Promise<VideoDetail> {
|
|
return request<VideoDetail>(`${BASE}/videos/${encodeURIComponent(id)}`);
|
|
}
|
|
|
|
export function fetchTranscript(videoId: string): Promise<TranscriptResponse> {
|
|
return request<TranscriptResponse>(
|
|
`${BASE}/videos/${encodeURIComponent(videoId)}/transcript`,
|
|
);
|
|
}
|
|
|
|
// ── Chapters (KeyMoments as timeline markers) ────────────────────────────────
|
|
|
|
export interface Chapter {
|
|
id: string;
|
|
title: string;
|
|
start_time: number;
|
|
end_time: number;
|
|
content_type: string;
|
|
chapter_status: string;
|
|
sort_order: number;
|
|
}
|
|
|
|
export interface ChaptersResponse {
|
|
video_id: string;
|
|
chapters: Chapter[];
|
|
}
|
|
|
|
export function fetchChapters(videoId: string): Promise<ChaptersResponse> {
|
|
return request<ChaptersResponse>(
|
|
`${BASE}/videos/${encodeURIComponent(videoId)}/chapters`,
|
|
);
|
|
}
|
|
|
|
// ── Creator chapter management ───────────────────────────────────────────────
|
|
|
|
export function fetchCreatorChapters(videoId: string): Promise<ChaptersResponse> {
|
|
return request<ChaptersResponse>(
|
|
`${BASE}/creator/${encodeURIComponent(videoId)}/chapters`,
|
|
);
|
|
}
|
|
|
|
export interface ChapterPatch {
|
|
title?: string;
|
|
start_time?: number;
|
|
end_time?: number;
|
|
chapter_status?: string;
|
|
}
|
|
|
|
export function updateChapter(chapterId: string, patch: ChapterPatch): Promise<Chapter> {
|
|
return request<Chapter>(
|
|
`${BASE}/creator/chapters/${encodeURIComponent(chapterId)}`,
|
|
{ method: "PATCH", body: JSON.stringify(patch) },
|
|
);
|
|
}
|
|
|
|
export interface ReorderItem {
|
|
id: string;
|
|
sort_order: number;
|
|
}
|
|
|
|
export function reorderChapters(videoId: string, order: ReorderItem[]): Promise<ChaptersResponse> {
|
|
return request<ChaptersResponse>(
|
|
`${BASE}/creator/${encodeURIComponent(videoId)}/chapters/reorder`,
|
|
{ method: "PUT", body: JSON.stringify({ chapters: order }) },
|
|
);
|
|
}
|
|
|
|
export function approveChapters(videoId: string, chapterIds: string[]): Promise<ChaptersResponse> {
|
|
return request<ChaptersResponse>(
|
|
`${BASE}/creator/${encodeURIComponent(videoId)}/chapters/approve`,
|
|
{ method: "POST", body: JSON.stringify({ chapter_ids: chapterIds }) },
|
|
);
|
|
}
|