@apocaliss92/scrypted-reolink-hub
Version: 
Reolink (HUBs) Plugin for Scrypted
111 lines (97 loc) • 4.29 kB
text/typescript
import { sleep } from "@scrypted/common/src/sleep";
import sdk, { MixinProvider, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, SettingValue, WritableDeviceState } from "@scrypted/sdk";
import { StorageSettings, StorageSettingsDict } from "@scrypted/sdk/storage-settings";
import fs from 'fs';
import { getBaseLogger } from '../../scrypted-apocaliss-base/src/basePlugin';
import ReolinkProvider, { pluginId, REOLINK_HUB_VIDEOCLIPS_INTERFACE } from "./main";
import ReolinkVideoclipssMixins from "./videoclipsMixin";
export default class ReolinkVideoclips extends ScryptedDeviceBase implements MixinProvider {
    initStorage: StorageSettingsDict<string> = {
    };
    storageSettings = new StorageSettings(this, this.initStorage);
    currentMixinsMap: Record<string, ReolinkVideoclipssMixins> = {};
    plugin: ReolinkProvider;
    ffmpegPath: string;
    thumbnailsToGenerate: { deviceId: string, thumbnailId: string }[] = [];
    generatingThumbnails = false;
    constructor(nativeId: string, plugin: ReolinkProvider) {
        super(nativeId);
        this.plugin = plugin;
        const logger = this.getLogger();
        this.init().catch(logger.error);
    }
    async init() {
        this.ffmpegPath = await sdk.mediaManager.getFFmpegPath();
        setInterval(async () => {
            if (!this.generatingThumbnails) {
                const item = this.thumbnailsToGenerate.shift();
                if (item) {
                    const { deviceId, thumbnailId } = item;
                    const deviceMixin = this.currentMixinsMap[deviceId];
                    const deviceLogger = deviceMixin.getLogger();
                    deviceLogger.log(`Generating thumbnail of clip ${thumbnailId}`);
                    this.generatingThumbnails = true;
                    const { videoclipUrl, thumbnailUrl } = await deviceMixin.getVideoclipParams(thumbnailId);
                    try {
                        const jpeg = await deviceMixin.generateThumbnail(videoclipUrl);
                        if (jpeg.length) {
                            deviceLogger.log(`Saving thumbnail in ${thumbnailUrl}`);
                            await fs.promises.writeFile(thumbnailUrl, jpeg);
                        } else {
                            deviceLogger.log('Not saving, image is corrupted');
                        }
                    } catch (e) {
                        deviceLogger.log('Failed generating thumbnail', videoclipUrl, thumbnailId, e);
                    } finally {
                        this.generatingThumbnails = false;
                        await sleep(3000);
                    }
                }
            }
        }, 1000);
    }
    async putSetting(key: string, value: SettingValue): Promise<void> {
        return this.storageSettings.putSetting(key, value);
    }
    public getLogger() {
        return getBaseLogger({
            console: this.console,
            storage: this.storageSettings,
        });
    }
    async getSettings() {
        try {
            const settings = await this.storageSettings.getSettings();
            return settings;
        } catch (e) {
            this.getLogger().log('Error in getSettings', e);
            return [];
        }
    }
    async canMixin(type: ScryptedDeviceType, interfaces: string[]): Promise<string[]> {
        return [
            ScryptedInterface.Camera,
            ScryptedInterface.VideoCamera,
        ].some(int => interfaces.includes(int)) &&
            interfaces.includes(pluginId) ?
            [
                ScryptedInterface.Settings,
                ScryptedInterface.VideoClips,
                REOLINK_HUB_VIDEOCLIPS_INTERFACE
            ] :
            undefined;
    }
    async getMixin(mixinDevice: any, mixinDeviceInterfaces: ScryptedInterface[], mixinDeviceState: WritableDeviceState): Promise<any> {
        return new ReolinkVideoclipssMixins({
            mixinDevice,
            mixinDeviceInterfaces,
            mixinDeviceState,
            mixinProviderNativeId: this.nativeId,
            group: 'Reolink HUB videoclips',
            groupKey: 'reolinkHubVideoclips',
        }, this)
    }
    async releaseMixin(id: string, mixinDevice: any): Promise<void> {
        await mixinDevice.release();
    }
}