mirror of
https://github.com/koush/scrypted.git
synced 2026-02-09 00:39:56 +00:00
core: publish beta
This commit is contained in:
4
plugins/core/package-lock.json
generated
4
plugins/core/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/core",
|
||||
"version": "0.1.61",
|
||||
"version": "0.1.62",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/core",
|
||||
"version": "0.1.61",
|
||||
"version": "0.1.62",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/core",
|
||||
"version": "0.1.61",
|
||||
"version": "0.1.62",
|
||||
"description": "Scrypted Core plugin. Provides the UI, websocket, and engine.io APIs.",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BufferConverter, HttpRequest, HttpRequestHandler, HttpResponse, HttpResponseOptions, ScryptedDeviceBase, ScryptedMimeTypes } from "@scrypted/sdk";
|
||||
import { BufferConverter, BufferConvertorOptions, HttpRequest, HttpRequestHandler, HttpResponse, HttpResponseOptions, MediaObject, RequestMediaObject, ScryptedDeviceBase, ScryptedMimeTypes } from "@scrypted/sdk";
|
||||
import sdk from "@scrypted/sdk";
|
||||
import mime from "mime/lite";
|
||||
import path from 'path';
|
||||
@@ -65,6 +65,87 @@ export class BufferHost extends ScryptedDeviceBase implements HttpRequestHandler
|
||||
}
|
||||
}
|
||||
|
||||
export class RequestMediaObjectHost extends ScryptedDeviceBase implements HttpRequestHandler, BufferConverter {
|
||||
secureHosted = new Map<string, { request: RequestMediaObject, fromMimeType: string, toMimeType: string }>()
|
||||
insecureHosted = new Map<string, { request: RequestMediaObject, fromMimeType: string, toMimeType: string }>()
|
||||
|
||||
constructor() {
|
||||
super('rmo-host');
|
||||
this.fromMimeType = ScryptedMimeTypes.RequestMediaObject;
|
||||
this.toMimeType = ScryptedMimeTypes.MediaObject;
|
||||
// this.toMimeType = secure ? ScryptedMimeTypes.LocalUrl : ScryptedMimeTypes.InsecureLocalUrl;
|
||||
}
|
||||
|
||||
async onRequest(request: HttpRequest, response: HttpResponse) {
|
||||
const normalizedRequest = Object.assign({}, request);
|
||||
normalizedRequest.url = normalizedRequest.url.replace(normalizedRequest.rootPath, '');
|
||||
const pathOnly = normalizedRequest.url.split('?')[0];
|
||||
const file = this.secureHosted.get(pathOnly) || this.insecureHosted.get(pathOnly);;
|
||||
|
||||
if (!file) {
|
||||
response.send('Not Found', {
|
||||
code: 404,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
let options: HttpResponseOptions = {
|
||||
headers: {
|
||||
'Content-Type': file.fromMimeType,
|
||||
}
|
||||
};
|
||||
|
||||
const q = new URLSearchParams(request.url.split('?')[1]);
|
||||
if (q.has('attachment')) {
|
||||
options.headers['Content-Disposition'] = 'attachment';
|
||||
}
|
||||
|
||||
try {
|
||||
const mo = await file.request();
|
||||
const data = await sdk.mediaManager.convertMediaObjectToBuffer(mo, mo.mimeType);
|
||||
|
||||
response.send(data);
|
||||
}
|
||||
catch (e) {
|
||||
this.secureHosted.delete(pathOnly);
|
||||
this.insecureHosted.delete(pathOnly);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async convert(request: RequestMediaObject, fromMimeType: string, toMimeType: string): Promise<MediaObject> {
|
||||
let hosted: typeof this.secureHosted;
|
||||
if (toMimeType === ScryptedMimeTypes.Url || toMimeType === ScryptedMimeTypes.LocalUrl) {
|
||||
hosted = this.secureHosted;
|
||||
toMimeType = ScryptedMimeTypes.LocalUrl;
|
||||
}
|
||||
else if (toMimeType === ScryptedMimeTypes.InsecureLocalUrl) {
|
||||
hosted = this.insecureHosted;
|
||||
}
|
||||
else {
|
||||
return request();
|
||||
}
|
||||
|
||||
const uuid = uuidv4();
|
||||
|
||||
const endpoint = await (toMimeType === ScryptedMimeTypes.LocalUrl ? endpointManager.getPublicLocalEndpoint(this.nativeId) : endpointManager.getInsecurePublicLocalEndpoint(this.nativeId));
|
||||
const data = await request();
|
||||
fromMimeType = data.mimeType;
|
||||
const extension = mime.getExtension(fromMimeType);
|
||||
|
||||
const filename = uuid + (extension ? `.${extension}` : '');
|
||||
|
||||
const pathOnly = `/${filename}`;
|
||||
hosted.set(pathOnly, { request, fromMimeType, toMimeType });
|
||||
// free this resource after an hour.
|
||||
setTimeout(() => hosted.delete(pathOnly), 1 * 60 * 60 * 1000);
|
||||
|
||||
const url = Buffer.from(`${endpoint}${filename}`);
|
||||
return sdk.mediaManager.createMediaObject(url, toMimeType);
|
||||
}
|
||||
}
|
||||
|
||||
export class FileHost extends ScryptedDeviceBase implements HttpRequestHandler, BufferConverter {
|
||||
hosted = new Map<string, { data: Buffer | string }>()
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import path from 'path';
|
||||
import { ScryptedDeviceBase, DeviceProvider, ScryptedInterface, ScryptedDeviceType, BufferConverter, MediaObject, VideoCamera, Camera, ScryptedMimeTypes, RequestMediaStreamOptions, HttpRequestHandler, HttpRequest, HttpResponse } from '@scrypted/sdk';
|
||||
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 { BufferHost, FileHost } from './converters';
|
||||
import { RequestMediaObjectHost, FileHost, BufferHost } from './converters';
|
||||
|
||||
export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, BufferConverter, HttpRequestHandler {
|
||||
httpHost: BufferHost;
|
||||
httpsHost: BufferHost;
|
||||
rmoHost: RequestMediaObjectHost;
|
||||
fileHost: FileHost;
|
||||
filesHost: FileHost;
|
||||
|
||||
@@ -33,6 +34,12 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
|
||||
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',
|
||||
@@ -50,6 +57,7 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
|
||||
})
|
||||
this.httpHost = new BufferHost(false);
|
||||
this.httpsHost = new BufferHost(true);
|
||||
this.rmoHost = new RequestMediaObjectHost();
|
||||
this.fileHost = new FileHost(false);
|
||||
this.filesHost = new FileHost(true);
|
||||
})();
|
||||
@@ -105,10 +113,12 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
|
||||
if (path === ScryptedInterface.Camera) {
|
||||
if (toMimeType === ScryptedMimeTypes.LocalUrl)
|
||||
return this.getLocalSnapshot(id, path, url.search);
|
||||
return await systemManager.getDeviceById<Camera>(id).takePicture() as any;
|
||||
const rmo: RequestMediaObject = async () => systemManager.getDeviceById<Camera>(id).takePicture();
|
||||
return mediaManager.createMediaObject(rmo, ScryptedMimeTypes.RequestMediaObject);
|
||||
}
|
||||
if (path === ScryptedInterface.VideoCamera) {
|
||||
return await systemManager.getDeviceById<VideoCamera>(id).getVideoStream() as any;
|
||||
const rmo: RequestMediaObject = async () => systemManager.getDeviceById<VideoCamera>(id).getVideoStream();
|
||||
return mediaManager.createMediaObject(rmo, ScryptedMimeTypes.RequestMediaObject);
|
||||
}
|
||||
else {
|
||||
throw new Error('Unrecognized Scrypted Media interface.')
|
||||
@@ -120,6 +130,8 @@ export class MediaCore extends ScryptedDeviceBase implements DeviceProvider, Buf
|
||||
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')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<v-autocomplete :small-chips="multiple" v-model="lazyValue" :items="devices" item-value="id" outlined :multiple="multiple"
|
||||
<v-autocomplete dense :small-chips="multiple" v-model="lazyValue" :items="devices" item-value="id" outlined :multiple="multiple"
|
||||
:label="title" :hint="description" persistent-hint @change="onInput">
|
||||
<template v-slot:append-outer>
|
||||
<slot name="append-outer"></slot>
|
||||
|
||||
@@ -3,37 +3,12 @@
|
||||
<v-container>
|
||||
<v-layout>
|
||||
<v-flex xs12>
|
||||
<v-text-field
|
||||
dense
|
||||
label="Notification Title"
|
||||
outlined
|
||||
v-model="lazyValue.notificationTitle"
|
||||
@input="onChange"
|
||||
></v-text-field>
|
||||
<v-text-field
|
||||
dense
|
||||
label="Notification Body"
|
||||
outlined
|
||||
v-model="lazyValue.notificationBody"
|
||||
@input="onChange"
|
||||
></v-text-field>
|
||||
<v-combobox
|
||||
dense
|
||||
@select="onSelect"
|
||||
:items="mediaInterfaces"
|
||||
label="Notification Media URL"
|
||||
outlined
|
||||
v-model="lazyValue.notificationMediaUrl"
|
||||
@input="onChange"
|
||||
:return-object="false"
|
||||
></v-combobox>
|
||||
<v-text-field
|
||||
dense
|
||||
label="Notification Media Mime Type"
|
||||
outlined
|
||||
v-model="lazyValue.notificationMediaMime"
|
||||
@input="onChange"
|
||||
></v-text-field>
|
||||
<v-text-field dense label="Notification Title" outlined v-model="lazyValue.notificationTitle"
|
||||
@input="onChange"></v-text-field>
|
||||
<v-text-field dense label="Notification Body" outlined v-model="lazyValue.notificationBody"
|
||||
@input="onChange"></v-text-field>
|
||||
<v-combobox dense :items="mediaInterfaces" label="Notification Media URL" outlined
|
||||
v-model="lazyValue.notificationMediaUrl" @input="onChange" :return-object="false"></v-combobox>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
@@ -64,14 +39,17 @@ export default {
|
||||
if (this.lazyValue.notificationMediaUrl.length) {
|
||||
this.rpc().sendNotification(
|
||||
this.lazyValue.notificationTitle,
|
||||
this.lazyValue.notificationBody,
|
||||
{
|
||||
body: this.lazyValue.notificationBody,
|
||||
},
|
||||
this.lazyValue.notificationMediaUrl,
|
||||
this.lazyValue.notificationMediaMime
|
||||
);
|
||||
} else {
|
||||
this.rpc().sendNotification(
|
||||
this.lazyValue.notificationTitle,
|
||||
this.lazyValue.notificationBody
|
||||
{
|
||||
body: this.lazyValue.notificationBody,
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -89,10 +67,6 @@ export default {
|
||||
ret.notificationMediaUrl,
|
||||
"https://home.scrypted.app/_punch/web_hi_res_512.png"
|
||||
);
|
||||
ret.notificationMediaMime = this.ensureString(
|
||||
ret.notificationMediaMime,
|
||||
"image/png"
|
||||
);
|
||||
return ret;
|
||||
},
|
||||
onChange: function () {
|
||||
@@ -104,9 +78,6 @@ export default {
|
||||
send() {
|
||||
this.update();
|
||||
},
|
||||
onSelect() {
|
||||
this.lazyValue.notificationMediaMime = "";
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
mediaInterfaces() {
|
||||
|
||||
Reference in New Issue
Block a user