UNPKG

camstreamerlib

Version:

Helper library for CamStreamer ACAP applications.

256 lines (255 loc) 9.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CamOverlayAPI = exports.BASE_URL = void 0; const utils_1 = require("./internal/utils"); const CamOverlayAPI_1 = require("./types/CamOverlayAPI"); const errors_1 = require("./errors/errors"); const common_1 = require("./types/common"); const zod_1 = require("zod"); const widgetsSchema_1 = require("./models/CamOverlayAPI/widgetsSchema"); const fileSchema_1 = require("./models/CamOverlayAPI/fileSchema"); exports.BASE_URL = '/local/camoverlay/api'; class CamOverlayAPI { client; constructor(client) { this.client = client; } static getProxyUrlPath = () => `${exports.BASE_URL}/proxy.cgi`; static getFilePreviewPath = (path) => `${exports.BASE_URL}/image.cgi?path=${encodeURIComponent(path)}`; async checkCameraTime() { const responseSchema = zod_1.z.discriminatedUnion('state', [ zod_1.z.object({ state: zod_1.z.literal(true), code: zod_1.z.number(), }), zod_1.z.object({ state: zod_1.z.literal(false), code: zod_1.z.number(), reason: zod_1.z.union([ zod_1.z.literal('INVALID_TIME'), zod_1.z.literal('COULDNT_RESOLVE_HOST'), zod_1.z.literal('CONNECTION_ERROR'), ]), message: zod_1.z.string(), }), ]); const response = await this._get(`${exports.BASE_URL}/camera_time.cgi`); const cameraTime = responseSchema.parse(response); if (!cameraTime.state) { console.error(`Camera time check failed: ${cameraTime.reason} - ${cameraTime.message}`); } return cameraTime.state; } async getNetworkCameraList() { const response = await this._get(`${exports.BASE_URL}/network_camera_list.cgi`); return common_1.networkCameraListSchema.parse(response.camera_list); } async wsAuthorization() { const responseSchema = zod_1.z.object({ status: zod_1.z.number(), message: zod_1.z.string(), data: zod_1.z.string(), }); const response = await this._get(`${exports.BASE_URL}/ws_authorization.cgi`); return responseSchema.parse(response).data; } async getMjpegStreamImage(mjpegUrl) { return await this._getBlob(`${exports.BASE_URL}/fetch_mjpeg_image.cgi?mjpeg_url=${encodeURIComponent(decodeURIComponent(mjpegUrl))}`); } async listFiles(fileType) { const fileDataSchema = zod_1.z.object({ code: zod_1.z.number(), list: fileSchema_1.fileListSchema, }); const files = await this._get(`${exports.BASE_URL}/upload_${fileType}.cgi`, { action: 'list', }); return fileSchema_1.fileListSchema.parse(files.list); } async uploadFile(fileType, formData, storage) { const path = `${exports.BASE_URL}/upload_${fileType}.cgi`; await this._post(path, formData, { action: 'upload', storage: storage, }); } async removeFile(fileType, fileParams) { const path = `${exports.BASE_URL}/upload_${fileType}.cgi`; await this._postUrlEncoded(path, { action: 'remove', ...fileParams, }); } async getFileStorage(fileType) { const storageDataListSchema = zod_1.z.array(zod_1.z.object({ type: fileSchema_1.storageSchema, state: zod_1.z.string(), })); const responseSchema = zod_1.z.object({ code: zod_1.z.number(), list: storageDataListSchema, }); const data = await this._get(`${exports.BASE_URL}/upload_${fileType}.cgi`, { action: 'get_storage', }); if (data.code !== 200) { throw new Error('Error occured while fetching file storage data'); } return storageDataListSchema.parse(data.list); } async getFilePreviewFromCamera(path) { return await this._getBlob(CamOverlayAPI.getFilePreviewPath(path)); } async updateInfoticker(serviceID, text) { await this._get(`${exports.BASE_URL}/infoticker.cgi?service_id=${serviceID}&text=${text}`); } async setEnabled(serviceID, enabled) { await this._post(`${exports.BASE_URL}/enabled.cgi?id_${serviceID}=${enabled ? 1 : 0}`, ''); } async isEnabled(serviceID) { const res = await this.client.get(`${exports.BASE_URL}/services.cgi?action=get`); if (res.ok) { const data = JSON.parse(await res.text()); for (const service of data.services) { if (service.id === serviceID) { return service.enabled === 1; } } throw new errors_1.ServiceNotFoundError(); } else { throw new Error(await (0, utils_1.responseStringify)(res)); } } async getSingleWidget(serviceId) { const data = await this._get(`${exports.BASE_URL}/services.cgi`, { action: 'get', service_id: serviceId.toString(), }); return widgetsSchema_1.widgetsSchema.parse(data); } async getWidgets() { const widgetList = await this._get(`${exports.BASE_URL}/services.cgi`, { action: 'get', }); const widgets = widgetList.services; widgets.forEach((widget) => { const parsedWidget = widgetsSchema_1.widgetsSchema.safeParse(widget); if (!parsedWidget.success) { console.warn(`[SERVICE SCHEMA MISMATCH]: Service ${widget.name} (${widget.id}) does not match the current schema, or is a hidden service.`); } }); return widgets; } async updateSingleWidget(widget) { const path = `${exports.BASE_URL}/services.cgi`; await this._postJsonEncoded(path, JSON.stringify(widget), { action: 'set', service_id: widget.id.toString(), }); } async updateWidgets(widgets) { const path = `${exports.BASE_URL}/services.cgi`; await this._postJsonEncoded(path, JSON.stringify({ services: widgets }), { action: 'set', }); } updateCGText(serviceID, fields) { const params = {}; for (const field of fields) { const name = field.field_name; params[name] = field.text; if (field.color !== undefined) { params[`${name}_color`] = field.color; } } return this.promiseCGUpdate(serviceID, 'update_text', params); } updateCGImagePos(serviceID, coordinates = '', x = 0, y = 0) { const params = { coord_system: coordinates, pos_x: x, pos_y: y, }; return this.promiseCGUpdate(serviceID, 'update_image', params); } updateCGImage(serviceID, path, coordinates = '', x = 0, y = 0) { const params = { coord_system: coordinates, pos_x: x, pos_y: y, image: path, }; return this.promiseCGUpdate(serviceID, 'update_image', params); } updateCGImageFromData(serviceID, imageType, imageData, coordinates = '', x = 0, y = 0) { const contentType = imageType === CamOverlayAPI_1.ImageType.PNG ? 'image/png' : 'image/jpeg'; const params = { coord_system: coordinates, pos_x: x, pos_y: y, }; return this.promiseCGUpdate(serviceID, 'update_image', params, contentType, imageData); } async promiseCGUpdate(serviceID, action, params = {}, contentType, data) { const path = `${exports.BASE_URL}/customGraphics.cgi`; let headers = {}; if (contentType !== undefined && data) { headers = { 'Content-Type': contentType }; } const res = await this.client.post(path, data ?? '', { action: action, service_id: serviceID.toString(), ...params, }, headers); if (!res.ok) { throw new Error(await (0, utils_1.responseStringify)(res)); } } async _get(...args) { const res = await this.client.get(...args); if (res.ok) { return (await res.json()); } else { throw new Error(await (0, utils_1.responseStringify)(res)); } } async _post(...args) { const res = await this.client.post(...args); if (res.ok) { return (await res.json()); } else { throw new Error(await (0, utils_1.responseStringify)(res)); } } async _getBlob(...args) { const res = await this.client.get(...args); if (res.ok) { return await this.parseBlobResponse(res); } else { throw new Error(await (0, utils_1.responseStringify)(res)); } } async parseBlobResponse(response) { try { return (await response.blob()); } catch (err) { throw new errors_1.ParsingBlobError(err); } } async _postUrlEncoded(path, params, headers) { const data = (0, utils_1.paramToUrl)(params); const baseHeaders = { 'Content-Type': 'application/x-www-form-urlencoded' }; return this._post(path, data, {}, { ...baseHeaders, ...headers }); } async _postJsonEncoded(...args) { const [path, data, params, headers] = args; const baseHeaders = { 'Accept': 'application/json', 'Content-Type': 'application/json' }; return this._post(path, data, params, { ...baseHeaders, ...headers }); } } exports.CamOverlayAPI = CamOverlayAPI;