mirror of
https://github.com/koush/scrypted.git
synced 2026-03-15 22:52:44 +00:00
144 lines
6.0 KiB
TypeScript
144 lines
6.0 KiB
TypeScript
import path from 'path';
|
|
import { ScryptedDeviceBase, DeviceProvider, ScryptedInterface, ScryptedDeviceType, BufferConverter, MediaObject, VideoCamera, Camera, ScryptedMimeTypes, RequestMediaStreamOptions, HttpRequestHandler, HttpRequest, HttpResponse, RequestMediaObject } from '@scrypted/sdk';
|
|
import sdk from '@scrypted/sdk';
|
|
const { systemManager, deviceManager, mediaManager, endpointManager } = sdk;
|
|
import { RequestMediaObjectHost, FileHost, BufferHost } from './converters';
|
|
import url from 'url';
|
|
|
|
export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, BufferConverter, HttpRequestHandler {
|
|
httpHost: BufferHost;
|
|
httpsHost: BufferHost;
|
|
rmoHost: RequestMediaObjectHost;
|
|
fileHost: FileHost;
|
|
filesHost: FileHost;
|
|
|
|
constructor(nativeId: string) {
|
|
super(nativeId);
|
|
|
|
this.fromMimeType = ScryptedMimeTypes.SchemePrefix + 'scrypted-media';
|
|
this.toMimeType = ScryptedMimeTypes.MediaObject;
|
|
|
|
(async () => {
|
|
await deviceManager.onDevicesChanged({
|
|
providerNativeId: this.nativeId,
|
|
devices: [
|
|
{
|
|
name: 'HTTP Buffer Host',
|
|
nativeId: 'http',
|
|
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
|
|
type: ScryptedDeviceType.API,
|
|
},
|
|
{
|
|
providerNativeId: this.nativeId,
|
|
name: 'HTTPS Buffer Host',
|
|
nativeId: 'https',
|
|
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
|
|
type: ScryptedDeviceType.API,
|
|
},
|
|
{
|
|
name: 'RequestMediaObject Host',
|
|
nativeId: 'rmo-host',
|
|
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
|
|
type: ScryptedDeviceType.API,
|
|
},
|
|
{
|
|
name: 'HTTP File Host',
|
|
nativeId: 'file',
|
|
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
|
|
type: ScryptedDeviceType.API,
|
|
},
|
|
{
|
|
providerNativeId: this.nativeId,
|
|
name: 'HTTPS File Host',
|
|
nativeId: 'files',
|
|
interfaces: [ScryptedInterface.BufferConverter, ScryptedInterface.HttpRequestHandler],
|
|
type: ScryptedDeviceType.API,
|
|
},
|
|
]
|
|
})
|
|
this.httpHost = new BufferHost(false);
|
|
this.httpsHost = new BufferHost(true);
|
|
this.rmoHost = new RequestMediaObjectHost();
|
|
this.fileHost = new FileHost(false);
|
|
this.filesHost = new FileHost(true);
|
|
})();
|
|
}
|
|
|
|
async onRequest(request: HttpRequest, response: HttpResponse): Promise<void> {
|
|
if (request.isPublicEndpoint) {
|
|
response.send('', {
|
|
code: 404,
|
|
});
|
|
return;
|
|
}
|
|
const pathname = request.url.substring(request.rootPath.length);
|
|
const [_, id, iface] = pathname.split('/');
|
|
try {
|
|
if (iface !== ScryptedInterface.Camera)
|
|
throw new Error();
|
|
|
|
const search = new URLSearchParams(pathname.split('?')[1]);
|
|
|
|
const picture = await systemManager.getDeviceById<Camera>(id).takePicture({
|
|
picture: {
|
|
width: parseInt(search.get('width')) || undefined,
|
|
height: parseInt(search.get('height')) || undefined,
|
|
}
|
|
});
|
|
const buffer = await mediaManager.convertMediaObjectToBuffer(picture, 'image/jpeg');
|
|
|
|
response.send(buffer, {
|
|
headers: {
|
|
'Content-Type': 'image/jpeg',
|
|
'Cache-Control': 'max-age=10',
|
|
}
|
|
});
|
|
}
|
|
catch (e) {
|
|
response.send('', {
|
|
code: 500,
|
|
});
|
|
}
|
|
}
|
|
|
|
async getLocalSnapshot(id: string, iface: string, search: string) {
|
|
const endpoint = await endpointManager.getAuthenticatedPath(this.nativeId);
|
|
const ret = url.resolve(path.join(endpoint, id, iface, `${Date.now()}.jpg`) + `${search}`, '');
|
|
return mediaManager.createMediaObject(Buffer.from(ret), ScryptedMimeTypes.LocalUrl);
|
|
}
|
|
|
|
async convert(data: string, fromMimeType: string, toMimeType: string): Promise<MediaObject> {
|
|
const url = new URL(data.toString());
|
|
const id = url.hostname;
|
|
const path = url.pathname.split('/')[1];
|
|
if (path === ScryptedInterface.Camera) {
|
|
if (toMimeType === ScryptedMimeTypes.LocalUrl)
|
|
return this.getLocalSnapshot(id, path, url.search);
|
|
const rmo: RequestMediaObject = async () => systemManager.getDeviceById<Camera>(id).takePicture();
|
|
return mediaManager.createMediaObject(rmo, ScryptedMimeTypes.RequestMediaObject);
|
|
}
|
|
if (path === ScryptedInterface.VideoCamera) {
|
|
const rmo: RequestMediaObject = async () => systemManager.getDeviceById<VideoCamera>(id).getVideoStream();
|
|
return mediaManager.createMediaObject(rmo, ScryptedMimeTypes.RequestMediaObject);
|
|
}
|
|
else {
|
|
throw new Error('Unrecognized Scrypted Media interface.')
|
|
}
|
|
}
|
|
|
|
async getDevice(nativeId: string) {
|
|
if (nativeId === 'http')
|
|
return this.httpHost;
|
|
if (nativeId === 'https')
|
|
return this.httpsHost;
|
|
if (nativeId === 'rmo-host')
|
|
return this.rmoHost;
|
|
if (nativeId === 'file')
|
|
return this.fileHost;
|
|
if (nativeId === 'files')
|
|
return this.filesHost;
|
|
}
|
|
|
|
async releaseDevice(id: string, nativeId: string): Promise<void> {
|
|
}
|
|
} |