Skip to content

Commit

Permalink
feat: routeset controlled ab player assignment
Browse files Browse the repository at this point in the history
  • Loading branch information
olzzon authored and Julusian committed Sep 27, 2024
1 parent e839b97 commit a884216
Show file tree
Hide file tree
Showing 16 changed files with 686 additions and 56 deletions.
41 changes: 41 additions & 0 deletions meteor/server/migration/X_X_X.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { StudioRouteSet, StudioRouteSetExclusivityGroup } from '@sofie-automatio
*/

export const addSteps = addMigrationSteps(CURRENT_SYSTEM_VERSION, [
// Add your migration here

{
id: `convert routesets to ObjectWithOverrides`,
canBeRunAutomatically: true,
Expand Down Expand Up @@ -52,6 +54,45 @@ export const addSteps = addMigrationSteps(CURRENT_SYSTEM_VERSION, [
}
},
},
{
id: `add abPlayers object`,
canBeRunAutomatically: true,
validate: async () => {
const studios = await Studios.findFetchAsync({ routeSetsWithOverrides: { $exists: true } })

for (const studio of studios) {
const routeSetsDefaults = studio.routeSetsWithOverrides.defaults as any as Record<
string,
StudioRouteSet
>
for (const key of Object.keys(routeSetsDefaults)) {
if (!routeSetsDefaults[key].abPlayers) {
return 'AB players must be added to routeSetsWithOverrides'
}
}
}

return false
},
migrate: async () => {
const studios = await Studios.findFetchAsync({ routeSetsWithOverrides: { $exists: true } })

for (const studio of studios) {
const newRouteSetswithOverrides = studio.routeSetsWithOverrides
for (const key of Object.keys(newRouteSetswithOverrides.defaults)) {
if (!newRouteSetswithOverrides.defaults[key].abPlayers) {
newRouteSetswithOverrides.defaults[key].abPlayers = []
}
}

await Studios.updateAsync(studio._id, {
$set: {
routeSetsWithOverrides: newRouteSetswithOverrides,
},
})
}
},
},
{
id: `convert routeSetExclusivityGroups to ObjectWithOverrides`,
canBeRunAutomatically: true,
Expand Down
2 changes: 2 additions & 0 deletions packages/corelib/src/dataModel/Studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
StudioRouteSet,
StudioRouteSetExclusivityGroup,
StudioRouteType,
StudioAbPlayerDisabling,
} from '@sofie-automation/shared-lib/dist/core/model/StudioRouteSet'

export { MappingsExt, MappingExt, MappingsHash }
Expand All @@ -26,6 +27,7 @@ export {
ResultingMappingRoutes,
StudioRouteSet,
StudioRouteType,
StudioAbPlayerDisabling,
}

export interface IStudioSettings {
Expand Down
10 changes: 0 additions & 10 deletions packages/corelib/src/overrideOpHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,13 +317,3 @@ export class OverrideOpHelperImpl implements OverrideOpHelperBatcher {
this.#saveOverrides(this.#object.overrides)
}
}

/**
* A helper to work with modifying an ObjectWithOverrides<T>
*/
export function useOverrideOpHelperBackend<T extends object>(
saveOverrides: (newOps: SomeObjectOverrideOp[]) => void,
objectWithOverrides: ObjectWithOverrides<T>
): OverrideOpHelperBatcher {
return new OverrideOpHelperImpl(saveOverrides, objectWithOverrides)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ABSessionAssignments } from '@sofie-automation/corelib/dist/dataModel/R
import { OnGenerateTimelineObjExt } from '@sofie-automation/corelib/dist/dataModel/Timeline'
import { literal } from '@sofie-automation/corelib/dist/lib'
import { protectString } from '@sofie-automation/corelib/dist/protectedString'
import { AssignmentResult, resolveAbAssignmentsFromRequests } from '../abPlaybackResolver'
import { AssignmentResult, PlayerId, resolveAbAssignmentsFromRequests } from '../abPlaybackResolver'
import { calculateSessionTimeRanges } from '../abPlaybackSessions'
import { AbSessionHelper } from '../abSessionHelper'

Expand Down Expand Up @@ -79,7 +79,7 @@ function resolveAbSessions(
timelineObjs: OnGenerateTimelineObjExt[],
previousAssignmentMap: ABSessionAssignments,
sessionPool: string,
playerIds: Array<number | string>,
playerIds: Array<PlayerId>,
now: number
): AssignmentResult {
const sessionRequests = calculateSessionTimeRanges(
Expand Down Expand Up @@ -458,7 +458,7 @@ describe('resolveMediaPlayers', () => {
},
inst_1_clip_def: {
sessionId: 'inst_1_clip_def',
playerId: 3,
playerId: 1,
lookahead: true,
},
}
Expand All @@ -482,13 +482,13 @@ describe('resolveMediaPlayers', () => {
[1, 2],
0
)
expect(assignments.failedRequired).toHaveLength(0)
expect(assignments.failedRequired).toEqual(['inst_2_clip_ghi'])
expect(assignments.failedOptional).toHaveLength(0)
expect(assignments.requests).toHaveLength(3)
expect(assignments.requests).toEqual([
{ end: 7400, id: 'inst_0_clip_abc', playerId: 5, start: 2400, optional: false },
{ end: 7400, id: 'inst_1_clip_def', playerId: 3, start: 2400, optional: false },
{ end: 6800, id: 'inst_2_clip_ghi', playerId: 1, start: 2800, optional: false },
{ end: 7400, id: 'inst_0_clip_abc', playerId: 2, start: 2400, optional: false },
{ end: 7400, id: 'inst_1_clip_def', playerId: 1, start: 2400, optional: false },
{ end: 6800, id: 'inst_2_clip_ghi', playerId: undefined, start: 2800, optional: false },
])

expect(mockGetPieceSessionId).toHaveBeenCalledTimes(3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -628,4 +628,149 @@ describe('resolveAbAssignmentsFromRequests', () => {
expectGotPlayer(res, 'e', 3)
expectGotPlayer(res, 'f', undefined)
})

describe('add/remove players', () => {
test('reshuffle lookahead when removing player', () => {
const requests: SessionRequest[] = [
// current clip
{
id: 'a',
start: 1000,
end: undefined,
playerId: 2,
},
// previous clip
{
id: 'b',
start: 0,
playerId: 1,
end: 5000,
},
// lookaheads
{
id: 'd',
start: Number.POSITIVE_INFINITY,
end: undefined,
lookaheadRank: 1,
playerId: 1,
},
{
id: 'e',
start: Number.POSITIVE_INFINITY,
playerId: 3, // From before
end: undefined,
lookaheadRank: 2,
},
{
id: 'f',
start: Number.POSITIVE_INFINITY,
end: undefined,
lookaheadRank: 3,
playerId: 2,
},
]

const res = resolveAbAssignmentsFromRequests(resolverOptions, TWO_SLOTS, requests, 10000)
expect(res).toBeTruthy()
expect(res.failedOptional).toEqual([])
expect(res.failedRequired).toEqual([])
expectGotPlayer(res, 'a', 2)
expectGotPlayer(res, 'b', 1)
expectGotPlayer(res, 'd', 1)
expectGotPlayer(res, 'e', undefined)
expectGotPlayer(res, 'f', undefined)
})

test('reshuffle current when removing player', () => {
const requests: SessionRequest[] = [
// current clip
{
id: 'a',
start: 1000,
end: undefined,
playerId: 3,
},
// previous clip
{
id: 'b',
start: 0,
playerId: 1,
end: 5000,
},
// lookaheads
{
id: 'd',
start: Number.POSITIVE_INFINITY,
end: undefined,
lookaheadRank: 1,
playerId: 1,
},
{
id: 'e',
start: Number.POSITIVE_INFINITY,
playerId: 2,
end: undefined,
lookaheadRank: 2,
},
]

const res = resolveAbAssignmentsFromRequests(resolverOptions, TWO_SLOTS, requests, 10000)
expect(res).toBeTruthy()
expect(res.failedOptional).toEqual([])
expect(res.failedRequired).toEqual([])
expectGotPlayer(res, 'a', 2)
expectGotPlayer(res, 'b', 1)
expectGotPlayer(res, 'd', 1)
expectGotPlayer(res, 'e', undefined)
})

test('add player allows distributing timed clips', () => {
const requests: SessionRequest[] = [
// current clip
{
id: 'a',
start: 1000,
end: 11000,
playerId: 1,
},
{
id: 'b',
start: 13000, // soon
end: undefined,
playerId: 1,
},
{
id: 'c',
start: 1000,
end: undefined,
playerId: 2,
},
// lookaheads
{
id: 'd',
start: Number.POSITIVE_INFINITY,
end: undefined,
lookaheadRank: 1,
playerId: 1,
},
{
id: 'e',
start: Number.POSITIVE_INFINITY,
playerId: 2,
end: undefined,
lookaheadRank: 2,
},
]

const res = resolveAbAssignmentsFromRequests(resolverOptions, THREE_SLOTS, requests, 10000)
expect(res).toBeTruthy()
expect(res.failedOptional).toEqual([])
expect(res.failedRequired).toEqual([])
expectGotPlayer(res, 'a', 1)
expectGotPlayer(res, 'b', 3)
expectGotPlayer(res, 'c', 2)
expectGotPlayer(res, 'd', 1)
expectGotPlayer(res, 'e', undefined)
})
})
})
Loading

0 comments on commit a884216

Please sign in to comment.