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 npm install @types /axios yarn compile yarn watch F5 yarn package
环境变量
1 2 SLOBS_PRODUCTION_DEBUG: true |false SLOBS_NO_SIGN: true |false
解决报错 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' ) ipcRenderer.send ('startUpdate' ) console.log (ipcRenderer.sendSync ('synchronous-message' , 'ping' )) ipcRenderer.on ('asynchronous-reply' , (event, arg) => { console.log (arg) }) 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 ) => { console .log (event.channel ) })
访客页(被webview加载的资源页面)
1 2 3 切记加上window .const {ipcRenderer} = window .require ('electron' ) ipcRenderer.sendToHost ('子页面信息' )
兼容electron嵌入 1 2 3 4 5 6 7 8 9 <script > 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
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 ```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.autoFixOnSave" : true , // 添加 vue 支持 "eslint.validate" : [ "javascript" , "javascriptreact" , { "language" : "vue" , "autoFix" : true } ], // "prettier.eslintIntegration" : true , // "prettier.semi" : false , // "prettier.singleQuote" : true , // "javascript.format.insertSpaceBeforeFunctionParenthesis" : false , // "vetur.format.defaultFormatter.html" : "js-beautify-html" , // "vetur.format.defaultFormatter.js" : "vscode-typescript" , "vetur.format.defaultFormatterOptions" : { "js-beautify-html" : { "wrap_attributes" : "force-expand-multiline" // } } }
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' ) ipcRenderer.send ('startUpdate' ) console.log (ipcRenderer.sendSync ('synchronous-message' , 'ping' )) ipcRenderer.on ('asynchronous-reply' , (event, arg) => { console.log (arg) }) ipcRenderer.send ('asynchronous-message' , 'ping' )
更新组件
原updater下增改文件
新增依赖包
yarn add @types/js-yaml
yarm add electron-log
迁移0.17.1版updater文件
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();
打包注意事项:
关闭签名 // if (!process.env.SLOBS_NO_SIGN) base.win.certificateSubjectName = ‘Streamlabs (General Workings, Inc.)’;
Streamlabs OBS
Simple, powerful, and efficient live streaming software built on Electron and 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:
Then, compile assets with webpack:
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:
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:
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:
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.
❤ 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.