Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions meteor/server/api/rest/v1/playlists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
} from '../../../collections'
import { DBRundownPlaylist } from '@sofie-automation/corelib/dist/dataModel/RundownPlaylist'
import { ServerClientAPI } from '../../client'
import { QueueNextSegmentResult, StudioJobs } from '@sofie-automation/corelib/dist/worker/studio'
import { QueueNextSegmentResult, StudioJobs, TakeNextPartResult } from '@sofie-automation/corelib/dist/worker/studio'
import { getCurrentTime } from '../../../lib/lib'
import { TriggerReloadDataResponse } from '@sofie-automation/meteor-lib/dist/api/userActions'
import { ServerRundownAPI } from '../../rundown'
Expand Down Expand Up @@ -457,7 +457,7 @@ class PlaylistsServerAPI implements PlaylistsRestAPI {
event: string,
rundownPlaylistId: RundownPlaylistId,
fromPartInstanceId: PartInstanceId | undefined
): Promise<ClientAPI.ClientResponse<void>> {
): Promise<ClientAPI.ClientResponse<TakeNextPartResult>> {
triggerWriteAccess()
const rundownPlaylist = await RundownPlaylists.findOneAsync(rundownPlaylistId)
if (!rundownPlaylist) throw new Error(`Rundown playlist ${rundownPlaylistId} does not exist`)
Expand Down Expand Up @@ -801,7 +801,7 @@ export function registerRoutes(registerRoute: APIRegisterHook<PlaylistsRestAPI>)
}
)

registerRoute<{ playlistId: string }, { fromPartInstanceId?: string }, void>(
registerRoute<{ playlistId: string }, { fromPartInstanceId?: string }, TakeNextPartResult>(
'post',
'/playlists/:playlistId/take',
new Map([
Expand Down
4 changes: 2 additions & 2 deletions meteor/server/lib/rest/v1/playlists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
RundownPlaylistId,
SegmentId,
} from '@sofie-automation/corelib/dist/dataModel/Ids'
import { QueueNextSegmentResult } from '@sofie-automation/corelib/dist/worker/studio'
import { QueueNextSegmentResult, TakeNextPartResult } from '@sofie-automation/corelib/dist/worker/studio'
import { Meteor } from 'meteor/meteor'

/* *************************************************************************
Expand Down Expand Up @@ -228,7 +228,7 @@ export interface PlaylistsRestAPI {
event: string,
rundownPlaylistId: RundownPlaylistId,
fromPartInstanceId: PartInstanceId | undefined
): Promise<ClientAPI.ClientResponse<void>>
): Promise<ClientAPI.ClientResponse<TakeNextPartResult>>
/**
* Clears the specified SourceLayers.
*
Expand Down
6 changes: 5 additions & 1 deletion packages/corelib/src/worker/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,10 @@ export interface SwitchRouteSetProps {
state: boolean | 'toggle'
}

export interface TakeNextPartResult {
nextTakeTime: number
}

/**
* Set of valid functions, of form:
* `id: (data) => return`
Expand All @@ -393,7 +397,7 @@ export type StudioJobFunc = {
[StudioJobs.QueueNextSegment]: (data: QueueNextSegmentProps) => QueueNextSegmentResult
[StudioJobs.ExecuteAction]: (data: ExecuteActionProps) => ExecuteActionResult
[StudioJobs.ExecuteBucketAdLibOrAction]: (data: ExecuteBucketAdLibOrActionProps) => ExecuteActionResult
[StudioJobs.TakeNextPart]: (data: TakeNextPartProps) => void
[StudioJobs.TakeNextPart]: (data: TakeNextPartProps) => TakeNextPartResult
[StudioJobs.DisableNextPiece]: (data: DisableNextPieceProps) => void
[StudioJobs.RemovePlaylist]: (data: RemovePlaylistProps) => void
[StudioJobs.RegeneratePlaylist]: (data: RegeneratePlaylistProps) => void
Expand Down
43 changes: 35 additions & 8 deletions packages/job-worker/src/playout/take.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ import { PlayoutRundownModel } from './model/PlayoutRundownModel.js'
import { convertNoteToNotification } from '../notifications/util.js'
import { PersistentPlayoutStateStore } from '../blueprints/context/services/PersistantStateStore.js'

import { TakeNextPartResult } from '@sofie-automation/corelib/dist/worker/studio'

/**
* Take the currently Next:ed Part (start playing it)
*/
export async function handleTakeNextPart(context: JobContext, data: TakeNextPartProps): Promise<void> {
export async function handleTakeNextPart(context: JobContext, data: TakeNextPartProps): Promise<TakeNextPartResult> {
const now = getCurrentTime()

return runJobWithPlayoutModel(
Expand Down Expand Up @@ -73,17 +75,29 @@ export async function handleTakeNextPart(context: JobContext, data: TakeNextPart
}
}
if (lastTakeTime && now - lastTakeTime < context.studio.settings.minimumTakeSpan) {
const nextTakeTime = lastTakeTime + context.studio.settings.minimumTakeSpan
logger.debug(
`Time since last take is shorter than ${context.studio.settings.minimumTakeSpan} for ${
playlist.currentPartInfo?.partInstanceId
}: ${now - lastTakeTime}`
)
throw UserError.create(UserErrorMessage.TakeRateLimit, {
duration: context.studio.settings.minimumTakeSpan,
})
throw UserError.create(
UserErrorMessage.TakeRateLimit,
{
duration: context.studio.settings.minimumTakeSpan,
nextAllowedTakeTime: nextTakeTime,
},
429
)
}

return performTakeToNextedPart(context, playoutModel, now)
const nextTakeTime = now + context.studio.settings.minimumTakeSpan

await performTakeToNextedPart(context, playoutModel, now)

return {
nextTakeTime,
}
}
)
}
Expand Down Expand Up @@ -154,7 +168,14 @@ export async function performTakeToNextedPart(
logger.debug(
`Take is blocked until ${currentPartInstance.partInstance.blockTakeUntil}. Which is in: ${remainingTime}`
)
throw UserError.create(UserErrorMessage.TakeBlockedDuration, { duration: remainingTime })
throw UserError.create(
UserErrorMessage.TakeBlockedDuration,
{
duration: remainingTime,
nextAllowedTakeTime: currentPartInstance.partInstance.blockTakeUntil,
},
425
)
}

// If there was a transition from the previous Part, then ensure that has finished before another take is permitted
Expand All @@ -166,11 +187,17 @@ export async function performTakeToNextedPart(
start &&
now < start + currentPartInstance.partInstance.part.inTransition.blockTakeDuration
) {
throw UserError.create(UserErrorMessage.TakeDuringTransition)
throw UserError.create(
UserErrorMessage.TakeDuringTransition,
{
nextAllowedTakeTime: start + currentPartInstance.partInstance.part.inTransition.blockTakeDuration,
},
425
)
}

if (currentPartInstance.isTooCloseToAutonext(true)) {
throw UserError.create(UserErrorMessage.TakeCloseToAutonext)
throw UserError.create(UserErrorMessage.TakeCloseToAutonext, undefined, 425)
}
}

Expand Down
8 changes: 6 additions & 2 deletions packages/meteor-lib/src/api/userActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { BucketAdLib } from '@sofie-automation/corelib/dist/dataModel/BucketAdLi
import { AdLibActionCommon } from '@sofie-automation/corelib/dist/dataModel/AdlibAction'
import { BucketAdLibAction } from '@sofie-automation/corelib/dist/dataModel/BucketAdLibAction'
import { Time } from '@sofie-automation/blueprints-integration'
import { ExecuteActionResult, QueueNextSegmentResult } from '@sofie-automation/corelib/dist/worker/studio'
import {
ExecuteActionResult,
QueueNextSegmentResult,
TakeNextPartResult,
} from '@sofie-automation/corelib/dist/worker/studio'
import {
AdLibActionId,
BucketAdLibActionId,
Expand Down Expand Up @@ -34,7 +38,7 @@ export interface NewUserActionAPI {
eventTime: Time,
rundownPlaylistId: RundownPlaylistId,
fromPartInstanceId: PartInstanceId | null
): Promise<ClientAPI.ClientResponse<void>>
): Promise<ClientAPI.ClientResponse<TakeNextPartResult>>
setNext(
userEvent: string,
eventTime: Time,
Expand Down
Loading