@@ -482,6 +482,7 @@ async function retreiveSnapshot(snapshotId: SnapshotId, cred0: Credentials): Pro
482482
483483 return readSnapshot
484484}
485+
485486async function restoreFromSnapshot (
486487 /** The snapshot data to restore */
487488 snapshot : AnySnapshot ,
@@ -490,22 +491,7 @@ async function restoreFromSnapshot(
490491) : Promise < void > {
491492 // Determine what kind of snapshot
492493
493- if ( ! _ . isObject ( snapshot ) ) throw new Meteor . Error ( 500 , `Restore input data is not an object` )
494- // First, some special (debugging) cases:
495- // @ts -expect-error is's not really a snapshot here:
496- if ( snapshot . externalId && snapshot . segments && snapshot . type === 'mos' ) {
497- // Special: Not a snapshot, but a datadump of a MOS rundown
498- const studioId : StudioId = Meteor . settings . manualSnapshotIngestStudioId || 'studio0'
499- const studioExists = await checkStudioExists ( studioId )
500- if ( studioExists ) {
501- await importIngestRundown ( studioId , snapshot as unknown as IngestRundown )
502- return
503- }
504- throw new Meteor . Error ( 500 , `No Studio found` )
505- }
506-
507494 // Then, continue as if it's a normal snapshot:
508-
509495 if ( ! snapshot . snapshot ) throw new Meteor . Error ( 500 , `Restore input data is not a snapshot (${ _ . keys ( snapshot ) } )` )
510496
511497 if ( snapshot . snapshot . type === SnapshotType . RUNDOWNPLAYLIST ) {
@@ -518,11 +504,7 @@ async function restoreFromSnapshot(
518504 )
519505 }
520506
521- // TODO: Improve this. This matches the 'old' behaviour
522- const studios = await Studios . findFetchAsync ( { } )
523- const snapshotStudioExists = studios . find ( ( studio ) => studio . _id === playlistSnapshot . playlist . studioId )
524- const studioId = snapshotStudioExists ? playlistSnapshot . playlist . studioId : studios [ 0 ] ?. _id
525- if ( ! studioId ) throw new Meteor . Error ( 500 , `No Studio found` )
507+ const studioId = await getStudioIdFromPlaylistSnapshot ( playlistSnapshot )
526508
527509 // A snapshot of a rundownPlaylist
528510 return restoreFromRundownPlaylistSnapshot ( snapshot as RundownPlaylistSnapshot , studioId , restoreDebugData )
@@ -534,6 +516,60 @@ async function restoreFromSnapshot(
534516 }
535517}
536518
519+ async function getStudioIdFromPlaylistSnapshot ( playlistSnapshot : RundownPlaylistSnapshot ) : Promise < StudioId > {
520+ // TODO: Improve this. This matches the 'old' behaviour
521+ const studios = await Studios . findFetchAsync ( { } )
522+ const snapshotStudioExists = studios . find ( ( studio ) => studio . _id === playlistSnapshot . playlist . studioId )
523+ const studioId = snapshotStudioExists ? playlistSnapshot . playlist . studioId : studios [ 0 ] ?. _id
524+ if ( ! studioId ) throw new Meteor . Error ( 500 , `No Studio found` )
525+ return studioId
526+ }
527+ /** Read the ingest data from a snapshot and pipe it into blueprints */
528+ async function ingestFromSnapshot (
529+ /** The snapshot data to restore */
530+ snapshot : AnySnapshot
531+ ) : Promise < void > {
532+ // Determine what kind of snapshot
533+ if ( ! snapshot . snapshot ) throw new Meteor . Error ( 500 , `Restore input data is not a snapshot (${ _ . keys ( snapshot ) } )` )
534+ if ( snapshot . snapshot . type === SnapshotType . RUNDOWNPLAYLIST ) {
535+ const playlistSnapshot = snapshot as RundownPlaylistSnapshot
536+
537+ const studioId = await getStudioIdFromPlaylistSnapshot ( playlistSnapshot )
538+
539+ // Read the ingestData from the snapshot
540+ const ingestData = playlistSnapshot . ingestData
541+
542+ const rundownData = ingestData . filter ( ( e ) => e . type === 'rundown' )
543+ const segmentData = ingestData . filter ( ( e ) => e . type === 'segment' )
544+ const partData = ingestData . filter ( ( e ) => e . type === 'part' )
545+
546+ if ( rundownData . length === 0 ) throw new Meteor . Error ( 402 , `No rundowns found in ingestData` )
547+
548+ for ( const seg of segmentData ) {
549+ seg . data . parts = partData
550+ . filter ( ( e ) => e . segmentId === seg . segmentId )
551+ . map ( ( e ) => e . data )
552+ . sort ( ( a , b ) => b . rank - a . rank )
553+ }
554+
555+ for ( let i = 0 ; i < rundownData . length ; i ++ ) {
556+ const rundown = rundownData [ i ]
557+
558+ const segmentsInRundown = segmentData . filter ( ( e ) => e . rundownId === rundown . rundownId )
559+
560+ const ingestRundown : IngestRundown = rundown . data
561+ ingestRundown . segments = segmentsInRundown . map ( ( s ) => s . data ) . sort ( ( a , b ) => b . rank - a . rank )
562+
563+ await importIngestRundown ( studioId , ingestRundown )
564+ }
565+ } else {
566+ throw new Meteor . Error (
567+ 402 ,
568+ `Unable to ingest a snapshot of type "${ snapshot . snapshot . type } ", did you mean to restore it?`
569+ )
570+ }
571+ }
572+
537573async function restoreFromRundownPlaylistSnapshot (
538574 snapshot : RundownPlaylistSnapshot ,
539575 studioId : StudioId ,
@@ -809,8 +845,16 @@ if (!Settings.enableUserAccounts) {
809845 if ( ! snapshot ) throw new Meteor . Error ( 400 , 'Restore Snapshot: Missing request body' )
810846
811847 const restoreDebugData = ctx . headers [ 'restore-debug-data' ] === '1'
848+ const ingestSnapshotData = ctx . headers [ 'ingest-snapshot-data' ] === '1'
849+
850+ if ( typeof snapshot !== 'object' || snapshot === null )
851+ throw new Meteor . Error ( 500 , `Restore input data is not an object` )
812852
813- await restoreFromSnapshot ( snapshot , restoreDebugData )
853+ if ( ingestSnapshotData ) {
854+ await ingestFromSnapshot ( snapshot )
855+ } else {
856+ await restoreFromSnapshot ( snapshot , restoreDebugData )
857+ }
814858
815859 ctx . response . status = 200
816860 ctx . response . body = content
0 commit comments