refactor for new host

This commit is contained in:
2025-12-20 06:52:18 -08:00
parent 622155e103
commit ddeb86527d
10 changed files with 2406 additions and 262 deletions
View File
-42
View File
@@ -1,42 +0,0 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["master"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
# Upload entire repository
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
+3
View File
@@ -0,0 +1,3 @@
node_modules
.wrangler
assets/*.js*
+3 -5
View File
@@ -1,13 +1,11 @@
# OBSConnect
This project provides a basic authentication page to make using a password on your OBS Websocket easier, by saving it once on the auth page and providing it to other pages after you allow it.
## For Developers
Send your users to the page `https://sugoidogo.github.io/obsconnect?redirect_uri=yourpageurlencodedhere` to prompt for acces to OBS-Websocket. If they allow the connection, this page will sort out gathering the connection info, testing that it works, and then returning the user to your page with the query string `?obsurl=ws://localhost:4455&obspassword=examplepassword&userChoice=allow` or `?userChoice=deny`, depending on what they chose. You can now save that info using something like [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and connect to obs with something like [obs-websocket-js](https://github.com/obs-websocket-community-projects/obs-websocket-js) for a fully abstracted connection method.
Send your users to the page `https://obsconnect.sugoidogo.com/?redirect_uri=yourpageurlencodedhere` to prompt for acces to OBS-Websocket. If they allow the connection, this page will sort out gathering the connection info, testing that it works, and then returning the user to your page with the query string `?obsurl=ws://localhost:4455&obspassword=examplepassword&userChoice=allow` or `?userChoice=deny`, depending on what they chose. You can now save that info using something like [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) and connect to obs with something like [obs-websocket-js](https://github.com/obs-websocket-community-projects/obs-websocket-js) for a fully abstracted connection method.
## For Users
Send [this page](https://github.com/sugoidogo/obsconnect) (THE LINK, NOT A SCREENSHOT) to the developer of whatever web-based obs tool you want to use it.
Send [this page](https://gitea.sugoidogo.com/sugoidogo/obsconnect) (THE LINK, NOT A SCREENSHOT) to the developer of whatever web-based obs tool you want to use it.
( If you user sent you this in a screenshot anyways, it's at github.com/sugoidogo/obsconnect )
## Support
Support information for all my software is on my [GitHub profile](https://github.com/sugoidogo)
( If you user sent you this in a screenshot anyways, it's at gitea.sugoidogo.com/sugoidogo/obsconnect )
## Security
This project stores your OBS Websocket password in `localStorage` for re-use whenever a new web app wants to connect to OBS. Depending on your browser, that means your password is stored unencrypted somewhere in your browser data. That would be a possible security concern, if obs-websocket weren't already [storing your password in plain text](https://github.com/obsproject/obs-websocket/discussions/766#:~:text=via%20this%20dialog.-,%5BTechnical%20Note%3A%5D,-This%20feature%20has).
## Licence
+46
View File
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<head>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgo=">
<script type="module" src="index.js"></script>
</head>
<style>
* {
font-size: 3vmin;
}
video {
max-width: 100vw;
max-height: 50vh;
}
</style>
<div id="status">Loading...</div>
<div id="permission">
<button onclick="allow()">Allow</button>
<button onclick="deny()">Deny</button>
</div>
<span id="connectionSettings" hidden>
<table>
<tr>
<td>Websocket URL:</td>
<td><input id="obsurl" type="url"></td>
</tr>
<tr>
<td>Websocket Password:</td>
<td><input id="obspassword" type="password"></td>
</tr>
</table>
<button id="connect" onclick="connect()">Connect</button>
<button id="useQR" onclick="useQrCode()">Use QR Code</button>
<button id="skip" onclick="skipVerification()">Skip Verification</button>
<br>
<span id="qr" hidden>
<video id="qrvideo" hidden></video>
<br>
<span>Make sure this device and the one running OBS are on the same network.</span>
<br>
<button onclick="screenCapture()">Screen Capture</button>
<span id="loadingCameras">Loading video device list...</span>
</span>
</span>
-215
View File
@@ -1,215 +0,0 @@
<style>
* {
font-size: 3vmin;
}
video {
max-width: 100vw;
max-height: 50vh;
}
</style>
<div id="status">Loading...</div>
<div id="permission">
<button onclick="allow()">Allow</button>
<button onclick="deny()">Deny</button>
</div>
<span id="connectionSettings" hidden>
<table>
<tr>
<td>Websocket URL:</td>
<td><input id="obsurl" type="url"></td>
</tr>
<tr>
<td>Websocket Password:</td>
<td><input id="obspassword" type="password"></td>
</tr>
</table>
<button id="connect" onclick="connect()">Connect</button>
<button id="useQR" onclick="useQrCode()">Use QR Code</button>
<br>
<span id="qr" hidden>
<video id="qrvideo" hidden></video>
<br>
<span>Make sure this device and the one running OBS are on the same network.</span>
<br>
<button onclick="screenCapture()">Screen Capture</button>
<span id="loadingCameras">Loading video device list...</span>
</span>
</span>
<script src="https://cdn.jsdelivr.net/npm/obs-websocket-js@5.0.1/dist/obs-ws.min.js"
integrity="sha256-UbkntZrYTokZf8tldcF9nmOn5CNgcmDP+MNsUcKUpEE=" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/qr-scanner@1.4.1/qr-scanner.umd.min.js"
integrity="sha256-jstRoCLjzwXwLN2o0DMkkwRHtqYCQMxrRkktAHwZekU=" crossorigin="anonymous">
</script>
<script>
const params = new URLSearchParams(window.location.search)
const redirect_uri = params.get('redirect_uri')
document.querySelector('#status').innerHTML = 'The website at:<br>' + redirect_uri + '<br>wants to connect to your OBS Websocket.<br>This will give them FULL CONTROL OF OBS.'
document.querySelector('#permission').hidden = false
const obs = new OBSWebSocket()
async function connect() {
document.querySelector('#status').innerHTML = 'Connecting to OBS...'
const url=document.querySelector('#obsurl').value
const password=document.querySelector('#obspassword').value
try {
await obs.connect(url,password)
} catch (error) {
const status=document.querySelector('#status')
if(status.innerHTML='Connecting to OBS...'){
status.innerHTML=error
}
return false
}
return true
}
let interval
const video = document.querySelector('video')
async function useQrCode() {
console.log('starting QR Code scanner')
interval = setInterval(qrScan, 1000)
const qr = document.querySelector('#qr')
qr.hidden = false
video.srcObject = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })
let mediaDevices = await navigator.mediaDevices.enumerateDevices()
mediaDevices = mediaDevices.filter(function (device) {
return device.kind == "videoinput"
})
for (const device of mediaDevices) {
const button = document.createElement('button')
button.innerHTML = device.label
button.onclick = function () { switchCamera(device) }
qr.appendChild(button)
}
document.querySelector('#loadingCameras').hidden = true
}
async function screenCapture() {
video.srcObject = null
const screenCaptureDevice = await navigator.mediaDevices.getDisplayMedia()
video.srcObject = screenCaptureDevice
video.play()
video.hidden = false
}
async function switchCamera(device) {
video.srcObject = null
const camera = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: device.deviceId } } })
video.srcObject = camera
video.play()
video.hidden = false
}
function qrScan() {
QrScanner.scanImage(video, { returnDetailedScanResult: true })
.then(onQrScan).catch(function (error) { console.warn(error) })
}
async function onQrScan(result) {
var data = result.data.split('/')
if (data.shift() != 'obsws:') {
console.log('found non-OBS QR Code')
return false
}
clearInterval(interval)
console.log('found OBS QR Code')
data.shift()
const fullurl = 'ws://' + data.shift()
const port = fullurl.split(':').pop()
const localurl = 'ws://localhost:' + port
const password = data.shift()
const obsurl = document.querySelector('#obsurl')
const obspassword = document.querySelector('#obspassword')
obspassword.value = password
obsurl.value = localurl
console.log('attempting localhost connection')
if (await connect()) {
return true
}
obsurl.value = fullurl
console.log('attempting local network connection')
if (await connect()) {
return true
}
return false
}
obs.addListener('ConnectionError', function onConnectionError(error){
document.querySelector('#status').innerHTML=error
})
obs.addListener('ConnectionClosed', function onConnectionClosed(error) {
switch (error.code) {
case 1000:
console.log('unknown error, trying again')
connect()
break
case 1006:
document.querySelector('#status').innerHTML = 'obs websocket not found.' +
'<br>Is <a href="https://github.com/obsproject/obs-websocket/releases/latest">obs-websocket</a> installed?' +
'<br>Is obs open? Check your websocket settings in OBS under the Tools menu.' +
'<br>Is the info below correct? Consider using the QR scanner.'
break
case 4009:
document.querySelector('#status').innerHTML = error.message.split(' ').slice(-3).join(' ').toLowerCase().replace('authentication', 'Password') +
'<br>You can view or change your websocket password in OBS under the Tools menu.'
break
default:
document.querySelector('#status').innerHTML = 'connection closed: Error ' + error.code + ': ' + error.message
break
}
})
obs.addListener('ConnectionOpened', function onConnectedOpened() {
console.log('connected to socket, saving url')
document.querySelector('#status').innerHTML = 'Connected'
localStorage.setItem('obsurl', document.querySelector('#obsurl').value)
})
obs.addListener('Identified', function onIdentified() {
console.log('authentication passed, saving password')
document.querySelector('#status').innerHTML = 'Password Passed'
localStorage.setItem('obspassword', document.querySelector('#obspassword').value)
//obs.disconnect()
redirect()
})
async function redirect() {
try {
document.querySelector('#status').innerHTML = 'Redirecting...'
const url = new URL(redirect_uri)
url.searchParams.append('obsurl', document.querySelector('#obsurl').value)
url.searchParams.append('obspassword', document.querySelector('#obspassword').value)
url.searchParams.append('userChoice', 'allow')
window.location.replace(url.href)
} catch (e) {
document.querySelector('#status').innerHTML = 'Error during redirect: '+e
console.error(e)
}
}
function allow() {
console.log('user allowed connection, attempting to use saved info')
document.querySelector('#permission').hidden = true
document.querySelector('#connectionSettings').hidden = false
document.querySelector('#obsurl').value = localStorage.getItem('obsurl') || 'ws://localhost:4455'
document.querySelector('#obspassword').value = localStorage.getItem('obspassword') || ''
connect()
}
function deny() {
console.log('user denied connection, returning to redirect_uri')
const url = new URL(redirect_uri)
url.searchParams.append('userChoice', 'deny')
window.location.replace(url.href)
}
async function bypass(){
const url=document.querySelector('#obsurl').value
await navigator.clipboard.writeText(url)
}
</script>
+2145
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
{
"scripts": {
"test": "wrangler dev --ip=localhost"
},
"dependencies": {
"obs-websocket-js": "^5.0.7",
"qr-scanner": "^1.4.2"
},
"devDependencies": {
"esbuild": "^0.27.2",
"wrangler": "^4.56.0"
}
}
+184
View File
@@ -0,0 +1,184 @@
import QrScanner from "qr-scanner"
import OBSWebSocket from "obs-websocket-js"
const params = new URLSearchParams(window.location.search)
const redirect_uri = params.get('redirect_uri')
document.querySelector('#status').innerHTML = 'The website at:<br>' + redirect_uri + '<br>wants to connect to your OBS Websocket.<br>This will give them FULL CONTROL OF OBS.'
document.querySelector('#permission').hidden = false
const obs = new OBSWebSocket()
async function connect() {
document.querySelector('#status').innerHTML = 'Connecting to OBS...'
const url = document.querySelector('#obsurl').value
const password = document.querySelector('#obspassword').value
try {
await obs.connect(url, password)
} catch (error) {
const status = document.querySelector('#status')
if (status.innerHTML = 'Connecting to OBS...') {
status.innerHTML = error
}
return false
}
return true
}
let interval
const video = document.querySelector('video')
async function useQrCode() {
console.log('starting QR Code scanner')
interval = setInterval(qrScan, 1000)
const qr = document.querySelector('#qr')
qr.hidden = false
video.srcObject = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } })
let mediaDevices = await navigator.mediaDevices.enumerateDevices()
mediaDevices = mediaDevices.filter(function (device) {
return device.kind == "videoinput"
})
for (const device of mediaDevices) {
const button = document.createElement('button')
button.innerHTML = device.label
button.onclick = function () { switchCamera(device) }
qr.appendChild(button)
}
document.querySelector('#loadingCameras').hidden = true
}
async function screenCapture() {
video.srcObject = null
const screenCaptureDevice = await navigator.mediaDevices.getDisplayMedia()
video.srcObject = screenCaptureDevice
video.play()
video.hidden = false
}
async function switchCamera(device) {
video.srcObject = null
const camera = await navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: device.deviceId } } })
video.srcObject = camera
video.play()
video.hidden = false
}
function qrScan() {
QrScanner.scanImage(video, { returnDetailedScanResult: true })
.then(onQrScan).catch(function (error) { console.warn(error) })
}
async function onQrScan(result) {
var data = result.data.split('/')
if (data.shift() != 'obsws:') {
console.log('found non-OBS QR Code')
return false
}
clearInterval(interval)
console.log('found OBS QR Code')
data.shift()
const fullurl = 'ws://' + data.shift()
const port = fullurl.split(':').pop()
const localurl = 'ws://localhost:' + port
const password = data.shift()
const obsurl = document.querySelector('#obsurl')
const obspassword = document.querySelector('#obspassword')
obspassword.value = password
obsurl.value = localurl
console.log('attempting localhost connection')
if (await connect()) {
return true
}
obsurl.value = fullurl
console.log('attempting local network connection')
if (await connect()) {
return true
}
return false
}
obs.addListener('ConnectionError', function onConnectionError(error) {
document.querySelector('#status').innerHTML = error
})
obs.addListener('ConnectionClosed', function onConnectionClosed(error) {
switch (error.code) {
case 1000:
console.log('unknown error, trying again')
connect()
break
case 1006:
document.querySelector('#status').innerHTML = 'obs websocket not found.' +
'<br>Is <a href="https://github.com/obsproject/obs-websocket/releases/latest">obs-websocket</a> installed?' +
'<br>Is obs open? Check your websocket settings in OBS under the Tools menu.' +
'<br>Is the info below correct? Consider using the QR scanner.'
break
case 4009:
document.querySelector('#status').innerHTML = error.message.split(' ').slice(-3).join(' ').toLowerCase().replace('authentication', 'Password') +
'<br>You can view or change your websocket password in OBS under the Tools menu.'
break
default:
document.querySelector('#status').innerHTML = 'connection closed: Error ' + error.code + ': ' + error.message
break
}
})
obs.addListener('ConnectionOpened', function onConnectedOpened() {
console.log('connected to socket, saving url')
document.querySelector('#status').innerHTML = 'Connected'
localStorage.setItem('obsurl', document.querySelector('#obsurl').value)
})
obs.addListener('Identified', function onIdentified() {
console.log('authentication passed, saving password')
document.querySelector('#status').innerHTML = 'Password Passed'
localStorage.setItem('obspassword', document.querySelector('#obspassword').value)
//obs.disconnect()
redirect()
})
async function redirect() {
try {
document.querySelector('#status').innerHTML = 'Redirecting...'
const url = new URL(redirect_uri)
url.searchParams.append('obsurl', document.querySelector('#obsurl').value)
url.searchParams.append('obspassword', document.querySelector('#obspassword').value)
url.searchParams.append('userChoice', 'allow')
window.location.replace(url.href)
} catch (e) {
document.querySelector('#status').innerHTML = 'Error during redirect: ' + e
console.error(e)
}
}
function allow() {
console.log('user allowed connection, attempting to use saved info')
document.querySelector('#permission').hidden = true
document.querySelector('#connectionSettings').hidden = false
document.querySelector('#skip').hidden = false
document.querySelector('#obsurl').value = localStorage.getItem('obsurl') || 'ws://localhost:4455'
document.querySelector('#obspassword').value = localStorage.getItem('obspassword') || ''
connect()
}
function deny() {
console.log('user denied connection, returning to redirect_uri')
const url = new URL(redirect_uri)
url.searchParams.append('userChoice', 'deny')
window.location.replace(url.href)
}
async function bypass() {
const url = document.querySelector('#obsurl').value
await navigator.clipboard.writeText(url)
}
function skipVerification() {
localStorage.setItem('obsurl', document.querySelector('#obsurl').value)
localStorage.setItem('obspassword', document.querySelector('#obspassword').value)
redirect()
}
globalThis.allow = allow
globalThis.deny = deny
globalThis.connect = connect
globalThis.useQrCode = useQrCode
globalThis.screenCapture = screenCapture
globalThis.skipVerification = skipVerification
+12
View File
@@ -0,0 +1,12 @@
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "obs-connect",
"compatibility_date": "2025-12-20",
"assets": {"directory": "assets"},
"workers_dev": false,
"keep_vars": true,
"build": {
"watch_dir": "./src",
"command": "esbuild --outdir=assets --format=esm --bundle --minify --sourcemap --sources-content src/*"
}
}