@norskvideo/norsk-studio-alpha 1.27.0-2025-07-09-0fcad3ea

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/README.md +10 -0
  2. package/client/info.js +43461 -0
  3. package/client/processor.audioLevel/styles.css +165 -0
  4. package/client/shared/style.css +1627 -0
  5. package/client/shared/tailwind.css +31 -0
  6. package/client/style.css +1074 -0
  7. package/lib/index.d.ts +3 -0
  8. package/lib/index.js +14 -0
  9. package/lib/index.js.map +1 -0
  10. package/lib/info.d.ts +3 -0
  11. package/lib/info.js +44 -0
  12. package/lib/info.js.map +1 -0
  13. package/lib/input.decklink/info.d.ts +3 -0
  14. package/lib/input.decklink/info.js +51 -0
  15. package/lib/input.decklink/info.js.map +1 -0
  16. package/lib/input.decklink/runtime.d.ts +12 -0
  17. package/lib/input.decklink/runtime.js +22 -0
  18. package/lib/input.decklink/runtime.js.map +1 -0
  19. package/lib/input.decklink/types.d.ts +23 -0
  20. package/lib/input.decklink/types.js +3 -0
  21. package/lib/input.decklink/types.js.map +1 -0
  22. package/lib/input.decklink/types.yaml +32 -0
  23. package/lib/input.mp4file/info.d.ts +3 -0
  24. package/lib/input.mp4file/info.js +34 -0
  25. package/lib/input.mp4file/info.js.map +1 -0
  26. package/lib/input.mp4file/runtime.d.ts +14 -0
  27. package/lib/input.mp4file/runtime.js +33 -0
  28. package/lib/input.mp4file/runtime.js.map +1 -0
  29. package/lib/input.mp4file/types.d.ts +23 -0
  30. package/lib/input.mp4file/types.js +3 -0
  31. package/lib/input.mp4file/types.js.map +1 -0
  32. package/lib/input.mp4file/types.yaml +30 -0
  33. package/lib/input.ndi/info.d.ts +3 -0
  34. package/lib/input.ndi/info.js +52 -0
  35. package/lib/input.ndi/info.js.map +1 -0
  36. package/lib/input.ndi/runtime.d.ts +24 -0
  37. package/lib/input.ndi/runtime.js +60 -0
  38. package/lib/input.ndi/runtime.js.map +1 -0
  39. package/lib/input.ndi/source-selection.d.ts +10 -0
  40. package/lib/input.ndi/source-selection.js +84 -0
  41. package/lib/input.ndi/source-selection.js.map +1 -0
  42. package/lib/input.ndi/types.d.ts +52 -0
  43. package/lib/input.ndi/types.js +3 -0
  44. package/lib/input.ndi/types.js.map +1 -0
  45. package/lib/input.ndi/types.yaml +37 -0
  46. package/lib/output.ndi/info.d.ts +8 -0
  47. package/lib/output.ndi/info.js +61 -0
  48. package/lib/output.ndi/info.js.map +1 -0
  49. package/lib/output.ndi/inline-view.d.ts +6 -0
  50. package/lib/output.ndi/inline-view.js +12 -0
  51. package/lib/output.ndi/inline-view.js.map +1 -0
  52. package/lib/output.ndi/runtime.d.ts +14 -0
  53. package/lib/output.ndi/runtime.js +35 -0
  54. package/lib/output.ndi/runtime.js.map +1 -0
  55. package/lib/output.ndi/types.d.ts +35 -0
  56. package/lib/output.ndi/types.js +3 -0
  57. package/lib/output.ndi/types.js.map +1 -0
  58. package/lib/output.ndi/types.yaml +72 -0
  59. package/lib/output.recorder/info.d.ts +10 -0
  60. package/lib/output.recorder/info.js +79 -0
  61. package/lib/output.recorder/info.js.map +1 -0
  62. package/lib/output.recorder/runtime.d.ts +66 -0
  63. package/lib/output.recorder/runtime.js +301 -0
  64. package/lib/output.recorder/runtime.js.map +1 -0
  65. package/lib/output.recorder/types.d.ts +225 -0
  66. package/lib/output.recorder/types.js +3 -0
  67. package/lib/output.recorder/types.js.map +1 -0
  68. package/lib/output.recorder/types.yaml +211 -0
  69. package/lib/processor.actionReplay/info.d.ts +25 -0
  70. package/lib/processor.actionReplay/info.js +77 -0
  71. package/lib/processor.actionReplay/info.js.map +1 -0
  72. package/lib/processor.actionReplay/runtime.d.ts +38 -0
  73. package/lib/processor.actionReplay/runtime.js +225 -0
  74. package/lib/processor.actionReplay/runtime.js.map +1 -0
  75. package/lib/processor.actionReplay/summary.d.ts +4 -0
  76. package/lib/processor.actionReplay/summary.js +76 -0
  77. package/lib/processor.actionReplay/summary.js.map +1 -0
  78. package/lib/processor.actionReplay/types.d.ts +38 -0
  79. package/lib/processor.actionReplay/types.js +3 -0
  80. package/lib/processor.actionReplay/types.js.map +1 -0
  81. package/lib/processor.actionReplay/types.yaml +74 -0
  82. package/lib/processor.audioLevel/info.d.ts +27 -0
  83. package/lib/processor.audioLevel/info.js +61 -0
  84. package/lib/processor.audioLevel/info.js.map +1 -0
  85. package/lib/processor.audioLevel/inline-view.d.ts +4 -0
  86. package/lib/processor.audioLevel/inline-view.js +26 -0
  87. package/lib/processor.audioLevel/inline-view.js.map +1 -0
  88. package/lib/processor.audioLevel/runtime.d.ts +26 -0
  89. package/lib/processor.audioLevel/runtime.js +86 -0
  90. package/lib/processor.audioLevel/runtime.js.map +1 -0
  91. package/lib/processor.audioLevel/summary-view.d.ts +7 -0
  92. package/lib/processor.audioLevel/summary-view.js +37 -0
  93. package/lib/processor.audioLevel/summary-view.js.map +1 -0
  94. package/lib/processor.audioLevel/types.d.ts +42 -0
  95. package/lib/processor.audioLevel/types.js +3 -0
  96. package/lib/processor.audioLevel/types.js.map +1 -0
  97. package/lib/processor.audioLevel/types.yaml +83 -0
  98. package/lib/processor.gemini-poc/info.d.ts +8 -0
  99. package/lib/processor.gemini-poc/info.js +59 -0
  100. package/lib/processor.gemini-poc/info.js.map +1 -0
  101. package/lib/processor.gemini-poc/runtime.d.ts +38 -0
  102. package/lib/processor.gemini-poc/runtime.js +132 -0
  103. package/lib/processor.gemini-poc/runtime.js.map +1 -0
  104. package/lib/processor.gemini-poc/types.d.ts +23 -0
  105. package/lib/processor.gemini-poc/types.js +3 -0
  106. package/lib/processor.gemini-poc/types.js.map +1 -0
  107. package/lib/processor.gemini-poc/types.yaml +43 -0
  108. package/lib/processor.mixMinus/info.d.ts +7 -0
  109. package/lib/processor.mixMinus/info.js +40 -0
  110. package/lib/processor.mixMinus/info.js.map +1 -0
  111. package/lib/processor.mixMinus/runtime.d.ts +23 -0
  112. package/lib/processor.mixMinus/runtime.js +85 -0
  113. package/lib/processor.mixMinus/runtime.js.map +1 -0
  114. package/lib/processor.mixMinus/types.d.ts +18 -0
  115. package/lib/processor.mixMinus/types.js +3 -0
  116. package/lib/processor.mixMinus/types.js.map +1 -0
  117. package/lib/processor.mixMinus/types.yaml +19 -0
  118. package/lib/processor.monetise/info.d.ts +3 -0
  119. package/lib/processor.monetise/info.js +72 -0
  120. package/lib/processor.monetise/info.js.map +1 -0
  121. package/lib/processor.monetise/runtime.d.ts +62 -0
  122. package/lib/processor.monetise/runtime.js +217 -0
  123. package/lib/processor.monetise/runtime.js.map +1 -0
  124. package/lib/processor.monetise/summary.d.ts +7 -0
  125. package/lib/processor.monetise/summary.js +40 -0
  126. package/lib/processor.monetise/summary.js.map +1 -0
  127. package/lib/processor.monetise/types.d.ts +16 -0
  128. package/lib/processor.monetise/types.js +3 -0
  129. package/lib/processor.monetise/types.js.map +1 -0
  130. package/lib/processor.monetise/types.yaml +9 -0
  131. package/lib/processor.whisper-transcribe/info.d.ts +9 -0
  132. package/lib/processor.whisper-transcribe/info.js +46 -0
  133. package/lib/processor.whisper-transcribe/info.js.map +1 -0
  134. package/lib/processor.whisper-transcribe/runtime.d.ts +22 -0
  135. package/lib/processor.whisper-transcribe/runtime.js +70 -0
  136. package/lib/processor.whisper-transcribe/runtime.js.map +1 -0
  137. package/lib/processor.whisper-transcribe/types.d.ts +21 -0
  138. package/lib/processor.whisper-transcribe/types.js +3 -0
  139. package/lib/processor.whisper-transcribe/types.js.map +1 -0
  140. package/lib/processor.whisper-transcribe/types.yaml +28 -0
  141. package/lib/shared/schemas.d.ts +8 -0
  142. package/lib/shared/schemas.js +44 -0
  143. package/lib/shared/schemas.js.map +1 -0
  144. package/lib/test/output.recorder.d.ts +1 -0
  145. package/lib/test/output.recorder.js +186 -0
  146. package/lib/test/output.recorder.js.map +1 -0
  147. package/lib/util.timestamps/info.d.ts +14 -0
  148. package/lib/util.timestamps/info.js +64 -0
  149. package/lib/util.timestamps/info.js.map +1 -0
  150. package/lib/util.timestamps/inline-view.d.ts +6 -0
  151. package/lib/util.timestamps/inline-view.js +95 -0
  152. package/lib/util.timestamps/inline-view.js.map +1 -0
  153. package/lib/util.timestamps/runtime.d.ts +13 -0
  154. package/lib/util.timestamps/runtime.js +51 -0
  155. package/lib/util.timestamps/runtime.js.map +1 -0
  156. package/lib/util.timestamps/types.d.ts +36 -0
  157. package/lib/util.timestamps/types.js +3 -0
  158. package/lib/util.timestamps/types.js.map +1 -0
  159. package/lib/util.timestamps/types.yaml +74 -0
  160. package/package.json +57 -0
@@ -0,0 +1,211 @@
1
+ openapi: 3.0.3
2
+ info:
3
+ title: Output Recorder API
4
+ version: 1.0.0
5
+ paths:
6
+ /timeline:
7
+ get:
8
+ summary: Returns all the available timelines in the store
9
+ description: Returns all the available timelines in the store
10
+ responses:
11
+ 200:
12
+ description: Successful operation
13
+ content:
14
+ application/json:
15
+ schema:
16
+ type: array
17
+ description: A list of the sources available
18
+ items:
19
+ $ref: "#/components/schemas/AvailableData"
20
+ /cut:
21
+ post:
22
+ summary: Creates a cut
23
+ description: Creates a cut and returns the URL to query in order to get the output
24
+ requestBody:
25
+ description: "Details about how this cut should take place"
26
+ content:
27
+ application/json:
28
+ schema:
29
+ type: object
30
+ properties:
31
+ start:
32
+ type: string
33
+ format: date
34
+ duration_s:
35
+ type: integer
36
+ required:
37
+ - start
38
+ - duration_s
39
+ responses:
40
+ 204:
41
+ description: Successful operation
42
+ content:
43
+ application/json:
44
+ schema:
45
+ type: object
46
+ description: URL to query the status of the cut
47
+ properties:
48
+ url:
49
+ type: string
50
+ format: uri
51
+ cutId:
52
+ type: string
53
+ required:
54
+ - url
55
+ - cutId
56
+ 400:
57
+ description: Unsuccessful operation
58
+ content:
59
+ application/json:
60
+ schema:
61
+ type: string
62
+ description: The reason for failure
63
+ /cut/{id}:
64
+ get:
65
+ summary: Get the current status of a cut
66
+ description: Returns the current status of the cut identified by the given id.
67
+ parameters:
68
+ - name: id
69
+ in: path
70
+ required: true
71
+ schema:
72
+ type: integer
73
+ responses:
74
+ 200:
75
+ description: Successful operation returning the status of the cut
76
+ content:
77
+ application/json:
78
+ schema:
79
+ $ref: "#/components/schemas/CutStatus"
80
+ 404:
81
+ description: Cut not found
82
+ content:
83
+ application/json:
84
+ schema:
85
+ type: string
86
+ description: The reason for failure
87
+
88
+ /download/{cut_id}:
89
+ get:
90
+ summary: Download generated mp4 file for a cut
91
+ description: Retrieves the generated mp4 file associated with the given cut id.
92
+ parameters:
93
+ - name: cut_id
94
+ in: path
95
+ required: true
96
+ schema:
97
+ type: integer
98
+ responses:
99
+ 200:
100
+ description: Successful operation - returns the mp4 file.
101
+ content:
102
+ video/mp4:
103
+ schema:
104
+ type: string
105
+ format: binary
106
+ 404:
107
+ description: Cut or file not found.
108
+ content:
109
+ application/json:
110
+ schema:
111
+ type: object
112
+ properties:
113
+ message:
114
+ type: string
115
+ required:
116
+ - message
117
+ 500:
118
+ description: Server error.
119
+ content:
120
+ application/json:
121
+ schema:
122
+ type: object
123
+ properties:
124
+ message:
125
+ type: string
126
+ required:
127
+ - message
128
+ components:
129
+ schemas:
130
+ RecorderSettings:
131
+ type: object
132
+ properties:
133
+ id:
134
+ type: string
135
+ displayName:
136
+ type: string
137
+ store_path:
138
+ type: string
139
+ cuts_path:
140
+ type: string
141
+ expiry_hours:
142
+ type: number
143
+ pruneIntervalMs:
144
+ type: number
145
+ nullable: true
146
+ required:
147
+ - id
148
+ - displayName
149
+ - store_path
150
+ - cuts_path
151
+ - expiry_hours
152
+
153
+ AvailableData:
154
+ type: object
155
+ properties:
156
+ start:
157
+ type: string
158
+ format: date
159
+ duration_s:
160
+ type: integer
161
+ required:
162
+ - start
163
+ - duration_s
164
+ CutNotReady:
165
+ type: object
166
+ properties:
167
+ status:
168
+ type: string
169
+ enum: ["not_ready"]
170
+ description: Indicates the cut is not ready yet.
171
+ percent_complete:
172
+ type: number
173
+ description: Percentage of the cut that is complete.
174
+ required:
175
+ - status
176
+ - percent_complete
177
+ CutReady:
178
+ type: object
179
+ properties:
180
+ status:
181
+ type: string
182
+ enum: ["ready"]
183
+ description: Indicates the cut is ready.
184
+ url:
185
+ type: string
186
+ format: uri
187
+ description: URL where the produced file can be accessed.
188
+ required:
189
+ - status
190
+ - url
191
+ CutFailed:
192
+ type: object
193
+ properties:
194
+ status:
195
+ type: string
196
+ enum: ["failed"]
197
+ description: Indicates the cut has failed.
198
+ reason:
199
+ type: string
200
+ description: Reason for the failure.
201
+ required:
202
+ - status
203
+ - reason
204
+ CutStatus:
205
+ oneOf:
206
+ - $ref: "#/components/schemas/CutNotReady"
207
+ - $ref: "#/components/schemas/CutReady"
208
+ - $ref: "#/components/schemas/CutFailed"
209
+ discriminator:
210
+ propertyName: status
211
+
@@ -0,0 +1,25 @@
1
+ import type Registration from "@norskvideo/norsk-studio/lib/extension/registration";
2
+ export default function ({ defineComponent, assertUnreachable, }: Registration): import("@norskvideo/norsk-studio/lib/extension/client-types").NodeInfo<{
3
+ id: string;
4
+ displayName: string;
5
+ __global: {
6
+ hardware?: "auto" | "software" | "nvidia" | "nvidiaAV1" | "quadra" | "quadraAV1";
7
+ };
8
+ notes?: string;
9
+ }, {
10
+ contentPlayerUrl?: string;
11
+ replaying: boolean;
12
+ }, {
13
+ type: "do-replay";
14
+ from: number;
15
+ duration: number;
16
+ }, {
17
+ type: "content-player-created";
18
+ url: string;
19
+ } | {
20
+ type: "replay-started";
21
+ } | {
22
+ type: "replay-finished";
23
+ }>;
24
+ export declare const hardwareNames: readonly ["quadra", "nvidia"];
25
+ export type HardwareName = typeof hardwareNames[number];
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.hardwareNames = void 0;
7
+ exports.default = default_1;
8
+ const config_1 = require("@norskvideo/norsk-studio/lib/shared/config");
9
+ const summary_1 = __importDefault(require("./summary"));
10
+ function default_1({ defineComponent, assertUnreachable, }) {
11
+ return defineComponent({
12
+ identifier: 'processor.actionReplay',
13
+ category: 'processor',
14
+ name: "Action Replay",
15
+ description: "Records and replays audio and video streams on demand for instant replay functionality",
16
+ subscription: {
17
+ accepts: {
18
+ type: 'simple-stream',
19
+ audio: true,
20
+ video: true
21
+ },
22
+ produces: {
23
+ type: 'simple-stream',
24
+ audio: true,
25
+ video: true
26
+ },
27
+ },
28
+ extraValidation: (ctx) => {
29
+ if (ctx.subscriptions.length == 0) {
30
+ return;
31
+ }
32
+ if (ctx.subscriptions.length > 1) {
33
+ ctx.addError("Action replay can only subscribe to a single source");
34
+ return;
35
+ }
36
+ ctx.requireExactAudio(1);
37
+ ctx.requireExactVideo(1);
38
+ },
39
+ runtime: {
40
+ summary: summary_1.default,
41
+ initialState: () => ({
42
+ replaying: false,
43
+ contentPlayerUrl: undefined
44
+ }),
45
+ handleEvent: (ev, state) => {
46
+ const evType = ev.type;
47
+ switch (evType) {
48
+ case "content-player-created":
49
+ return { ...state, contentPlayerUrl: ev.url };
50
+ case "replay-started":
51
+ return { ...state, replaying: true };
52
+ case "replay-finished":
53
+ return { ...state, replaying: false };
54
+ default:
55
+ return assertUnreachable(evType);
56
+ }
57
+ }
58
+ },
59
+ display: (desc) => {
60
+ const { __global: _, ...rem } = desc.config;
61
+ return rem;
62
+ },
63
+ configForm: {
64
+ global: {
65
+ hardware: (0, config_1.HardwareSelection)()
66
+ },
67
+ form: {
68
+ notes: { help: "Notes about this component", hint: { type: 'text', optional: true } },
69
+ }
70
+ }
71
+ });
72
+ }
73
+ exports.hardwareNames = [
74
+ 'quadra',
75
+ 'nvidia'
76
+ ];
77
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../src/processor.actionReplay/info.ts"],"names":[],"mappings":";;;;;;AAOA,4BAiEC;AArED,uEAA+E;AAC/E,wDAAoC;AAGpC,mBAAwB,EACtB,eAAe,EACf,iBAAiB,GACJ;IAEb,OAAO,eAAe,CAAgF;QACpG,UAAU,EAAE,wBAAwB;QACpC,QAAQ,EAAE,WAAW;QACrB,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,wFAAwF;QACrG,YAAY,EAAE;YACZ,OAAO,EAAE;gBACP,IAAI,EAAE,eAAe;gBACrB,KAAK,EAAE,IAAI;gBACX,KAAK,EAAE,IAAI;aACZ;YACD,QAAQ,EAAE;gBACR,IAAI,EAAE,eAAe;gBACrB,KAAK,EAAE,IAAI;gBACX,KAAK,EAAE,IAAI;aACZ;SACF;QACD,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;gBAAC,OAAO;YAAC,CAAC;YAE9C,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,GAAG,CAAC,QAAQ,CAAC,qDAAqD,CAAC,CAAC;gBACpE,OAAO;YACT,CAAC;YACD,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;YACzB,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,EAAE;YACP,OAAO,EAAE,iBAAW;YACpB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;gBACnB,SAAS,EAAE,KAAK;gBAChB,gBAAgB,EAAE,SAAS;aAC5B,CAAC;YACF,WAAW,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE;gBACzB,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC;gBACvB,QAAQ,MAAM,EAAE,CAAC;oBACf,KAAK,wBAAwB;wBAC3B,OAAO,EAAE,GAAG,KAAK,EAAE,gBAAgB,EAAE,EAAE,CAAC,GAAG,EAAE,CAAA;oBAC/C,KAAK,gBAAgB;wBACnB,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;oBACtC,KAAK,iBAAiB;wBACpB,OAAO,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;oBACvC;wBACE,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;SACF;QACD,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAChB,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC;YAC5C,OAAO,GAAG,CAAC;QACb,CAAC;QACD,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,QAAQ,EAAE,IAAA,0BAAiB,GAAwG;aACpI;YACD,IAAI,EAAE;gBACJ,KAAK,EAAE,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;aACtF;SACF;KACF,CAAC,CAAC;AACL,CAAC;AAEY,QAAA,aAAa,GAAG;IAC3B,QAAQ;IACR,QAAQ;CACA,CAAA"}
@@ -0,0 +1,38 @@
1
+ import { AudioEncodeNode, CmafAudioOutputNode, CmafMultiVariantOutputNode, CmafVideoOutputNode, MediaStorePlayerNode, MediaStoreRecorderNode, Norsk, SourceMediaNode, StreamKey, StreamMetadataOverrideNode, StreamSwitchSmoothNode } from '@norskvideo/norsk-sdk';
2
+ import { OnCreated, RelatedMediaNodes, RuntimeUpdates, ServerComponentDefinition, ServerComponentSchemas, StudioComponentInputStream, StudioRuntime, StudioShared } from '@norskvideo/norsk-studio/lib/extension/runtime-types';
3
+ import { components } from './types';
4
+ export type ActionReplayConfig = components['schemas']['ActionReplayConfig'];
5
+ export type ActionReplayState = components['schemas']['ActionReplayState'];
6
+ export type ActionReplayEvent = components['schemas']['ActionReplayEvent'];
7
+ export type ActionReplayCommand = components['schemas']['ActionReplayCommand'];
8
+ export default class ActionReplayDefinition implements ServerComponentDefinition<ActionReplayConfig, ActionReplay, ActionReplayState, ActionReplayCommand, ActionReplayEvent> {
9
+ schemas(): Promise<ServerComponentSchemas>;
10
+ create(norsk: Norsk, cfg: ActionReplayConfig, cb: OnCreated<ActionReplay>, runtime: StudioRuntime<ActionReplayState, ActionReplayCommand, ActionReplayEvent>): Promise<void>;
11
+ handleCommand(node: ActionReplay, command: ActionReplayCommand): void;
12
+ }
13
+ export declare class ActionReplay {
14
+ id: string;
15
+ norsk: Norsk;
16
+ cfg: ActionReplayConfig;
17
+ initialised: Promise<void>;
18
+ updates: RuntimeUpdates<ActionReplayState, ActionReplayCommand, ActionReplayEvent>;
19
+ shared: StudioShared;
20
+ relatedMediaNodes: RelatedMediaNodes;
21
+ smooth?: StreamSwitchSmoothNode<'source' | 'replay'>;
22
+ audioEncode?: AudioEncodeNode;
23
+ videoEncode?: SourceMediaNode;
24
+ audioCmaf?: CmafAudioOutputNode;
25
+ videoCmaf?: CmafVideoOutputNode;
26
+ mvCmaf?: CmafMultiVariantOutputNode;
27
+ writer?: MediaStoreRecorderNode;
28
+ reader?: MediaStorePlayerNode;
29
+ currentSources: StudioComponentInputStream[];
30
+ passthrough?: StreamMetadataOverrideNode;
31
+ audioStreamKey?: StreamKey;
32
+ videoStreamKey?: StreamKey;
33
+ constructor(norsk: Norsk, cfg: ActionReplayConfig, runtime: StudioRuntime<ActionReplayState, ActionReplayCommand, ActionReplayEvent>);
34
+ initialise(): Promise<void>;
35
+ replay(from: number, duration: number): Promise<void>;
36
+ subscribe(sources: StudioComponentInputStream[]): Promise<void>;
37
+ teardown(): void;
38
+ }
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ActionReplay = void 0;
7
+ const norsk_sdk_1 = require("@norskvideo/norsk-sdk");
8
+ const runtime_types_1 = require("@norskvideo/norsk-studio/lib/extension/runtime-types");
9
+ const util_1 = require("@norskvideo/norsk-studio/lib/shared/util");
10
+ const logging_1 = require("@norskvideo/norsk-studio/lib/server/logging");
11
+ const os_1 = require("os");
12
+ const config_1 = require("@norskvideo/norsk-studio/lib/shared/config");
13
+ const path_1 = __importDefault(require("path"));
14
+ const schemas_1 = require("../shared/schemas");
15
+ class ActionReplayDefinition {
16
+ async schemas() {
17
+ return (0, schemas_1.schemaFromTypes)(path_1.default.join(__dirname, 'types.yaml'), {
18
+ config: 'ActionReplayConfig',
19
+ state: 'ActionReplayState'
20
+ });
21
+ }
22
+ async create(norsk, cfg, cb, runtime) {
23
+ const node = new ActionReplay(norsk, cfg, runtime);
24
+ await node.initialised;
25
+ cb(node);
26
+ }
27
+ handleCommand(node, command) {
28
+ const cmdType = command.type;
29
+ switch (cmdType) {
30
+ case 'do-replay':
31
+ void node.replay(command.from, command.duration);
32
+ break;
33
+ default:
34
+ (0, util_1.assertUnreachable)(cmdType);
35
+ }
36
+ }
37
+ }
38
+ exports.default = ActionReplayDefinition;
39
+ class ActionReplay {
40
+ id;
41
+ norsk;
42
+ cfg;
43
+ initialised;
44
+ updates;
45
+ shared;
46
+ relatedMediaNodes = new runtime_types_1.RelatedMediaNodes();
47
+ smooth;
48
+ audioEncode;
49
+ videoEncode;
50
+ audioCmaf;
51
+ videoCmaf;
52
+ mvCmaf;
53
+ writer;
54
+ reader;
55
+ currentSources = [];
56
+ passthrough;
57
+ audioStreamKey;
58
+ videoStreamKey;
59
+ constructor(norsk, cfg, runtime) {
60
+ this.id = cfg.id;
61
+ this.norsk = norsk;
62
+ this.cfg = cfg;
63
+ this.updates = runtime.updates;
64
+ this.shared = runtime.shared;
65
+ this.initialised = this.initialise();
66
+ }
67
+ async initialise() {
68
+ this.passthrough = await this.norsk.processor.transform.streamMetadataOverride({
69
+ id: `${this.id}-output`,
70
+ });
71
+ this.relatedMediaNodes.addOutput(this.passthrough);
72
+ }
73
+ async replay(from, duration) {
74
+ if (this.reader) {
75
+ (0, logging_1.debuglog)("Multiple replay attempts started, ignoring", { from, duration });
76
+ return;
77
+ }
78
+ if (!this.writer || !this.smooth) {
79
+ (0, logging_1.errorlog)("Attempt to do replay before node is set up???", { from, duration });
80
+ return;
81
+ }
82
+ if (!this.audioStreamKey || !this.videoStreamKey) {
83
+ (0, logging_1.errorlog)("Attempt to do replay with no known stream keys", { from, duration });
84
+ return;
85
+ }
86
+ this.updates.raiseEvent({
87
+ type: 'replay-started'
88
+ });
89
+ const smooth = this.smooth;
90
+ const cut = this.writer?.cutListEntry({
91
+ durationMs: duration * 1000,
92
+ startDateTime: new Date((new Date()).getTime() - (from * 1000)),
93
+ streamSelection: [
94
+ [this.videoStreamKey, this.videoStreamKey],
95
+ [this.audioStreamKey, this.audioStreamKey]
96
+ ],
97
+ trimPartialGops: false
98
+ });
99
+ this.reader = await this.norsk.mediaStore.player({
100
+ id: `${this.id}-reader`,
101
+ cuts: [cut],
102
+ sourceName: `${this.id}-cut`,
103
+ onCreate: (node) => {
104
+ smooth.subscribeToPins(this.currentSources.map((s) => s.selectToPin("source"))
105
+ .concat([
106
+ { source: node, sourceSelector: (0, norsk_sdk_1.avToPin)("replay") }
107
+ ]));
108
+ },
109
+ onClose: () => {
110
+ this.reader = undefined;
111
+ this.updates.raiseEvent({
112
+ type: 'replay-finished'
113
+ });
114
+ smooth.subscribeToPins(this.currentSources.map((s) => s.selectToPin("source")));
115
+ }
116
+ });
117
+ }
118
+ async subscribe(sources) {
119
+ this.currentSources = sources;
120
+ const video = this.currentSources.find((s) => s.isMedia("video"));
121
+ const audio = this.currentSources.find((s) => s.isMedia("audio"));
122
+ if (!video?.metadata || !audio?.metadata) {
123
+ this.teardown();
124
+ return;
125
+ }
126
+ const videoMetadata = video.metadata.message.value;
127
+ const audioMetadata = audio.metadata.message.value;
128
+ this.audioStreamKey = audio.metadata.streamKey;
129
+ this.videoStreamKey = video.metadata.streamKey;
130
+ (0, logging_1.infolog)("Action replay node has a valid context, spinning up some nodes", { videoMetadata, audioMetadata });
131
+ this.smooth = await this.norsk.processor.control.streamSwitchSmooth({
132
+ id: `${this.id}-switch`,
133
+ outputSource: `${this.id}-source`,
134
+ outputResolution: { width: videoMetadata.width, height: videoMetadata.height },
135
+ frameRate: videoMetadata.frameRate ?? { frames: 25, seconds: 1 },
136
+ sampleRate: audioMetadata.sampleRate,
137
+ channelLayout: audioMetadata.channelLayout ?? 'stereo',
138
+ hardwareAcceleration: (0, config_1.contractHardwareAcceleration)(this.cfg.__global.hardware, ["quadra", "nvidia"]),
139
+ activeSource: 'source',
140
+ transitionDurationMs: 500.0,
141
+ onInboundContextChange: async (ctx) => {
142
+ if (ctx.get('replay')?.length == 2) {
143
+ await this.smooth?.switchSource('replay');
144
+ }
145
+ else {
146
+ await this.smooth?.switchSource('source');
147
+ }
148
+ }
149
+ });
150
+ this.relatedMediaNodes.addInput(this.smooth);
151
+ const dir = (0, os_1.tmpdir)();
152
+ this.writer = await this.norsk.mediaStore.recorder({
153
+ id: `${this.id}-store`,
154
+ name: `${this.id}-store`,
155
+ path: dir,
156
+ chunkFileDurationSeconds: 60,
157
+ expiry: {
158
+ expire: 'byTime',
159
+ durationS: 500
160
+ }
161
+ });
162
+ this.videoEncode = await this.shared.previewEncode(video.select(), this.cfg.__global.hardware);
163
+ this.audioEncode = await this.norsk.processor.transform.audioEncode({
164
+ id: `${this.id}-audio-encode`,
165
+ channelLayout: 'stereo',
166
+ bitrate: 64000,
167
+ outputRenditionName: `${this.id}-preview`,
168
+ codec: {
169
+ kind: 'aac',
170
+ sampleRate: audioMetadata.sampleRate,
171
+ profile: 'lc'
172
+ }
173
+ });
174
+ const localDestination = {
175
+ id: `${this.id}-local`,
176
+ type: 'local',
177
+ retentionPeriodSeconds: 360
178
+ };
179
+ this.audioCmaf = await this.norsk.output.cmafAudio({
180
+ id: `${this.id}-cmaf-audio`,
181
+ segmentDurationSeconds: 2,
182
+ partDurationSeconds: 0.5,
183
+ destinations: [localDestination]
184
+ });
185
+ this.videoCmaf = await this.norsk.output.cmafVideo({
186
+ id: `${this.id}-cmaf-video`,
187
+ segmentDurationSeconds: 2,
188
+ partDurationSeconds: 0.5,
189
+ destinations: [localDestination]
190
+ });
191
+ this.mvCmaf = await this.norsk.output.cmafMultiVariant({
192
+ id: `${this.id}-cmaf-mv`,
193
+ playlistName: `${this.id}-mv`,
194
+ destinations: [localDestination]
195
+ });
196
+ this.smooth.subscribeToPins(sources.map((s) => s.selectToPin("source")), (ctx) => {
197
+ if (ctx.streams.length == 2)
198
+ return 'accept';
199
+ return 'deny';
200
+ });
201
+ this.audioEncode.subscribe([audio.select()]);
202
+ this.audioCmaf.subscribe([
203
+ { source: this.audioEncode, sourceSelector: norsk_sdk_1.selectAudio }
204
+ ]);
205
+ this.videoCmaf.subscribe([
206
+ { source: this.videoEncode, sourceSelector: norsk_sdk_1.selectVideo }
207
+ ]);
208
+ this.mvCmaf.subscribe([
209
+ { source: this.audioCmaf, sourceSelector: norsk_sdk_1.selectPlaylist },
210
+ { source: this.videoCmaf, sourceSelector: norsk_sdk_1.selectPlaylist },
211
+ ]);
212
+ this.updates.raiseEvent({
213
+ type: 'content-player-created',
214
+ url: this.mvCmaf.url
215
+ });
216
+ this.passthrough?.subscribe([
217
+ { source: this.smooth, sourceSelector: norsk_sdk_1.selectAV }
218
+ ]);
219
+ this.writer.subscribe(sources.map((s) => s.select()));
220
+ }
221
+ teardown() {
222
+ }
223
+ }
224
+ exports.ActionReplay = ActionReplay;
225
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/processor.actionReplay/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ActionReplayState, ActionReplayConfig, ActionReplayCommand } from "./runtime";
2
+ import type { ViewProps } from "@norskvideo/norsk-studio/lib/extension/client-types";
3
+ declare function SummaryView({ state, config, sendCommand }: ViewProps<ActionReplayConfig, ActionReplayState, ActionReplayCommand>): import("react/jsx-runtime").JSX.Element;
4
+ export default SummaryView;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const hls_js_1 = __importDefault(require("hls.js"));
9
+ let changingDuration = false;
10
+ function SummaryView({ state, config, sendCommand }) {
11
+ const url = state.contentPlayerUrl;
12
+ const id = config.id;
13
+ const previewVideo = (0, react_1.useRef)(null);
14
+ const [lastSeek, setLastSeek] = (0, react_1.useState)(undefined);
15
+ const [playbackDuration, setPlaybackDuration] = (0, react_1.useState)(10);
16
+ (0, react_1.useEffect)(() => {
17
+ if (!url)
18
+ return;
19
+ if (!previewVideo.current)
20
+ return;
21
+ if (hls_js_1.default.isSupported()) {
22
+ const hls = new hls_js_1.default();
23
+ hls.loadSource(url);
24
+ hls.attachMedia(previewVideo.current);
25
+ }
26
+ else if (previewVideo.current.canPlayType('application/vnd.apple.mpegurl')) {
27
+ previewVideo.current.src = url;
28
+ }
29
+ }, [state.contentPlayerUrl]);
30
+ if (!url)
31
+ return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "..." });
32
+ return (0, jsx_runtime_1.jsxs)("div", { className: "mb-5", children: [(0, jsx_runtime_1.jsx)("h5", { children: "Preview" }), (0, jsx_runtime_1.jsx)("video", { ref: previewVideo, controls: true, onSeeked: onSeeked, autoPlay: true, muted: true, className: state.replaying ? "hidden" : "", id: `${id}-video` }), state.replaying ? (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: "Current Performing Replay" }) :
33
+ (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [lastSeek ?
34
+ (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("p", { children: ["Replay from ", lastSeek.time.toFixed(1), "(s) "] }), (0, jsx_runtime_1.jsxs)("p", { className: "block mb-2 text-sm font-medium text-gray-900 dark:text-white", children: ["Duration: ", playbackDuration, "s"] }), (0, jsx_runtime_1.jsx)("input", { id: "duration-range", type: "range", min: currentMinDuration(), max: currentMaxDuration(), defaultValue: playbackDuration, className: "w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700", onChange: onDurationChange, onInput: onDurationChange })] })
35
+ :
36
+ (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {}), (0, jsx_runtime_1.jsx)("button", { onClick: sendReplayCommand, type: "button", className: "mt-2 mb-2 text-white w-full justify-center bg-primary-700 hover:bg-primary-800 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800", children: "Replay" })] })] });
37
+ function sendReplayCommand() {
38
+ if (!previewVideo.current)
39
+ return;
40
+ if (!lastSeek)
41
+ return;
42
+ const fromHead = previewVideo.current.duration - lastSeek.time;
43
+ sendCommand({
44
+ type: "do-replay",
45
+ from: fromHead,
46
+ duration: playbackDuration
47
+ });
48
+ }
49
+ function onDurationChange(e) {
50
+ const v = parseInt(e.currentTarget.value, 10);
51
+ setPlaybackDuration(v);
52
+ }
53
+ function currentMinDuration() {
54
+ if (!previewVideo.current || !lastSeek)
55
+ return 10;
56
+ return Math.min(10, previewVideo.current.duration - lastSeek.time);
57
+ }
58
+ function currentMaxDuration() {
59
+ if (!previewVideo.current || !lastSeek)
60
+ return 30;
61
+ return Math.min(30, previewVideo.current.duration - lastSeek.time);
62
+ }
63
+ function onSeeked() {
64
+ if (changingDuration) {
65
+ changingDuration = false;
66
+ return;
67
+ }
68
+ const v = previewVideo.current;
69
+ if (v?.currentTime && v.duration)
70
+ setLastSeek({ time: v?.currentTime, end: v?.duration });
71
+ else
72
+ setLastSeek(undefined);
73
+ }
74
+ }
75
+ exports.default = SummaryView;
76
+ //# sourceMappingURL=summary.js.map