Skip to content

Commit 07eab14

Browse files
committed
feat: HTTP API for fetching Playlist data - Active Playlist WIP
1 parent 0191284 commit 07eab14

7 files changed

Lines changed: 450 additions & 1 deletion

File tree

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
.node-version
1+
22.13.1

meteor/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@sofie-automation/blueprints-integration": "portal:../packages/blueprints-integration",
4646
"@sofie-automation/corelib": "portal:../packages/corelib",
4747
"@sofie-automation/job-worker": "portal:../packages/job-worker",
48+
"@sofie-automation/live-status-gateway-api": "1.53.0-nightly-release53-20250508-073553-5c20bea.0",
4849
"@sofie-automation/meteor-lib": "portal:../packages/meteor-lib",
4950
"@sofie-automation/shared-lib": "portal:../packages/shared-lib",
5051
"app-root-path": "^3.1.0",

meteor/server/api/rest/v1/playlists.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ import { getCurrentTime } from '../../../lib/lib'
3434
import { TriggerReloadDataResponse } from '@sofie-automation/meteor-lib/dist/api/userActions'
3535
import { ServerRundownAPI } from '../../rundown'
3636
import { triggerWriteAccess } from '../../../security/securityVerify'
37+
import {
38+
ActivePlaylistEvent,
39+
ActivePlaylistTiming,
40+
ActivePlaylistTimingMode,
41+
} from '@sofie-automation/live-status-gateway-api'
42+
import { PlaylistTimingType, RundownPlaylistTiming } from '@sofie-automation/blueprints-integration'
3743

3844
class PlaylistsServerAPI implements PlaylistsRestAPI {
3945
constructor(private context: ServerAPIContext) {}
@@ -50,6 +56,75 @@ class PlaylistsServerAPI implements PlaylistsRestAPI {
5056
)
5157
}
5258

59+
async getActiveRundownPlaylist(
60+
_connection: Meteor.Connection,
61+
_event: string
62+
): Promise<ClientAPI.ClientResponse<Omit<ActivePlaylistEvent, 'event' | 'currentSegment'>>> {
63+
const rundownPlaylist = (
64+
await RundownPlaylists.findFetchAsync(
65+
{ activationId: { $exists: true, $ne: undefined } },
66+
{
67+
projection: {
68+
_id: 1,
69+
name: 1,
70+
rundownIdsInOrder: 1,
71+
currentPartInfo: 1,
72+
// segmentsStartedPlayback: 1, somehow get current segment,
73+
nextPartInfo: 1,
74+
publicData: 1,
75+
timing: 1,
76+
quickLoop: 1,
77+
},
78+
limit: 1,
79+
}
80+
)
81+
)?.[0] as Pick<
82+
DBRundownPlaylist,
83+
| '_id'
84+
| 'name'
85+
| 'rundownIdsInOrder'
86+
| 'currentPartInfo'
87+
| 'nextPartInfo'
88+
| 'publicData'
89+
| 'timing'
90+
| 'quickLoop'
91+
>
92+
return ClientAPI.responseSuccess({
93+
id: unprotectString(rundownPlaylist._id),
94+
name: rundownPlaylist.name,
95+
rundownIds: rundownPlaylist.rundownIdsInOrder.map((id) => unprotectString(id)),
96+
currentPart: rundownPlaylist.currentPartInfo,
97+
nextPart: rundownPlaylist.nextPartInfo,
98+
publicData: rundownPlaylist.publicData,
99+
timing: this.convertTiming(rundownPlaylist.timing),
100+
quickLoop: rundownPlaylist.quickLoop,
101+
} as Omit<ActivePlaylistEvent, 'event' | 'currentSegment'>)
102+
}
103+
104+
convertTiming(timing: RundownPlaylistTiming): ActivePlaylistTiming {
105+
switch (timing.type) {
106+
case PlaylistTimingType.None:
107+
return {
108+
timingMode: ActivePlaylistTimingMode.NONE,
109+
expectedDurationMs: timing.expectedDuration,
110+
}
111+
case PlaylistTimingType.ForwardTime:
112+
return {
113+
timingMode: ActivePlaylistTimingMode.FORWARD_MINUS_TIME,
114+
expectedStart: Number(timing.expectedStart),
115+
expectedDurationMs: timing.expectedDuration,
116+
expectedEnd: timing.expectedEnd ? Number(timing.expectedEnd) : undefined,
117+
}
118+
case PlaylistTimingType.BackTime:
119+
return {
120+
timingMode: ActivePlaylistTimingMode.BACK_MINUS_TIME,
121+
expectedStart: timing.expectedStart ? Number(timing.expectedStart) : undefined,
122+
expectedDurationMs: timing.expectedDuration,
123+
expectedEnd: Number(timing.expectedEnd),
124+
}
125+
}
126+
}
127+
53128
async activate(
54129
connection: Meteor.Connection,
55130
event: string,
@@ -548,6 +623,17 @@ export function registerRoutes(registerRoute: APIRegisterHook<PlaylistsRestAPI>)
548623
}
549624
)
550625

626+
registerRoute<never, never, Omit<ActivePlaylistEvent, 'event' | 'currentSegment'>>(
627+
'get',
628+
'/playlists/active', // should we use '/playlist'?
629+
new Map(),
630+
playlistsAPIFactory,
631+
async (serverAPI, connection, event, _params, _body) => {
632+
logger.info(`API GET: Active playlist`)
633+
return await serverAPI.getActiveRundownPlaylist(connection, event)
634+
}
635+
)
636+
551637
registerRoute<{ playlistId: string }, { rehearsal: boolean }, void>(
552638
'put',
553639
'/playlists/:playlistId/activate',

meteor/server/lib/rest/v1/playlists.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '@sofie-automation/corelib/dist/dataModel/Ids'
1313
import { QueueNextSegmentResult } from '@sofie-automation/corelib/dist/worker/studio'
1414
import { Meteor } from 'meteor/meteor'
15+
import { ActivePlaylistEvent } from '@sofie-automation/live-status-gateway-api'
1516

1617
/* *************************************************************************
1718
This file contains types and interfaces that are used by the REST API.
@@ -29,6 +30,15 @@ export interface PlaylistsRestAPI {
2930
connection: Meteor.Connection,
3031
event: string
3132
): Promise<ClientAPI.ClientResponse<Array<{ id: string }>>>
33+
/**
34+
* Gets a specific RundownPlaylist.
35+
* @param connection Connection data including client and header details
36+
* @param event User event string
37+
*/
38+
getActiveRundownPlaylist(
39+
connection: Meteor.Connection,
40+
event: string
41+
): Promise<ClientAPI.ClientResponse<Omit<ActivePlaylistEvent, 'event' | 'currentSegment'>>>
3242
/**
3343
* Activates a Playlist.
3444
*

meteor/yarn.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,6 +1221,15 @@ __metadata:
12211221
languageName: node
12221222
linkType: soft
12231223

1224+
"@sofie-automation/live-status-gateway-api@npm:1.53.0-nightly-release53-20250508-073553-5c20bea.0":
1225+
version: 1.53.0-nightly-release53-20250508-073553-5c20bea.0
1226+
resolution: "@sofie-automation/live-status-gateway-api@npm:1.53.0-nightly-release53-20250508-073553-5c20bea.0"
1227+
dependencies:
1228+
tslib: "npm:^2.6.2"
1229+
checksum: 10/b34644c0626acf6a96247dc82ec9d55ef9b596d7862fc9a7af719a8562833063bd3c209b7ff3c2f3b1e1e3a6ec4b2b5ebff12244ce4c857b132b35dc0b7c4838
1230+
languageName: node
1231+
linkType: hard
1232+
12241233
"@sofie-automation/meteor-lib@portal:../packages/meteor-lib::locator=automation-core%40workspace%3A.":
12251234
version: 0.0.0-use.local
12261235
resolution: "@sofie-automation/meteor-lib@portal:../packages/meteor-lib::locator=automation-core%40workspace%3A."
@@ -2263,6 +2272,7 @@ __metadata:
22632272
"@sofie-automation/code-standard-preset": "npm:^3.0.0"
22642273
"@sofie-automation/corelib": "portal:../packages/corelib"
22652274
"@sofie-automation/job-worker": "portal:../packages/job-worker"
2275+
"@sofie-automation/live-status-gateway-api": "npm:1.53.0-nightly-release53-20250508-073553-5c20bea.0"
22662276
"@sofie-automation/meteor-lib": "portal:../packages/meteor-lib"
22672277
"@sofie-automation/shared-lib": "portal:../packages/shared-lib"
22682278
"@types/app-root-path": "npm:^1.2.8"

packages/openapi/api/actions.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ paths:
3939
# playlist operations
4040
/playlists:
4141
$ref: 'definitions/playlists.yaml#/resources/playlists'
42+
/playlists/active:
43+
$ref: 'definitions/playlists.yaml#/resources/playlist'
4244
/playlists/{playlistId}/activate:
4345
$ref: 'definitions/playlists.yaml#/resources/activate'
4446
/playlists/{playlistId}/deactivate:

0 commit comments

Comments
 (0)