Skip to content

Commit 586d713

Browse files
committed
feat: Add broadcast creation, stream binding, and thumbnail actions
Add create broadcast action with title, description, visibility, scheduled start time, auto-start/stop, monitor stream, thumbnail, and stream binding options. Add standalone set thumbnail and bind/unbind stream actions. Add last_created_broadcast_id variable, available streams cache with listStreams API, and update HELP.md documentation.
1 parent 0a9981b commit 586d713

File tree

14 files changed

+944
-26
lines changed

14 files changed

+944
-26
lines changed

companion/HELP.md

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ broadcasts that the action might be performed upon, or by specifying its ID (the
88
part after the `?v=...` in a YouTube video URL) as textual input. A checkbox
99
switches between the two modes.
1010

11-
The module currently only allows already-created broadcasts to be manipulated:
12-
it doesn't offer a way to create them itself. You'll have to create a broadcast
13-
in YouTube Studio in order to be able to manipulate it.
11+
The module can create new broadcasts and manipulate existing ones.
1412

1513
## Available actions
1614

@@ -47,6 +45,18 @@ in YouTube Studio in order to be able to manipulate it.
4745
the description.
4846
- **Add chapter timecode to description** - This action inserts a chapter
4947
timecode at the end of the description.
48+
- **Create new broadcast** - This action creates a new YouTube broadcast with
49+
the specified settings. Supports using an existing broadcast as a template to
50+
copy settings from (title, description, monitor stream, and stream binding).
51+
Options include scheduled start time (now, minutes from now, or custom ISO
52+
8601), privacy status, auto-start/auto-stop, thumbnail upload, and stream
53+
binding.
54+
- **Set broadcast thumbnail** - This action uploads and sets a custom thumbnail
55+
image for a broadcast. Accepts a local file path or URL to a JPEG/PNG image
56+
(max 2MB).
57+
- **Bind stream to broadcast** - This action binds a video stream to a
58+
broadcast, which is required before going live. Select a stream from the
59+
dropdown or enter a stream ID manually.
5060

5161
[ytapi]: https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/transition
5262

@@ -165,6 +175,34 @@ completing the consent process can be found underneath that link.
165175
Consent while in "Testing" status only lasts a week. After that you'll have to
166176
reopen the consent screen and recomplete the consent process.
167177

178+
## Available feedbacks
179+
180+
- **Broadcast status** - Changes button colors based on the broadcast lifecycle
181+
state (ready, testing, live, complete). Colors are configurable.
182+
- **Health of stream bound to broadcast** - Changes button colors based on the
183+
health of the video stream bound to a broadcast (good, ok, bad, no data).
184+
185+
## Available variables
186+
187+
Per-broadcast variables (where `ID` is the YouTube broadcast ID):
188+
189+
- `broadcast_ID_lifecycle` - Lifecycle state of the broadcast
190+
- `broadcast_ID_health` - Health of the stream bound to the broadcast
191+
192+
Unfinished broadcast variables (where `N` is the index, starting from 0):
193+
194+
- `unfinished_N` - Name of unfinished broadcast #N
195+
- `unfinished_N_id` - ID of unfinished broadcast #N
196+
- `unfinished_short_N` - Shortened name of unfinished broadcast #N
197+
- `unfinished_state_N` - State of unfinished broadcast #N
198+
- `unfinished_health_N` - Stream health of unfinished broadcast #N
199+
- `unfinished_concurrent_viewers_N` - Concurrent viewers of unfinished broadcast #N
200+
201+
Global variables:
202+
203+
- `last_created_broadcast_id` - ID of the most recently created broadcast (via
204+
the "Create new broadcast" action)
205+
168206
## Action configuration
169207

170208
When creating actions to operate upon a broadcast, pick the broadcast to work
@@ -179,6 +217,21 @@ to switch to a text input and enter it there. The text field supports
179217
variables, so you can also store the broadcast ID in a variable and change that
180218
variable as needed.
181219

220+
### Using templates with Create broadcast
221+
222+
When creating a broadcast, you can check "Use existing broadcast as template" to
223+
copy settings from an existing broadcast. Template values serve as defaults:
224+
any value you explicitly set will override the template. This is useful for
225+
creating broadcasts with consistent settings. The template's description,
226+
monitor stream setting, and stream binding will be copied if you don't provide
227+
your own.
228+
229+
### Using the last created broadcast ID
230+
231+
After creating a broadcast, its ID is stored in the `last_created_broadcast_id`
232+
variable. You can use this variable in subsequent actions (via text input mode)
233+
to operate on the newly created broadcast without knowing its ID in advance.
234+
182235
## Thanks
183236

184237
Big thanks to members of [AVC Silicon Hill](https://avc.sh.cvut.cz/) for

src/__mocks__/@googleapis/youtube.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ export function makeMockYT(memory: StateMemory): YoutubeAPI {
3636
setVisibility: vi.fn<YoutubeAPI['setVisibility']>().mockImplementation(async () => {
3737
return Promise.resolve();
3838
}),
39+
createBroadcast: vi.fn<YoutubeAPI['createBroadcast']>().mockImplementation(async () => {
40+
return Promise.resolve('newBroadcastId');
41+
}),
42+
setThumbnail: vi.fn<YoutubeAPI['setThumbnail']>().mockImplementation(async () => {
43+
return Promise.resolve();
44+
}),
45+
listStreams: vi.fn<YoutubeAPI['listStreams']>().mockImplementation(async () => {
46+
return Promise.resolve(memory.Streams);
47+
}),
48+
bindBroadcastToStream: vi.fn<YoutubeAPI['bindBroadcastToStream']>().mockImplementation(async () => {
49+
return Promise.resolve();
50+
}),
3951
};
4052
}
4153

@@ -80,6 +92,11 @@ export class FakeYouTube {
8092
insertCuepoint:
8193
vi.fn<LiveBroadcastsMethod<'insertCuepoint', [youtube_v3.Params$Resource$Livebroadcasts$Insertcuepoint]>>(),
8294
update: vi.fn<LiveBroadcastsMethod<'update', [youtube_v3.Params$Resource$Livebroadcasts$Update]>>(),
95+
insert: vi.fn(),
96+
bind: vi.fn(),
97+
};
98+
thumbnails = {
99+
set: vi.fn(),
83100
};
84101
}
85102

src/actions.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const SampleMemory: StateMemory = {
2727
},
2828
},
2929
Streams: {},
30+
BoundStreams: {},
3031
UnfinishedBroadcasts: [],
32+
LastCreatedBroadcast: null,
3133
};
3234

3335
//
@@ -36,7 +38,7 @@ const SampleMemory: StateMemory = {
3638

3739
describe('Action list', () => {
3840
test('Module has required actions', () => {
39-
const result = listActions({ broadcasts: SampleMemory.Broadcasts, unfinishedCount: 3, core: null });
41+
const result = listActions({ broadcasts: SampleMemory.Broadcasts, unfinishedCount: 3, core: null, streams: {} });
4042
expect(result).toHaveProperty(ActionId.InitBroadcast);
4143
expect(result).toHaveProperty(ActionId.StartBroadcast);
4244
expect(result).toHaveProperty(ActionId.StopBroadcast);
@@ -114,8 +116,8 @@ describe('Action callback', () => {
114116
void coreKO.init();
115117

116118
// List actions
117-
const actionsOK = listActions({ broadcasts: SampleMemory.Broadcasts, unfinishedCount: 0, core: coreOK });
118-
const actionsKO = listActions({ broadcasts: SampleMemory.Broadcasts, unfinishedCount: 0, core: coreKO });
119+
const actionsOK = listActions({ broadcasts: SampleMemory.Broadcasts, unfinishedCount: 0, core: coreOK, streams: {} });
120+
const actionsKO = listActions({ broadcasts: SampleMemory.Broadcasts, unfinishedCount: 0, core: coreKO, streams: {} });
119121

120122
// Make event
121123
function makeEvent(actionId: string, options: CompanionOptionValues): CompanionActionEvent {

0 commit comments

Comments
 (0)