@scrypted/server 0.7.93 → 0.7.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of @scrypted/server might be problematic. Click here for more details.
- package/dist/asynciterable-utils.d.ts +2 -0
- package/dist/asynciterable-utils.js +24 -0
- package/dist/asynciterable-utils.js.map +1 -0
- package/dist/cert.d.ts +6 -0
- package/dist/cert.js +75 -0
- package/dist/cert.js.map +1 -0
- package/dist/collection.d.ts +1 -0
- package/dist/collection.js +16 -0
- package/dist/collection.js.map +1 -0
- package/dist/db-types.d.ts +38 -0
- package/dist/db-types.js +45 -0
- package/dist/db-types.js.map +1 -0
- package/dist/event-registry.d.ts +19 -0
- package/dist/event-registry.js +92 -0
- package/dist/event-registry.js.map +1 -0
- package/dist/http-interfaces.d.ts +3 -0
- package/dist/http-interfaces.js +73 -0
- package/dist/http-interfaces.js.map +1 -0
- package/dist/infer-defaults.d.ts +11 -0
- package/dist/infer-defaults.js +119 -0
- package/dist/infer-defaults.js.map +1 -0
- package/dist/io.d.ts +22 -0
- package/dist/io.js +3 -0
- package/dist/io.js.map +1 -0
- package/dist/level.d.ts +110 -0
- package/dist/level.js +135 -0
- package/dist/level.js.map +1 -0
- package/dist/listen-zero.d.ts +13 -0
- package/dist/listen-zero.js +48 -0
- package/dist/listen-zero.js.map +1 -0
- package/dist/logger.d.ts +29 -0
- package/dist/logger.js +78 -0
- package/dist/logger.js.map +1 -0
- package/dist/media-helpers.d.ts +5 -0
- package/dist/media-helpers.js +89 -0
- package/dist/media-helpers.js.map +1 -0
- package/dist/mixin/mixin-cycle.d.ts +3 -0
- package/dist/mixin/mixin-cycle.js +32 -0
- package/dist/mixin/mixin-cycle.js.map +1 -0
- package/dist/plugin/acl.d.ts +16 -0
- package/dist/plugin/acl.js +83 -0
- package/dist/plugin/acl.js.map +1 -0
- package/dist/plugin/descriptor.d.ts +22 -0
- package/dist/plugin/descriptor.js +35 -0
- package/dist/plugin/descriptor.js.map +1 -0
- package/dist/plugin/media.d.ts +71 -0
- package/dist/plugin/media.js +420 -0
- package/dist/plugin/media.js.map +1 -0
- package/dist/plugin/mediaobject.d.ts +10 -0
- package/dist/plugin/mediaobject.js +26 -0
- package/dist/plugin/mediaobject.js.map +1 -0
- package/dist/plugin/plugin-api.d.ts +106 -0
- package/dist/plugin/plugin-api.js +120 -0
- package/dist/plugin/plugin-api.js.map +1 -0
- package/dist/plugin/plugin-console.d.ts +28 -0
- package/dist/plugin/plugin-console.js +291 -0
- package/dist/plugin/plugin-console.js.map +1 -0
- package/dist/plugin/plugin-debug.d.ts +4 -0
- package/dist/plugin/plugin-debug.js +3 -0
- package/dist/plugin/plugin-debug.js.map +1 -0
- package/dist/plugin/plugin-device.d.ts +54 -0
- package/dist/plugin/plugin-device.js +413 -0
- package/dist/plugin/plugin-device.js.map +1 -0
- package/dist/plugin/plugin-error.d.ts +2 -0
- package/dist/plugin/plugin-error.js +7 -0
- package/dist/plugin/plugin-error.js.map +1 -0
- package/dist/plugin/plugin-host-api.d.ts +43 -0
- package/dist/plugin/plugin-host-api.js +179 -0
- package/dist/plugin/plugin-host-api.js.map +1 -0
- package/dist/plugin/plugin-host.d.ts +45 -0
- package/dist/plugin/plugin-host.js +398 -0
- package/dist/plugin/plugin-host.js.map +1 -0
- package/dist/plugin/plugin-http.d.ts +18 -0
- package/dist/plugin/plugin-http.js +120 -0
- package/dist/plugin/plugin-http.js.map +1 -0
- package/dist/plugin/plugin-lazy-remote.d.ts +31 -0
- package/dist/plugin/plugin-lazy-remote.js +75 -0
- package/dist/plugin/plugin-lazy-remote.js.map +1 -0
- package/dist/plugin/plugin-npm-dependencies.d.ts +8 -0
- package/dist/plugin/plugin-npm-dependencies.js +103 -0
- package/dist/plugin/plugin-npm-dependencies.js.map +1 -0
- package/dist/plugin/plugin-remote-stats.d.ts +8 -0
- package/dist/plugin/plugin-remote-stats.js +30 -0
- package/dist/plugin/plugin-remote-stats.js.map +1 -0
- package/dist/plugin/plugin-remote-websocket.d.ts +29 -0
- package/dist/plugin/plugin-remote-websocket.js +152 -0
- package/dist/plugin/plugin-remote-websocket.js.map +1 -0
- package/dist/plugin/plugin-remote-worker.d.ts +5 -0
- package/dist/plugin/plugin-remote-worker.js +348 -0
- package/dist/plugin/plugin-remote-worker.js.map +1 -0
- package/dist/plugin/plugin-remote.d.ts +75 -0
- package/dist/plugin/plugin-remote.js +598 -0
- package/dist/plugin/plugin-remote.js.map +1 -0
- package/dist/plugin/plugin-repl.d.ts +2 -0
- package/dist/plugin/plugin-repl.js +74 -0
- package/dist/plugin/plugin-repl.js.map +1 -0
- package/dist/plugin/plugin-state-check.d.ts +1 -0
- package/dist/plugin/plugin-state-check.js +27 -0
- package/dist/plugin/plugin-state-check.js.map +1 -0
- package/dist/plugin/plugin-volume.d.ts +3 -0
- package/dist/plugin/plugin-volume.js +31 -0
- package/dist/plugin/plugin-volume.js.map +1 -0
- package/dist/plugin/runtime/child-process-worker.d.ts +20 -0
- package/dist/plugin/runtime/child-process-worker.js +42 -0
- package/dist/plugin/runtime/child-process-worker.js.map +1 -0
- package/dist/plugin/runtime/node-fork-worker.d.ts +9 -0
- package/dist/plugin/runtime/node-fork-worker.js +67 -0
- package/dist/plugin/runtime/node-fork-worker.js.map +1 -0
- package/dist/plugin/runtime/node-thread-worker.d.ts +20 -0
- package/dist/plugin/runtime/node-thread-worker.js +73 -0
- package/dist/plugin/runtime/node-thread-worker.js.map +1 -0
- package/dist/plugin/runtime/python-worker.d.ts +10 -0
- package/dist/plugin/runtime/python-worker.js +91 -0
- package/dist/plugin/runtime/python-worker.js.map +1 -0
- package/dist/plugin/runtime/runtime-worker.d.ts +26 -0
- package/dist/plugin/runtime/runtime-worker.js +3 -0
- package/dist/plugin/runtime/runtime-worker.js.map +1 -0
- package/dist/plugin/socket-serializer.d.ts +5 -0
- package/dist/plugin/socket-serializer.js +17 -0
- package/dist/plugin/socket-serializer.js.map +1 -0
- package/dist/plugin/system.d.ts +39 -0
- package/dist/plugin/system.js +216 -0
- package/dist/plugin/system.js.map +1 -0
- package/dist/rpc-buffer-serializer.d.ts +11 -0
- package/dist/rpc-buffer-serializer.js +30 -0
- package/dist/rpc-buffer-serializer.js.map +1 -0
- package/dist/rpc-serializer.d.ts +24 -0
- package/dist/rpc-serializer.js +144 -0
- package/dist/rpc-serializer.js.map +1 -0
- package/dist/rpc.d.ts +147 -0
- package/dist/rpc.js +689 -0
- package/dist/rpc.js.map +1 -0
- package/dist/runtime.d.ts +103 -0
- package/dist/runtime.js +815 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scrypted-main-exports.d.ts +6 -0
- package/dist/scrypted-main-exports.js +57 -0
- package/dist/scrypted-main-exports.js.map +1 -0
- package/dist/scrypted-main.d.ts +1 -0
- package/dist/scrypted-main.js +8 -0
- package/dist/scrypted-main.js.map +1 -0
- package/dist/scrypted-plugin-main.d.ts +2 -0
- package/dist/scrypted-plugin-main.js +43 -0
- package/dist/scrypted-plugin-main.js.map +1 -0
- package/dist/scrypted-server-main.d.ts +6 -0
- package/dist/scrypted-server-main.js +559 -0
- package/dist/scrypted-server-main.js.map +1 -0
- package/dist/server-settings.d.ts +5 -0
- package/dist/server-settings.js +91 -0
- package/dist/server-settings.js.map +1 -0
- package/dist/services/addresses.d.ts +7 -0
- package/dist/services/addresses.js +43 -0
- package/dist/services/addresses.js.map +1 -0
- package/dist/services/alerts.d.ts +9 -0
- package/dist/services/alerts.js +27 -0
- package/dist/services/alerts.js.map +1 -0
- package/dist/services/cors.d.ts +18 -0
- package/dist/services/cors.js +18 -0
- package/dist/services/cors.js.map +1 -0
- package/dist/services/info.d.ts +5 -0
- package/dist/services/info.js +18 -0
- package/dist/services/info.js.map +1 -0
- package/dist/services/plugin.d.ts +46 -0
- package/dist/services/plugin.js +172 -0
- package/dist/services/plugin.js.map +1 -0
- package/dist/services/service-control.d.ts +8 -0
- package/dist/services/service-control.js +39 -0
- package/dist/services/service-control.js.map +1 -0
- package/dist/services/users.d.ts +19 -0
- package/dist/services/users.js +75 -0
- package/dist/services/users.js.map +1 -0
- package/dist/sleep.d.ts +1 -0
- package/dist/sleep.js +8 -0
- package/dist/sleep.js.map +1 -0
- package/dist/state.d.ts +39 -0
- package/dist/state.js +247 -0
- package/dist/state.js.map +1 -0
- package/dist/threading.d.ts +3 -0
- package/dist/threading.js +93 -0
- package/dist/threading.js.map +1 -0
- package/dist/usertoken.d.ts +11 -0
- package/dist/usertoken.js +52 -0
- package/dist/usertoken.js.map +1 -0
- package/package.json +2 -2
- package/src/plugin/plugin-host-api.ts +3 -1
@@ -0,0 +1,83 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.AccessControls = void 0;
|
4
|
+
/**
|
5
|
+
* Scrypted Access Controls allow selective reading of state, subscription to evemts,
|
6
|
+
* and invocation of methods.
|
7
|
+
* Everything else should be rejected.
|
8
|
+
*/
|
9
|
+
class AccessControls {
|
10
|
+
acl;
|
11
|
+
constructor(acl) {
|
12
|
+
this.acl = acl;
|
13
|
+
}
|
14
|
+
deny(reason = 'User does not have permission') {
|
15
|
+
throw new Error(reason);
|
16
|
+
}
|
17
|
+
shouldRejectDevice(id) {
|
18
|
+
if (this.acl.devicesAccessControls === null)
|
19
|
+
return false;
|
20
|
+
if (!this.acl.devicesAccessControls)
|
21
|
+
return true;
|
22
|
+
const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);
|
23
|
+
return !dacls.length;
|
24
|
+
}
|
25
|
+
shouldRejectProperty(id, property) {
|
26
|
+
if (this.acl.devicesAccessControls === null)
|
27
|
+
return false;
|
28
|
+
if (!this.acl.devicesAccessControls)
|
29
|
+
return true;
|
30
|
+
const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);
|
31
|
+
for (const dacl of dacls) {
|
32
|
+
if (!dacl.properties || dacl.properties.includes(property))
|
33
|
+
return false;
|
34
|
+
}
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
shouldRejectEvent(id, eventDetails) {
|
38
|
+
if (this.acl.devicesAccessControls === null)
|
39
|
+
return false;
|
40
|
+
if (!this.acl.devicesAccessControls)
|
41
|
+
return true;
|
42
|
+
const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);
|
43
|
+
const { property } = eventDetails;
|
44
|
+
if (property) {
|
45
|
+
for (const dacl of dacls) {
|
46
|
+
if (!dacl.properties || dacl.properties.includes(property))
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
const { eventInterface } = eventDetails;
|
51
|
+
for (const dacl of dacls) {
|
52
|
+
if (!dacl.interfaces || dacl.interfaces.includes(eventInterface))
|
53
|
+
return false;
|
54
|
+
}
|
55
|
+
return true;
|
56
|
+
}
|
57
|
+
shouldRejectInterface(id, scryptedInterface) {
|
58
|
+
if (this.acl.devicesAccessControls === null)
|
59
|
+
return false;
|
60
|
+
if (!this.acl.devicesAccessControls)
|
61
|
+
return true;
|
62
|
+
const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);
|
63
|
+
for (const dacl of dacls) {
|
64
|
+
if (!dacl.interfaces || dacl.interfaces.includes(scryptedInterface))
|
65
|
+
return false;
|
66
|
+
}
|
67
|
+
return true;
|
68
|
+
}
|
69
|
+
shouldRejectMethod(id, method) {
|
70
|
+
if (this.acl.devicesAccessControls === null)
|
71
|
+
return false;
|
72
|
+
if (!this.acl.devicesAccessControls)
|
73
|
+
return true;
|
74
|
+
const dacls = this.acl.devicesAccessControls.filter(dacl => dacl.id === id);
|
75
|
+
for (const dacl of dacls) {
|
76
|
+
if (!dacl.methods || dacl.methods.includes(method))
|
77
|
+
return false;
|
78
|
+
}
|
79
|
+
return true;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
exports.AccessControls = AccessControls;
|
83
|
+
//# sourceMappingURL=acl.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"acl.js","sourceRoot":"","sources":["../../src/plugin/acl.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { ScryptedInterface, ScryptedInterfaceDescriptor } from "@scrypted/types";
|
2
|
+
export declare const allInterfaceProperties: string[];
|
3
|
+
export declare function getPropertyInterfaces(descriptors: {
|
4
|
+
[scryptedInterface: string]: ScryptedInterfaceDescriptor;
|
5
|
+
}): {
|
6
|
+
[property: string]: ScryptedInterface;
|
7
|
+
};
|
8
|
+
export declare const propertyInterfaces: {
|
9
|
+
[property: string]: ScryptedInterface;
|
10
|
+
};
|
11
|
+
export declare function getInterfaceMethods(descriptors: {
|
12
|
+
[scryptedInterface: string]: ScryptedInterfaceDescriptor;
|
13
|
+
}, interfaces: Set<string>): string[];
|
14
|
+
export declare function getInterfaceProperties(descriptors: {
|
15
|
+
[scryptedInterface: string]: ScryptedInterfaceDescriptor;
|
16
|
+
}, interfaces: Set<string>): string[];
|
17
|
+
export declare function isValidInterfaceMethod(descriptors: {
|
18
|
+
[scryptedInterface: string]: ScryptedInterfaceDescriptor;
|
19
|
+
}, interfaces: Set<string>, method: string): boolean;
|
20
|
+
export declare function isValidInterfaceProperty(descriptors: {
|
21
|
+
[scryptedInterface: string]: ScryptedInterfaceDescriptor;
|
22
|
+
}, interfaces: string[], property: string): boolean;
|
@@ -0,0 +1,35 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.isValidInterfaceProperty = exports.isValidInterfaceMethod = exports.getInterfaceProperties = exports.getInterfaceMethods = exports.propertyInterfaces = exports.getPropertyInterfaces = exports.allInterfaceProperties = void 0;
|
4
|
+
const types_1 = require("@scrypted/types");
|
5
|
+
exports.allInterfaceProperties = [].concat(...Object.values(types_1.ScryptedInterfaceDescriptors).map(type => type.properties));
|
6
|
+
function getPropertyInterfaces(descriptors) {
|
7
|
+
const propertyInterfaces = {};
|
8
|
+
for (const descriptor of Object.values(descriptors)) {
|
9
|
+
for (const property of descriptor.properties) {
|
10
|
+
propertyInterfaces[property] = descriptor.name;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
return propertyInterfaces;
|
14
|
+
}
|
15
|
+
exports.getPropertyInterfaces = getPropertyInterfaces;
|
16
|
+
exports.propertyInterfaces = getPropertyInterfaces(types_1.ScryptedInterfaceDescriptors);
|
17
|
+
function getInterfaceMethods(descriptors, interfaces) {
|
18
|
+
return Object.values(descriptors).filter(e => interfaces.has(e.name)).map(type => type.methods).flat();
|
19
|
+
}
|
20
|
+
exports.getInterfaceMethods = getInterfaceMethods;
|
21
|
+
function getInterfaceProperties(descriptors, interfaces) {
|
22
|
+
return Object.values(descriptors).filter(e => interfaces.has(e.name)).map(type => type.properties).flat();
|
23
|
+
}
|
24
|
+
exports.getInterfaceProperties = getInterfaceProperties;
|
25
|
+
function isValidInterfaceMethod(descriptors, interfaces, method) {
|
26
|
+
const availableMethods = getInterfaceMethods(descriptors, interfaces);
|
27
|
+
return availableMethods.includes(method) || descriptors[types_1.ScryptedInterface.ScryptedDevice].methods.includes(method);
|
28
|
+
}
|
29
|
+
exports.isValidInterfaceMethod = isValidInterfaceMethod;
|
30
|
+
function isValidInterfaceProperty(descriptors, interfaces, property) {
|
31
|
+
const availableProperties = getInterfaceProperties(descriptors, new Set(interfaces));
|
32
|
+
return availableProperties.includes(property);
|
33
|
+
}
|
34
|
+
exports.isValidInterfaceProperty = isValidInterfaceProperty;
|
35
|
+
//# sourceMappingURL=descriptor.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"descriptor.js","sourceRoot":"","sources":["../../src/plugin/descriptor.ts"],"names":[],"mappings":";;;AAAA,2CAA+G;AAElG,QAAA,sBAAsB,GAAa,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,oCAA4B,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAEvI,SAAgB,qBAAqB,CAAC,WAAyE;IAC3G,MAAM,kBAAkB,GAA8C,EAAE,CAAC;IAEzE,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE;QACjD,KAAK,MAAM,QAAQ,IAAI,UAAU,CAAC,UAAU,EAAE;YAC1C,kBAAkB,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,IAAyB,CAAC;SACvE;KACJ;IAED,OAAO,kBAAkB,CAAC;AAC9B,CAAC;AAVD,sDAUC;AAEY,QAAA,kBAAkB,GAAG,qBAAqB,CAAC,oCAA4B,CAAC,CAAC;AAEtF,SAAgB,mBAAmB,CAAC,WAAyE,EAAE,UAAuB;IAClI,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAC3G,CAAC;AAFD,kDAEC;AAED,SAAgB,sBAAsB,CAAC,WAAyE,EAAE,UAAuB;IACrI,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;AAC9G,CAAC;AAFD,wDAEC;AAED,SAAgB,sBAAsB,CAAC,WAAyE,EAAE,UAAuB,EAAE,MAAc;IACrJ,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACtE,OAAO,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,yBAAiB,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACvH,CAAC;AAHD,wDAGC;AAED,SAAgB,wBAAwB,CAAC,WAAyE,EAAE,UAAoB,EAAE,QAAgB;IACtJ,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IACrF,OAAO,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAClD,CAAC;AAHD,4DAGC"}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { BufferConverter, DeviceManager, FFmpegInput, MediaManager, MediaObject as MediaObjectInterface, MediaObjectOptions, ScryptedDevice, ScryptedNativeId, SystemDeviceState, SystemManager } from "@scrypted/types";
|
3
|
+
import { MediaObjectRemote } from "./plugin-api";
|
4
|
+
type IdBufferConverter = BufferConverter & {
|
5
|
+
id: string;
|
6
|
+
name: string;
|
7
|
+
};
|
8
|
+
export declare abstract class MediaManagerBase implements MediaManager {
|
9
|
+
builtinConverters: IdBufferConverter[];
|
10
|
+
extraConverters: IdBufferConverter[];
|
11
|
+
constructor();
|
12
|
+
addConverter(converter: IdBufferConverter): Promise<void>;
|
13
|
+
clearConverters(): Promise<void>;
|
14
|
+
convertMediaObjectToJSON<T>(mediaObject: MediaObjectInterface, toMimeType: string): Promise<T>;
|
15
|
+
abstract getSystemState(): {
|
16
|
+
[id: string]: {
|
17
|
+
[property: string]: SystemDeviceState;
|
18
|
+
};
|
19
|
+
};
|
20
|
+
abstract getDeviceById<T>(id: string): T & ScryptedDevice;
|
21
|
+
abstract getPluginDeviceId(): string;
|
22
|
+
abstract getMixinConsole(mixinId: string, nativeId: ScryptedNativeId): Console;
|
23
|
+
getFFmpegPath(): Promise<string>;
|
24
|
+
getFilesPath(): Promise<string>;
|
25
|
+
getConverters(): IdBufferConverter[];
|
26
|
+
ensureMediaObjectRemote(mediaObject: string | MediaObjectInterface): MediaObjectRemote;
|
27
|
+
convertMediaObject<T>(mediaObject: MediaObjectInterface, toMimeType: string): Promise<T>;
|
28
|
+
convertMediaObjectToInsecureLocalUrl(mediaObject: string | MediaObjectInterface, toMimeType: string): Promise<string>;
|
29
|
+
convertMediaObjectToBuffer(mediaObject: MediaObjectInterface, toMimeType: string): Promise<Buffer>;
|
30
|
+
convertMediaObjectToLocalUrl(mediaObject: string | MediaObjectInterface, toMimeType: string): Promise<string>;
|
31
|
+
convertMediaObjectToUrl(mediaObject: string | MediaObjectInterface, toMimeType: string): Promise<string>;
|
32
|
+
createMediaObjectRemote<T extends MediaObjectOptions>(data: any | Buffer | Promise<string | Buffer>, mimeType: string, options?: T): MediaObjectRemote & T;
|
33
|
+
createFFmpegMediaObject(ffMpegInput: FFmpegInput, options?: MediaObjectOptions): Promise<MediaObjectInterface>;
|
34
|
+
createMediaObjectFromUrl(data: string, options?: MediaObjectOptions): Promise<MediaObjectInterface>;
|
35
|
+
createMediaObject<T extends MediaObjectOptions>(data: any, mimeType: string, options?: T): Promise<MediaObjectInterface & T>;
|
36
|
+
convert(converters: IdBufferConverter[], mediaObject: MediaObjectRemote, toMimeType: string): Promise<{
|
37
|
+
data: Buffer | string | any;
|
38
|
+
mimeType: string;
|
39
|
+
}>;
|
40
|
+
}
|
41
|
+
export declare class MediaManagerImpl extends MediaManagerBase {
|
42
|
+
systemManager: SystemManager;
|
43
|
+
deviceManager: DeviceManager;
|
44
|
+
constructor(systemManager: SystemManager, deviceManager: DeviceManager);
|
45
|
+
getSystemState(): {
|
46
|
+
[id: string]: {
|
47
|
+
[property: string]: SystemDeviceState;
|
48
|
+
};
|
49
|
+
};
|
50
|
+
getDeviceById<T>(id: string): T;
|
51
|
+
getPluginDeviceId(): string;
|
52
|
+
getMixinConsole(mixinId: string, nativeId: string): Console;
|
53
|
+
}
|
54
|
+
export declare class MediaManagerHostImpl extends MediaManagerBase {
|
55
|
+
pluginDeviceId: string;
|
56
|
+
getSystemState: () => {
|
57
|
+
[id: string]: {
|
58
|
+
[property: string]: SystemDeviceState;
|
59
|
+
};
|
60
|
+
};
|
61
|
+
console: Console;
|
62
|
+
getDeviceById: (id: string) => any;
|
63
|
+
constructor(pluginDeviceId: string, getSystemState: () => {
|
64
|
+
[id: string]: {
|
65
|
+
[property: string]: SystemDeviceState;
|
66
|
+
};
|
67
|
+
}, console: Console, getDeviceById: (id: string) => any);
|
68
|
+
getPluginDeviceId(): string;
|
69
|
+
getMixinConsole(mixinId: string, nativeId: string): Console;
|
70
|
+
}
|
71
|
+
export {};
|
@@ -0,0 +1,420 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.MediaManagerHostImpl = exports.MediaManagerImpl = exports.MediaManagerBase = void 0;
|
7
|
+
const types_1 = require("@scrypted/types");
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
9
|
+
const ffmpeg_static_1 = __importDefault(require("ffmpeg-static"));
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
11
|
+
const https_1 = __importDefault(require("https"));
|
12
|
+
const mime_1 = __importDefault(require("mime"));
|
13
|
+
const mkdirp_1 = __importDefault(require("mkdirp"));
|
14
|
+
const node_dijkstra_1 = __importDefault(require("node-dijkstra"));
|
15
|
+
const os_1 = __importDefault(require("os"));
|
16
|
+
const path_1 = __importDefault(require("path"));
|
17
|
+
const whatwg_mimetype_1 = __importDefault(require("whatwg-mimetype"));
|
18
|
+
const mediaobject_1 = require("./mediaobject");
|
19
|
+
function typeMatches(target, candidate) {
|
20
|
+
// candidate will accept anything
|
21
|
+
if (candidate === '*' || target === '*')
|
22
|
+
return true;
|
23
|
+
return target === candidate;
|
24
|
+
}
|
25
|
+
function mimeMatches(target, candidate) {
|
26
|
+
return typeMatches(target.type, candidate.type) && typeMatches(target.subtype, candidate.subtype);
|
27
|
+
}
|
28
|
+
const httpsAgent = new https_1.default.Agent({
|
29
|
+
rejectUnauthorized: false
|
30
|
+
});
|
31
|
+
function getBuiltinId(n) {
|
32
|
+
return 'builtin-' + n;
|
33
|
+
}
|
34
|
+
function getExtraId(n) {
|
35
|
+
return 'extra-' + n;
|
36
|
+
}
|
37
|
+
class MediaManagerBase {
|
38
|
+
builtinConverters = [];
|
39
|
+
extraConverters = [];
|
40
|
+
constructor() {
|
41
|
+
for (const h of ['http', 'https']) {
|
42
|
+
this.builtinConverters.push({
|
43
|
+
id: getBuiltinId(this.builtinConverters.length),
|
44
|
+
name: 'HTTP Converter',
|
45
|
+
fromMimeType: types_1.ScryptedMimeTypes.SchemePrefix + h,
|
46
|
+
toMimeType: types_1.ScryptedMimeTypes.MediaObject,
|
47
|
+
convert: async (data, fromMimeType, toMimeType) => {
|
48
|
+
const ab = await axios_1.default.get(data.toString(), {
|
49
|
+
responseType: 'arraybuffer',
|
50
|
+
httpsAgent,
|
51
|
+
});
|
52
|
+
const mimeType = ab.headers['content-type'] || toMimeType;
|
53
|
+
const mo = this.createMediaObject(Buffer.from(ab.data), mimeType);
|
54
|
+
return mo;
|
55
|
+
}
|
56
|
+
});
|
57
|
+
}
|
58
|
+
this.builtinConverters.push({
|
59
|
+
id: getBuiltinId(this.builtinConverters.length),
|
60
|
+
name: 'File Converter',
|
61
|
+
fromMimeType: types_1.ScryptedMimeTypes.SchemePrefix + 'file',
|
62
|
+
toMimeType: types_1.ScryptedMimeTypes.MediaObject,
|
63
|
+
convert: async (data, fromMimeType, toMimeType) => {
|
64
|
+
const url = data.toString();
|
65
|
+
const filename = url.substring('file:'.length);
|
66
|
+
if (toMimeType === types_1.ScryptedMimeTypes.FFmpegInput) {
|
67
|
+
const ffmpegInput = {
|
68
|
+
url,
|
69
|
+
inputArguments: [
|
70
|
+
'-i', filename,
|
71
|
+
]
|
72
|
+
};
|
73
|
+
return this.createFFmpegMediaObject(ffmpegInput);
|
74
|
+
}
|
75
|
+
const ab = await fs_1.default.promises.readFile(filename);
|
76
|
+
const mt = mime_1.default.getType(data.toString());
|
77
|
+
const mo = this.createMediaObject(ab, mt);
|
78
|
+
return mo;
|
79
|
+
}
|
80
|
+
});
|
81
|
+
this.builtinConverters.push({
|
82
|
+
id: getBuiltinId(this.builtinConverters.length),
|
83
|
+
name: 'Url to FFmpegInput Converter',
|
84
|
+
fromMimeType: types_1.ScryptedMimeTypes.Url,
|
85
|
+
toMimeType: types_1.ScryptedMimeTypes.FFmpegInput,
|
86
|
+
async convert(data, fromMimeType) {
|
87
|
+
const url = data.toString();
|
88
|
+
const args = {
|
89
|
+
url,
|
90
|
+
inputArguments: [
|
91
|
+
'-i', url,
|
92
|
+
],
|
93
|
+
};
|
94
|
+
return Buffer.from(JSON.stringify(args));
|
95
|
+
}
|
96
|
+
});
|
97
|
+
this.builtinConverters.push({
|
98
|
+
id: getBuiltinId(this.builtinConverters.length),
|
99
|
+
name: 'FFmpegInput to MediaStreamUrl Converter',
|
100
|
+
fromMimeType: types_1.ScryptedMimeTypes.FFmpegInput,
|
101
|
+
toMimeType: types_1.ScryptedMimeTypes.MediaStreamUrl,
|
102
|
+
async convert(data, fromMimeType) {
|
103
|
+
return data;
|
104
|
+
}
|
105
|
+
});
|
106
|
+
this.builtinConverters.push({
|
107
|
+
id: getBuiltinId(this.builtinConverters.length),
|
108
|
+
name: 'MediaStreamUrl to FFmpegInput Converter',
|
109
|
+
fromMimeType: types_1.ScryptedMimeTypes.MediaStreamUrl,
|
110
|
+
toMimeType: types_1.ScryptedMimeTypes.FFmpegInput,
|
111
|
+
async convert(data, fromMimeType) {
|
112
|
+
const mediaUrl = JSON.parse(data.toString());
|
113
|
+
const inputArguments = [
|
114
|
+
'-i', mediaUrl.url,
|
115
|
+
];
|
116
|
+
const ret = Object.assign({
|
117
|
+
inputArguments,
|
118
|
+
}, mediaUrl);
|
119
|
+
if (mediaUrl.url.startsWith('rtsp')) {
|
120
|
+
ret.container = 'rtsp';
|
121
|
+
inputArguments.unshift("-rtsp_transport", "tcp");
|
122
|
+
}
|
123
|
+
return Buffer.from(JSON.stringify(ret));
|
124
|
+
}
|
125
|
+
});
|
126
|
+
// todo: move this to snapshot plugin
|
127
|
+
this.builtinConverters.push({
|
128
|
+
id: getBuiltinId(this.builtinConverters.length),
|
129
|
+
name: 'Image Converter',
|
130
|
+
fromMimeType: 'image/*',
|
131
|
+
toMimeType: 'image/*',
|
132
|
+
convert: async (data, fromMimeType) => {
|
133
|
+
return data;
|
134
|
+
}
|
135
|
+
});
|
136
|
+
}
|
137
|
+
async addConverter(converter) {
|
138
|
+
converter.id = getExtraId(this.extraConverters.length);
|
139
|
+
this.extraConverters.push(converter);
|
140
|
+
}
|
141
|
+
async clearConverters() {
|
142
|
+
this.extraConverters = [];
|
143
|
+
}
|
144
|
+
async convertMediaObjectToJSON(mediaObject, toMimeType) {
|
145
|
+
const buffer = await this.convertMediaObjectToBuffer(mediaObject, toMimeType);
|
146
|
+
return JSON.parse(buffer.toString());
|
147
|
+
}
|
148
|
+
async getFFmpegPath() {
|
149
|
+
// try to get the ffmpeg path as a value of another variable
|
150
|
+
// ie, in docker builds:
|
151
|
+
// export SCRYPTED_FFMPEG_PATH_ENV_VARIABLE=SCRYPTED_RASPBIAN_FFMPEG_PATH
|
152
|
+
const v = process.env.SCRYPTED_FFMPEG_PATH_ENV_VARIABLE;
|
153
|
+
if (v) {
|
154
|
+
const f = process.env[v];
|
155
|
+
if (f && fs_1.default.existsSync(f))
|
156
|
+
return f;
|
157
|
+
}
|
158
|
+
// try to get the ffmpeg path from a variable
|
159
|
+
// ie:
|
160
|
+
// export SCRYPTED_FFMPEG_PATH=/usr/local/bin/ffmpeg
|
161
|
+
const f = process.env.SCRYPTED_FFMPEG_PATH;
|
162
|
+
if (f && fs_1.default.existsSync(f))
|
163
|
+
return f;
|
164
|
+
const defaultPath = os_1.default.platform() === 'win32' ? 'ffmpeg.exe' : 'ffmpeg';
|
165
|
+
return ffmpeg_static_1.default || defaultPath;
|
166
|
+
}
|
167
|
+
async getFilesPath() {
|
168
|
+
const filesPath = process.env.SCRYPTED_PLUGIN_VOLUME;
|
169
|
+
if (!filesPath)
|
170
|
+
throw new Error('SCRYPTED_PLUGIN_VOLUME env variable not set?');
|
171
|
+
const ret = path_1.default.join(filesPath, 'files');
|
172
|
+
mkdirp_1.default.sync(ret);
|
173
|
+
return ret;
|
174
|
+
}
|
175
|
+
getConverters() {
|
176
|
+
const converters = Object.entries(this.getSystemState())
|
177
|
+
.filter(([id, state]) => state[types_1.ScryptedInterfaceProperty.interfaces]?.value?.includes(types_1.ScryptedInterface.BufferConverter))
|
178
|
+
.map(([id]) => {
|
179
|
+
const device = this.getDeviceById(id);
|
180
|
+
return {
|
181
|
+
id,
|
182
|
+
name: device.name,
|
183
|
+
fromMimeType: device.fromMimeType,
|
184
|
+
toMimeType: device.toMimeType,
|
185
|
+
convert(data, fromMimeType, toMimeType, options) {
|
186
|
+
return device.convert(data, fromMimeType, toMimeType, options);
|
187
|
+
},
|
188
|
+
};
|
189
|
+
});
|
190
|
+
// builtins should be after system converters. these should not be overriden by system,
|
191
|
+
// as it could cause system instability with misconfiguration.
|
192
|
+
converters.push(...this.builtinConverters);
|
193
|
+
// extra converters are added last and do allow overriding builtins, as
|
194
|
+
// the instability would be confined to a single plugin.
|
195
|
+
converters.push(...this.extraConverters);
|
196
|
+
return converters;
|
197
|
+
}
|
198
|
+
ensureMediaObjectRemote(mediaObject) {
|
199
|
+
if (typeof mediaObject === 'string') {
|
200
|
+
const mime = mime_1.default.getType(mediaObject);
|
201
|
+
return this.createMediaObjectRemote(mediaObject, mime);
|
202
|
+
}
|
203
|
+
return mediaObject;
|
204
|
+
}
|
205
|
+
async convertMediaObject(mediaObject, toMimeType) {
|
206
|
+
const converted = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
207
|
+
return converted.data;
|
208
|
+
}
|
209
|
+
async convertMediaObjectToInsecureLocalUrl(mediaObject, toMimeType) {
|
210
|
+
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
211
|
+
const converted = this.createMediaObjectRemote(intermediate.data, intermediate.mimeType);
|
212
|
+
const url = await this.convert(this.getConverters(), converted, types_1.ScryptedMimeTypes.InsecureLocalUrl);
|
213
|
+
return url.data.toString();
|
214
|
+
}
|
215
|
+
async convertMediaObjectToBuffer(mediaObject, toMimeType) {
|
216
|
+
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
217
|
+
return intermediate.data;
|
218
|
+
}
|
219
|
+
async convertMediaObjectToLocalUrl(mediaObject, toMimeType) {
|
220
|
+
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
221
|
+
const converted = this.createMediaObjectRemote(intermediate.data, intermediate.mimeType);
|
222
|
+
const url = await this.convert(this.getConverters(), converted, types_1.ScryptedMimeTypes.LocalUrl);
|
223
|
+
return url.data.toString();
|
224
|
+
}
|
225
|
+
async convertMediaObjectToUrl(mediaObject, toMimeType) {
|
226
|
+
const intermediate = await this.convert(this.getConverters(), this.ensureMediaObjectRemote(mediaObject), toMimeType);
|
227
|
+
const converted = this.createMediaObjectRemote(intermediate.data, intermediate.mimeType);
|
228
|
+
const url = await this.convert(this.getConverters(), converted, types_1.ScryptedMimeTypes.Url);
|
229
|
+
return url.data.toString();
|
230
|
+
}
|
231
|
+
createMediaObjectRemote(data, mimeType, options) {
|
232
|
+
if (typeof data === 'string')
|
233
|
+
throw new Error('string is not a valid type. if you intended to send a url, use createMediaObjectFromUrl.');
|
234
|
+
if (!mimeType)
|
235
|
+
throw new Error('no mimeType provided');
|
236
|
+
if (mimeType === types_1.ScryptedMimeTypes.MediaObject)
|
237
|
+
return data;
|
238
|
+
if (data.constructor?.name === Object.name)
|
239
|
+
data = Buffer.from(JSON.stringify(data));
|
240
|
+
const sourceId = typeof options?.sourceId === 'string' ? options?.sourceId : this.getPluginDeviceId();
|
241
|
+
if (sourceId) {
|
242
|
+
options ||= {};
|
243
|
+
options.sourceId = sourceId;
|
244
|
+
}
|
245
|
+
return new mediaobject_1.MediaObject(mimeType, data, options);
|
246
|
+
}
|
247
|
+
async createFFmpegMediaObject(ffMpegInput, options) {
|
248
|
+
return this.createMediaObjectRemote(Buffer.from(JSON.stringify(ffMpegInput)), types_1.ScryptedMimeTypes.FFmpegInput, options);
|
249
|
+
}
|
250
|
+
async createMediaObjectFromUrl(data, options) {
|
251
|
+
const url = new URL(data);
|
252
|
+
const scheme = url.protocol.slice(0, -1);
|
253
|
+
const mimeType = types_1.ScryptedMimeTypes.SchemePrefix + scheme;
|
254
|
+
const sourceId = typeof options?.sourceId === 'string' ? options?.sourceId : this.getPluginDeviceId();
|
255
|
+
class MediaObjectImpl {
|
256
|
+
__proxy_props = {
|
257
|
+
mimeType,
|
258
|
+
sourceId,
|
259
|
+
};
|
260
|
+
mimeType = mimeType;
|
261
|
+
sourceId = sourceId;
|
262
|
+
async getData() {
|
263
|
+
return Promise.resolve(data);
|
264
|
+
}
|
265
|
+
}
|
266
|
+
return new MediaObjectImpl();
|
267
|
+
}
|
268
|
+
async createMediaObject(data, mimeType, options) {
|
269
|
+
return this.createMediaObjectRemote(data, mimeType, options);
|
270
|
+
}
|
271
|
+
async convert(converters, mediaObject, toMimeType) {
|
272
|
+
// console.log('converting', mediaObject.mimeType, toMimeType);
|
273
|
+
const mediaMime = new whatwg_mimetype_1.default(mediaObject.mimeType);
|
274
|
+
const outputMime = new whatwg_mimetype_1.default(toMimeType);
|
275
|
+
if (mimeMatches(mediaMime, outputMime)) {
|
276
|
+
return {
|
277
|
+
mimeType: outputMime.essence,
|
278
|
+
data: await mediaObject.getData(),
|
279
|
+
};
|
280
|
+
}
|
281
|
+
let sourceId = mediaObject?.sourceId;
|
282
|
+
if (typeof sourceId !== 'string')
|
283
|
+
sourceId = this.getPluginDeviceId();
|
284
|
+
const console = this.getMixinConsole(sourceId, undefined);
|
285
|
+
const converterMap = new Map();
|
286
|
+
for (const c of converters) {
|
287
|
+
converterMap.set(c.id, c);
|
288
|
+
}
|
289
|
+
const nodes = {};
|
290
|
+
const mediaNode = {};
|
291
|
+
nodes['mediaObject'] = mediaNode;
|
292
|
+
nodes['output'] = {};
|
293
|
+
for (const converter of converters) {
|
294
|
+
try {
|
295
|
+
const inputMime = new whatwg_mimetype_1.default(converter.fromMimeType);
|
296
|
+
const convertedMime = new whatwg_mimetype_1.default(converter.toMimeType);
|
297
|
+
// catch all converters should be heavily weighted so as not to use them.
|
298
|
+
const inputWeight = parseFloat(inputMime.parameters.get('converter-weight')) || (inputMime.essence === '*/*' ? 1000 : 1);
|
299
|
+
// const convertedWeight = parseFloat(convertedMime.parameters.get('converter-weight')) || (convertedMime.essence === ScryptedMimeTypes.MediaObject ? 1000 : 1);
|
300
|
+
// const conversionWeight = inputWeight + convertedWeight;
|
301
|
+
const targetId = converter.id;
|
302
|
+
const node = nodes[targetId] = {};
|
303
|
+
// edge matches
|
304
|
+
for (const candidate of converters) {
|
305
|
+
try {
|
306
|
+
const candidateMime = new whatwg_mimetype_1.default(candidate.fromMimeType);
|
307
|
+
if (!mimeMatches(convertedMime, candidateMime))
|
308
|
+
continue;
|
309
|
+
const outputWeight = parseFloat(candidateMime.parameters.get('converter-weight')) || (candidateMime.essence === '*/*' ? 1000 : 1);
|
310
|
+
const candidateId = candidate.id;
|
311
|
+
node[candidateId] = inputWeight + outputWeight;
|
312
|
+
}
|
313
|
+
catch (e) {
|
314
|
+
console.warn(candidate.name, 'skipping converter due to error', e);
|
315
|
+
}
|
316
|
+
}
|
317
|
+
// source matches
|
318
|
+
if (mimeMatches(mediaMime, inputMime)) {
|
319
|
+
mediaNode[targetId] = inputWeight;
|
320
|
+
}
|
321
|
+
// target output matches
|
322
|
+
if (mimeMatches(outputMime, convertedMime) || converter.toMimeType === types_1.ScryptedMimeTypes.MediaObject) {
|
323
|
+
node['output'] = inputWeight;
|
324
|
+
}
|
325
|
+
}
|
326
|
+
catch (e) {
|
327
|
+
console.warn('skipping converter due to error', e);
|
328
|
+
}
|
329
|
+
}
|
330
|
+
const graph = new node_dijkstra_1.default();
|
331
|
+
for (const id of Object.keys(nodes)) {
|
332
|
+
graph.addNode(id, nodes[id]);
|
333
|
+
}
|
334
|
+
const route = graph.path('mediaObject', 'output');
|
335
|
+
if (!route || !route.length)
|
336
|
+
throw new Error(`no converter found: ${mediaObject?.mimeType} to ${toMimeType}`);
|
337
|
+
// pop off the mediaObject start node, no conversion necessary.
|
338
|
+
route.shift();
|
339
|
+
// also remove the output node.
|
340
|
+
route.splice(route.length - 1);
|
341
|
+
let value = await mediaObject.getData();
|
342
|
+
let valueMime = new whatwg_mimetype_1.default(mediaObject.mimeType);
|
343
|
+
while (route.length) {
|
344
|
+
const node = route.shift();
|
345
|
+
const converter = converterMap.get(node);
|
346
|
+
const converterToMimeType = new whatwg_mimetype_1.default(converter.toMimeType);
|
347
|
+
const converterFromMimeType = new whatwg_mimetype_1.default(converter.fromMimeType);
|
348
|
+
const type = converterToMimeType.type === '*' ? valueMime.type : converterToMimeType.type;
|
349
|
+
const subtype = converterToMimeType.subtype === '*' ? valueMime.subtype : converterToMimeType.subtype;
|
350
|
+
let targetMimeType = `${type}/${subtype}`;
|
351
|
+
if (!route.length && outputMime.parameters.size) {
|
352
|
+
const withParameters = new whatwg_mimetype_1.default(targetMimeType);
|
353
|
+
for (const k of outputMime.parameters.keys()) {
|
354
|
+
withParameters.parameters.set(k, outputMime.parameters.get(k));
|
355
|
+
}
|
356
|
+
targetMimeType = outputMime.toString();
|
357
|
+
}
|
358
|
+
if (converter.toMimeType === types_1.ScryptedMimeTypes.MediaObject) {
|
359
|
+
const mo = await converter.convert(value, valueMime.essence, toMimeType, { sourceId });
|
360
|
+
const found = await this.convertMediaObject(mo, toMimeType);
|
361
|
+
return {
|
362
|
+
data: found,
|
363
|
+
mimeType: toMimeType,
|
364
|
+
};
|
365
|
+
}
|
366
|
+
value = await converter.convert(value, valueMime.essence, targetMimeType, { sourceId });
|
367
|
+
valueMime = new whatwg_mimetype_1.default(targetMimeType);
|
368
|
+
}
|
369
|
+
return {
|
370
|
+
data: value,
|
371
|
+
mimeType: valueMime.essence,
|
372
|
+
};
|
373
|
+
}
|
374
|
+
}
|
375
|
+
exports.MediaManagerBase = MediaManagerBase;
|
376
|
+
class MediaManagerImpl extends MediaManagerBase {
|
377
|
+
systemManager;
|
378
|
+
deviceManager;
|
379
|
+
constructor(systemManager, deviceManager) {
|
380
|
+
super();
|
381
|
+
this.systemManager = systemManager;
|
382
|
+
this.deviceManager = deviceManager;
|
383
|
+
}
|
384
|
+
getSystemState() {
|
385
|
+
return this.systemManager.getSystemState();
|
386
|
+
}
|
387
|
+
getDeviceById(id) {
|
388
|
+
return this.systemManager.getDeviceById(id);
|
389
|
+
}
|
390
|
+
getPluginDeviceId() {
|
391
|
+
return this.deviceManager.getDeviceState().id;
|
392
|
+
}
|
393
|
+
getMixinConsole(mixinId, nativeId) {
|
394
|
+
if (typeof mixinId !== 'string')
|
395
|
+
return this.deviceManager.getDeviceConsole(nativeId);
|
396
|
+
return this.deviceManager.getMixinConsole(mixinId, nativeId);
|
397
|
+
}
|
398
|
+
}
|
399
|
+
exports.MediaManagerImpl = MediaManagerImpl;
|
400
|
+
class MediaManagerHostImpl extends MediaManagerBase {
|
401
|
+
pluginDeviceId;
|
402
|
+
getSystemState;
|
403
|
+
console;
|
404
|
+
getDeviceById;
|
405
|
+
constructor(pluginDeviceId, getSystemState, console, getDeviceById) {
|
406
|
+
super();
|
407
|
+
this.pluginDeviceId = pluginDeviceId;
|
408
|
+
this.getSystemState = getSystemState;
|
409
|
+
this.console = console;
|
410
|
+
this.getDeviceById = getDeviceById;
|
411
|
+
}
|
412
|
+
getPluginDeviceId() {
|
413
|
+
return this.pluginDeviceId;
|
414
|
+
}
|
415
|
+
getMixinConsole(mixinId, nativeId) {
|
416
|
+
return this.console;
|
417
|
+
}
|
418
|
+
}
|
419
|
+
exports.MediaManagerHostImpl = MediaManagerHostImpl;
|
420
|
+
//# sourceMappingURL=media.js.map
|