Skip to content

Commit 4119369

Browse files
author
Tom Maneri
committed
merged with vision_service
2 parents 1a11e80 + cc8e30d commit 4119369

6 files changed

Lines changed: 138 additions & 34 deletions

File tree

app/components-react/sidebar/NavTools.m.less

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,11 @@
233233
}
234234
}
235235
}
236+
237+
.vision {
238+
color: var(--nav-active) !important;
239+
240+
i {
241+
color: var(--nav-active) !important;
242+
}
243+
}

app/components-react/sidebar/NavTools.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import MenuItem from 'components-react/shared/MenuItem';
1515
import UltraIcon from 'components-react/shared/UltraIcon';
1616
import PlatformIndicator from './PlatformIndicator';
1717
import { AuthModal } from 'components-react/shared/AuthModal';
18+
import { useRealmObject } from 'components-react/hooks/realm';
1819

1920
export default function SideNav() {
2021
const {
@@ -25,8 +26,11 @@ export default function SideNav() {
2526
SideNavService,
2627
WindowsService,
2728
UrlService,
29+
VisionService,
2830
} = Services;
2931

32+
const visionState = useRealmObject(VisionService.state);
33+
3034
const isDevMode = Utils.isDevMode();
3135

3236
const {
@@ -53,8 +57,7 @@ export default function SideNav() {
5357
const [dashboardOpening, setDashboardOpening] = useState(false);
5458
const [showModal, setShowModal] = useState(false);
5559

56-
function openSettingsWindow(type?: string, category?: string) {
57-
UsageStatisticsService.actions.recordClick('SideNav2', type ?? 'settings');
60+
function openSettingsWindow(category?: string) {
5861
SettingsService.actions.showSettings(category);
5962
}
6063

@@ -182,6 +185,15 @@ export default function SideNav() {
182185
onClick={() => openHelp()}
183186
/>
184187
);
188+
} else if (menuItem.key === EMenuItemKey.Vision) {
189+
return (
190+
<NavToolsItem
191+
key={menuItem.key}
192+
menuItem={menuItem}
193+
className={visionState.isRunning ? styles.vision : undefined}
194+
onClick={() => openSettingsWindow('Vision')}
195+
/>
196+
);
185197
} else if (menuItem.key === EMenuItemKey.Settings) {
186198
return (
187199
<NavToolsItem

app/components-react/windows/settings/Vision.tsx

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,82 @@
11
import { useRealmObject } from 'components-react/hooks/realm';
22
import { Services } from 'components-react/service-provider';
33
import React, { useEffect } from 'react';
4-
import { Button } from 'antd';
4+
import { Button, Progress } from 'antd';
5+
import { ObsSettingsSection } from './ObsSettings';
6+
import { confirmAsync } from 'components-react/modals';
7+
8+
function VisionInstalling(props: { percent: number; isUpdate: boolean }) {
9+
const message = props.isUpdate ? 'Updating...' : 'Installing...';
10+
11+
return (
12+
<ObsSettingsSection title={message}>
13+
<div style={{ marginBottom: 16 }}>
14+
<Progress
15+
percent={props.percent * 100}
16+
status="active"
17+
format={percent => `${(percent || 0).toFixed(0)}%`}
18+
/>
19+
</div>
20+
</ObsSettingsSection>
21+
);
22+
}
23+
24+
function VisionInfo(props: {
25+
installedVersion: string;
26+
isRunning: boolean;
27+
isCurrentlyUpdating: boolean;
28+
pid: number;
29+
port: number;
30+
}) {
31+
return (
32+
<ObsSettingsSection title="Streamlabs Vision">
33+
<div style={{ marginBottom: 16 }}>
34+
<div>Installed: {props.installedVersion ? 'Yes' : 'No'}</div>
35+
<div>Version: {props.installedVersion}</div>
36+
<div>Running: {props.isRunning ? 'Yes' : 'No'}</div>
37+
{props.isRunning && props.pid && <div>PID: {props.pid}</div>}
38+
{props.isRunning && props.port && <div>Port: {props.port}</div>}
39+
</div>
40+
</ObsSettingsSection>
41+
);
42+
}
543

644
export function VisionSettings() {
745
const { VisionService } = Services;
846
const state = useRealmObject(VisionService.state);
947

1048
useEffect(() => {
11-
VisionService.loadCurrentManifest();
12-
}, []);
49+
if (state.needsUpdate) {
50+
let message = 'Streamlabs Vision must be updated before you can use it.';
51+
let button = 'Update Now';
1352

14-
function installVision() {
15-
VisionService.actions.ensureVision();
16-
}
53+
if (!state.installedVersion) {
54+
message =
55+
'Streamlabs needs to download additional components. Would you like to install them now?';
56+
button = 'Install';
57+
}
58+
59+
confirmAsync({ title: message, okText: button }).then(confirmed => {
60+
if (confirmed) {
61+
VisionService.actions.installOrUpdate();
62+
}
63+
});
64+
}
65+
}, []);
1766

1867
return (
1968
<div>
20-
<div>Installed: {state.installedVersion ? 'Yes' : 'No'}</div>
21-
{state.installedVersion && <div>Version: {state.installedVersion}</div>}
22-
{state.installedVersion && <div>Running: {state.isRunning ? 'Yes' : 'No'}</div>}
23-
{state.isCurrentlyUpdating && <div>Progress: {state.percentDownloaded}</div>}
24-
{state.isCurrentlyUpdating && state.isInstalling && <div>Installing...</div>}
25-
{!state.installedVersion && !state.isCurrentlyUpdating && (
26-
<Button onClick={() => installVision()}>Install</Button>
27-
)}
28-
{state.installedVersion && !state.isRunning && (
29-
<Button onClick={() => installVision()}>Start</Button>
69+
<VisionInfo
70+
installedVersion={state.installedVersion}
71+
isRunning={state.isRunning}
72+
isCurrentlyUpdating={state.isCurrentlyUpdating}
73+
pid={state.pid || 0}
74+
port={state.port || 0}
75+
/>
76+
77+
{state.isCurrentlyUpdating && (
78+
<VisionInstalling percent={state.percentDownloaded} isUpdate={!!state.installedVersion} />
3079
)}
31-
{state.isRunning && state.pid && <div>PID: {state.pid}</div>}
32-
{state.isRunning && state.port && <div>Port: {state.port}</div>}
3380
</div>
3481
);
3582
}

app/services/side-nav/menu-data.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export enum EMenuItemKey {
2525
GetHelp = 'get-help',
2626
Settings = 'settings',
2727
Login = 'login',
28+
Vision = 'vision',
2829
}
2930

3031
/**
@@ -160,6 +161,7 @@ export const menuTitles = (item: EMenuItemKey | ESubMenuItemKey | string) => {
160161
[ESubMenuItemKey.Widgets]: $t('Widgets'),
161162
[ESubMenuItemKey.TipSettings]: $t('Tip Settings'),
162163
[ESubMenuItemKey.Multistream]: $t('Multistream'),
164+
[EMenuItemKey.Vision]: 'Vision',
163165
}[item];
164166
};
165167

@@ -190,6 +192,7 @@ export const SideBarBottomNavData = (): IMenu => ({
190192
SideNavMenuItems()[EMenuItemKey.GetPrime],
191193
SideNavMenuItems()[EMenuItemKey.Dashboard],
192194
SideNavMenuItems()[EMenuItemKey.GetHelp],
195+
SideNavMenuItems()[EMenuItemKey.Vision],
193196
SideNavMenuItems()[EMenuItemKey.Settings],
194197
SideNavMenuItems()[EMenuItemKey.Login],
195198
],
@@ -306,6 +309,12 @@ export const SideNavMenuItems = (): TMenuItems => ({
306309
isActive: true,
307310
isExpanded: false,
308311
},
312+
[EMenuItemKey.Vision]: {
313+
key: EMenuItemKey.Vision,
314+
icon: 'fas fa-eye',
315+
isActive: true,
316+
isExpanded: false,
317+
},
309318
[EMenuItemKey.Settings]: {
310319
key: EMenuItemKey.Settings,
311320
icon: 'icon-settings',

app/services/sources/properties-managers/smart-browser-source-manager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ export class SmartBrowserSourceManager extends PropertiesManager {
1616

1717
if (['visionEvent', 'userStateUpdated'].includes(e.type)) {
1818
//@ts-ignore
19-
console.log("success", JSON.stringify(e));
19+
console.log('success', JSON.stringify(e));
2020
this.obsSource.sendMessage({ message: JSON.stringify(e) });
2121
}
2222
});
23+
this.visionService.ensureVision();
2324
}
2425

2526
destroy() {

app/services/vision/index.ts

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { OutputStreamHandler } from 'services/platform-apps/api/modules/native-c
88
import crypto from 'crypto';
99
import { importExtractZip } from 'util/slow-imports';
1010
import { pipeline } from 'stream/promises';
11-
import { HostsService, SourcesService, UserService } from 'app-services';
11+
import { HostsService, SourcesService, SettingsService, UserService } from 'app-services';
1212
import { RealmObject } from 'services/realm';
1313
import { ObjectSchema } from 'realm';
1414
import http from 'http';
@@ -34,6 +34,7 @@ export class VisionState extends RealmObject {
3434
isRunning: boolean;
3535
pid: number;
3636
port: number;
37+
needsUpdate: boolean;
3738

3839
static schema: ObjectSchema = {
3940
name: 'VisionState',
@@ -44,7 +45,8 @@ export class VisionState extends RealmObject {
4445
isRunning: { type: 'bool', default: false },
4546
isInstalling: { type: 'bool', default: false },
4647
pid: { type: 'int', default: 0 },
47-
port: { type: 'int', default: 0 }
48+
port: { type: 'int', default: 0 },
49+
needsUpdate: { type: 'bool', default: false },
4850
},
4951
};
5052
}
@@ -64,6 +66,7 @@ export class VisionService extends Service {
6466
@Inject() userService: UserService;
6567
@Inject() hostsService: HostsService;
6668
@Inject() private sourcesService: SourcesService;
69+
@Inject() settingsService: SettingsService;
6770

6871
state = VisionState.inject();
6972

@@ -104,25 +107,46 @@ export class VisionService extends Service {
104107
}
105108

106109
/**
107-
* Ensures the following:
108-
* - vision is downloaded and up to date
109-
* - vision is running and sending events
110-
* - we are subscribed to events
110+
* Will pop up a dialog if vision is not installed
111+
* or requires an update.
111112
*/
112113
async ensureVision() {
114+
if (this.proc && this.proc.exitCode != null) return;
115+
113116
const needsUpdate = await this.isNewVersionAvailable();
114117

118+
this.state.db.write(() => {
119+
this.state.needsUpdate = needsUpdate;
120+
});
121+
115122
if (needsUpdate) {
116-
await this.update(progress => {
117-
this.state.db.write(() => {
118-
this.state.percentDownloaded = progress.percent;
119-
});
123+
this.settingsService.showSettings('Vision');
124+
} else {
125+
await this.startVision();
126+
}
127+
}
128+
129+
async installOrUpdate() {
130+
if (this.state.isCurrentlyUpdating) return;
131+
132+
await this.update(progress => {
133+
this.state.db.write(() => {
134+
this.state.percentDownloaded = progress.percent;
120135
});
136+
});
121137

122-
await this.loadCurrentManifest();
123-
}
138+
await this.loadCurrentManifest();
139+
140+
this.state.db.write(() => {
141+
this.state.needsUpdate = false;
142+
this.state.percentDownloaded = 0;
143+
});
124144

125-
if (this.proc && this.proc.killed) {
145+
await this.startVision();
146+
}
147+
148+
async startVision() {
149+
if (this.proc && this.proc.exitCode != null) {
126150
this.proc = null;
127151
}
128152

@@ -435,6 +459,9 @@ export class VisionService extends Service {
435459
this.eventSource.onmessage = e => {
436460
console.log('GOT EVENT', e.data);
437461

462+
// Filter out game process detection events
463+
if (e.data['events'].find((e: any) => e.name === 'game_process_detected')) return;
464+
438465
const headers = authorizedHeaders(
439466
this.userService.apiToken,
440467
new Headers({ 'Content-Type': 'application/json' }),

0 commit comments

Comments
 (0)