diff --git a/src/components/VideoPlayer/VideoPlayer.tsx b/src/components/VideoPlayer/VideoPlayer.tsx index 0897de5..effb2ac 100644 --- a/src/components/VideoPlayer/VideoPlayer.tsx +++ b/src/components/VideoPlayer/VideoPlayer.tsx @@ -83,6 +83,8 @@ export interface VideoPlayerProps { playerRef: any; locationRef: RefObject; videoLocationRef: RefObject; + filename?:string + path?: string } const videoStyles = { @@ -117,6 +119,8 @@ export const VideoPlayer = ({ timelineActions, locationRef, videoLocationRef, + path, + filename }: VideoPlayerProps) => { const containerRef = useRef(null); const [videoObjectFit] = useState("contain"); @@ -178,6 +182,7 @@ export const VideoPlayer = ({ seekTo, togglePictureInPicture, downloadResource, + } = useVideoPlayerController({ autoPlay, playerRef, @@ -185,6 +190,8 @@ export const VideoPlayer = ({ retryAttempts, isMuted, videoRef, + filename, + path }); const showControlsMobile = diff --git a/src/components/VideoPlayer/VideoPlayerParent.tsx b/src/components/VideoPlayer/VideoPlayerParent.tsx index 0206677..3017843 100644 --- a/src/components/VideoPlayer/VideoPlayerParent.tsx +++ b/src/components/VideoPlayer/VideoPlayerParent.tsx @@ -14,6 +14,8 @@ export interface VideoPlayerParentProps { autoPlay?: boolean; onEnded?: (e: React.SyntheticEvent) => void; timelineActions?: TimelineAction[]; + path?: string + filename?: string } export const VideoPlayerParent = ({ videoRef, @@ -23,6 +25,8 @@ export const VideoPlayerParent = ({ autoPlay, onEnded, timelineActions, + path, + filename }: VideoPlayerParentProps) => { const context = useContext(GlobalContext) const playerRef = useRef(null); @@ -91,6 +95,8 @@ export const VideoPlayerParent = ({ playerRef={playerRef} locationRef={locationRef} videoLocationRef={videoLocationRef} + filename={filename} + path={path} /> ); }; diff --git a/src/components/VideoPlayer/useVideoPlayerController.tsx b/src/components/VideoPlayer/useVideoPlayerController.tsx index da19fb8..220ee0c 100644 --- a/src/components/VideoPlayer/useVideoPlayerController.tsx +++ b/src/components/VideoPlayer/useVideoPlayerController.tsx @@ -17,6 +17,8 @@ interface UseVideoControls { retryAttempts?: number; isMuted: boolean; videoRef: any; + filename?: string + path?: string } export const useVideoPlayerController = (props: UseVideoControls) => { @@ -27,6 +29,8 @@ export const useVideoPlayerController = (props: UseVideoControls) => { qortalVideoResource, retryAttempts, isMuted, + filename = "", + path = "" } = props; const [isFullscreen, setIsFullscreen] = useState(false); @@ -43,6 +47,8 @@ export const useVideoPlayerController = (props: UseVideoControls) => { useResourceStatus({ resource: !startedFetch ? null : qortalVideoResource, retryAttempts, + filename, + path, }); const idleTime = 5000; // Time in milliseconds diff --git a/src/hooks/useAllResourceStatus.tsx b/src/hooks/useAllResourceStatus.tsx new file mode 100644 index 0000000..4512f93 --- /dev/null +++ b/src/hooks/useAllResourceStatus.tsx @@ -0,0 +1,24 @@ +import React from 'react' +import { usePublishStore } from '../state/publishes'; +import { Service } from '../types/interfaces/resources'; + +export const useAllResourceStatus = () => + usePublishStore((state) => + Object.entries(state.resourceStatus) + .filter(([_, status]) => status !== null) + .map(([id, status]) => { + const parts = id.split('-'); + const service = parts[0] as Service; + const name = parts[1] || ''; + const identifier = parts.length > 2 ? parts.slice(2).join('-') : ''; + const { path, filename, ...rest } = status!; + + return { + id, + metadata: { service, name, identifier }, + status: rest, + path, + filename + }; + }) + ); \ No newline at end of file diff --git a/src/hooks/useResourceStatus.tsx b/src/hooks/useResourceStatus.tsx index d6d7ed2..6924115 100644 --- a/src/hooks/useResourceStatus.tsx +++ b/src/hooks/useResourceStatus.tsx @@ -5,10 +5,14 @@ import { QortalGetMetadata } from "../types/interfaces/resources"; interface PropsUseResourceStatus { resource: QortalGetMetadata | null; retryAttempts?: number; + path?: string + filename?:string } export const useResourceStatus = ({ resource, retryAttempts = 200, + path, + filename }: PropsUseResourceStatus) => { const resourceId = !resource ? null : `${resource.service}-${resource.name}-${resource.identifier}`; const status = usePublishStore((state)=> state.getResourceStatus(resourceId)) || null @@ -41,7 +45,9 @@ export const useResourceStatus = ({ "status": "SEARCHING", "localChunkCount": 0, "totalChunkCount": 0, - "percentLoaded": 0 + "percentLoaded": 0, + path: path || "", + filename: filename || "" } ); } diff --git a/src/index.ts b/src/index.ts index 05b693b..0d640ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ export {TimelineAction} from './components/VideoPlayer/VideoPlayer' export { useAudioPlayerHotkeys } from './components/AudioPlayer/useAudioPlayerHotkeys'; export { VideoPlayerParent as VideoPlayer } from './components/VideoPlayer/VideoPlayerParent'; export { useListReturn } from './hooks/useListData'; +export { useAllResourceStatus } from './hooks/useAllResourceStatus'; import './index.css' export { executeEvent, subscribeToEvent, unsubscribeFromEvent } from './utils/events'; export { formatBytes, formatDuration } from './utils/numbers'; diff --git a/src/state/publishes.ts b/src/state/publishes.ts index 87e32be..9d9f06c 100644 --- a/src/state/publishes.ts +++ b/src/state/publishes.ts @@ -1,5 +1,5 @@ import { create } from "zustand"; -import { QortalGetMetadata } from "../types/interfaces/resources"; +import { QortalGetMetadata, Service } from "../types/interfaces/resources"; import { Resource } from "../hooks/useResources"; interface PublishCache { @@ -28,8 +28,16 @@ export interface ResourceStatus { localChunkCount: number totalChunkCount: number percentLoaded: number - + path?: string + filename?: string } +interface ResourceStatusEntry { + id: string; + metadata: QortalGetMetadata; + status: ResourceStatus; + path?: string; + filename?: string; +} interface PublishState { publishes: Record; resourceStatus: Record; @@ -39,6 +47,8 @@ interface PublishState { setPublish: (qortalGetMetadata: QortalGetMetadata, data: Resource | null, customExpiry?: number) => void; clearExpiredPublishes: () => void; publishExpiryDuration: number; // Default expiry duration + getAllResourceStatus: () => ResourceStatusEntry[]; + } export const usePublishStore = create((set, get) => ({ @@ -92,10 +102,13 @@ export const usePublishStore = create((set, get) => ({ })); }, getResourceStatus: (resourceId) => { - if(!resourceId) return null; - const status = get().resourceStatus[resourceId]; - return status || null; - }, + if (!resourceId) return null; + const status = get().resourceStatus[resourceId]; + if (!status) return null; + + const { path, filename, ...rest } = status; + return rest; +}, clearExpiredPublishes: () => { set((state) => { const now = Date.now(); @@ -105,4 +118,30 @@ export const usePublishStore = create((set, get) => ({ return { publishes: updatedPublishes }; }); }, +getAllResourceStatus: () => { + const { resourceStatus } = get(); + + return Object.entries(resourceStatus) + .filter(([_, status]) => status !== null) + .map(([id, status]) => { + const parts = id.split('-'); + const service = parts[0] as Service; + const name = parts[1] || ''; + const identifier = parts.length > 2 ? parts.slice(2).join('-') : ''; + + const { path, filename, ...rest } = status!; // extract path from old ResourceStatus + + return { + id, + metadata: { + service, + name, + identifier, + }, + status: rest, + path, + filename + }; + }); +} }));