Example #1
0
akala.injectWithNameAsync(['$agent.api/lifttt'], async (lifttt: Client<Connection>) =>
{
    var cl = akala.api.jsonrpcws(channel).createClient(lifttt, {
        executeAction: function (action)
        {
            switch (action.name)
            {
                case 'log':
                    console.log(action.params.message);
                    break;
            }
        },

        executeCondition: function (condition)
        {

        },
        stopTrigger: function (trigger)
        {

        },
        executeTrigger: async function (trigger)
        {
            return null;
        }
    });
    var server = cl.$proxy();
    await server.registerChannel({ name: 'console', view: '@domojs/lifttt/fs.html', icon: 'terminal' });
    await server.registerAction({ name: 'log', fields: [{ name: 'message', type: 'string' }] })
})
Example #2
0
File: fs.ts Project: domojs/lifttt
akala.injectWithNameAsync(['$agent.api/lifttt'], async (lifttt: Client<Connection>) =>
{
    var registeredTriggers: { [triggerId: string]: fs.FSWatcher } = {};

    var writeFile = promisify(fs.writeFile);

    var cl = akala.api.jsonrpcws(channel).createClient(lifttt, {
        executeAction: function (action)
        {
            switch (action.name)
            {
                case 'write':
                    return writeFile(action.params.file as string, action.params.data);
            }
        },
        executeCondition: function (condition)
        {

        },
        stopTrigger: async function (trigger)
        {
            if (registeredTriggers[trigger.id])
            {
                registeredTriggers[trigger.id].close();
                delete registeredTriggers[trigger.id];
            }
        },
        executeTrigger: async function (trigger)
        {
            switch (trigger.name)
            {
                case 'watch':
                    var stat = await promisify(fs.stat)(trigger.params['path'] as string);
                    if (stat.isDirectory() || stat.isFile())
                    {
                        var id = uuid();
                        var watcher = fs.watch(trigger.params['path'] as string, function (event, fileName)
                        {
                            if (!trigger.params['event'] || trigger.params['event'] == event)
                                server.trigger({ id: id, data: { path: fileName, mtime: new Date().toJSON() } });
                        });
                        registeredTriggers[id] = watcher;
                    }
                    break;
            }
            return null;
        }
    });
    var server = cl.$proxy();
    await server.registerChannel({ name: 'fs', view: '@domojs/lifttt/fs.html', icon: 'file' });
    await server.registerTrigger({ name: 'watch', icon: 'file-medical-alt', view: '@domojs/lifttt/fs-watch.html', fields: [{ name: 'path', type: 'string' }] })
    await server.registerAction({ name: 'write', icon: 'file-medical-alt', view: '@domojs/lifttt/fs-watch.html', fields: [{ name: 'path', type: 'string' }, { name: 'data', type: 'string' }] })
})
Example #3
0
akala.injectWithNameAsync(['$agent.api/media'], function (client: Client<Connection>)
{
    var s = akala.api.jsonrpcws(media.scrapper).createClient(client, {
        scrap: function (media: media.TVShow | media.Movie)
        {
            switch (media.subType)
            {
                case 'movie':
                    fs.writeFile(media.path + '.nfo', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                    <movie>
                        <title>${media.name}</title>
                        <sorttitle>${media.displayName}</sorttitle>
                        <thumb aspect="poster">${media.cover}</thumb>
                    </movie>`, 'utf8', function (err)
                        {
                            if (err)
                                akala.logger.error(err);
                        });

                    break;
                case 'tvshow':

                    fs.writeFile(media.path + '.nfo', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                    <episodedetails>
                        <title>${media.name}</title>
                        <sorttitle>${media.displayName}</sorttitle>
                        <thumb aspect="poster">${media.cover}</thumb>
                        <season>${media.season}</season>
                        <episode>${media.episode}</episode>
                    </episodedetails>`, 'utf8', function (err)
                        {
                            if (err)
                                akala.logger.error(err);
                        });
                    break;
            }

            return media;

        }
    }).$proxy();
    s.register({ type: 'video', priority: 20 });
});
Example #4
0
akala.injectWithNameAsync(['$agent.api/lifttt'], async (lifttt: Client<Connection>) =>
{
    var cl = akala.api.jsonrpcws(channel).createClient(lifttt, {
        executeAction: function (action)
        {
            switch (action.name)
            {
                case 'call':
                    var http: akala.Http = akala.resolve('$http');
                    return http.call(action.params as any).then((response) => { return; });
                    break;
            }
        },

        executeCondition: function (condition)
        {

        },
        stopTrigger: function (trigger)
        {

        },
        executeTrigger: async function (trigger)
        {
            return null;
        }
    });
    var server = cl.$proxy();
    await server.registerChannel({ name: 'http', icon: 'html5' });
    await server.registerAction({
        name: 'call', fields: [
            { name: 'url', type: 'string' },
            { name: 'method', type: 'string' },
            { name: 'queryString', type: 'string' },
            { name: 'body', type: 'string' },
            { name: 'headers', type: 'string' },
            { name: 'contentType', type: 'string' },
            { name: 'type', type: 'string' },
        ]
    })
})
Example #5
0
akala.injectWithNameAsync(['$agent.api/zeroconf', '$agent.api/media'], function (zeroconfClient, mediaClient)
{
    var kodis: { [id: string]: PromiseLike<{ Player: KodiPlayerProxy, Playlist: KodiPlaylistProxy }> } = {};
    var timers: { [id: string]: NodeJS.Timer } = {};
    function startTimer(id: string)
    {
        if (timers[id])
            return;
        timers[id] = setInterval(function ()
        {
            client.status({ target: id });
        }, 1000)
    }

    function stopTimer(id: string)
    {
        if (timers[id])
            clearInterval(timers[id]);
        timers[id] = null;
    }


    var client = akala.api.jsonrpcws(media.player).createClient(mediaClient, {
        mute(p)
        {

        },
        async status(p)
        {
            var kodi = await kodis[p.identity];
            var players = await kodi.Player.GetActivePlayers(null)
            if (players.length > 0)
            {
                debug.verbose(players);
                var player = await kodi.Player.GetProperties({ playerid: players[0].playerid, properties: ['position', 'percentage', 'repeat', 'canseek', 'time', 'totaltime', 'speed'] });
                debug.verbose(player);
                return client.$proxy().status({
                    identity: p.identity,
                    state: player.speed ? 'playing' : 'paused',
                    position: player.percentage / 100,
                    time: player.time.seconds + 60 * player.time.minutes + 3600 * player.time.hours,
                    length: player.totaltime.seconds + 60 * player.totaltime.minutes + 3600 * player.totaltime.hours,
                });
            }
            else
            {
                client.$proxy().status({
                    identity: p.identity,
                    state: 'stopped',
                });
                stopTimer(p.identity);
            }

        },
        async playlist(p: { target: string })
        {
            var kodi = await kodis[p.target];
            var players = await kodi.Player.GetActivePlayers(null);
            if (players.length > 0)
            {
                debug.log(players);
                var properties = await kodi.Player.GetProperties({ playerid: players[0].playerid, properties: ['playlistid', 'speed'] });
                if (typeof (properties.playlistid) != 'undefined')
                {
                    var item: { item: Item & { current?: boolean } } = await kodi.Player.GetItem({ playerid: players[0].playerid, properties: ['title', 'artist', 'albumartist', 'fanart', 'plot', 'season', 'episode', 'thumbnail', 'file', 'art'] })
                    {
                        akala.extend(item.item, { current: true });
                        var playlist = await kodi.Playlist.GetItems({ playlistid: properties.playlistid, properties: ['title', 'artist', 'albumartist', 'fanart', 'plot', 'season', 'episode', 'thumbnail', 'file', 'art'] })
                        debug.verbose(playlist);
                        if (playlist && !playlist.items)
                            playlist.items = [item.item]
                        else
                            playlist.items.unshift(item.item);
                        debug.verbose(playlist.items);
                        if (properties.speed > 0)
                            startTimer(p.target);
                        if (playlist && playlist.items)
                            client.$proxy().playlist({
                                identity: p.target, playlist: akala.map(playlist.items, function (media: Item & { current?: boolean })
                                {
                                    return { url: media.file.replace(/smb:\/\//, 'file://///'), current: media.current };
                                })
                            });
                    }
                }
            }
        },
        async next(p)
        {
            var kodi = await kodis[p.target];
            var players = await kodi.Player.GetActivePlayers(null);
            if (players.length > 0)
            {
                debug.verbose(players);
                kodi.Player.GoNext({ playerid: players[0].playerid })
            }
        },
        async previous(p)
        {
            var kodi = await kodis[p.target];
            var players = await kodi.Player.GetActivePlayers(null);
            if (players.length > 0)
            {
                debug.verbose(players);
                kodi.Player.GoPrevious({ playerid: players[0].playerid })
            }
        },
        async pause(p)
        {
            var kodi = await kodis[p.target];
            var players = await kodi.Player.GetActivePlayers(null);
            if (players.length > 0)
            {
                debug.verbose(players);
                var status = await kodi.Player.PlayPause({ playerid: players[0].playerid });
                if (status.speed)
                    startTimer(p.target);
                else
                    stopTimer(p.target);
            }
        },
        async stop(p)
        {
            var kodi = await kodis[p.target];
            var players = await kodi.Player.GetActivePlayers(null);
            if (players.length > 0)
            {
                debug.verbose(players);
                await kodi.Player.Stop({ playerid: players[0].playerid });
                stopTimer(p.target);
            }
        },
        async play(p)
        {
            var kodi = await kodis[p.target];
            var media = p.media;
            debug.info(media);
            if (typeof (media) != 'undefined')
            {
                if (!media || isNaN(Number(media.path)))
                {
                    media.path = decodeURIComponent(media.path);
                    media.path = media.path.replace(/file:\/\/\/\/\//, 'smb://');
                    debug.verbose(media);
                    var result = await kodi.Playlist.GetPlaylists(null);
                    debug.verbose(result);
                    var mediaType = media.id.substring('media:'.length, media.id.indexOf(':', 'media:'.length));
                    debug.verbose(mediaType);
                    if (result && result.items)
                    {
                        var playlist = akala.grep(result.items, function (e)
                        {
                            return e.type == mediaType;
                        })[0];
                        if (typeof (playlist) != 'undefined')
                        {
                            await kodi.Playlist.Add({ playlistid: playlist.playlistid, item: { file: media.path } });
                            startTimer(p.target);
                        }
                    }
                    else
                    {
                        await kodi.Player.Open({ item: { file: media.path } });
                        startTimer(p.target);
                    }
                }
                else
                {
                    throw new Error('Not implemented')
                }
            }
            else
                this.pause();
        }
    });
    akala.api.jsonrpcws(sd.meta).createClient(zeroconfClient, {
        add: function (kodiService: KodiService)
        {
            kodis[kodiService.id] = new Promise((resolve, reject) =>
            {
                var kodi = new Client();

                kodi.connect('ws://' + kodiService.referer.address + ':' + kodiService.port + '/jsonrpc', function connected(err)
                {
                    if (err)
                    {
                        debug.error(err);
                        reject(err);
                    }
                    debug.log('connected to ' + kodiService.name);

                    kodi.send('JSONRPC.Introspect', [], async function (error, reply)
                    {
                        if (error)
                        {
                            debug.error(error);
                            reject(error);
                        }
                        else
                        {
                            akala.each(reply['methods'], function (m, i)
                            {
                                var ns = (i as string).split('.');
                                if (typeof (kodi[ns[0]]) == 'undefined')
                                    kodi[ns[0]] = {};
                                kodi[ns[0]][ns[1]] = function (params)
                                {
                                    return new Promise<any>((resolve, reject) =>
                                    {
                                        if (!kodi.isConnected())
                                        {
                                            client.$proxy().unregisterPlayer({ identity: kodiService.id, name: kodiService.name })
                                            reject(new Error('Not connected'));
                                            return;
                                        }

                                        akala.each(m.params, function (value)
                                        {
                                            if (value.required && typeof (params[value.name]) == 'undefined')
                                            {
                                                throw JSON.stringify(params) + ' is missing the required param ' + value.name + ' for ' + ns[1];
                                            }
                                        });
                                        akala.logger.verbose('calling ' + i, JSON.stringify(params));
                                        kodi.send(i as string, params, (error, result) =>
                                        {
                                            if (error)
                                                reject(error);
                                            else
                                                resolve(result);
                                        });
                                    });
                                }
                            })
                            akala.each(reply['notifications'], function (i, m)
                            {
                                var ns = i.split('.');
                                if (typeof (kodi[ns[0]]) == 'undefined')
                                    kodi[ns[0]] = {};
                                kodi[ns[0]][ns[1]] = function (callback)
                                {
                                    if (typeof (callback) == 'undefined')
                                    {
                                        throw 'callback is missing for ' + ns[1];
                                    }
                                    akala.logger.info('monitoring ' + i, JSON.stringify(i));
                                    kodi.expose(i, callback);
                                }
                            })
                            debug('kodi client built');
                            await kodi['JSONRPC'].SetConfiguration({ notifications: { gui: false, system: true, player: true, audiolibrary: false, other: false, videolibrary: false } });
                            kodi['Player'].OnPause(function ()
                            {
                                debug('OnPause')
                                client.status({ target: kodiService.id });
                                stopTimer(kodiService.id);
                            });
                            kodi['Player'].OnPlay(function ()
                            {
                                debug('OnPlay')
                                client.status({ target: kodiService.id });
                                client.playlist({ target: kodiService.id });
                                startTimer(kodiService.id);
                            });
                            kodi['Player'].OnSeek(function ()
                            {
                                debug('OnSeek')
                                client.status({ target: kodiService.id });
                            });
                            kodi['Player'].OnPropertyChanged(function ()
                            {
                                debug('OnPropertyChanged')
                                client.status({ target: kodiService.id });
                            });
                            kodi['Player'].OnStop(function ()
                            {
                                debug('OnStop')
                                client.status({ target: kodiService.id });
                                stopTimer(kodiService.id);
                            });

                            resolve(kodi as any);
                        }
                    });
                });
            })
        },
        delete(service: KodiService)
        {
            client.$proxy().unregisterPlayer({ identity: service.id, name: service.name });
        }
    }).$proxy().notify({ type: 'xmbc-jsonrpc' });

});
Example #6
0
akala.injectWithNameAsync(['$agent.api/lifttt', '$worker'], function (client: Client<Connection>, worker: EventEmitter)
{
    var recipes: { [name: string]: Recipe & { triggerId?: string } } = {};
    var triggerMap: { [id: string]: Recipe } = {};
    var init: boolean;
    var recipeFile = path.resolve(process.cwd(), '../../../recipes.json');
    exists(recipeFile).then(async (exists) =>
    {
        if (exists)
        {
            logger.verbose(recipeFile + ' exists')
            var recipeStore: { [id: string]: Recipe } = JSON.parse(await readFile(recipeFile, { encoding: 'utf8' }));
            logger.verbose(recipeStore);
            init = true;
            worker.on('ready', function ()
            {
                setTimeout(function ()
                {

                    logger.verbose('initializing recipes')
                    akala.eachAsync(recipeStore, async function (recipe, name, next)
                    {
                        delete recipe.triggerId;
                        try
                        {
                            await cl.insert(recipe, init);
                        }
                        catch
                        {
                            setTimeout(cl.insert, 60000, recipe, true);
                        }
                        next();
                    }, function ()
                        {
                            init = false;
                        });
                }, 30000)
            })
        }
        else
            logger.info(recipeFile + ' does not exist');
    });

    var server = akala.api.jsonrpcws(organizer).createServerProxy(client);
    var cl = akala.api.jsonrpcws(organizer).createClient(client, {
        trigger: async (param) =>
        {
            var triggerData = akala.extend({ $date: new Date() }, param.data);
            var conditionsData: PayloadDataType = null;
            akala.logger.verbose(`trigger ${param.id} received`);
            if (triggerMap[param.id].condition)
            {
                var result = interpolate(triggerMap[param.id].condition.params, triggerData);
                conditionsData = await server.executeCondition({ name: triggerMap[param.id].condition.name, channel: triggerMap[param.id].condition.channel, params: { $triggerData: triggerData, ...result } });
            }

            akala.logger.verbose(`interpolating: ${JSON.stringify(triggerMap[param.id].action.params)}`);
            akala.logger.verbose(`triggerData: ${JSON.stringify(triggerData)}`);
            akala.logger.verbose(`conditionsData: ${JSON.stringify(conditionsData)}`);
            await server.executeAction({ name: triggerMap[param.id].action.name, channel: triggerMap[param.id].action.channel, params: interpolate(triggerMap[param.id].action.params, { $triggerData: triggerData, $conditionsData: conditionsData }) });
        },
        async update(param)
        {
            if (!(param.name in recipes))
                return Promise.reject({ status: 404, message: 'recipe does not exist' });

            if (recipes[param.recipe.name].triggerId)
            {
                await server.stopTrigger({ id: recipes[param.recipe.name].triggerId });
                delete triggerMap[recipes[param.recipe.name].triggerId];
            }
            if (param.name != param.recipe.name)
            {
                delete recipes[param.name];
                param.recipe.name = param.name;
            }
            recipes[param.name] = param.recipe;
            await writeFile(recipeFile, JSON.stringify(recipes));
            recipes[param.recipe.name].triggerId = await server.executeTrigger(param.recipe.trigger);
            triggerMap[recipes[param.recipe.name].triggerId] = param.recipe;
        },
        async insert(recipe, init?: boolean)
        {
            if (recipe.name in recipes)
                return Promise.reject({ status: 403, message: 'recipe already exists' });

            recipes[recipe.name] = recipe;
            if (!init)
                await writeFile(recipeFile, JSON.stringify(recipes));
            logger.verbose(`requesting trigger ${recipe.trigger}`);
            recipes[recipe.name].triggerId = await server.executeTrigger(recipe.trigger);
            triggerMap[recipes[recipe.name].triggerId] = recipe;
        },
        get(param)
        {
            return recipes[param.name];
        },
        list()
        {
            return akala.map(recipes, function (recipe)
            {
                return recipe;
            }, true);
        }
    });
    server.registerOrganizer({ id:os.hostname() });
});
Example #7
0
    akala.injectWithName(['$worker'], function (worker)
    {
        function getMainDevice(name)
        {
            var indexOfDot = name.indexOf('.');
            if (indexOfDot > 0)
                var mainDevice = name.substr(0, indexOfDot);
            else
                var mainDevice = name;

            return deviceCollection[mainDevice];
        }

        var client = akala.api.jsonrpcws(devices.deviceType).createClient(c, {
            exec: function (p)
            {
                var cmd = p.command;
                var mainDevice = getMainDevice(p.device);
                if (p.device != mainDevice.name)
                {
                    switch (p.device.substring(mainDevice.name.length + 1))
                    {
                        case 'power':
                            if (p.command == 'off')
                                cmd = 'PF'
                            else
                                cmd = 'PO'
                            break;
                        case 'mute':
                            if (p.command == 'off')
                                cmd = 'MF';
                            else
                                cmd = 'MO';
                            break;
                        case 'volume':
                            switch (p.command)
                            {
                                case 'up':
                                    cmd = 'VU';
                                    break;
                                case 'down':
                                    cmd = 'VD';
                                    break;
                                case 'set':
                                    cmd = 'VL';
                                    break;
                            }
                            break;
                        case 'input':
                            switch (p.command)
                            {
                                case 'Game':
                                    cmd = '49FN';
                                    break;
                                case 'Dvd':
                                    cmd = '04FN';
                                    break;
                                case 'Sat/Cbl':
                                    cmd = '06FN';
                                    break;
                                case 'Dvr/Bdr':
                                    cmd = '15FN';
                                    break;
                                case 'iPod':
                                    cmd = '17FN';
                                    break;
                                case 'Video':
                                    cmd = '10FN';
                                    break;
                                case 'BD':
                                    cmd = '25FN';
                                    break;
                            }
                            break;
                    }
                }
                return api.send(cmd, mainDevice['address']).then((result) => undefined);
            },
            getStatus: function (device)
            {
                var mainDevice = getMainDevice(device.device);

                if (mainDevice.name == device.device)
                    return Promise.resolve(mainDevice.status());
                else
                    return Promise.resolve(mainDevice.subdevices[device.device.substring(mainDevice.name.length + 1)].status());
            },
            save: (p) =>
            {
                if (p.device.name.indexOf('.') > -1)
                    return p.device;
                deviceCollection[p.device.name] = p.device;
                p.device['address'] = p.body.IP || p.device.name;
                p.device.statusMethod = 'pull';
                p.device.subdevices = [
                    {
                        name: "power",
                        type: 'pioneer',
                        category: 'switch',
                        classes: ['power', 'switch'],
                        statusMethod: 'pull',
                        status: function ()
                        {
                            return api.send('?P', p.device.name).then(function (result)
                            {
                                console.log('result:' + result);
                                if (result)
                                    result = result.trim();
                                return { state: result == 'PWR0', color: result == 'PWR0' ? 'green' : 'red' };
                            });
                        },
                        commands: ['on', 'off']
                    },
                    {
                        name: "mute",
                        type: 'pioneer',
                        category: 'switch',
                        statusMethod: 'pull',
                        status: function ()
                        {
                            console.log('mute status');
                            return api.send('?M', p.device.name).then((result) =>
                            {
                                console.log(result);
                                return { state: result == 'MUT0', color: result == 'MUT0' ? 'green' : 'red' };
                            });
                        },
                        commands: ['on', 'off']
                    },
                    {
                        name: "volume",
                        type: 'pioneer',
                        category: 'input',
                        statusMethod: 'pull',
                        status: function ()
                        {
                            var status = {};
                            return api.send('?V', p.device.name).then(function (result)
                            {
                                return { state: Number(/\d+/.exec(result)) * 100 / 185 };
                            });
                        },
                        commands: ['up', 'down', 'set']
                    },
                    {
                        name: "input",
                        type: 'pioneer',
                        category: 'values',
                        statusMethod: 'pull',
                        status: function ()
                        {
                            return api.send('?FN', p.device.name).then(function (result)
                            {
                                console.log(result);
                                switch (Number(/[0-9]+/.exec(result)))
                                {
                                    case 49:
                                        return { state: 'Game' };
                                    case 25:
                                        return { state: 'BD' };
                                    case 4:
                                        return { state: 'Dvd' };
                                    case 6:
                                        return { state: 'Sat/Cbl' };
                                    case 15:
                                        return { state: 'Dvr/Bdr' };
                                    case 17:
                                        return { state: 'iPod' };
                                    case 10:
                                        return { state: 'Video' };
                                    default:
                                        return null;
                                }
                            });
                        },
                        commands: ['Game', 'Dvd', 'Sat/Cbl', 'Dvr/Bdr', 'iPod', 'Video', 'BD']
                    }
                ]
                return p.device;
            }
        });

        worker.on('ready', function ()
        {
            client.$proxy().register({ commandMode: 'dynamic', name: 'pioneer', view: '/@domojs/pioneer/device.html' });
        });
    })();