-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fcf9536
commit a15eac1
Showing
45 changed files
with
604 additions
and
604 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
{ | ||
"name": "@sceneify/core-old", | ||
"version": "1.0.0-beta.0", | ||
"description": "", | ||
"main": "./cjs/index.cjs", | ||
"browser": "./lib/index.js", | ||
"module": "./esm/index.js", | ||
"types": "./dts/index.d.ts", | ||
"author": "", | ||
"license": "ISC", | ||
"scripts": { | ||
"test": "jest -i" | ||
}, | ||
"dependencies": { | ||
"next-tick": "^1.1.0", | ||
"obs-websocket-js": "5.0.1" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^27.0.3", | ||
"@types/next-tick": "^1.0.0", | ||
"@types/node": "^16.9.3", | ||
"@types/ws": "^7.4.6", | ||
"jest": "^27.4.5" | ||
}, | ||
"files": [ | ||
"cjs/**/*.{cjs,map}", | ||
"dist", | ||
"dts", | ||
"esm/**/*.{js,map}", | ||
"lib", | ||
"lib/**/*.{js,map}", | ||
"src/**/*.{ts,tsx,json}" | ||
], | ||
"packemon": [ | ||
{ | ||
"format": "cjs", | ||
"platform": "node" | ||
}, | ||
{ | ||
"format": [ | ||
"lib", | ||
"esm" | ||
], | ||
"platform": "browser" | ||
} | ||
], | ||
"engines": { | ||
"node": ">=12.17.0", | ||
"npm": ">=6.13.0" | ||
}, | ||
"jest": { | ||
"preset": "ts-jest", | ||
"globals": { | ||
"ts-jest": { | ||
"tsconfig": "<rootDir>/tests/tsconfig.json" | ||
} | ||
} | ||
}, | ||
"type": "commonjs" | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
import ObsWebSocket, { EventSubscription } from "obs-websocket-js"; | ||
|
||
import { | ||
OBSEventTypes, | ||
OBSRequestTypes, | ||
OBSResponseTypes, | ||
Settings, | ||
} from "./types"; | ||
import { Scene } from "./Scene"; | ||
import { Input } from "./Input"; | ||
import { SourceRefs } from "./Source"; | ||
|
||
export class OBS { | ||
/** | ||
* The OBS websocket connection used internally | ||
*/ | ||
socket = new ObsWebSocket(); | ||
|
||
/** | ||
* All of the sources that this OBS instance has access to, excluding scenes | ||
*/ | ||
inputs = new Map<string, Input>(); | ||
|
||
/** | ||
* All of the scenes that this OBS instance has access to | ||
*/ | ||
scenes = new Map<string, Scene>(); | ||
|
||
/** @internal */ | ||
rpcVersion!: number; | ||
|
||
/** | ||
* Connect this OBS instance to a websocket | ||
*/ | ||
async connect(url: string, password?: string) { | ||
const data = await this.socket.connect(url, password, { | ||
eventSubscriptions: | ||
EventSubscription.Scenes | | ||
EventSubscription.Inputs | | ||
EventSubscription.Filters | | ||
EventSubscription.SceneItems | | ||
EventSubscription.MediaInputs, | ||
}); | ||
|
||
this.rpcVersion = data.negotiatedRpcVersion; | ||
|
||
this.inputs.clear(); | ||
this.scenes.clear(); | ||
} | ||
|
||
/** | ||
* Goes though each source in OBS and removes it if Sceneify owns it, | ||
* and there are no references to the source in code. | ||
*/ | ||
async clean() { | ||
const { scenes } = await this.call("GetSceneList"); | ||
const { inputs } = await this.call("GetInputList"); | ||
|
||
const sourcesSettings = await Promise.all( | ||
[ | ||
...scenes.map((s) => s.sceneName), | ||
...inputs.map((i) => i.inputName), | ||
].map(async (sourceName) => { | ||
const { sourceSettings } = await this.call("GetSourcePrivateSettings", { | ||
sourceName, | ||
}).catch(() => ({ | ||
sourceName, | ||
sourceSettings: {} as Settings, | ||
})); | ||
|
||
return { | ||
sourceName, | ||
sourceSettings, | ||
}; | ||
}) | ||
); | ||
|
||
const sourcesRefs = sourcesSettings.reduce( | ||
(acc, data) => ({ | ||
...acc, | ||
...(data.sourceSettings.SCENEIFY_LINKED === false && | ||
data.sourceSettings.SCENEIFY_REFS | ||
? { [data.sourceName]: data.sourceSettings.SCENEIFY_REFS } | ||
: {}), | ||
}), | ||
{} as Record<string, SourceRefs> | ||
); | ||
|
||
// Delete refs that are actually in use | ||
for (let [_, scene] of this.scenes) { | ||
for (let item of scene.items) { | ||
delete sourcesRefs[item.source.name]?.[scene.name]?.[item.ref]; | ||
|
||
if ( | ||
Object.keys(sourcesRefs[item.source.name]?.[scene.name] ?? {}) | ||
.length === 0 | ||
) { | ||
delete sourcesRefs[item.source.name]?.[scene.name]; | ||
} | ||
|
||
if (Object.keys(sourcesRefs[item.source.name] ?? {}).length === 0) { | ||
delete sourcesRefs[item.source.name]; | ||
} | ||
} | ||
} | ||
|
||
const danglingItems = Object.values(sourcesRefs) | ||
.filter((r) => r !== undefined) | ||
.reduce( | ||
(acc, sourceRefs) => { | ||
let danglingInputItems = []; | ||
|
||
for (let [sceneName, refs] of Object.entries(sourceRefs)) { | ||
for (let sceneItemId of Object.values(refs)) { | ||
if (sourceRefs[sceneName] !== undefined) | ||
danglingInputItems.push({ | ||
sceneName, | ||
sceneItemId, | ||
}); | ||
} | ||
} | ||
|
||
return [...acc, ...danglingInputItems]; | ||
}, | ||
[] as { | ||
sceneName: string; | ||
sceneItemId: number; | ||
}[] | ||
); | ||
|
||
await Promise.all( | ||
danglingItems.map((data) => | ||
this.call("RemoveSceneItem", data).catch(() => {}) | ||
) | ||
); | ||
|
||
const danglingOBSScenes = scenes.filter( | ||
({ sceneName }) => | ||
!this.scenes.has(sceneName) && sourcesRefs[sceneName] !== undefined | ||
); | ||
|
||
await Promise.all( | ||
danglingOBSScenes.map(({ sceneName }) => | ||
this.call("RemoveScene", { sceneName }).catch(() => {}) | ||
) | ||
); | ||
|
||
for (let danglingCodeScene of this.scenes.keys()) { | ||
if (scenes.every(({ sceneName }) => sceneName !== danglingCodeScene)) | ||
this.scenes.delete(danglingCodeScene); | ||
} | ||
|
||
for (let danglingCodeInputs of this.inputs.keys()) { | ||
if (inputs.every(({ inputName }) => inputName !== danglingCodeInputs)) | ||
this.inputs.delete(danglingCodeInputs); | ||
} | ||
|
||
// TODO: Clean filters | ||
await Promise.all( | ||
[...[...this.inputs.values()], ...[...this.scenes.values()]].map( | ||
(input) => input.refreshRefs().catch(() => {}) | ||
) | ||
); | ||
} | ||
|
||
call<T extends keyof OBSRequestTypes>( | ||
requestType: T, | ||
requestData?: OBSRequestTypes[T] | ||
): Promise<OBSResponseTypes[T]> { | ||
return this.socket.call(requestType as any, requestData as any); | ||
} | ||
|
||
on<T extends keyof OBSEventTypes>( | ||
event: T, | ||
callback: (data: OBSEventTypes[T]) => void | ||
) { | ||
this.socket.on(event, callback as any); | ||
return this; | ||
} | ||
|
||
off<T extends keyof OBSEventTypes>( | ||
event: T, | ||
callback: (data: OBSEventTypes[T]) => void | ||
) { | ||
this.socket.off(event, callback as any); | ||
} | ||
|
||
/** | ||
* Streaming state | ||
*/ | ||
|
||
streaming = false; | ||
|
||
async startStreaming() { | ||
await this.call("StartStream"); | ||
|
||
this.streaming = true; | ||
} | ||
|
||
async stopStreaming() { | ||
await this.call("StopStream"); | ||
|
||
this.streaming = false; | ||
} | ||
|
||
async toggleStreaming() { | ||
const { outputActive } = await this.call("ToggleStream"); | ||
|
||
this.streaming = outputActive; | ||
} | ||
} |
File renamed without changes.
Oops, something went wrong.