예제 #1
0
def download_file(item, local_file):
    if not (item and local_file):
        return False
    LOGGER.info(f"Downloading {local_file} ...")
    try:
        with item.open(stream=True) as response:
            with open(local_file, "wb") as file_out:
                copyfileobj(response.raw, file_out)
        item_modified_time = time.mktime(item.date_modified.timetuple())
        os.utime(local_file, (item_modified_time, item_modified_time))
    except (exceptions.ICloudPyAPIResponseException, FileNotFoundError,
            Exception) as e:
        LOGGER.error(f"Failed to download {local_file}: {str(e)}")
        return False
    return True
def get_username(config):
    username = None
    config_path = ["app", "credentials", "username"]
    if not traverse_config_path(config=config, config_path=config_path):
        LOGGER.error(
            f"username is missing in {config_path_to_string(config_path)}. Please set the username."
        )
    else:
        username = get_config_value(config=config, config_path=config_path)
        username = username.strip()
        if len(username) == 0:
            username = None
            LOGGER.error(
                f"username is empty in {config_path_to_string(config_path)}.")
    return username
예제 #3
0
    def _process_method(self, value: str, execute: bool = True) -> str:
        LOGGER.debug(f"Processando parse método {value}...")

        method_definition = value.split("@")[1]
        method_name = method_definition[0:method_definition.find("(")]

        if method_name not in AVAILABLE_METHODS:
            raise MethodNotImplementedException()

        if "user_input" == method_name and self.action_execution.arguments:
            return self.action_execution.arguments[self.index_method_executed]

        original_arguments = method_definition[method_definition.find("(") +
                                               1:method_definition.find(")")]

        # refs.: https://stackoverflow.com/a/48838456/7973282
        parsed_arguments = eval("dict({})".format(original_arguments))

        parsed_arguments = {
            k: self._change_value(v)
            for k, v in parsed_arguments.items()
        }

        parsed_arguments["execute"] = execute

        parsed_arguments = ",".join([
            f"{k}='{v}'" if isinstance(v, str) else f"{k}={v}"
            for k, v in parsed_arguments.items()
        ])

        method_definition = f"{method_name}({parsed_arguments})"

        try:
            return eval(f"template_methods.{method_definition}")
        except TypeError as e:
            LOGGER.error(str(e))
            raise InvalidTemplateException()
예제 #4
0
def send(config, last_send=None, dry_run=False):
    sent_on = None
    email = config_parser.get_smtp_email(config=config)
    to_email = config_parser.get_smtp_to_email(config=config)
    host = config_parser.get_smtp_host(config=config)
    port = config_parser.get_smtp_port(config=config)
    no_tls = config_parser.get_smtp_no_tls(config=config)
    password = config_parser.get_smtp_password(config=config)

    if last_send and last_send > datetime.datetime.now() - datetime.timedelta(hours=24):
        LOGGER.info("Throttling email to once a day")
        sent_on = last_send
    elif email and host and port:
        try:
            sent_on = datetime.datetime.now()
            if not dry_run:
                smtp = smtplib.SMTP(host, port)
                smtp.set_debuglevel(0)
                smtp.connect(host, port)
                if not no_tls:
                    smtp.starttls()

                if password:
                    smtp.login(email, password)

                msg = build_message(email)

                smtp.sendmail(from_addr=email, to_addrs=to_email, msg=msg.as_string())
                smtp.quit()
        except (Exception) as e:
            sent_on = None
            LOGGER.error(f"Failed to send email: {str(e)}.")
    else:
        LOGGER.warning("Not sending 2FA notification because SMTP is not configured")

    return sent_on
예제 #5
0
def sync():
    last_send = None
    enable_sync_drive = True
    enable_sync_photos = True
    drive_sync_interval = 0
    photos_sync_interval = 0
    sleep_for = 10
    while True:
        config = read_config()
        username = config_parser.get_username(config=config)
        if username:
            try:
                if ENV_ICLOUD_PASSWORD_KEY in os.environ:
                    password = os.environ.get(ENV_ICLOUD_PASSWORD_KEY)
                    utils.store_password_in_keyring(username=username,
                                                    password=password)
                else:
                    password = utils.get_password_from_keyring(
                        username=username)
                api = ICloudPyService(
                    apple_id=username,
                    password=password,
                    cookie_directory=DEFAULT_COOKIE_DIRECTORY,
                )
                if not api.requires_2sa:
                    if "drive" in config and enable_sync_drive:
                        sync_drive.sync_drive(config=config, drive=api.drive)
                        drive_sync_interval = config_parser.get_drive_sync_interval(
                            config=config)
                    if "photos" in config and enable_sync_photos:
                        sync_photos.sync_photos(config=config,
                                                photos=api.photos)
                        photos_sync_interval = config_parser.get_photos_sync_interval(
                            config=config)
                    if "drive" not in config and "photos" not in config:
                        LOGGER.warning(
                            "Nothing to sync. Please add drive: and/or photos: section in config.yaml file."
                        )
                else:
                    LOGGER.error("Error: 2FA is required. Please log in.")
                    # Retry again
                    sleep_for = config_parser.get_retry_login_interval(
                        config=config)
                    next_sync = (
                        datetime.datetime.now() +
                        datetime.timedelta(seconds=sleep_for)).strftime("%c")
                    LOGGER.info(f"Retrying login at {next_sync} ...")
                    last_send = notify.send(config, last_send)
                    sleep(sleep_for)
                    continue
            except exceptions.ICloudPyNoStoredPasswordAvailableException:
                LOGGER.error(
                    "Password is not stored in keyring. Please save the password in keyring."
                )
                sleep_for = config_parser.get_retry_login_interval(
                    config=config)
                next_sync = (
                    datetime.datetime.now() +
                    datetime.timedelta(seconds=sleep_for)).strftime("%c")
                LOGGER.info(f"Retrying login at {next_sync} ...")
                last_send = notify.send(config, last_send)
                sleep(sleep_for)
                continue

        if "drive" not in config and "photos" in config:
            sleep_for = photos_sync_interval
            enable_sync_drive = False
            enable_sync_photos = True
        elif "drive" in config and "photos" not in config:
            sleep_for = drive_sync_interval
            enable_sync_drive = True
            enable_sync_photos = False
        elif ("drive" in config and "photos" in config
              and drive_sync_interval <= photos_sync_interval):
            sleep_for = photos_sync_interval - drive_sync_interval
            photos_sync_interval -= drive_sync_interval
            enable_sync_drive = True
            enable_sync_photos = False
        else:
            sleep_for = drive_sync_interval - photos_sync_interval
            drive_sync_interval -= photos_sync_interval
            enable_sync_drive = False
            enable_sync_photos = True
        next_sync = (datetime.datetime.now() +
                     datetime.timedelta(seconds=sleep_for)).strftime("%c")
        LOGGER.info(f"Resyncing at {next_sync} ...")
        if (config_parser.get_drive_sync_interval(config=config) < 0 if "drive"
                in config else True and config_parser.get_photos_sync_interval(
                    config=config) < 0 if "photos" in config else True):
            break
        sleep(sleep_for)