streamlabs-obs

Streamlabs-obs是一款强大的直播推流客户端,使用Electron和OBS技术。Vue+Typescript进项开发。
本文将记录在二次开发历程。
Simple, powerful, and efficient live streaming software built on Electron and OBS.

核心文档

https://github.com/stream-labs/streamlabs-obs-api-docs

https://stream-labs.github.io/streamlabs-obs-api-docs/docs/index.html

https://dev.streamlabs.com/docs

开发调试步骤

1
2
3
4
5
6
7
yarn install  // Install all node modules via yarn: 安装依赖
npm install @types/axios
yarn compile // compile assets with webpack: 编译assets文件
yarn watch // 监听变动
F5 // debugger调试

yarn package // 打包exe

环境变量

  • process.env
1
2
SLOBS_PRODUCTION_DEBUG: true|false //开启devTools
SLOBS_NO_SIGN: true|false //默认开启,建议关闭,否则yarn package将失败

解决报错

Delete eslint(prettier/prettier) 报错解决方案:

1
2
git config --global core.autocrlf false
git clone x.git

持久化

  • 场景持久化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
缓存地址:
C:\Users\Administrator\AppData\Roaming\slobs-client\SceneCollections

Parse服务持久化:scene-collections.ts、Login.tsx、index.ts(user模块下)

/**
* 关闭程序(缓存为登录状态)或退出登录时,上传场景信息
*/
async saveParseByYitong()

/**
* 启动应用(缓存为登录状态)或登录时,加载场景数据
*/
async loadParseByYitong()

页面跳转

this.navigationService.navigate(‘Studio’);

Main(主进程)和Renderer(渲染器进程)通信

Main

1
2
3
4
5
6
7
8
9
10
11
12
import { ipcMain } from 'electron'
ipcMain.on('startUpdate', (e, arg) => {
autoUpdater.quitAndInstall()
})
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})

Renderer

1
2
3
4
5
6
7
const { ipcRenderer } = require('electron') // electron-vue: ipcRenderer = this.$electron.ipcRenderer
ipcRenderer.send('startUpdate')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')

webview所在页面 https://www.electronjs.org/docs/api/webview-tag
webview 调用 加载页 方法通过.executeJavaScript(code[, userGesture, callback])或者webview.send()发送,而在访客页使用ipcRenderer.on()监听
访客页需要调用webview所在页面的方法,则需要在webview中加上属性 nodeintegration=“true”

1
2
3
4
let webview=document.getElementById('test');
webview.addEventListener('ipc-message', (event) => { //ipc-message监听,被webview加载页面传来的信息
console.log(event.channel)//最终收到消息输出 子页面信息
})

访客页(被webview加载的资源页面)

1
2
3
切记加上window.
const {ipcRenderer} = window.require('electron')
ipcRenderer.sendToHost('子页面信息') //向webview所在页面发送消息

兼容electron嵌入

1
2
3
4
5
6
7
8
9
<script>
// 兼容electron嵌入
if(window.require){window.nodeRequire = require;}
delete window.require;
delete window.exports;
delete window.module;
</script>
</script>
<script src="//public.yitong.com/libs/jquery/1.11.1/jquery.min.js"></script>

缓存 数据持久化

@mutation()
SET_SETTINGS(settingsData: ISettingsState) {
this.state = Object.assign({}, this.state, settingsData);
}

// 持久化
obs.NodeObs.OBS_settings_saveSettings(categoryName, settingsFormData[categoryName]);

与obs交互

创建图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
this.editorCommandsService.executeCommand('EditSourcePropertiesCommand', this.sourceId, [
properties[changedIndex],
]);

properties[0] = {
"defaultPath": "",
"description": "图像文件",
"enabled": true,
"filters": [
{
"extensions": [
"bmp",
"tga",
"png",
"jpeg",
"jpg",
"gif",
"psd"
],
"name": "All formats"
},
{
"extensions": [
"bmp"
],
"name": "BMP Files"
},
{
"extensions": [
"tga"
],
"name": "Targa Files"
},
{
"extensions": [
"png"
],
"name": "PNG Files"
},
{
"extensions": [
"jpeg",
"jpg"
],
"name": "JPEG Files"
},
{
"extensions": [
"gif"
],
"name": "GIF Files"
},
{
"extensions": [
"psd"
],
"name": "PSD Files"
},
{
"extensions": [
"*"
],
"name": "All Files"
}
],
"name": "file",
"type": "OBS_PROPERTY_FILE",
"value": "https://image.yitong.com/uploads/adyt/2018-04-19/42f5f49db3a64c9ea881811344485bfc.jpg",
"visible": true
}

创建音视频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
{
"defaultPath": "",
"description": "本地文件",
"enabled": true,
"filters": [
{
"extensions": [
"mp4",
"ts",
"mov",
"flv",
"mkv",
"avi",
"mp3",
"ogg",
"aac",
"wav",
"gif",
"webm"
],
"name": "所有媒体文件"
},
{
"extensions": [
"mp4",
"ts",
"mov",
"flv",
"mkv",
"avi",
"gif",
"webm"
],
"name": "视频文件"
},
{
"extensions": [
"mp3",
"aac",
"ogg",
"wav"
],
"name": "音频文件"
},
{
"extensions": [
"*"
],
"name": "所有文件"
}
],
"name": "local_file",
"type": "OBS_PROPERTY_FILE",
"value": "F:\\我的素材\\MP4\\1.mp4",
"visible": true
}

setting

setting.ts SET_SETTINGS 配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
{
"General": {
"WarnBeforeStartingStream": false,
"WarnBeforeStoppingStream": false,
"RecordWhenStreaming": false,
"KeepRecordingWhenStreamStops": false,
"ReplayBufferWhileStreaming": false,
"KeepReplayBufferStreamStops": false,
"SnappingEnabled": true,
"SnapDistance": 10,
"ScreenSnapping": true,
"SourceSnapping": true,
"CenterSnapping": false,
"HideProjectorCursor": false,
"ProjectorAlwaysOnTop": false,
"SaveProjectors": false,
"SysTrayEnabled": false,
"SysTrayWhenStarted": false,
"SysTrayMinimizeToTray": false
},
"Stream": {
"streamType": "rtmp_common",
"service": "Twitch",
"show_all": false,
"server": "auto",
"key": ""
},
"Output": {
"Mode": "Simple",
"VBitrate": 600,
"StreamEncoder": "x264",
"ABitrate": "64",
"UseAdvanced": false,
"FilePath": "C:\\Users\\chensong\\Videos",
"FileNameWithoutSpace": false,
"RecQuality": "Stream",
"RecFormat": "flv",
"MuxerCustom": "",
"RecRB": true,
"RecRBTime": 20
},
"Audio": {
"SampleRate": 44100,
"ChannelSetup": "Stereo",
"Desktop Audio ": "default",
"Desktop Audio 2": null,
"Mic/Aux ": "default",
"Mic/Aux 2": null,
"Mic/Aux 3": null
},
"Video": {
"Base": "1920x1080",
"Output": "1280x720",
"ScaleType": "bicubic",
"FPSType": "Common FPS Values",
"FPSCommon": "30"
},
"Advanced": {
"ProcessPriority": "Normal",
"ColorFormat": "NV12",
"ColorSpace": "601",
"ColorRange": "Partial",
"ForceGPUAsRenderDevice": true,
"MonitoringDeviceName": "Default",
"DisableAudioDucking": false,
"FilenameFormatting": "%CCYY-%MM-%DD %hh-%mm-%ss",
"OverwriteIfExists": false,
"RecRBPrefix": "Replay",
"RecRBSuffix": "",
"DelayEnable": false,
"DelaySec": 20,
"DelayPreserve": true,
"Reconnect": true,
"RetryDelay": 10,
"MaxRetries": 20,
"BindIP": "default",
"NewSocketLoopEnable": false,
"LowLatencyEnable": false,
"browserHWAccel": true,
"fileCaching": true
}
}

场景保存

state.ts flushManifestFile writeDataToCollectionFile

1
2
3
```

### slobs缓存清除

C:\Users\chensong\AppData\Roaming\slobs-client
C:\Users\chensong\AppData\Roaming\slobs-plugins

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

# vscode settings.json

```hash
{
"typescript.validate.enable": false,
"[javascript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"git.autofetch": true,
"update.enableWindowsBackgroundUpdates": false,
"update.mode": "none",
"editor.parameterHints": true,
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
"files.associations": {
"*.cjson": "jsonc",
"*.wxss": "css",
"*.wxs": "javascript"
},
"emmet.includeLanguages": {
"wxml": "html"
},
"minapp-vscode.disableAutoConfig": true,
"editor.renderIndentGuides": false,
"psi-header.templates": [
{
"language": "*",
"template": [
"@File: <<filename>>",
"@Author: csorz",
"@Date: <<filecreated('YYYY-MM-DD HH:mm:ss')>>",
"@Last Modified by: csorz",
"@Last Modified time: <<dateformat('YYYY-MM-DD HH:mm:ss')>>"
]
},
],
"background.enabled": true,
"background.useDefault": false,
"background.customImages": [
"file:///F:/我的素材/IMG/p1_people.png"
],
"background.style": {
"opacity": 0.5,
"background-size": "20%"
},
"background.useFront": true,
"editor.wordWrap": "on",
// vscode默认启用了根据文件类型自动设置tabsize的选项
"editor.detectIndentation": true,
// 重新设定tabsize
"editor.tabSize": 2,
// #每次保存的时候自动格式化
"editor.formatOnSave": false,
// #每次保存的时候将代码按eslint格式进行修复
"eslint.autoFixOnSave": true,
// 添加 vue 支持
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true
}
],
// #让prettier使用eslint的代码格式进行校验
"prettier.eslintIntegration": true,
// #去掉代码结尾的分号
"prettier.semi": false,
// #使用单引号替代双引号
"prettier.singleQuote": true,
// #让函数(名)和后面的括号之间加个空格
"javascript.format.insertSpaceBeforeFunctionParenthesis": false,
// #这个按用户自身习惯选择
"vetur.format.defaultFormatter.html": "js-beautify-html",
// #让vue中的js按编辑器自带的ts格式进行格式化
"vetur.format.defaultFormatter.js": "vscode-typescript",
"vetur.format.defaultFormatterOptions": {
"js-beautify-html": {
"wrap_attributes": "force-expand-multiline"
// #vue组件中html代码格式化样式
}
}
}

Main(主进程)和Renderer(渲染器进程)通信

Main

1
2
3
4
5
6
7
8
9
10
11
12
import { ipcMain } from 'electron'
ipcMain.on('startUpdate', (e, arg) => {
autoUpdater.quitAndInstall()
})
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.returnValue = 'pong'
})

Renderer

1
2
3
4
5
6
7
const { ipcRenderer } = require('electron') // electron-vue: ipcRenderer = this.$electron.ipcRenderer
ipcRenderer.send('startUpdate')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')

更新组件

  1. 原updater下增改文件
  2. 新增依赖包
  • yarn add @types/js-yaml
  • yarm add electron-log
  1. 迁移0.17.1版updater文件
  2. main.js文件修改
  • 删除 const bootstrap = require(‘./updater/build/bootstrap.js’);
  • 新增 const bootstrap = require(‘./updater/bootstrap.js’);
  • 保留 const bundleUpdater = require(‘./updater/build/bundle-updater.js’);
  • 保留 await bundleUpdater(__dirname); // bundleUpdater 其作用是替换index.html中cdn脚本为本地脚本
  • updateInfo判断变更,对象字段变更
  • 新版startApp为异步方法 -> await startApp();

打包注意事项:

  1. 关闭签名 // if (!process.env.SLOBS_NO_SIGN) base.win.certificateSubjectName = ‘Streamlabs (General Workings, Inc.)’;

Streamlabs OBS

Build Status

Simple, powerful, and efficient live streaming software built on Electron and OBS.

Streamlabs OBS

This application currently only supports 64-bit Windows.

Dependencies

Node.js

Node is required for installing npm packages and for running
various scripts. We recommend the current LTS release, 8.x.x:

https://nodejs.org

Yarn

In order to ensure you are using the correct version of each
node module, you should use the yarn package manager.
Installation instructions can be found here:

https://yarnpkg.com/en/docs/install

Installation

Install all node modules via yarn:

1
yarn install

Then, compile assets with webpack:

1
yarn compile

Starting

If you are using Visual Studio Code, you can start the app
using the built in debugger (default F5).

Otherwise, you can run the app with:

1
yarn start

Environment Variables

These variables can be used in development to force certain behavior.

SLOBS_FORCE_AUTO_UPDATE: Force the auto-updater to run in development. Normally
this would only run in production.

SLOBS_CACHE_DIR: Force a different location for the user data cache directory.

SLOBS_DISABLE_MAIN_LOGGING: Disable javascript logging in the main process.

SLOBS_REPORT_TO_SENTRY: Report errors to sentry in the dev environment

Packaging / Distributing

Currently only Windows x64 packaging is supported.

Packaging

Make sure the app is not running in your dev environment
before you start the packaging process.

You can package the app by running:

1
yarn package

This will package a distributable installer .exe to the dist/
directory. There is also an unpacked version in dist/win-unpacked.

Releasing

If you want to release a new version to the update server, you will need
the following variables in your environment:

1
2
3
4
5
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
CSC_LINK
CSC_KEY_PASSWORD
SENTRY_AUTH_TOKEN

Only authorized team members have permission to release new versions.
If you need help setting up your environment for release, you can ask
someone on the team for help.

If your environment is properly set up, you can use the automated
release script to push out a new release.

Simply run:

1
yarn release

and follow the instructions.

Legacy Release Checklist

NOTE: This checklist is deprecated, and is only kept here in case
the automated deploy script isn’t working and we need to do a
manual deploy.

  • Merge staging into master - DO NOT “Squash & Merge”, just do a regular merge
  • Check out master
  • If submodules are out of date git submodule update --init --recursive
  • Remove node modules rm -rf node_modules
  • Install fresh packages yarn install
  • Install node-obs with latest plugins yarn install-node-obs
  • Compile assets yarn compile
  • Run the test suite yarn test
  • Change the version in package.json
  • Commit and push
  • Tag the repo git tag 'v0.0.11' and git push --tags
  • Package the app yarn package
  • Run the packaged version in dist/win-unpacked and make sure it runs
  • Deploy the new version yarn deploy
  • Merge master back into staging

❤ OBS Developers

At its core, Streamlabs OBS is powered by the OBS
engine. We want to thank all of the developers over at the OBS project for
their years of tireless hard work, without which Streamlabs OBS wouldn’t exist today.


streamlabs-obs
http://example.com/20200729-streamlabs-obs/
作者
csorz
发布于
2020年7月29日
许可协议