def blink_video_schedule(event, context):
    """Triggered from a message on a Cloud Pub/Sub topic.
    Args:
         event (dict): Event payload.
         context (google.cloud.functions.Context): Metadata for the event."""

    FILENAME = 'blink_creds.json'

    #FILENAME = re.sub(r"\/.*\/(.*\.\w{1,4}",r'\1',FILE)
    #BLOB_UPLOAD = BLINK_BUCKET.blob(f"{create_file_path()[1:]}/{FILENAME}") #Set filename format (uploads/year/month/filename).
    #BLOB_UPLOAD.upload_from_filename(FILE)

    USER_NAME, PASSWORD = load_credentials()

    AUTH = Auth({"username": USER_NAME, "password": PASSWORD}, no_prompt=True)

    pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    if pubsub_message == 'RUN':
        blink = Blink()
        blink.auth = AUTH
        blink.start()
        AUTH.send_auth_key(blink, '167363')
        blink.setup_post_verify()

        #print(type(blink.save(f'{FILENAME}')))

        CREDS = json_load("blink_creds.json")

        blob_blink = BLINK_BUCKET.blob('blink_creds.json')

        blob_blink.upload_from_string(data=json.dumps(CREDS),
                                      content_type='application/json')

        print('i am before the cameras')
        print(blink.cameras.items())
        try:
            for name, camera in blink.cameras.items():
                print('i am inside the camera')
                print(name)  # Name of the camera
                print(
                    camera.attributes)  # Print available attributes of camera
        except ValueError:
            print('there is some error')

        blink.download_videos(since='2018/07/04 09:34')
        return "SUCCESS"
Beispiel #2
0
class TestAuth(unittest.TestCase):
    """Test the Auth class in blinkpy."""
    def setUp(self):
        """Set up Login Handler."""
        self.auth = Auth()

    def tearDown(self):
        """Clean up after test."""
        self.auth = None

    @mock.patch("blinkpy.helpers.util.gen_uid")
    @mock.patch("blinkpy.auth.util.getpass")
    def test_empty_init(self, getpwd, genuid):
        """Test initialization with no params."""
        auth = Auth()
        self.assertDictEqual(auth.data, {})
        getpwd.return_value = "bar"
        genuid.return_value = 1234
        with mock.patch("builtins.input", return_value="foo"):
            auth.validate_login()
        expected_data = {
            "username": "******",
            "password": "******",
            "uid": 1234,
            "device_id": const.DEVICE_ID,
        }
        self.assertDictEqual(auth.data, expected_data)

    @mock.patch("blinkpy.helpers.util.gen_uid")
    @mock.patch("blinkpy.auth.util.getpass")
    def test_barebones_init(self, getpwd, genuid):
        """Test basebones initialization."""
        login_data = {"username": "******", "password": "******"}
        auth = Auth(login_data)
        self.assertDictEqual(auth.data, login_data)
        getpwd.return_value = "bar"
        genuid.return_value = 1234
        with mock.patch("builtins.input", return_value="foo"):
            auth.validate_login()
        expected_data = {
            "username": "******",
            "password": "******",
            "uid": 1234,
            "device_id": const.DEVICE_ID,
        }
        self.assertDictEqual(auth.data, expected_data)

    def test_full_init(self):
        """Test full initialization."""
        login_data = {
            "username": "******",
            "password": "******",
            "token": "token",
            "host": "host",
            "region_id": "region_id",
            "client_id": "client_id",
            "account_id": "account_id",
            "uid": 1234,
            "notification_key": 4321,
            "device_id": "device_id",
        }
        auth = Auth(login_data)
        self.assertEqual(auth.token, "token")
        self.assertEqual(auth.host, "host")
        self.assertEqual(auth.region_id, "region_id")
        self.assertEqual(auth.client_id, "client_id")
        self.assertEqual(auth.account_id, "account_id")
        auth.validate_login()
        self.assertDictEqual(auth.login_attributes, login_data)

    def test_bad_response_code(self):
        """Check bad response code from server."""
        self.auth.is_errored = False
        fake_resp = mresp.MockResponse({"code": 404}, 404)
        with self.assertRaises(exceptions.ConnectionError):
            self.auth.validate_response(fake_resp, True)
        self.assertTrue(self.auth.is_errored)

        self.auth.is_errored = False
        fake_resp = mresp.MockResponse({"code": 101}, 401)
        with self.assertRaises(UnauthorizedError):
            self.auth.validate_response(fake_resp, True)
        self.assertTrue(self.auth.is_errored)

    def test_good_response_code(self):
        """Check good response code from server."""
        fake_resp = mresp.MockResponse({"foo": "bar"}, 200)
        self.auth.is_errored = True
        self.assertEqual(self.auth.validate_response(fake_resp, True),
                         {"foo": "bar"})
        self.assertFalse(self.auth.is_errored)

    def test_response_not_json(self):
        """Check response when not json."""
        fake_resp = "foobar"
        self.auth.is_errored = True
        self.assertEqual(self.auth.validate_response(fake_resp, False),
                         "foobar")
        self.assertFalse(self.auth.is_errored)

    def test_response_bad_json(self):
        """Check response when not json but expecting json."""
        self.auth.is_errored = False
        with self.assertRaises(BlinkBadResponse):
            self.auth.validate_response(None, True)
        self.assertTrue(self.auth.is_errored)

    def test_header(self):
        """Test header data."""
        self.auth.token = "bar"
        expected_header = {
            "TOKEN_AUTH": "bar",
            "user-agent": const.DEFAULT_USER_AGENT,
            "content-type": "application/json",
        }
        self.assertDictEqual(self.auth.header, expected_header)

    def test_header_no_token(self):
        """Test header without token."""
        self.auth.token = None
        self.assertEqual(self.auth.header, None)

    @mock.patch("blinkpy.auth.Auth.validate_login", return_value=None)
    @mock.patch("blinkpy.auth.api.request_login")
    def test_login(self, mock_req, mock_validate):
        """Test login handling."""
        fake_resp = mresp.MockResponse({"foo": "bar"}, 200)
        mock_req.return_value = fake_resp
        self.assertEqual(self.auth.login(), {"foo": "bar"})

    @mock.patch("blinkpy.auth.Auth.validate_login", return_value=None)
    @mock.patch("blinkpy.auth.api.request_login")
    def test_login_bad_response(self, mock_req, mock_validate):
        """Test login handling when bad response."""
        fake_resp = mresp.MockResponse({"foo": "bar"}, 404)
        mock_req.return_value = fake_resp
        self.auth.is_errored = False
        with self.assertRaises(LoginError):
            self.auth.login()
        with self.assertRaises(TokenRefreshFailed):
            self.auth.refresh_token()
        self.assertTrue(self.auth.is_errored)

    @mock.patch("blinkpy.auth.Auth.login")
    def test_refresh_token(self, mock_login):
        """Test refresh token method."""
        mock_login.return_value = {
            "account": {
                "account_id": 5678,
                "client_id": 1234,
                "tier": "test"
            },
            "auth": {
                "token": "foobar"
            },
        }
        self.assertTrue(self.auth.refresh_token())
        self.assertEqual(self.auth.region_id, "test")
        self.assertEqual(self.auth.token, "foobar")
        self.assertEqual(self.auth.client_id, 1234)
        self.assertEqual(self.auth.account_id, 5678)

    @mock.patch("blinkpy.auth.Auth.login")
    def test_refresh_token_failed(self, mock_login):
        """Test refresh token failed."""
        mock_login.return_value = {}
        self.auth.is_errored = False
        with self.assertRaises(TokenRefreshFailed):
            self.auth.refresh_token()
        self.assertTrue(self.auth.is_errored)

    def test_check_key_required(self):
        """Check key required method."""
        self.auth.login_response = {}
        self.assertFalse(self.auth.check_key_required())

        self.auth.login_response = {
            "account": {
                "client_verification_required": False
            }
        }
        self.assertFalse(self.auth.check_key_required())

        self.auth.login_response = {
            "account": {
                "client_verification_required": True
            }
        }
        self.assertTrue(self.auth.check_key_required())

    @mock.patch("blinkpy.auth.api.request_logout")
    def test_logout(self, mock_req):
        """Test logout method."""
        mock_blink = MockBlink(None)
        mock_req.return_value = True
        self.assertTrue(self.auth.logout(mock_blink))

    @mock.patch("blinkpy.auth.api.request_verify")
    def test_send_auth_key(self, mock_req):
        """Check sending of auth key."""
        mock_blink = MockBlink(None)
        mock_req.return_value = mresp.MockResponse({"valid": True}, 200)
        self.assertTrue(self.auth.send_auth_key(mock_blink, 1234))
        self.assertTrue(mock_blink.available)

        mock_req.return_value = mresp.MockResponse(None, 200)
        self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))

        mock_req.return_value = mresp.MockResponse({}, 200)
        self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))

        self.assertTrue(self.auth.send_auth_key(mock_blink, None))

    @mock.patch("blinkpy.auth.api.request_verify")
    def test_send_auth_key_fail(self, mock_req):
        """Check handling of auth key failure."""
        mock_blink = MockBlink(None)
        mock_req.return_value = mresp.MockResponse(None, 200)
        self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))
        mock_req.return_value = mresp.MockResponse({}, 200)
        self.assertFalse(self.auth.send_auth_key(mock_blink, 1234))

    @mock.patch("blinkpy.auth.Auth.validate_response")
    @mock.patch("blinkpy.auth.Auth.refresh_token")
    def test_query_retry(self, mock_refresh, mock_validate):
        """Check handling of request retry."""
        self.auth.session = MockSession()
        mock_validate.side_effect = [UnauthorizedError, "foobar"]
        mock_refresh.return_value = True
        self.assertEqual(self.auth.query(url="http://example.com"), "foobar")

    @mock.patch("blinkpy.auth.Auth.validate_response")
    @mock.patch("blinkpy.auth.Auth.refresh_token")
    def test_query_retry_failed(self, mock_refresh, mock_validate):
        """Check handling of failed retry request."""
        self.auth.session = MockSession()
        mock_validate.side_effect = [UnauthorizedError, BlinkBadResponse]
        mock_refresh.return_value = True
        self.assertEqual(self.auth.query(url="http://example.com"), None)

        mock_validate.side_effect = [UnauthorizedError, TokenRefreshFailed]
        self.assertEqual(self.auth.query(url="http://example.com"), None)

    def test_default_session(self):
        """Test default session creation."""
        sess = self.auth.create_session()
        adapter = sess.adapters["https://"]
        self.assertEqual(adapter.max_retries.total, 3)
        self.assertEqual(adapter.max_retries.backoff_factor, 1)
        self.assertEqual(adapter.max_retries.status_forcelist,
                         [429, 500, 502, 503, 504])

    def test_custom_session_full(self):
        """Test full custom session creation."""
        opts = {"backoff": 2, "retries": 10, "retry_list": [404]}
        sess = self.auth.create_session(opts=opts)
        adapter = sess.adapters["https://"]
        self.assertEqual(adapter.max_retries.total, 10)
        self.assertEqual(adapter.max_retries.backoff_factor, 2)
        self.assertEqual(adapter.max_retries.status_forcelist, [404])

    def test_custom_session_partial(self):
        """Test partial custom session creation."""
        opts1 = {"backoff": 2}
        opts2 = {"retries": 5}
        opts3 = {"retry_list": [101, 202]}
        sess1 = self.auth.create_session(opts=opts1)
        sess2 = self.auth.create_session(opts=opts2)
        sess3 = self.auth.create_session(opts=opts3)
        adapt1 = sess1.adapters["https://"]
        adapt2 = sess2.adapters["https://"]
        adapt3 = sess3.adapters["https://"]

        self.assertEqual(adapt1.max_retries.total, 3)
        self.assertEqual(adapt1.max_retries.backoff_factor, 2)
        self.assertEqual(adapt1.max_retries.status_forcelist,
                         [429, 500, 502, 503, 504])

        self.assertEqual(adapt2.max_retries.total, 5)
        self.assertEqual(adapt2.max_retries.backoff_factor, 1)
        self.assertEqual(adapt2.max_retries.status_forcelist,
                         [429, 500, 502, 503, 504])

        self.assertEqual(adapt3.max_retries.total, 3)
        self.assertEqual(adapt3.max_retries.backoff_factor, 1)
        self.assertEqual(adapt3.max_retries.status_forcelist, [101, 202])
Beispiel #3
0
class Blink:
    """Class to initialize communication."""

    def __init__(
        self,
        refresh_rate=DEFAULT_REFRESH,
        motion_interval=DEFAULT_MOTION_INTERVAL,
        no_owls=False,
    ):
        """
        Initialize Blink system.

        :param refresh_rate: Refresh rate of blink information.
                             Defaults to 15 (seconds)
        :param motion_interval: How far back to register motion in minutes.
                                Defaults to last refresh time.
                                Useful for preventing motion_detected property
                                from de-asserting too quickly.
        :param no_owls: Disable searching for owl entries (blink mini cameras only known entity).  Prevents an uneccessary API call if you don't have these in your network.
        """
        self.auth = Auth()
        self.account_id = None
        self.client_id = None
        self.network_ids = []
        self.urls = None
        self.sync = CaseInsensitiveDict({})
        self.last_refresh = None
        self.refresh_rate = refresh_rate
        self.networks = []
        self.cameras = CaseInsensitiveDict({})
        self.video_list = CaseInsensitiveDict({})
        self.motion_interval = motion_interval
        self.version = __version__
        self.available = False
        self.key_required = False
        self.homescreen = {}
        self.no_owls = no_owls

    @util.Throttle(seconds=MIN_THROTTLE_TIME)
    def refresh(self, force=False, force_cache=False):
        """
        Perform a system refresh.

        :param force: Used to override throttle, resets refresh
        :param force_cache: Used to force update without overriding throttle
        """
        if self.check_if_ok_to_update() or force or force_cache:
            if not self.available:
                self.setup_post_verify()

            self.get_homescreen()
            for sync_name, sync_module in self.sync.items():
                _LOGGER.debug("Attempting refresh of sync %s", sync_name)
                sync_module.refresh(force_cache=(force or force_cache))
            if not force_cache:
                # Prevents rapid clearing of motion detect property
                self.last_refresh = int(time.time())
            return True
        return False

    def start(self):
        """Perform full system setup."""
        try:
            self.auth.startup()
            self.setup_login_ids()
            self.setup_urls()
            self.get_homescreen()
        except (LoginError, TokenRefreshFailed, BlinkSetupError):
            _LOGGER.error("Cannot setup Blink platform.")
            self.available = False
            return False

        self.key_required = self.auth.check_key_required()
        if self.key_required:
            if self.auth.no_prompt:
                return True
            self.setup_prompt_2fa()
        return self.setup_post_verify()

    def setup_prompt_2fa(self):
        """Prompt for 2FA."""
        email = self.auth.data["username"]
        pin = input(f"Enter code sent to {email}: ")
        result = self.auth.send_auth_key(self, pin)
        self.key_required = not result

    def setup_post_verify(self):
        """Initialize blink system after verification."""
        try:
            self.setup_networks()
            networks = self.setup_network_ids()
            cameras = self.setup_camera_list()
        except BlinkSetupError:
            self.available = False
            return False

        for name, network_id in networks.items():
            sync_cameras = cameras.get(network_id, {})
            self.setup_sync_module(name, network_id, sync_cameras)

        self.cameras = self.merge_cameras()

        self.available = True
        self.key_required = False
        return True

    def setup_sync_module(self, name, network_id, cameras):
        """Initialize a sync module."""
        self.sync[name] = BlinkSyncModule(self, name, network_id, cameras)
        self.sync[name].start()

    def get_homescreen(self):
        """Get homecreen information."""
        if self.no_owls:
            _LOGGER.debug("Skipping owl extraction.")
            self.homescreen = {}
            return
        self.homescreen = api.request_homescreen(self)

    def setup_owls(self):
        """Check for mini cameras."""
        network_list = []
        camera_list = []
        try:
            for owl in self.homescreen["owls"]:
                name = owl["name"]
                network_id = str(owl["network_id"])
                if network_id in self.network_ids:
                    camera_list.append(
                        {network_id: {"name": name, "id": network_id, "type": "mini"}}
                    )
                    continue
                if owl["onboarded"]:
                    network_list.append(str(network_id))
                    self.sync[name] = BlinkOwl(self, name, network_id, owl)
                    self.sync[name].start()
        except KeyError:
            # No sync-less devices found
            pass

        self.network_ids.extend(network_list)
        return camera_list

    def setup_camera_list(self):
        """Create camera list for onboarded networks."""
        all_cameras = {}
        response = api.request_camera_usage(self)
        try:
            for network in response["networks"]:
                camera_network = str(network["network_id"])
                if camera_network not in all_cameras:
                    all_cameras[camera_network] = []
                for camera in network["cameras"]:
                    all_cameras[camera_network].append(
                        {"name": camera["name"], "id": camera["id"]}
                    )
            mini_cameras = self.setup_owls()
            for camera in mini_cameras:
                for network, camera_info in camera.items():
                    all_cameras[network].append(camera_info)
            return all_cameras
        except (KeyError, TypeError):
            _LOGGER.error("Unable to retrieve cameras from response %s", response)
            raise BlinkSetupError

    def setup_login_ids(self):
        """Retrieve login id numbers from login response."""
        self.client_id = self.auth.client_id
        self.account_id = self.auth.account_id

    def setup_urls(self):
        """Create urls for api."""
        try:
            self.urls = util.BlinkURLHandler(self.auth.region_id)
        except TypeError:
            _LOGGER.error(
                "Unable to extract region is from response %s", self.auth.login_response
            )
            raise BlinkSetupError

    def setup_networks(self):
        """Get network information."""
        response = api.request_networks(self)
        try:
            self.networks = response["summary"]
        except (KeyError, TypeError):
            raise BlinkSetupError

    def setup_network_ids(self):
        """Create the network ids for onboarded networks."""
        all_networks = []
        network_dict = {}
        try:
            for network, status in self.networks.items():
                if status["onboarded"]:
                    all_networks.append(f"{network}")
                    network_dict[status["name"]] = network
        except AttributeError:
            _LOGGER.error(
                "Unable to retrieve network information from %s", self.networks
            )
            raise BlinkSetupError

        self.network_ids = all_networks
        return network_dict

    def check_if_ok_to_update(self):
        """Check if it is ok to perform an http request."""
        current_time = int(time.time())
        last_refresh = self.last_refresh
        if last_refresh is None:
            last_refresh = 0
        if current_time >= (last_refresh + self.refresh_rate):
            return True
        return False

    def merge_cameras(self):
        """Merge all sync camera dicts into one."""
        combined = CaseInsensitiveDict({})
        for sync in self.sync:
            combined = util.merge_dicts(combined, self.sync[sync].cameras)
        return combined

    def save(self, file_name):
        """Save login data to file."""
        util.json_save(self.auth.login_attributes, file_name)

    def download_videos(
        self, path, since=None, camera="all", stop=10, delay=1, debug=False
    ):
        """
        Download all videos from server since specified time.

        :param path: Path to write files.  /path/<cameraname>_<recorddate>.mp4
        :param since: Date and time to get videos from.
                      Ex: "2018/07/28 12:33:00" to retrieve videos since
                      July 28th 2018 at 12:33:00
        :param camera: Camera name to retrieve.  Defaults to "all".
                       Use a list for multiple cameras.
        :param stop: Page to stop on (~25 items per page. Default page 10).
        :param delay: Number of seconds to wait in between subsequent video downloads.
        :param debug: Set to TRUE to prevent downloading of items.
                      Instead of downloading, entries will be printed to log.
        """
        if since is None:
            since_epochs = self.last_refresh
        else:
            parsed_datetime = parse(since, fuzzy=True)
            since_epochs = parsed_datetime.timestamp()

        formatted_date = util.get_time(time_to_convert=since_epochs)
        _LOGGER.info("Retrieving videos since %s", formatted_date)

        if not isinstance(camera, list):
            camera = [camera]

        for page in range(1, stop):
            response = api.request_videos(self, time=since_epochs, page=page)
            _LOGGER.debug("Processing page %s", page)
            try:
                result = response["media"]
                if not result:
                    raise KeyError
            except (KeyError, TypeError):
                _LOGGER.info("No videos found on page %s. Exiting.", page)
                break

            self._parse_downloaded_items(result, camera, path, delay, debug)

    def _parse_downloaded_items(self, result, camera, path, delay, debug):
        """Parse downloaded videos."""
        for item in result:
            try:
                created_at = item["created_at"]
                camera_name = item["device_name"]
                is_deleted = item["deleted"]
                address = item["media"]
            except KeyError:
                _LOGGER.info("Missing clip information, skipping...")
                continue

            if camera_name not in camera and "all" not in camera:
                _LOGGER.debug("Skipping videos for %s.", camera_name)
                continue

            if is_deleted:
                _LOGGER.debug("%s: %s is marked as deleted.", camera_name, address)
                continue

            clip_address = f"{self.urls.base_url}{address}"
            filename = f"{camera_name}-{created_at}"
            filename = f"{slugify(filename)}.mp4"
            filename = os.path.join(path, filename)

            if not debug:
                if os.path.isfile(filename):
                    _LOGGER.info("%s already exists, skipping...", filename)
                    continue

                response = api.http_get(
                    self,
                    url=clip_address,
                    stream=True,
                    json=False,
                    timeout=TIMEOUT_MEDIA,
                )
                with open(filename, "wb") as vidfile:
                    copyfileobj(response.raw, vidfile)

                _LOGGER.info("Downloaded video to %s", filename)
            else:
                print(
                    (
                        f"Camera: {camera_name}, Timestamp: {created_at}, "
                        "Address: {address}, Filename: {filename}"
                    )
                )
            if delay > 0:
                time.sleep(delay)
	file_path = f'/uploads/{year}/{month}'
	return file_path

FILENAME= 'blink_creds.json'
#FILENAME = re.sub(r"\/.*\/(.*\.\w{1,4}",r'\1',FILE)
#BLOB_UPLOAD = BLINK_BUCKET.blob(f"{create_file_path()[1:]}/{FILENAME}") #Set filename format (uploads/year/month/filename).
#BLOB_UPLOAD.upload_from_filename(FILE)

USER_NAME, PASSWORD = load_credentials()

AUTH = Auth({"username": USER_NAME, "password": PASSWORD}, no_prompt=True)

blink = Blink()
blink.auth = AUTH
blink.start()
AUTH.send_auth_key(blink, '399587')
blink.setup_post_verify()



print(type(blink.save(f'{FILENAME}')))

CREDS = json_load("blink_creds.json")

blob_blink = BLINK_BUCKET.blob('blink_creds.json')

blob_blink.upload_from_string(
   data=json.dumps(CREDS),
   content_type='application/json'
 )