Exemplo n.º 1
0
class DirectoryShotsProvider(PipelineShotProvider):
    def __init__(self, folder: str = None):
        super().__init__("DIRC")
        self.helper = CommonHelper()
        self.folder = folder
        self.SourceImagePattern = re.compile(AppSettings.SOURCE_IMAGE_PATTARN)

    def FromDir(self, folder: str):
        self = DirectoryShotsProvider()
        shots = asq.query(os.listdir(folder)) \
                .where(lambda f: self.IsSourceImage(f)) \
                .select(lambda f: CamShot(os.path.join(folder, f))) \
                .to_list()
        self.log.debug("Loaded {} shots from directory {}".format(
            len(shots), folder))
        for s in shots:
            s.LoadImage()
        return [PipelineShot(s, i) for i, s in enumerate(shots)]

    def IsSourceImage(self, filename: str):
        return self.SourceImagePattern.search(filename)

    def GetShotsProtected(self, pShots: []):
        dt: datetime = None
        dtStr = None
        folder = self.folder if self.folder else self.config.pathFrom()
        if len(pShots) > 0 and 'PROV:IMAP' in pShots[
                0].Metadata and 'start' in pShots[0].Metadata['PROV:IMAP']:
            meta = pShots[0].Metadata
            dtStr = meta['PROV:IMAP']['start']
            dt = self.helper.FromTimeStampStr(dtStr)
            self.log.debug(f'Search files: ⏱️ {dt} in 📁 {folder}')
        else:
            self.log.warning(
                "No event start time found in metadata['PROV:IMAP']")

        # path_from: F:\inetpub\ftproot\Camera\Foscam\FI9805W_C4D6553DECE1
        # to found: \snap\MDAlarm_20190926-122821.jpg
        filenames = list(
            self.helper.WalkFiles(
                folder, lambda x: self.helper.FileNameByDateRange(
                    x, dt, self.config.camera_triggered_interval_sec) and self.
                helper.IsImage(x), self.config.ignore_dir))  # self.log

        pShots = [
            PipelineShot(CamShot(filenames[i]), i)
            for i in range(len(filenames))
        ]
        for pShot in pShots:
            meta = self.CreateMetadata(pShot)
            meta['start'] = dtStr if dtStr else self.helper.ToTimeStampStr(
                pShots[0].Shot.GetDatetime())
            meta['filename'] = pShot.OriginalShot.fullname
            yield pShot
class ImapShotsProvider(PipelineShotProvider):
    def __init__(self, tempFolder='temp'):
        super().__init__("IMAP")
        self.secretConfig = SecretConfig()
        self.secretConfig.fromJsonFile()
        self.tempFolder = tempFolder
        self.helper = CommonHelper()

    def GetShotsProtected(self, pShots: []):
        self.Connect()
        mail = self.GetLastMail(self.config.imap_folder)
        os.makedirs(self.tempFolder, exist_ok=True)
        file_template = self.tempFolder + '/{:%Y%m%d-%H%M%S}-{}.jpg'
        shots = self.SaveAttachments(mail, file_template, self.CleanOldFiles)
        pShots.extend(shots)
        self.Disconnect()
        return shots

    def CleanOldFiles(self, shot: CamShot):
        secs = self.config.camera_triggered_interval_sec
        dt = shot.GetDatetime(False)
        if not dt:
            return
        condition = lambda f: self.helper.FileNameByDateRange(f, dt, secs)
        removed = self.helper.CleanFolder(self.tempFolder, condition)
        [self.log.info(f'REMOVED: {f}') for f in removed]

    # filePattern : /path_to_file/{:%Y%m%d-%H%M%S}-{}.jpg
    def SaveAttachments(self, mail, filePattern: str, beforeFirstSave: None):
        index = 0
        result = []
        first_dt = None
        for part in mail.walk():
            if (part.get_content_maintype() != 'image'):
                continue
            fileName = part.get_filename()

            if bool(fileName):
                memShot = CamShot(fileName)
                dtShot = memShot.GetDatetime()
                #dtShot = dt + datetime.timedelta(0,index)
                shot = CamShot(filePattern.format(dtShot, self.config.camera))
                if index == 0:
                    first_dt = dtShot
                    if beforeFirstSave:
                        beforeFirstSave(shot)
                if not shot.Exist():
                    shot.Write(part.get_payload(decode=True))
                else:
                    self.log.info(
                        f'Attachment already exists: {shot.fullname}')

                pShot = PipelineShot(shot, index)
                meta = self.CreateMetadata(pShot)
                meta["start"] = self.helper.ToTimeStampStr(first_dt)
                meta["filename"] = fileName
                result.append(pShot)
            index += 1
        return result

    def GetLastMail(self, imap_folder: str):
        self.imapSession.select(imap_folder)
        typ, data = self.imapSession.search(None, 'ALL')
        if typ != 'OK':
            self.log.error(f'Error searching in imap folder: {imap_folder}')
            raise ValueError('Error searching in imap folder: ' + imap_folder)

        # Iterating over all emails
        ids = data[0].split()
        self.log.debug(f'Found {len(ids)} mails in "{imap_folder}"')
        msgId = ids[-1].decode('utf-8')
        #for msgId in data[0].split():
        typ, messageParts = self.imapSession.fetch(msgId, '(RFC822)')
        if typ != 'OK':
            self.log.error(f'Error fetching mail: {msgId}')
            raise ValueError('Error fetching mail: ' + msgId)

        emailBody = messageParts[0][1].decode('utf-8')
        mail = email.message_from_string(emailBody)
        subject, _ = email.header.decode_header(mail['subject'])[0]
        self.log.info("#{} | {}".format(msgId, subject.decode('utf-8')))
        return mail

    def Connect(self):
        self.imapSession = imaplib.IMAP4_SSL('imap.gmail.com')
        typ, accountDetails = self.imapSession.login(
            self.secretConfig.gmail_username, self.secretConfig.gmail_password)
        if typ != 'OK':
            self.log.debug('Not able to sign in!')
            print('Not able to sign in!')
            raise ConnectionError('imap.gmail.com')
        self.log.debug(f'Connection: {accountDetails}')

    def Disconnect(self):
        self.imapSession.select()
        self.imapSession.close()
        self.imapSession.logout()