From f229224f94f33f6568a9eb173e9e332f9a70d2c0 Mon Sep 17 00:00:00 2001 From: Saelmala Date: Tue, 3 Sep 2024 16:57:15 +0200 Subject: [PATCH] feat: support to add media player and html sources --- .../pipelines/multiviews/multiviews.ts | 10 +- src/api/agileLive/websocket.ts | 28 ++-- src/api/manager/productions.ts | 1 + src/api/manager/workflow.ts | 26 +++- src/app/production/[id]/page.tsx | 50 ++++-- src/components/dragElement/DragItem.tsx | 51 +++--- src/components/modal/AddSourceModal.tsx | 2 +- src/components/sourceCard/SourceCard.tsx | 85 ++++++---- src/components/sourceCards/SourceCards.tsx | 91 ++++++++--- .../sourceListItem/SourceListItem.tsx | 4 +- src/hooks/items/addSetupItem.ts | 3 +- src/hooks/useDragableItems.ts | 146 ++++++++++++++++-- src/interfaces/Source.ts | 4 +- src/interfaces/production.ts | 14 -- 14 files changed, 372 insertions(+), 143 deletions(-) diff --git a/src/api/agileLive/pipelines/multiviews/multiviews.ts b/src/api/agileLive/pipelines/multiviews/multiviews.ts index d710cc40..d92b269f 100644 --- a/src/api/agileLive/pipelines/multiviews/multiviews.ts +++ b/src/api/agileLive/pipelines/multiviews/multiviews.ts @@ -53,13 +53,15 @@ export async function createMultiviewForPipeline( } const pipelineUUID = productionSettings.pipelines[multiviewIndex].pipeline_id!; - const sources = await getSourcesByIds( - sourceRefs.map((ref) => ref._id.toString()) - ); + const sources = await getSourcesByIds( + sourceRefs + .filter((ref) => ref._id !== undefined) + .map((ref) => ref._id!.toString()) + ); const sourceRefsWithLabels = sourceRefs.map((ref) => { if (!ref.label) { const source = sources.find( - (source) => source._id.toString() === ref._id.toString() + (source) => source._id.toString() === ref._id?.toString() ); ref.label = source?.name || ''; } diff --git a/src/api/agileLive/websocket.ts b/src/api/agileLive/websocket.ts index 57c50697..4e26e8dd 100644 --- a/src/api/agileLive/websocket.ts +++ b/src/api/agileLive/websocket.ts @@ -15,33 +15,31 @@ function createWebSocket(): Promise { }); } -export async function createHtmlWebSocket() { +export async function createControlPanelWebSocket() { const ws = await createWebSocket(); return { - create: (input: number) => { + createHtml: (input: number) => { + ws.send('html reset'); ws.send(`html create ${input} 1920 1080`); - // delay the loading of the placeholder page to ensure the browser instance is ready setTimeout(() => { ws.send( `html load ${input} ${process.env.NEXTAUTH_URL}/html_input?input=${input}` ); }, 1000); }, - close: (input: number) => { - ws.send(`html close ${input}`); - } - }; -} - -export async function createMediaplayerWebSocket() { - const ws = await createWebSocket(); - return { - create: (input: number) => { + createMediaplayer: (input: number) => { + ws.send('media reset'); ws.send(`media create ${input} ${process.env.MEDIAPLAYER_PLACEHOLDER}`); ws.send(`media play ${input}`); }, - close: (input: number) => { + closeHtml: (input: number) => { + ws.send(`html close ${input}`); + }, + closeMediaplayer: (input: number) => { ws.send(`media close ${input}`); + }, + close: () => { + ws.close(); } - }; + } } diff --git a/src/api/manager/productions.ts b/src/api/manager/productions.ts index e68524ad..714d822d 100644 --- a/src/api/manager/productions.ts +++ b/src/api/manager/productions.ts @@ -2,6 +2,7 @@ import { Db, ObjectId, UpdateResult } from 'mongodb'; import { getDatabase } from '../mongoClient/dbClient'; import { Production, ProductionWithId } from '../../interfaces/production'; import { Log } from '../logger'; +import { SourceReference, Type } from '../../interfaces/Source'; export async function getProductions(): Promise { const db = await getDatabase(); diff --git a/src/api/manager/workflow.ts b/src/api/manager/workflow.ts index 30678a7d..10753228 100644 --- a/src/api/manager/workflow.ts +++ b/src/api/manager/workflow.ts @@ -49,6 +49,7 @@ import { Result } from '../../interfaces/result'; import { Monitoring } from '../../interfaces/monitoring'; import { getDatabase } from '../mongoClient/dbClient'; import { updatedMonitoringForProduction } from './job/syncMonitoring'; +import { createControlPanelWebSocket } from '../agileLive/websocket'; const isUsed = (pipeline: ResourcesPipelineResponse) => { const hasStreams = pipeline.streams.length > 0; @@ -308,6 +309,10 @@ export async function stopProduction( (p) => p.pipeline_id ); + const controlPanelWS = await createControlPanelWebSocket(); + const htmlSources = production.sources.filter((source) => source.type === 'html'); + const mediaPlayerSources = production.sources.filter((source) => source.type === 'mediaplayer'); + for (const source of production.sources) { for (const stream_uuid of source.stream_uuids || []) { await deleteStreamByUuid(stream_uuid).catch((error) => { @@ -316,6 +321,9 @@ export async function stopProduction( } } + htmlSources.map((source) => controlPanelWS.closeHtml(source.input_slot)); + mediaPlayerSources.map((source) => controlPanelWS.closeMediaplayer(source.input_slot)); + for (const id of pipelineIds) { Log().info(`Stopping pipeline '${id}'`); if (!id) continue; @@ -448,9 +456,21 @@ export async function startProduction( // Try to setup streams from ingest(s) to pipeline(s) start try { // Get sources from the DB + // Skapa en createHtmlWebSocket, spara + const controlPanelWS = await createControlPanelWebSocket(); + const htmlSources = production.sources.filter((source) => source.type === 'html'); + const mediaPlayerSources = production.sources.filter((source) => source.type === 'mediaplayer'); + + htmlSources.map((source) => controlPanelWS.createHtml(source.input_slot)); + mediaPlayerSources.map((source) => controlPanelWS.createMediaplayer(source.input_slot)); + + controlPanelWS.close(); + + // Nedan behöver göras efter att vi har skapat en produktion + // TODO: Hämta production.sources, för varje html-reference --> create i createHtmlWebSocket, för varje mediaplayer i production.sources skapa en createWebSocket const sources = await getSourcesByIds( - production.sources.map((source) => { - return source._id.toString(); + production.sources.filter((source) => source._id !== undefined).map((source) => { + return source._id!.toString(); }) ).catch((error) => { if (error === "Can't connect to Database") { @@ -716,7 +736,7 @@ export async function startProduction( ...production, sources: production.sources.map((source) => { const streamsForSource = streams?.filter( - (stream) => stream.source_id === source._id.toString() + (stream) => stream.source_id === source._id?.toString() ); return { ...source, diff --git a/src/app/production/[id]/page.tsx b/src/app/production/[id]/page.tsx index d68bd179..86dbebbd 100644 --- a/src/app/production/[id]/page.tsx +++ b/src/app/production/[id]/page.tsx @@ -10,7 +10,8 @@ import { AddSourceStatus, DeleteSourceStatus, SourceReference, - SourceWithId + SourceWithId, + Type } from '../../../interfaces/Source'; import { useGetProduction, usePutProduction } from '../../../hooks/productions'; import { Production } from '../../../interfaces/production'; @@ -40,8 +41,8 @@ import { RemoveSourceModal } from '../../../components/modal/RemoveSourceModal'; import { useDeleteStream, useCreateStream } from '../../../hooks/streams'; import { MonitoringButton } from '../../../components/button/MonitoringButton'; import { useGetMultiviewPreset } from '../../../hooks/multiviewPreset'; -import { ISource } from '../../../hooks/useDragableItems'; import { useMultiviews } from '../../../hooks/multiviews'; +import { v4 as uuidv4 } from 'uuid'; export default function ProductionConfiguration({ params }: PageProps) { const t = useTranslate(); @@ -59,6 +60,8 @@ export default function ProductionConfiguration({ params }: PageProps) { const [selectedSourceRef, setSelectedSourceRef] = useState< SourceReference | undefined >(); + const [sourceReferenceToAdd, setSourceReferenceToAdd] = + useState(); const [createStream, loadingCreateStream] = useCreateStream(); const [deleteStream, loadingDeleteStream] = useDeleteStream(); //PRODUCTION @@ -93,6 +96,29 @@ export default function ProductionConfiguration({ params }: PageProps) { refreshControlPanels(); }, [productionSetup?.isActive]); + // TODO: Väldigt lik den för ingest_source --> ändra?? + const addSourceToProduction = (type: Type) => { + const newSource: SourceReference = { + _id: uuidv4(), + type: type, + label: type === 'html' ? 'HTML Input' : 'Media Player Source', + input_slot: getFirstEmptySlot() + }; + setSourceReferenceToAdd(newSource); + + if (productionSetup) { + const updatedSetup = addSetupItem(newSource, productionSetup); + if (!updatedSetup) return; + setProductionSetup(updatedSetup); + putProduction(updatedSetup._id.toString(), updatedSetup).then(() => { + refreshProduction(); + setAddSourceModal(false); + setSourceReferenceToAdd(undefined); + }); + setAddSourceStatus(undefined); + } + }; + const setSelectedControlPanel = (controlPanel: string[]) => { setProductionSetup((prevState) => { if (!prevState) return; @@ -371,6 +397,7 @@ export default function ProductionConfiguration({ params }: PageProps) { const updatedSetup = addSetupItem( { _id: source._id.toString(), + type: 'ingest_source', label: source.ingest_source_name, input_slot: getFirstEmptySlot() }, @@ -442,8 +469,9 @@ export default function ProductionConfiguration({ params }: PageProps) { } if (result.ok) { if (result.value.success) { - const sourceToAdd = { + const sourceToAdd: SourceReference = { _id: result.value.streams[0].source_id, + type: 'ingest_source', label: selectedSource.name, stream_uuids: result.value.streams.map((r) => r.stream_uuid), input_slot: getFirstEmptySlot() @@ -464,11 +492,13 @@ export default function ProductionConfiguration({ params }: PageProps) { } }; + // TODO: HTML och MEDIA PLAYER KÄLLOR TAS INTE BORT const handleRemoveSource = async () => { if ( productionSetup && productionSetup.isActive && selectedSourceRef && + // Gör det här att sourcen inte tas bort ordentligt? selectedSourceRef.stream_uuids ) { const multiview = @@ -674,15 +704,12 @@ export default function ProductionConfiguration({ params }: PageProps) { {productionSetup?.sources && sources.size > 0 && ( { updateProduction(productionSetup._id, updated); }} - onSourceUpdate={( - source: SourceReference, - sourceItem: ISource - ) => { - sourceItem.label = source.label; + onSourceUpdate={(source: SourceReference) => { updateSource(source, productionSetup); }} onSourceRemoval={(source: SourceReference) => { @@ -693,6 +720,7 @@ export default function ProductionConfiguration({ params }: PageProps) { const updatedSetup = removeSetupItem( { _id: source._id, + type: source.type, label: source.label, input_slot: source.input_slot }, @@ -730,11 +758,9 @@ export default function ProductionConfiguration({ params }: PageProps) { onClickSource={() => { setInventoryVisible(true); }} - onClickHtml={() => { - /* */ - }} + onClickHtml={() => addSourceToProduction('html')} onClickMediaplayer={() => { - /* */ + addSourceToProduction('mediaplayer'); }} /> diff --git a/src/components/dragElement/DragItem.tsx b/src/components/dragElement/DragItem.tsx index fdc7cde7..e4403947 100644 --- a/src/components/dragElement/DragItem.tsx +++ b/src/components/dragElement/DragItem.tsx @@ -1,11 +1,12 @@ -import React, { ReactElement, memo, useRef } from 'react'; +import React, { ReactElement, memo, useEffect, useRef } from 'react'; import { useDrag, useDrop } from 'react-dnd'; import { SourceReference } from '../../interfaces/Source'; import { ObjectId } from 'mongodb'; import { Production } from '../../interfaces/production'; +import { v4 as uuidv4 } from 'uuid'; interface IDrag { - id: ObjectId; + id: ObjectId | string; selectingText: boolean; onMoveItem: (currentId: string, nextId: string) => void; children: ReactElement; @@ -14,11 +15,10 @@ interface IDrag { updateProduction: (updated: Production) => void; productionSetup: Production; } - const DragItem: React.FC = memo( ({ id, - selectingText: selectingText, + selectingText, onMoveItem, children, previousOrder, @@ -28,34 +28,43 @@ const DragItem: React.FC = memo( }) => { const ref = useRef(null); + const oid = typeof id === 'string' ? id : id.toString(); + const [{ isDragging }, connectDrag] = useDrag({ canDrag: !selectingText, type: 'Card', - item: { id }, - collect: (monitor) => { - return { - isDragging: monitor.isDragging() - }; - } + item: { oid }, + collect: (monitor) => ({ + isDragging: monitor.isDragging() + }) }); const [, connectDrop] = useDrop({ accept: 'Card', - hover(hoveredOverItem: { id: ObjectId }) { - if (hoveredOverItem.id !== id && id) { - onMoveItem(hoveredOverItem.id.toString(), id.toString()); + hover(hoveredOverItem: { oid: string }) { + if (hoveredOverItem.oid !== oid) { + onMoveItem(hoveredOverItem.oid.toString(), oid.toString()); } }, drop() { - const isSame = previousOrder.every( - (item, index) => item._id === currentOrder[index]._id - ); + const isSameLength = previousOrder.length === currentOrder.length; + const isSame = isSameLength + ? previousOrder.every( + (item, index) => item._id === currentOrder[index]?._id + ) + : false; + if (!isSame) { console.log('ORDER CHANGED'); + const updatedProduction = { ...productionSetup, - sources: currentOrder + sources: currentOrder.map((source) => ({ + ...source, + _id: source._id || uuidv4() // Ensure ID consistency + })) }; + updateProduction(updatedProduction); } } @@ -68,12 +77,12 @@ const DragItem: React.FC = memo( return ( <> - {React.Children.map(children, (child) => { - return React.cloneElement(child, { + {React.Children.map(children, (child) => + React.cloneElement(child, { forwardedRef: ref, style: containerStyle - }); - })} + }) + )} ); } diff --git a/src/components/modal/AddSourceModal.tsx b/src/components/modal/AddSourceModal.tsx index bacb9656..d81c1714 100644 --- a/src/components/modal/AddSourceModal.tsx +++ b/src/components/modal/AddSourceModal.tsx @@ -26,8 +26,8 @@ export function AddSourceModal({ return (
+

HEJ

{t('workflow.add_source_modal', { name })}

-
{status && }
+ {source && } + {source && ( +

+ {t('source.ingest', { + ingest: source.ingest_name + })} +

+ )} + {(source || sourceRef) && ( + + )}
); } diff --git a/src/components/sourceCards/SourceCards.tsx b/src/components/sourceCards/SourceCards.tsx index 9666bccc..2de146bf 100644 --- a/src/components/sourceCards/SourceCards.tsx +++ b/src/components/sourceCards/SourceCards.tsx @@ -6,49 +6,62 @@ import { Production } from '../../interfaces/production'; import DragItem from '../dragElement/DragItem'; import SourceCard from '../sourceCard/SourceCard'; import { EmptySlotCard } from '../emptySlotCard/EmptySlotCard'; -import { ISource, useDragableItems } from '../../hooks/useDragableItems'; +import { useDragableItems } from '../../hooks/useDragableItems'; +import { useSources } from '../../hooks/sources/useSources'; export default function SourceCards({ productionSetup, + sourceRef, updateProduction, onSourceUpdate, onSourceRemoval }: { productionSetup: Production; + sourceRef?: SourceReference; updateProduction: (updated: Production) => void; - onSourceUpdate: (source: SourceReference, sourceItem: ISource) => void; + onSourceUpdate: (source: SourceReference) => void; onSourceRemoval: (source: SourceReference) => void; }) { - const [items, moveItem, loading] = useDragableItems(productionSetup.sources); + const [items, moveItems] = useDragableItems(productionSetup.sources); + const referenceItems = productionSetup.sources; const [selectingText, setSelectingText] = useState(false); - const currentOrder: SourceReference[] = items.map((source) => { + const currentOrder: SourceReference[] = referenceItems.map((source) => { return { - _id: source._id.toString(), - label: source.label, - input_slot: source.input_slot, + _id: sourceRef ? sourceRef._id : source._id.toString(), + type: sourceRef ? sourceRef.type : 'ingest_source', + label: sourceRef ? sourceRef.label : source.label, + input_slot: sourceRef ? sourceRef.input_slot : source.input_slot, stream_uuids: source.stream_uuids }; }); + const [inventorySources, loading] = useSources(); + + const ingRefs = referenceItems.filter((ri) => ri.type === 'ingest_source'); + + const isIngestSource = (sourceR: SourceReference) => { + const source = inventorySources.get(sourceR._id); + if (!source) return false; + return true; + }; const gridItems: React.JSX.Element[] = []; let tempItems = [...items]; let firstEmptySlot = items.length + 1; - if (!items || items.length === 0) return null; - for (let i = 0; i < items[items.length - 1].input_slot; i++) { - if (!items.some((source) => source.input_slot === i + 1)) { + let tempReferenceItems = [...referenceItems]; + + let bigItemsArray = [...tempItems, ...referenceItems]; + + if (!bigItemsArray || bigItemsArray.length === 0) return null; + for (let i = 0; i < bigItemsArray[bigItemsArray.length - 1].input_slot; i++) { + if (!bigItemsArray.some((source) => source.input_slot === i + 1)) { firstEmptySlot = i + 1; break; } } - for (let i = 0; i < items[items.length - 1].input_slot; i++) { - // console.log(`On input slot: ${i + 1}`); - // console.log(`Checking sources:`); - // console.log(tempItems); + for (let i = 0; i < bigItemsArray[bigItemsArray.length - 1].input_slot; i++) { tempItems.every((source) => { if (source.input_slot === i + 1) { - // console.log(`Found source on input slot: ${i + 1}`); - // console.log(`Removing source "${source.name}" from sources list`); tempItems = tempItems.filter((i) => i._id !== source._id); // console.log(`Adding source "${source.name}" to grid`); if (!productionSetup.isActive) { @@ -65,8 +78,9 @@ export default function SourceCards({ > @@ -78,10 +92,15 @@ export default function SourceCards({ } else { gridItems.push( @@ -107,6 +126,38 @@ export default function SourceCards({ return false; } }); + + tempReferenceItems + .filter((refs) => refs.type !== 'ingest_source') + .forEach((sourceRef) => { + if (sourceRef.input_slot === i + 1) { + if (!productionSetup.isActive) { + gridItems.push( + + + setSelectingText(isSelecting) + } + src="" + /> + + ); + } + } + }); } return <>{gridItems}; } diff --git a/src/components/sourceListItem/SourceListItem.tsx b/src/components/sourceListItem/SourceListItem.tsx index a76ca053..bae56d68 100644 --- a/src/components/sourceListItem/SourceListItem.tsx +++ b/src/components/sourceListItem/SourceListItem.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { Source, SourceWithId } from '../../interfaces/Source'; +import { Source, SourceReference, SourceWithId } from '../../interfaces/Source'; import { PreviewThumbnail } from './PreviewThumbnail'; import { getSourceThumbnail } from '../../utils/source'; import videoSettings from '../../utils/videoSettings'; @@ -95,7 +95,7 @@ function InventoryListItem({ : [] ); } - }, [source.audio_stream.audio_mapping]); + }, [source?.audio_stream.audio_mapping]); return (
  • a.input_slot - b.input_slot) }; - return { ...updatedSetup, sources: [ ...productionSetup.sources, { _id: source._id, + type: source.type, label: source.label, stream_uuids: source.stream_uuids, input_slot: source.input_slot diff --git a/src/hooks/useDragableItems.ts b/src/hooks/useDragableItems.ts index 427ffbf1..d7845d02 100644 --- a/src/hooks/useDragableItems.ts +++ b/src/hooks/useDragableItems.ts @@ -9,24 +9,58 @@ export interface ISource extends SourceWithId { stream_uuids?: string[]; src: string; } + +// Kolla hur det här funkar med allting +// är items som ställer till det export function useDragableItems( sources: SourceReference[] -): [ISource[], (originId: string, destinationId: string) => void, boolean] { +): [(SourceReference | ISource)[], (originId: string, destinationId: string) => void, boolean] { + const [ingestSources, setIngestSources] = useState([]); + const [inventorySources, loading] = useSources(); + + const [allSources, setAllSources] = useState<(SourceReference | ISource)[]>([]); + const [items, setItems] = useState( sources.flatMap((ref) => { const source = inventorySources.get(ref._id); if (!source) return []; return { ...source, + _id: ref._id, label: ref.label, input_slot: ref.input_slot, stream_uuids: ref.stream_uuids, - src: getSourceThumbnail(source) + src: getSourceThumbnail(source), }; }) ); + const [refItems, setRefItems] = useState( + sources.flatMap((ref) => { + return {... ref} + }) + ); + + const [allItems, setAllItems] = useState<(SourceReference | ISource)[]>( + sources.flatMap((ref) => { + if (ref.type === 'ingest_source') { + const source = inventorySources.get(ref._id); + if (!source) return []; + return { + ...source, + _id: ref._id, + label: ref.label, + input_slot: ref.input_slot, + stream_uuids: ref.stream_uuids, + src: getSourceThumbnail(source), + }; + } else { + return {...ref} + } + }) + ) + useEffect(() => { setItems( sources.flatMap((ref) => { @@ -34,34 +68,116 @@ export function useDragableItems( if (!source) return []; return { ...source, + _id: ref._id, label: ref.label, input_slot: ref.input_slot, stream_uuids: ref.stream_uuids, - src: getSourceThumbnail(source) + src: getSourceThumbnail(source), }; }) ); }, [sources, inventorySources]); + useEffect(() => { + setAllItems( + sources.flatMap((ref) => { + if (ref.type === 'ingest_source') { + const source = inventorySources.get(ref._id); + if (!source) return []; + return { + ...source, + _id: ref._id, + label: ref.label, + input_slot: ref.input_slot, + stream_uuids: ref.stream_uuids, + src: getSourceThumbnail(source), + }; + } else { + return {...ref} + } + }) + ) + }) + + // useEffect(() => { + // setIngestSources( + // sources.flatMap((ref) => { + // const source = inventorySources.get(ref._id); + // if (!source) return []; + // return { + // ...source, + // _id: ref._id, + // label: ref.label, + // input_slot: ref.input_slot, + // stream_uuids: ref.stream_uuids, + // src: getSourceThumbnail(source), + // }; + // }) + // ); + // }, [sources, inventorySources]); + + // useEffect(() => { + // setRefSources(sources.filter((ref) => ref.type !== 'ingest_source')); + // }, [sources]) + + // useEffect(() => { + // setAllSources([...refSources, ...ingestSources]); + // }, [refSources, ingestSources]); + const moveItem = (originId: string, destinationId: string) => { const originSource = items.find((i) => i._id.toString() === originId); const destinationSource = items.find( (i) => i._id.toString() === destinationId ); + if (!originSource || !destinationSource) return; + const originInputSlot = originSource.input_slot; const destinationInputSlot = destinationSource.input_slot; - originSource.input_slot = destinationInputSlot; - destinationSource.input_slot = originInputSlot; - const updatedItems = [ - ...items.filter( - (i) => i._id !== originSource._id && i._id !== destinationSource._id - ), - originSource, - destinationSource - ].sort((a, b) => a.input_slot - b.input_slot); - setItems(updatedItems); + + // Swap input slots + const updatedItems = items.map((item) => { + if (item._id === originSource._id) return { ...item, input_slot: destinationInputSlot }; + if (item._id === destinationSource._id) return { ...item, input_slot: originInputSlot }; + return item; + }).sort((a, b) => a.input_slot - b.input_slot); + + if (updatedItems){ + setItems(updatedItems);} }; - return [items, moveItem, loading]; -} + const moveItems = (originId: string, destinationId: string) => { + const originSource = allItems.find((i) => i._id.toString() === originId); + const destinationSource = allItems.find((i) => i._id.toString() === destinationId); + + if (!originSource || !destinationSource) return; + + const originInputSlot = originSource.input_slot; + const destinationInputSlot = destinationSource.input_slot; + + const updatedItems = allItems.map((item) => { + if (item._id === originSource._id) return { ...item, input_slot: destinationInputSlot }; + if (item._id === destinationSource._id) return {...item, input_slot: originInputSlot }; + return item; + }).sort((a, b) => a.input_slot - b.input_slot); + + if (updatedItems) { + setAllItems(updatedItems); + } + }; + + // const moveItem = (originId: string, destinationId: string) => { + // const originIndex = items.findIndex((i) => i._id === originId); + // const destinationIndex = items.findIndex((i) => i._id === destinationId); + + // if (originIndex === -1 || destinationIndex === -1) return; + + // const updatedItems = [...items]; + // const [movedItem] = updatedItems.splice(originIndex, 1); + // updatedItems.splice(destinationIndex, 0, movedItem); + + // setItems(updatedItems); + // } + + return [allItems, moveItems, loading]; +} \ No newline at end of file diff --git a/src/interfaces/Source.ts b/src/interfaces/Source.ts index 99e57042..f7309462 100644 --- a/src/interfaces/Source.ts +++ b/src/interfaces/Source.ts @@ -1,6 +1,7 @@ import { ObjectId, WithId } from 'mongodb'; export type SourceType = 'camera' | 'graphics' | 'microphone'; export type SourceStatus = 'ready' | 'new' | 'gone'; +export type Type = 'ingest_source' | 'html' | 'mediaplayer'; export type VideoStream = { height?: number; width?: number; @@ -16,7 +17,7 @@ export type AudioStream = { export type Numbers = number | number[]; export interface Source { - _id?: ObjectId; + _id: ObjectId | string; status: SourceStatus; name: string; type: SourceType; @@ -32,6 +33,7 @@ export interface Source { export interface SourceReference { _id: string; + type: Type; label: string; stream_uuids?: string[]; input_slot: number; diff --git a/src/interfaces/production.ts b/src/interfaces/production.ts index b979a5ca..eb4d9655 100644 --- a/src/interfaces/production.ts +++ b/src/interfaces/production.ts @@ -3,25 +3,11 @@ import { SourceReference } from './Source'; import { ControlConnection } from './controlConnections'; import { PipelineSettings } from './pipeline'; -interface HtmlReference { - _id: string; - input_slot: number; - label: string; -} - -interface MediaplayerReference { - _id: string; - input_slot: number; - label: string; -} - export interface Production { _id: string; isActive: boolean; name: string; sources: SourceReference[]; - html: HtmlReference[]; - mediaplayers: MediaplayerReference[]; production_settings: ProductionSettings; }