Example #1
0
    async def zipped(self, camera_id, group):
        key = self.get_argument('key', None)
        camera_config = config.get_camera(camera_id)

        if key:
            logging.debug('serving zip file for group "%(group)s" of camera %(id)s with key %(key)s' % {
                'group': group or 'ungrouped', 'id': camera_id, 'key': key})

            if utils.is_local_motion_camera(camera_config):
                data = mediafiles.get_prepared_cache(key)
                if not data:
                    logging.error('prepared cache data for key "%s" does not exist' % key)

                    raise HTTPError(404, 'no such key')

                pretty_filename = camera_config['camera_name'] + '_' + group
                pretty_filename = re.sub('[^a-zA-Z0-9]', '_', pretty_filename)

                self.set_header('Content-Type', 'application/zip')
                self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + '.zip;')
                return self.finish(data)

            elif utils.is_remote_camera(camera_config):
                resp = await remote.get_zipped_content(camera_config, media_type='picture', key=key, group=group)
                if resp.error:
                    return self.finish_json({'error': 'Failed to download zip file from %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config), 'msg': resp.error}})

                self.set_header('Content-Type', resp.result['content_type'])
                self.set_header('Content-Disposition', resp.result['content_disposition'])
                return self.finish(resp.result['data'])

            else:  # assuming simple mjpeg camera
                raise HTTPError(400, 'unknown operation')

        else:  # prepare
            logging.debug('preparing zip file for group "%(group)s" of camera %(id)s' % {
                'group': group or 'ungrouped', 'id': camera_id})

            if utils.is_local_motion_camera(camera_config):
                data = await mediafiles.get_zipped_content(camera_config, media_type='picture', group=group)
                if data is None:
                    return self.finish_json({'error': 'Failed to create zip file.'})

                key = mediafiles.set_prepared_cache(data)
                logging.debug('prepared zip file for group "%(group)s" of camera %(id)s with key %(key)s' % {
                    'group': group or 'ungrouped', 'id': camera_id, 'key': key})
                self.finish_json({'key': key})

            elif utils.is_remote_camera(camera_config):
                resp = await remote.make_zipped_content(camera_config, media_type='picture', group=group)
                if resp.error:
                    return self.finish_json({'error': 'Failed to make zip file at %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config), 'msg': resp.error}})

                return self.finish_json({'key': resp.result['key']})

            else:  # assuming simple mjpeg camera
                raise HTTPError(400, 'unknown operation')
Example #2
0
    async def list(self, camera_id):
        logging.debug('listing movies for camera %(id)s' % {'id': camera_id})

        camera_config = config.get_camera(camera_id)
        if utils.is_local_motion_camera(camera_config):
            media_list = await mediafiles.list_media(camera_config,
                                                     media_type='movie',
                                                     prefix=self.get_argument(
                                                         'prefix', None))
            if media_list is None:
                self.finish_json({'error': 'Failed to get movies list.'})

            return self.finish_json({
                'mediaList': media_list,
                'cameraName': camera_config['camera_name']
            })

        elif utils.is_remote_camera(camera_config):
            resp = await remote.list_media(camera_config,
                                           media_type='movie',
                                           prefix=self.get_argument(
                                               'prefix', None))
            if resp.error:
                return self.finish_json({
                    'error':
                    'Failed to get movie list for %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config),
                        'msg': resp.error
                    }
                })

            return self.finish_json(resp.media_list)

        else:  # assuming simple mjpeg camera
            raise HTTPError(400, 'unknown operation')
Example #3
0
    async def delete_all(self, camera_id, group):
        logging.debug('deleting movie group "%(group)s" of camera %(id)s' % {
            'group': group or 'ungrouped',
            'id': camera_id
        })

        camera_config = config.get_camera(camera_id)
        if utils.is_local_motion_camera(camera_config):
            try:
                mediafiles.del_media_group(camera_config, group, 'movie')
                return self.finish_json()

            except Exception as e:
                return self.finish_json({'error': str(e)})

        elif utils.is_remote_camera(camera_config):
            resp = await remote.del_media_group(camera_config,
                                                group=group,
                                                media_type='movie')
            if resp.error:
                return self.finish_json({
                    'error':
                    'Failed to delete movie group at %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config),
                        'msg': resp.error
                    }
                })

            return self.finish_json()

        else:  # assuming simple mjpeg camera
            raise HTTPError(400, 'unknown operation')
Example #4
0
    async def delete(self, camera_id, filename):
        logging.debug('deleting movie %(filename)s of camera %(id)s' % {
            'filename': filename,
            'id': camera_id
        })

        camera_config = config.get_camera(camera_id)
        if utils.is_local_motion_camera(camera_config):
            try:
                mediafiles.del_media_content(camera_config, filename, 'movie')
                return self.finish_json()

            except Exception as e:
                return self.finish_json({'error': str(e)})

        elif utils.is_remote_camera(camera_config):
            resp = await remote.del_media_content(camera_config,
                                                  filename=filename,
                                                  media_type='movie')
            if resp.error:
                return self.finish_json({
                    'error':
                    'Failed to delete movie from %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config),
                        'msg': resp.error
                    }
                })

            return self.finish_json()

        else:  # assuming simple mjpeg camera
            raise HTTPError(400, 'unknown operation')
Example #5
0
    async def download(self, camera_id, filename):
        logging.debug('downloading picture %(filename)s of camera %(id)s' % {
            'filename': filename, 'id': camera_id})

        camera_config = config.get_camera(camera_id)
        if utils.is_local_motion_camera(camera_config):
            content = mediafiles.get_media_content(camera_config, filename, 'picture')

            pretty_filename = camera_config['camera_name'] + '_' + os.path.basename(filename)
            self.set_header('Content-Type', 'image/jpeg')
            self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';')

            return self.finish(content)

        elif utils.is_remote_camera(camera_config):
            resp = await remote.get_media_content(camera_config, filename=filename, media_type='picture')
            if resp.error:
                return self.finish_json({'error': 'Failed to download picture from %(url)s: %(msg)s.' % {
                    'url': remote.pretty_camera_url(camera_config), 'msg': resp.error}})

            pretty_filename = os.path.basename(filename)  # no camera name available w/o additional request
            self.set_header('Content-Type', 'image/jpeg')
            self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';')

            return self.finish(resp.result)

        else:  # assuming simple mjpeg camera
            raise HTTPError(400, 'unknown operation')
Example #6
0
    async def get_config(self, camera_id):
        if camera_id:
            logging.debug('getting config for camera %(id)s' %
                          {'id': camera_id})

            if camera_id not in config.get_camera_ids():
                raise HTTPError(404, 'no such camera')

            local_config = config.get_camera(camera_id)
            if utils.is_local_motion_camera(local_config):
                ui_config = config.motion_camera_dict_to_ui(local_config)

                return self.finish_json(ui_config)

            elif utils.is_remote_camera(local_config):
                resp = await remote.get_config(local_config)
                if resp.error:
                    msg = 'Failed to get remote camera configuration for %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(local_config),
                        'msg': resp.error
                    }
                    return self.finish_json_with_error(msg)

                for key, value in list(local_config.items()):
                    resp.remote_ui_config[key.replace('@', '')] = value

                # replace the real device url with the remote camera path
                resp.remote_ui_config['device_url'] = remote.pretty_camera_url(
                    local_config)
                return self.finish_json(resp.remote_ui_config)

            else:  # assuming simple mjpeg camera
                ui_config = config.simple_mjpeg_camera_dict_to_ui(local_config)

                return self.finish_json(ui_config)

        else:
            logging.debug('getting main config')

            ui_config = config.main_dict_to_ui(config.get_main())
            return self.finish_json(ui_config)
Example #7
0
    async def post(self, camera_id, action):
        camera_id = int(camera_id)
        if camera_id not in config.get_camera_ids():
            raise HTTPError(404, 'no such camera')

        local_config = config.get_camera(camera_id)
        if utils.is_remote_camera(local_config):
            resp = await remote.exec_action(local_config, action)
            if resp.error:
                msg = 'Failed to execute action on remote camera at %(url)s: %(msg)s.' % {
                    'url': remote.pretty_camera_url(local_config),
                    'msg': resp.error
                }

                return self.finish_json({'error': msg})

            return self.finish_json()

        if action == 'snapshot':
            logging.debug('executing snapshot action for camera with id %s' %
                          camera_id)
            await self.snapshot(camera_id)
            return

        elif action == 'record_start':
            logging.debug(
                'executing record_start action for camera with id %s' %
                camera_id)
            return self.record_start(camera_id)

        elif action == 'record_stop':
            logging.debug(
                'executing record_stop action for camera with id %s' %
                camera_id)
            return self.record_stop(camera_id)

        action_commands = config.get_action_commands(local_config)
        command = action_commands.get(action)
        if not command:
            raise HTTPError(400, 'unknown action')

        logging.debug('executing %s action for camera with id %s: "%s"' %
                      (action, camera_id, command))
        self.run_command_bg(command)
Example #8
0
    def _handle_get_config_response(self, camera_id, local_config,
                                    resp: utils.GetConfigResponse,
                                    cameras: list, length: list) -> None:
        if resp.error:
            cameras.append({
                'id':
                camera_id,
                'name':
                '<' + remote.pretty_camera_url(local_config) + '>',
                'enabled':
                False,
                'streaming_framerate':
                1,
                'framerate':
                1
            })

        else:
            resp.remote_ui_config['id'] = camera_id

            if not resp.remote_ui_config['enabled'] and local_config[
                    '@enabled']:
                # if a remote camera is disabled, make sure it's disabled locally as well
                local_config['@enabled'] = False
                config.set_camera(camera_id, local_config)

            elif resp.remote_ui_config[
                    'enabled'] and not local_config['@enabled']:
                # if a remote camera is locally disabled, make sure the remote config says the same thing
                resp.remote_ui_config['enabled'] = False

            for key, value in list(local_config.items()):
                resp.remote_ui_config[key.replace('@', '')] = value

            cameras.append(resp.remote_ui_config)

        finished = self.check_finished(cameras, length)
        return
Example #9
0
    async def get(self, camera_id, filename=None, include_body=True):
        logging.debug('downloading movie %(filename)s of camera %(id)s' % {
            'filename': filename,
            'id': camera_id
        })

        self.pretty_filename = os.path.basename(filename)

        if camera_id is not None:
            camera_id = int(camera_id)
            if camera_id not in config.get_camera_ids():
                raise HTTPError(404, 'no such camera')

        camera_config = config.get_camera(camera_id)

        if utils.is_local_motion_camera(camera_config):
            filename = mediafiles.get_media_path(camera_config, filename,
                                                 'movie')
            self.pretty_filename = camera_config[
                'camera_name'] + '_' + self.pretty_filename
            await StaticFileHandler.get(self,
                                        filename,
                                        include_body=include_body)
            return

        elif utils.is_remote_camera(camera_config):
            # we will cache the movie since it takes a while to fetch from the remote camera
            # and we may be going to play it back in the browser, which will fetch the video in chunks
            tmpfile = self.tmpdir + '/' + self.pretty_filename
            if os.path.isfile(tmpfile):
                # have a cached copy, update the timestamp so it's not flushed
                import time
                mtime = os.stat(tmpfile).st_mtime
                os.utime(tmpfile, (time.time(), mtime))
                await StaticFileHandler.get(self,
                                            tmpfile,
                                            include_body=include_body)
                return

            resp = await remote.get_media_content(camera_config,
                                                  filename,
                                                  media_type='movie')
            if resp.error:
                return self.finish_json({
                    'error':
                    'Failed to download movie from %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config),
                        'msg': resp.error
                    }
                })

            # check if the file has been created by another request while we were fetching the movie
            if not os.path.isfile(tmpfile):
                tmp = open(tmpfile, 'wb')
                tmp.write(resp.result)
                tmp.close()

            await StaticFileHandler.get(self,
                                        tmpfile,
                                        include_body=include_body)
            return

        else:  # assuming simple mjpeg camera
            raise HTTPError(400, 'unknown operation')
Example #10
0
    async def timelapse(self, camera_id, group):
        key = self.get_argument('key', None)
        check = self.get_argument('check', False)
        camera_config = config.get_camera(camera_id)

        if key:  # download
            logging.debug('serving timelapse movie for group "%(group)s" of camera %(id)s with key %(key)s' % {
                'group': group or 'ungrouped', 'id': camera_id, 'key': key})

            if utils.is_local_motion_camera(camera_config):
                data = mediafiles.get_prepared_cache(key)
                if data is None:
                    logging.error('prepared cache data for key "%s" does not exist' % key)

                    raise HTTPError(404, 'no such key')

                pretty_filename = camera_config['camera_name'] + '_' + group
                pretty_filename = re.sub('[^a-zA-Z0-9]', '_', pretty_filename)
                pretty_filename += '.' + mediafiles.FFMPEG_EXT_MAPPING.get(camera_config['movie_codec'], 'avi')

                self.set_header('Content-Type', 'video/x-msvideo')
                self.set_header('Content-Disposition', 'attachment; filename=' + pretty_filename + ';')
                return self.finish(data)

            elif utils.is_remote_camera(camera_config):
                resp = await remote.get_timelapse_movie(camera_config, key, group=group)
                if resp.error:
                    msg = 'Failed to download timelapse movie from %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config), 'msg': resp.error}

                    return self.finish_json({'error': msg})

                self.set_header('Content-Type', resp.result['content_type'])
                self.set_header('Content-Disposition', resp.result['content_disposition'])
                return self.finish(resp.result['data'])

            else:  # assuming simple mjpeg camera
                raise HTTPError(400, 'unknown operation')

        elif check:
            logging.debug('checking timelapse movie status for group "%(group)s" of camera %(id)s' % {
                'group': group or 'ungrouped', 'id': camera_id})

            if utils.is_local_motion_camera(camera_config):
                status = mediafiles.check_timelapse_movie()
                if status['progress'] == -1 and status['data']:
                    key = mediafiles.set_prepared_cache(status['data'])
                    logging.debug('prepared timelapse movie for group "%(group)s" of camera %(id)s with key %(key)s' % {
                        'group': group or 'ungrouped', 'id': camera_id, 'key': key})
                    return self.finish_json({'key': key, 'progress': -1})

                else:
                    return self.finish_json(status)

            elif utils.is_remote_camera(camera_config):
                resp = await remote.check_timelapse_movie(camera_config, group=group)
                if resp.error:
                    msg = 'Failed to check timelapse movie progress at %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config), 'msg': resp.error}

                    return self.finish_json({'error': msg})

                if resp.result['progress'] == -1 and resp.result.get('key'):
                    self.finish_json({'key': resp.result['key'], 'progress': -1})

                else:
                    self.finish_json(resp.result)

            else:  # assuming simple mjpeg camera
                raise HTTPError(400, 'unknown operation')

        else:  # start timelapse
            interval = int(self.get_argument('interval'))
            framerate = int(self.get_argument('framerate'))

            msg = 'preparing timelapse movie for group "%(group)s" of camera %(id)s with rate %(framerate)s/%(int)s' % {
                'group': group or 'ungrouped', 'id': camera_id, 'framerate': framerate, 'int': interval}
            logging.debug(msg)

            if utils.is_local_motion_camera(camera_config):
                status = mediafiles.check_timelapse_movie()
                if status['progress'] != -1:
                    return self.finish_json({'progress': status['progress']})  # timelapse already active

                else:
                    mediafiles.make_timelapse_movie(camera_config, framerate, interval, group=group)
                    return self.finish_json({'progress': -1})

            elif utils.is_remote_camera(camera_config):
                check_timelapse_resp = await remote.check_timelapse_movie(camera_config, group=group)
                if check_timelapse_resp.error:
                    return self.finish_json({'error': 'Failed to make timelapse movie at %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config), 'msg': check_timelapse_resp.error}})

                if check_timelapse_resp.result['progress'] != -1:
                    # timelapse already active
                    return self.finish_json({'progress': check_timelapse_resp.result['progress']})

                make_timelapse_resp = await remote.make_timelapse_movie(camera_config, framerate, interval, group=group)
                if make_timelapse_resp.error:
                    return self.finish_json({'error': 'Failed to make timelapse movie at %(url)s: %(msg)s.' % {
                        'url': remote.pretty_camera_url(camera_config), 'msg': make_timelapse_resp.error}})

                return self.finish_json({'progress': -1})

            else:  # assuming simple mjpeg camera
                raise HTTPError(400, 'unknown operation')