From c2a297302857f0fee6e3ab7e87c943dc9df4faf2 Mon Sep 17 00:00:00 2001 From: Johan Nyman Date: Tue, 7 Nov 2023 15:53:33 +0100 Subject: [PATCH] chore: shared model --- packages/shared/model/src/model.ts | 134 +++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 16 deletions(-) diff --git a/packages/shared/model/src/model.ts b/packages/shared/model/src/model.ts index 39b77f3..b2e2a1f 100644 --- a/packages/shared/model/src/model.ts +++ b/packages/shared/model/src/model.ts @@ -1,11 +1,15 @@ import { ProtectedString } from './ProtectedString.js' +/* + These types are shared between the server and the client +*/ + export type RundownPlaylistId = ProtectedString<'RundownPlaylistId', string> export interface RundownPlaylist { _id: RundownPlaylistId /** Rundown playlist slug - user-presentable name */ - name: string + label: string created: number modified: number @@ -15,6 +19,14 @@ export interface RundownPlaylist { rehearsal: boolean /** Actual time of playback starting */ startedPlayback?: number + + // To be implemented later: + // timing: { + // expectedStart?: number + // expectedEnd?: number + // expectedDuration?: number + // startedPlayback?: number + // } } export type RundownId = ProtectedString<'RundownId', string> @@ -22,21 +34,40 @@ export interface Rundown { _id: RundownId playlistId: RundownPlaylistId + /** The position of the Rundown within its Playlist */ + rank: number + + // To be implemented later: + // timing: { + // expectedStart?: number + // expectedEnd?: number + // expectedDuration?: number + // startedPlayback?: number + // } } export type SegmentId = ProtectedString<'SegmentId', string> export interface Segment { _id: SegmentId rundownId: RundownId + /** The position of the Segment within its Rundown */ + rank: number /** User-presentable name (Slug) for the Title */ - name: string + label: string /** Hide the Segment in the UI */ isHidden?: boolean + // To be implemented later: /** User-facing identifier that can be used by the User to identify the contents of a segment in the Rundown source system */ - identifier?: string + // identifier?: string + + timing: { + expectedStart?: number + expectedEnd?: number + budgetDuration?: number + } } export type PartId = ProtectedString<'PartId', string> @@ -44,9 +75,17 @@ export interface Part { _id: PartId rundownId: RundownId segmentId: SegmentId + /** The position of the Part within its Segment */ + rank: number + + isOnAir: boolean + isNext: boolean + + /** The story title/slug, displayable to user */ + label: string - /** The story title */ - title: string + /** An alternative override to show in the rendered prompter output */ + prompterLabel?: string /** User-facing identifier that can be used by the User to identify the contents of a segment in the Rundown source system */ identifier?: string @@ -57,19 +96,82 @@ export interface Part { /** Expected duration of the Part, in milliseconds */ expectedDuration?: number - /** The type of Part, eg STK, FULL. To be displayed to user */ - displayType: string + /** Is true if the Part has been updated since user last saw it. User can acknowledge*/ + isNew?: boolean + + /** The type of Part, eg STK, FULL. */ + display: { + /** Styling information (colors, etc.) */ + type: PartDisplayType // ie sourceLayer.type in Sofie + /** Label to be displayed to user */ + label: string // ie sourceLayer.name in Sofie + } + + scriptContents?: ScriptContents +} +export enum PartDisplayType { + KAM, + FULL, + STK, + SPL, + DIR, } -export type PieceId = ProtectedString<'PieceId', string> -export interface Piece { - _id: PieceId - rundownId: RundownId - partId: PartId +/** Stored as markdown */ +export type ScriptContents = string - /** Expected duration of the piece, in milliseconds */ - expectedDuration?: number +/** TBD, something used to mark places in ScriptContents */ +export type TextMarkerId = ProtectedString<'TextMarkerId', string> + +/** Represents a view of the prompter, is streamed from the viewPort. This is always the last connected viewport. */ +export interface ViewPort { + _id: 'viewport' + + /** + * When a ViewPort starts up, it randomizes its instanceId and sends it to the Server. + * If the ViewPorts' instanceId is the "last one" it is in control. + * The ViewPort "in control" will stream its data to the server continuously. + * If a ViewPort is not "in control" it could listen to the ViewPort data and jump to the same position to stay in sync. + */ + instanceId: string + + /** The width of the viewport (as percentage of viewport height) */ + width: number + + /** Current position of the viewport */ + position: ViewPortPosition +} + +/** Set by a user */ +export interface PrompterSettings { + fontSize: number // in percentage of viewport height + + mirrorHorizontally: boolean + mirrorVertically: boolean + + focusPosition: 'start' | 'center' | 'end' + showFocusPosition: boolean + + /** Adds padding between the edge of the screen and the text */ + marginHorizontal: number + /** In percentage of viewport height */ + marginVertical: number +} + +/** Sent from the user control interface to the ViewPort */ +export type ControllerMessage = { + speed: number // unit (lines per second)? + /** If set, viewport should jump to that position */ + position?: ViewPortPosition +} - content: SomePieceContent +/** Defines a position of the viewport */ +export interface ViewPortPosition { + /** + * The Part which the current offset is calculated from. + * `null` means "top of page" + */ + scrollOffsetTarget: SegmentId | PartId | TextMarkerId | null + /** The position of the ViewPort */ + scrollOffset: number } -type SomePieceContent = unknown // todo