Skip to content

Commit 3d684b4

Browse files
committed
Merge branch 'master' into release50
2 parents df429e6 + df32ce3 commit 3d684b4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3143
-1
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
title: About Sofie
3+
hide_table_of_contents: true
4+
sidebar_label: About Sofie
5+
sidebar_position: 1
6+
---
7+
8+
# NRK Sofie TV Automation System
9+
10+
![The producer's view in Sofie](https://raw.githubusercontent.com/nrkno/Sofie-TV-automation/master/images/Sofie_GUI_example.jpg)
11+
12+
_**Sofie**_ is a web-based TV automation system for studios and live shows, used in daily live TV news productions by the Norwegian public service broadcaster [**NRK**](https://www.nrk.no/about/) since September 2018.
13+
14+
## Key Features
15+
16+
- User-friendly, modern web-based GUI
17+
- State-based device control and playout of video, audio, and graphics
18+
- Modular device-control architecture with support for several hardware \(and software\) setups
19+
- Modular data-ingest architecture, supports MOS and Google spreadsheets
20+
- Plug-in architecture for programming shows
21+
22+
_The NRK logo is a registered trademark of Norsk rikskringkasting AS. The license does not grant any right to use, in any way, any trademarks, service marks or logos of Norsk rikskringkasting AS._
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# API Documentation
2+
3+
The Sofie Blueprints API and the Sofie Peripherals API documentation is automatically generated and available through
4+
[nrkno.github.io/sofie-core/typedoc](https://nrkno.github.io/sofie-core/typedoc).
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
description: >-
3+
The Sofie team happily encourage contributions to the Sofie project, and
4+
kindly ask you to observe these guidelines when doing so.
5+
sidebar_position: 2
6+
---
7+
8+
# Contribution Guidelines
9+
10+
## About the Sofie TV Studio Automation Project
11+
12+
The Sofie project includes a number of open source applications and libraries developed and maintained by the Norwegian public service broadcaster, [NRK](https://www.nrk.no/about/). Sofie has been used to produce live shows at NRK since September 2018.
13+
14+
A list of the "Sofie repositories" [can be found here](libraries.md). NRK owns the copyright of the contents of the official Sofie repositories, including the source code, related files, as well as the Sofie logo.
15+
16+
The Sofie team at NRK is responsible for development and maintenance. We also do thorough testing of each release to avoid regressions in functionality and ensure interoperability with the various hardware and software involved.
17+
18+
The Sofie team welcomes open source contributions and will actively work towards enabling contributions to become mergeable into the Sofie repositories. However, as main stakeholder and maintainer we reserve the right to refuse any contributions.
19+
20+
21+
## About Contributions
22+
23+
Thank you for considering contributing to the Sofie project!
24+
25+
Before you start, there are a few things you should know:
26+
27+
### “Discussions Before Pull Requests”
28+
29+
**Minor changes** (most bug fixes and small features) can be submitted directly as pull requests to the appropriate official repo.
30+
31+
However, Sofie is a big project with many differing users and use cases. **Larger changes** might be more difficult to merge into an official repository if NRK has not been made aware of their existence beforehand. To facilitate a timely handling of larger contributions, there’s a workflow intended to keep an open dialogue between all interested parties:
32+
33+
1. Contributor opens an RFC (as a _GitHub issue_) in the appropriate repository.
34+
2. NRK evaluates the RFC, usually within a week.
35+
3. (If needed) NRK establishes contact with the RFC author, who will be invited to a workshop where the RFC is discussed. Meeting notes are published publicly on the RFC thread.
36+
4. The contributor references the RFC when a pull request is ready.
37+
38+
### Base contributions on the in-development branch (or the master branch)
39+
In order to facilitate merging, we ask that contributions are based on the latest (at the time of the pull request) _in-development_ branch (often named `release*`), alternatively the stable (eg. `master`) branch. NRK will take responsibility for rebasing stable contributions to the latest in-development branch if needed.
40+
See **CONTRIBUTING.md** in each official repository for details on which branch to use as a base for contributions.
41+
42+
## Developer Guidelines
43+
44+
### Pull Requests
45+
46+
We encourage you to open PRs early! If it’s still in development, open the PR as a draft.
47+
48+
### Types
49+
50+
All official Sofie repositories use TypeScript. When you contribute code, be sure to keep it as strictly typed as possible.
51+
52+
### Code Style & Formatting
53+
54+
Most of the projects use a linter (eslint) and a formatter (prettier). Before submitting a pull request, please make sure it conforms to the linting rules by running yarn lint. yarn lint --fix can fix most of the issues.
55+
56+
### Documentation
57+
58+
We rely on two types of documentation; the [Sofie documentation](https://nrkno.github.io/sofie-core/) ([source code](https://github.com/nrkno/sofie-core/tree/master/packages/documentation)) and inline code documentation.
59+
60+
We don't aim to have the "absolute perfect documentation possible", BUT we do try to improve and add documentation to have a good-enough-to-be-comprehensible standard. We think that:
61+
62+
* _What_ something does is not as important – we can read the code for that.
63+
* _Why_ something does something, **is** important. Implied usage, side-effects, descriptions of the context etcetera...
64+
65+
When you contribute, we ask you to also update any documentation where needed.
66+
67+
### Updating Dependencies​
68+
When updating dependencies in a library, it is preferred to do so via `yarn upgrade-interactive --latest` whenever possible. This is so that the versions in `package.json` are also updated as we have no guarantee that the library will work with versions lower than that used in the `yarn.lock` file, even if it is compatible with the semver range in `package.json`. After this, a `yarn upgrade` can be used to update any child dependencies
69+
70+
Be careful when bumping across major versions.
71+
72+
Also, each of the libraries has a minimum nodejs version specified in their package.json. Care must be taken when updating dependencies to ensure its compatibility is retained.
73+
74+
### Resolutions​
75+
76+
We sometimes use the `yarn resolutions` property in `package.json` to fix security vulnerabilities in dependencies of libraries that haven't released a fix yet. If adding a new one, try to make it as specific as possible to ensure it doesn't have unintended side effects.
77+
78+
When updating other dependencies, it is a good idea to make sure that the resolutions defined still apply and are correct.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"label": "For Blueprint Developers",
3+
"position": 4
4+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import React, { useState } from 'react'
2+
3+
/**
4+
* This is a demo showing the interactions between the part and piece groups on the timeline.
5+
* The maths should be the same as in `meteor/lib/rundown/timings.ts`, but in a simplified form
6+
*/
7+
8+
const MS_TO_PIXEL_CONSTANT = 0.1
9+
10+
const viewPortStyle = {
11+
width: '100%',
12+
backgroundSize: '40px 40px',
13+
backgroundImage:
14+
'linear-gradient(to right, grey 1px, transparent 1px), linear-gradient(to bottom, grey 1px, transparent 1px)',
15+
overflowX: 'hidden',
16+
display: 'flex',
17+
flexDirection: 'column',
18+
position: 'relative',
19+
}
20+
21+
export function PartTimingsDemo() {
22+
const [postrollA1, setPostrollA1] = useState(0)
23+
const [postrollA2, setPostrollA2] = useState(0)
24+
const [prerollB1, setPrerollB1] = useState(0)
25+
const [prerollB2, setPrerollB2] = useState(0)
26+
const [outTransitionDuration, setOutTransitionDuration] = useState(0)
27+
const [inTransitionBlockDuration, setInTransitionBlockDuration] = useState(0)
28+
const [inTransitionContentsDelay, setInTransitionContentsDelay] = useState(0)
29+
const [inTransitionKeepaliveDuration, setInTransitionKeepaliveDuration] = useState(0)
30+
31+
// Arbitrary point in time for the take to be based around
32+
const takeTime = 2400
33+
34+
const outTransitionTime = outTransitionDuration - inTransitionKeepaliveDuration
35+
36+
// The amount of time needed to preroll Part B before the 'take' point
37+
const partBPreroll = Math.max(prerollB1, prerollB2)
38+
const prerollTime = partBPreroll - inTransitionContentsDelay
39+
40+
// The amount to delay the part 'switch' to, to ensure the outTransition has time to complete as well as any prerolls for part B
41+
const takeOffset = Math.max(0, outTransitionTime, prerollTime)
42+
const takeDelayed = takeTime + takeOffset
43+
44+
// Calculate the part A objects
45+
const pieceA1 = { time: 0, duration: takeDelayed + inTransitionKeepaliveDuration + postrollA1 }
46+
const pieceA2 = { time: 0, duration: takeDelayed + inTransitionKeepaliveDuration + postrollA2 }
47+
const partA = { time: 0, duration: Math.max(pieceA1.duration, pieceA2.duration) } // part stretches to contain the piece
48+
49+
// Calculate the transition objects
50+
const pieceOutTransition = {
51+
time: partA.time + partA.duration - outTransitionDuration - Math.max(postrollA1, postrollA2),
52+
duration: outTransitionDuration,
53+
}
54+
const pieceInTransition = { time: takeDelayed, duration: inTransitionBlockDuration }
55+
56+
// Calculate the part B objects
57+
const partBBaseDuration = 2600
58+
const partB = { time: takeTime, duration: partBBaseDuration + takeOffset }
59+
const pieceB1 = { time: takeDelayed + inTransitionContentsDelay - prerollB1, duration: partBBaseDuration + prerollB1 }
60+
const pieceB2 = { time: takeDelayed + inTransitionContentsDelay - prerollB2, duration: partBBaseDuration + prerollB2 }
61+
const pieceB3 = { time: takeDelayed + inTransitionContentsDelay + 300, duration: 200 }
62+
63+
return (
64+
<div>
65+
<div style={viewPortStyle}>
66+
<TimelineGroup {...pieceInTransition} name="In Transition" color="pink" />
67+
<TimelineGroup {...pieceOutTransition} name="Out Transition" color="lightblue" />
68+
69+
<TimelineGroup {...partA} name="PartGroup A" color="green" />
70+
<TimelineGroup {...pieceA1} name="Piece A1" color="orange" />
71+
<TimelineGroup {...pieceA2} name="Piece A2" color="orange" />
72+
73+
<TimelineGroup {...partB} name="PartGroup B" color="green" />
74+
<TimelineGroup {...pieceB1} name="Piece B1" color="orange" />
75+
<TimelineGroup {...pieceB2} name="Piece B2" color="orange" />
76+
<TimelineGroup {...pieceB3} name="Super B3" color="orange" />
77+
78+
<TimelineMarker time={takeTime} title="Take time" />
79+
<TimelineMarker time={takeDelayed} title="Take Delayed" />
80+
<TimelineMarker time={takeDelayed + inTransitionContentsDelay} title="Content Base time" />
81+
</div>
82+
83+
{/* Controls */}
84+
<table className="margin-top--md">
85+
<InputRow label="Piece B1 Preroll Duration" max={1000} value={prerollB1} setValue={setPrerollB1} />
86+
<InputRow label="Piece B2 Preroll Duration" max={1000} value={prerollB2} setValue={setPrerollB2} />
87+
<InputRow label="Piece A1 Postroll Duration" max={1000} value={postrollA1} setValue={setPostrollA1} />
88+
<InputRow label="Piece A2 Postroll Duration" max={1000} value={postrollA2} setValue={setPostrollA2} />
89+
<InputRow
90+
label="Part A Out Transition Duration"
91+
max={1000}
92+
value={outTransitionDuration}
93+
setValue={setOutTransitionDuration}
94+
/>
95+
<InputRow
96+
label="Part B In Transition Block Duration"
97+
max={1000}
98+
value={inTransitionBlockDuration}
99+
setValue={setInTransitionBlockDuration}
100+
/>
101+
<InputRow
102+
label="Part B In Transition Contents Delay"
103+
max={1000}
104+
value={inTransitionContentsDelay}
105+
setValue={setInTransitionContentsDelay}
106+
/>
107+
<InputRow
108+
label="Part B In Transition Keepalive"
109+
max={1000}
110+
value={inTransitionKeepaliveDuration}
111+
setValue={setInTransitionKeepaliveDuration}
112+
/>
113+
</table>
114+
</div>
115+
)
116+
}
117+
118+
function TimelineGroup({ duration, time, name, color }) {
119+
return (
120+
<div
121+
style={{
122+
height: '25px',
123+
marginBottom: '2px',
124+
whiteSpace: 'nowrap',
125+
126+
marginLeft: `${time * MS_TO_PIXEL_CONSTANT}px`,
127+
width: `${duration * MS_TO_PIXEL_CONSTANT}px`,
128+
background: color,
129+
}}
130+
>
131+
{name}
132+
</div>
133+
)
134+
}
135+
136+
function TimelineMarker({ time, title }) {
137+
return (
138+
<div
139+
style={{
140+
borderLeft: '2px dashed red',
141+
display: 'inline-block',
142+
width: '1px',
143+
144+
float: 'left',
145+
position: 'absolute',
146+
top: 0,
147+
height: '100%',
148+
149+
marginLeft: `${time * MS_TO_PIXEL_CONSTANT}px`,
150+
}}
151+
title={title}
152+
>
153+
&nbsp;
154+
</div>
155+
)
156+
}
157+
158+
function InputRow({ label, max, value, setValue }) {
159+
return (
160+
<tr>
161+
<td>{label}</td>
162+
<td>
163+
<input
164+
type="range"
165+
min={0}
166+
max={max}
167+
value={value}
168+
onChange={(e) => setValue(parseInt(e.currentTarget.value))}
169+
/>
170+
</td>
171+
</tr>
172+
)
173+
}

0 commit comments

Comments
 (0)