ADD functionality to retrieve and display clips by ID
This commit is contained in:
@@ -1,10 +1,14 @@
|
|||||||
import {useEffect, useState} from "react";
|
import {useEffect, useState} from "react";
|
||||||
import {useParams} from "react-router-dom";
|
import {useParams} from "react-router-dom";
|
||||||
|
import type {Clip} from "../utils/types";
|
||||||
|
import {getClipById} from "../utils/endpoints.ts";
|
||||||
|
import Box from "../components/Box.tsx"
|
||||||
|
|
||||||
const VideoPlayer = () => {
|
const VideoPlayer = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const [videoUrl, setVideoUrl] = useState<string>("");
|
const [videoUrl, setVideoUrl] = useState<string>("");
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [clip, setClip] = useState<Clip | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Fetch the video URL from the server
|
// Fetch the video URL from the server
|
||||||
@@ -23,6 +27,14 @@ const VideoPlayer = () => {
|
|||||||
console.error("Error fetching video:", err);
|
console.error("Error fetching video:", err);
|
||||||
setError("Failed to load video. Please try again later.");
|
setError("Failed to load video. Please try again later.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
setError("Clip ID is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getClipById(id).then((fetchedClip) => {setClip(fetchedClip)})
|
||||||
|
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -41,6 +53,11 @@ const VideoPlayer = () => {
|
|||||||
|
|
||||||
{error && <div className="text-red-500 mt-2">{error}</div>}
|
{error && <div className="text-red-500 mt-2">{error}</div>}
|
||||||
{!videoUrl && !error && <div className="text-gray-500 mt-2">Loading video...</div>}
|
{!videoUrl && !error && <div className="text-gray-500 mt-2">Loading video...</div>}
|
||||||
|
|
||||||
|
<Box className={"p-2 m-2"}>
|
||||||
|
<p className={"text-2xl font-bold text-gray-600"}>{clip?.title}</p>
|
||||||
|
</Box>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -167,6 +167,23 @@ const getClips = async (setError: Function): Promise< Clip[]> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getClipById = async (id: string): Promise<Clip | null> => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/v1/clips/${id}`, {credentials: "include",});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error('Failed to fetch clip:', response.status);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: APIResponse = await response.json();
|
||||||
|
return result.data;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
console.error('Error fetching clip:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
uploadFile,
|
uploadFile,
|
||||||
editFile,
|
editFile,
|
||||||
@@ -174,5 +191,6 @@ export {
|
|||||||
getProgress,
|
getProgress,
|
||||||
getMetadata,
|
getMetadata,
|
||||||
getUser,
|
getUser,
|
||||||
getClips
|
getClips,
|
||||||
|
getClipById
|
||||||
};
|
};
|
||||||
@@ -29,6 +29,7 @@ public class SecurityConfig {
|
|||||||
http
|
http
|
||||||
.csrf(AbstractHttpConfigurer::disable)
|
.csrf(AbstractHttpConfigurer::disable)
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
|
.requestMatchers("/api/v1/download/clip/**").authenticated()
|
||||||
.requestMatchers("/api/v1/auth/login", "/api/v1/auth/user").permitAll()
|
.requestMatchers("/api/v1/auth/login", "/api/v1/auth/user").permitAll()
|
||||||
.requestMatchers("/api/v1/upload", "/api/v1/download/**").permitAll()
|
.requestMatchers("/api/v1/upload", "/api/v1/download/**").permitAll()
|
||||||
.requestMatchers("/api/v1/edit/**", "/api/v1/process/**", "/api/v1/progress/**").permitAll()
|
.requestMatchers("/api/v1/edit/**", "/api/v1/process/**", "/api/v1/progress/**").permitAll()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
|||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -33,4 +34,20 @@ public class ClipController {
|
|||||||
new APIResponse<>("success", "Clips retrieved successfully", clips)
|
new APIResponse<>("success", "Clips retrieved successfully", clips)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ResponseEntity<APIResponse<Clip>> getClipById(@AuthenticationPrincipal OAuth2User principal, @PathVariable Long id) {
|
||||||
|
if (principal == null) {
|
||||||
|
throw new NotAuthenticated("User is not authenticated");
|
||||||
|
}
|
||||||
|
|
||||||
|
Clip clip = clipService.getClipById(id);
|
||||||
|
if (clip == null) {
|
||||||
|
return ResponseEntity.notFound().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
new APIResponse<>("success", "Clip retrieved successfully", clip)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.springframework.http.HttpHeaders;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.MediaTypeFactory;
|
import org.springframework.http.MediaTypeFactory;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -51,7 +53,7 @@ public class DownloadController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/clip/{id}")
|
@GetMapping("/clip/{id}")
|
||||||
public ResponseEntity<Resource> downloadClip(@PathVariable Long id) {
|
public ResponseEntity<Resource> downloadClip(@AuthenticationPrincipal OAuth2User principal, @PathVariable Long id) {
|
||||||
Resource resource = downloadService.downloadClip(id);
|
Resource resource = downloadService.downloadClip(id);
|
||||||
|
|
||||||
if (resource == null || !resource.exists()) {
|
if (resource == null || !resource.exists()) {
|
||||||
|
|||||||
@@ -100,4 +100,8 @@ public class ClipService {
|
|||||||
clip.setVideoPath(outputFile.getPath());
|
clip.setVideoPath(outputFile.getPath());
|
||||||
clipRepository.save(clip);
|
clipRepository.save(clip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Clip getClipById(Long id) {
|
||||||
|
return clipRepository.findById(id).orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user