Ejemplo n.º 1
0
 def isLegalExtension(self, extension):
     """Check whether extension denotes a file type which is handled by Entry or its subclasses.
     
     String extension is the file name extension (without '.', upper and lower case handled)
     Return Boolean indicating whether extension is handled by Entry
     """
     try:
         Installer.getProductTrader().getClassFor(extension.lower())
     except:  # no class registered for this extension
         return (False)
     return (True)
Ejemplo n.º 2
0
 def __init__(self):
     self.logger = Logger.__call__().get_logger()
     self.version = ""
     self.file_name = ""
     self.l_installer = Installer()
     self.parsed_command = ""
     self.m_Commands = dict()
     self.m_Commands["install"] = self.install
     self.m_Commands["follow"] = self.follow
     self.m_Commands["ping"] = self.ping
     self.m_Commands["configure"] = self.configure
     self.m_Commands["uninstall"] = self.uninstall
     self.m_Commands["update"] = self.download
     self.m_Commands["download"] = self.download
     self.m_Commands["download_cfg"] = self.download_cfg
Ejemplo n.º 3
0
 def getRawImageFromPath(cls, aMediaCollection, path):
     """Return a raw image to represent the media content of the given file.
             
     Is a class method to be useful during import.
     
     Credits for JPG/EXIF rotation: 
     https://jdhao.github.io/2019/07/31/image_rotation_exif_info/
     
     Model.MediaCollection aMediaCollection
     String path
     Return wx.Image or None
     """
     (_, extension) = os.path.splitext(path)
     extension = extension[1:].lower(
     )  # normalize by removing leading dot and converting to lowercase
     imageType = None
     rawImage = None
     rotation = 'N'  # N: normal, L: left, R: right, M: mirror
     if ((extension == 'jpg') or (extension == 'jpeg')):
         imageType = wx.BITMAP_TYPE_JPEG
         metadata = cls.getMetadataFromPath(path)
         rotation = cls.getRotationFromMetadata(metadata)
     elif (extension == 'png'):
         imageType = wx.BITMAP_TYPE_PNG
     elif (extension == 'gif'):
         imageType = wx.BITMAP_TYPE_GIF
     elif (extension == 'tif'):
         imageType = wx.BITMAP_TYPE_TIF
     if (imageType):
         try:
             rawImage = wx.Image(path, imageType)
         except Exception as exc:
             Logger.warning(
                 'Image.getRawImageFromPath(): Failed to load media "%s" due to\n%s'
                 % (path, exc))
             try:
                 rawImage = wx.Image(
                     os.path.join(Installer.getLibraryPath(),
                                  Image.PreviewImageFilename),
                     wx.BITMAP_TYPE_JPEG)
             except Exception as exc:
                 Logger.error(
                     'Image.getRawImageFromPath(): Failed to load default image due to\n%s'
                     % exc)
             rotation = 'N'
         if (rotation != 'N'):
             Logger.debug('Image.getRawImageFromPath(): Rotating %s' %
                          rotation)
             if (rotation == 'R'):
                 rawImage = rawImage.Rotate90(True)
             elif (rotation == 'L'):
                 rawImage = rawImage.Rotate90(False)
             else:  # must be 'M'
                 rawImage = rawImage.Rotate180()
     else:
         Logger.warning(
             'Image.getRawImageFromPath(): Illegal type in "%s"!' % path)
     return (rawImage)
Ejemplo n.º 4
0
    def getSubclassForPath(self, path):
        """Return the subclass of Entry to create an entry for the specified file.

        path String
        Returns a subclass of Entry 
        """
        if (os.path.isdir(path)):
            clas = Installer.getProductTrader().getClassFor(
                self.SpecificationGroup)
        else:
            (dummy, extension) = os.path.splitext(path)
            extension = extension[1:].lower()  # remove leading '.'
            try:
                clas = Installer.getProductTrader().getClassFor(extension)
            except:
                Logger.error(
                    'Entry.getSubclassForPath(): No class registered to instantiate "%s" media "%s"!'
                    % (extension, path))
                return (None)
        return (clas)
Ejemplo n.º 5
0
 def setSelectedEntry(self, entry):
     """Set the selected entry.
     """
     Logger.debug('MediaCollection.setSelectedEntry(%s)' % entry)
     previousSelection = self.selectedEntry
     self.selectedEntry = entry
     if (self.selectedEntry):  # store selected entry for next program run
         path = entry.getPath()
         path = path[len(Installer.getMediaPath()) + 1:]  # remove "/" as well
         self.setConfiguration(GlobalConfigurationOptions.LastMedia, path)
     if (previousSelection != self.selectedEntry):
         self.changedAspect('selection')
Ejemplo n.º 6
0
 def setNameHandler(self):
     """Set the class singleton name handler. 
     
     Even if a name handler was defined, there are no dependencies and it can be simply discarded.
     Registering names of all Entrys does not hurt, as there are none when the class is initialized via setModel()
     """
     path = Installer.getNamesFilePath()
     Logger.debug(
         'OrganizationByName.setNameHandler(): Loading name handler from "%s"'
         % path)
     self.nameHandler = MediaNameHandler(path)
     Logger.debug(
         'OrganizationByName.setNameHandler(): Registering names...')
     for entry in self.getModel():
         self.nameHandler.registerNameAsUsed(entry.getOrganizer().getName())
     Logger.debug('OrganizationByName.setNameHandler(): Names registered')
Ejemplo n.º 7
0
 def remove(
         self):  # TODO: inform MediaOrganization as well, to release names
     """Remove self from the image set. 
     
     Move the image file into the trash directory.
     """
     self.changedAspect('remove')
     self.setParentGroup(None)
     self.releaseCacheWithPriority(self.__class__.CachingLevelRawData)
     self.releaseCacheWithPriority(
         self.__class__.CachingLevelFullsizeBitmap)
     self.releaseCacheWithPriority(
         self.__class__.CachingLevelThumbnailBitmap)
     # move to trash
     oldName = self.getPath()
     newName = os.path.join(
         self.model.rootDirectory, Installer.getTrashPath(),
         (self.getFilename() + '.' + self.getExtension()))
     newName = makeUnique(newName)
     Logger.debug('Trashing "%s" (into "%s")' % (oldName, newName))
     try:
         os.rename(oldName, newName)
     except Exception as e:
         Logger.error('Trashing "%s" failed:\n%s' % (oldName, e))
Ejemplo n.º 8
0
        for entry in self.getSubEntries():
            entry.removeNewIndicator()


    def renumberMedia(self, pairList):
        """Renumber media grouped in self according to pairList.
        
        List pairList contains pairs of numbers indicating the current and new number.
        """
        pass


# Internal - to change without notice
    def getGroupSize(self):
        """Return the number of media grouped in self.

        Return Number
        """
        result = 0
        for subEntry in self.getSubEntries(filtering=True):
            if (subEntry.__class__ == Group):
                result = (result + subEntry.getGroupSize())
            else:
                result = (result + 1) 
        return(result)



# Class Initialization
Installer.getProductTrader().registerClassFor(Group, Entry.SpecificationGroup)  # register Group to handle directories
Ejemplo n.º 9
0
class Command:
    """  Handles for received messages """
    server = None
    client = None
    fileName = ""
    timer = 0

    def __init__(self):
        self.logger = Logger.__call__().get_logger()
        self.version = ""
        self.file_name = ""
        self.l_installer = Installer()
        self.parsed_command = ""
        self.m_Commands = dict()
        self.m_Commands["install"] = self.install
        self.m_Commands["follow"] = self.follow
        self.m_Commands["ping"] = self.ping
        self.m_Commands["configure"] = self.configure
        self.m_Commands["uninstall"] = self.uninstall
        self.m_Commands["update"] = self.download
        self.m_Commands["download"] = self.download
        self.m_Commands["download_cfg"] = self.download_cfg

    """ Init Websocket in the classe"""

    def set_websocket(self, server, clients):
        Command.server = server
        Command.client = clients

    """ Parsing Commands """
    """{
       {
        "command": "download_cfg",
        "software": {
          "name": "Firefox",
          "file": "Firefox.exe",
          "path": "AppData/Mozilla/Firefox",
          "url": "https://url/download/cfg"
          "extension": "tgz"
        }
       }
       """

    def new_command(self, command):
        try:
            self.parsed_command = json.loads(
                command,
                object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
        except json.JSONDecodeError as e:
            eprintlog(format(str(e)))
            self.logger.debug(format(str(e)))
        else:
            self.logger.info(self.parsed_command)

    """  Check if the Command is valid """

    def is_valid_command(self):
        if hasattr(self.parsed_command, 'command'):
            for l_command in self.m_Commands:
                if l_command == self.parsed_command.command:
                    return True

        return False

    """  Execute Command """

    def run(self):
        return self.m_Commands[self.parsed_command.command]()

    """ Ping """

    def ping(self):
        return PacketError(self.parsed_command.command, PacketType.PING,
                           Enum.PACKET_PING)

    """  Follow Process """

    def follow(self):
        status = self.l_installer.follower(self.parsed_command.software.file)
        if status == "running":
            packet = PacketError(self.parsed_command.software.file,
                                 PacketType.F_RUNNING, Enum.PACKET_FOLLOW,
                                 self.parsed_command.software.name)
        else:
            packet = PacketError(self.parsed_command.software.file,
                                 PacketType.F_FINISH, Enum.PACKET_FOLLOW,
                                 self.parsed_command.software.name)

        packet.path = self.parsed_command.software.path
        return packet

    """  Configuration Software """

    def configure(self):
        if self.parsed_command.software.extension == "tar.gz" or self.parsed_command.software.extension == "tgz":
            tar = tarfile.open(
                'configuration\\' + self.parsed_command.software.file, "r:gz")
            tar.extractall('configuration\\' +
                           self.parsed_command.software.name)
            tar.close()
            copytree('configuration\\' + self.parsed_command.software.name,
                     ConfigurationFolder + self.parsed_command.software.path)

        packet = PacketError(self.parsed_command.software.file,
                             PacketType.OK_CONFIGURATION,
                             Enum.PACKET_CONFIGURATION,
                             self.parsed_command.software.name)
        packet.path = self.parsed_command.software.path
        return packet

    """  Installation Software """

    def install(self):
        self.l_installer.init(self.parsed_command.software)
        t = threading.Thread(target=self.l_installer.install,
                             args=(Command.server, Command.client))
        threads.append(t)
        t.start()
        return

    """  Uninstallation Software """

    def uninstall(self):
        self.l_installer.init(self.parsed_command.software)
        t = threading.Thread(target=self.l_installer.uninstall,
                             args=(Command.server, Command.client))
        threads.append(t)
        t.start()
        return

    """  Download Software """

    def download(self):
        self.fileName = self.parsed_command.software.file
        try:
            urllib.request.urlopen(self.parsed_command.software.url)
        except urllib.error.HTTPError as e:
            eprintlog(e.code)
            eprintlog(e.read())
            self.logger.debug(format(str(e)))
            packet = PacketError(e.code, PacketType.FAILED_DOWNLOAD,
                                 Enum.PACKET_DOWNLOAD_STATE,
                                 self.parsed_command.software.name)
            packet.path = self.parsed_command.software.path
            Command.server.send_message(Command.client, packet.toJSON())
        except URLError as urlerror:
            if hasattr(urlerror, 'reason'):
                self.logger.debug(format(str(e)))
                eprintlog('We failed to reach a server.')
                eprintlog('Reason: ', urlerror.reason)
                packet = PacketError(urlerror.reason,
                                     PacketType.FAILED_DOWNLOAD,
                                     Enum.PACKET_DOWNLOAD_STATE,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.path
                Command.server.send_message(Command.client, packet.toJSON())
            elif hasattr(urlerror, 'code'):
                self.logger.debug(format(str(e)))
                eprintlog('The server couldn\'t fulfill the request.')
                eprintlog('Error code: ', urlerror.code)
                packet = PacketError(urlerror.code, PacketType.FAILED_DOWNLOAD,
                                     Enum.PACKET_DOWNLOAD_STATE,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.path
                Command.server.send_message(Command.client, packet.toJSON())
        else:
            threading.Thread(
                target=urlretrieve,
                args=(self.parsed_command.software.url,
                      'install/' + self.parsed_command.software.file,
                      self.reporthook)).start()
        return

    """  Download Configure """

    def download_cfg(self):
        self.fileName = self.parsed_command.software.file
        try:
            urllib.request.urlopen(self.parsed_command.software.url)
        except urllib.error.HTTPError as e:
            eprintlog(e.code)
            eprintlog(e.read())
            packet = PacketError(e.code, PacketType.FAILED_DOWNLOAD,
                                 Enum.PACKET_DOWNLOAD_STATE,
                                 self.parsed_command.software.name)
            packet.path = self.parsed_command.software.path
            Command.server.send_message(Command.client, packet.toJSON())
        except URLError as urlerror:
            if hasattr(urlerror, 'reason'):
                eprintlog('We failed to reach a server.')
                eprintlog('Reason: ', urlerror.reason)
                packet = PacketError(urlerror.reason,
                                     PacketType.FAILED_DOWNLOAD,
                                     Enum.PACKET_DOWNLOAD_STATE_CFG,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.url
                Command.server.send_message(Command.client, packet.toJSON())
            elif hasattr(urlerror, 'code'):
                eprintlog('The server couldn\'t fulfill the request.')
                eprintlog('Error code: ', urlerror.code)
                packet = PacketError(urlerror.code, PacketType.FAILED_DOWNLOAD,
                                     Enum.PACKET_DOWNLOAD_STATE_CFG,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.url
                Command.server.send_message(Command.client, packet.toJSON())
        else:
            threading.Thread(
                target=urlretrieve,
                args=(self.parsed_command.software.url,
                      'configuration/' + self.parsed_command.software.file,
                      self.reporthook_cfg)).start()
        return

    def reporthook(self, blocknum, blocksize, totalsize):
        readsofar = blocknum * blocksize
        if totalsize > 0:
            percent = readsofar * 1e2 / totalsize
            currenttimer = int(round(time.time() * 1000))
            if currenttimer > self.timer + 500:
                self.timer = currenttimer
                packet = PacketError(percent, PacketType.F_RUNNING,
                                     Enum.PACKET_DOWNLOAD_STATE,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.path
                Command.server.send_message(Command.client, packet.toJSON())

            if readsofar >= totalsize:  # near the end
                packet = PacketError(percent, PacketType.F_FINISH,
                                     Enum.PACKET_DOWNLOAD_STATE,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.path
                Command.server.send_message(Command.client, packet.toJSON())
        else:  # total size is unknown
            sys.stderr.write("read %d\n" % (readsofar, ))

    def reporthook_cfg(self, blocknum, blocksize, totalsize):
        readsofar = blocknum * blocksize
        if totalsize > 0:
            percent = readsofar * 1e2 / totalsize
            currenttimer = int(round(time.time() * 1000))
            if currenttimer > self.timer + 500:
                self.timer = currenttimer
                packet = PacketError(percent, PacketType.F_RUNNING,
                                     Enum.PACKET_DOWNLOAD_STATE_CFG,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.path
                Command.server.send_message(Command.client, packet.toJSON())

            if readsofar >= totalsize:  # near the end
                packet = PacketError(percent, PacketType.F_FINISH,
                                     Enum.PACKET_DOWNLOAD_STATE_CFG,
                                     self.parsed_command.software.name)
                packet.path = self.parsed_command.software.path
                Command.server.send_message(Command.client, packet.toJSON())
        else:  # total size is unknown
            sys.stderr.write("read %d\n" % (readsofar, ))
Ejemplo n.º 10
0
 def setRootDirectory (self, rootDir, processIndicator):
     """Change the root directory to process a different image set.
     
     String rootDir
     PhasedProgressBar progressIndicator
     """
     processIndicator.beginPhase(3)
     self.rootDirectory = os.path.normpath(rootDir)
     # clear all data
     self.selectedEntry = None
     self.initialEntry = None
     CachingController.clear()
     # set up the configuration persistence
     #TODO: Must move to app to be available while mediacollection is created
     self.configuration = SecureConfigParser(Installer.getConfigurationFilePath())
     self.configuration.read(Installer.getConfigurationFilePath())
     if (not self.configuration.has_section(GUIId.AppTitle)):
         self.configuration.add_section(GUIId.AppTitle)
     #
     if (os.path.exists(Installer.getNamesFilePath())): 
         self.organizedByDate = False
         self.organizationStrategy = OrganizationByName
         filterClass = FilterByName
     else:
         self.organizedByDate = True
         self.organizationStrategy = OrganizationByDate
         filterClass = FilterByDate  
     self.organizationStrategy.setModel(self)
     processIndicator.beginStep(_('Reading tag definitions'))
     self.classHandler = MediaClassHandler(Installer.getClassFilePath())
     if (self.classHandler.isLegalElement(MediaCollection.ReorderTemporaryTag)):
         index = 1
         tag = ('%s%d' % (MediaCollection.ReorderTemporaryTag, index))
         while (self.classHandler.isLegalElement(tag)):
             index = (index + 1)
             tag = ('%s%d' % (tag, index))
         MediaCollection.ReorderTemporaryTag = tag
         Logger.warning('MediaCollection.setRootDirectory(): Temporary reordering tag changed to "%s"' % tag)
     # read groups and images
     self.root = Entry.createInstance(self, self.rootDirectory)
     self.loadSubentries(self.root, processIndicator)  # implicit progressIndicator.beginStep()
     processIndicator.beginStep(_('Calculating collection properties'))
     self.cacheCollectionProperties()
     self.filter = filterClass(self) 
     self.filter.addObserverForAspect(self, 'filterChanged')
     self.filteredEntries = self.getCollectionSize()
     # select initial entry
     if (os.path.exists(Installer.getInitialFilePath())):
         self.initialEntry = Entry.createInstance(self, Installer.getInitialFilePath())
     path = self.getConfiguration(GlobalConfigurationOptions.LastMedia)
     if (path):
         if (not os.path.isabs(path)):  # TODO: unconditional when relative path is stored for last media
             path = os.path.join(Installer.getMediaPath(), path)
         entry = self.getEntry(path=path)
         if (entry):
             Logger.info('MediaCollection.setRootDirectory(): selecting "%s" from last run.' % path)
             if (entry.isGroup() 
                 and (100 < len(entry.getSubEntries()))):
                 entry = entry.getSubEntries()[0]
                 Logger.info('MediaColleection.setRootDirectory(): Reselected "%s" because initial group contained more than 100 entries.' % entry)
             self.setSelectedEntry(entry)
         else:
             Logger.info('MediaCollection.setRootDirectory(): last viewed media "%s" does not exist.' % path)
             self.setSelectedEntry(self.root)
     else: 
         Logger.info('MediaCollection.setRootDirectory(): last viewed media not saved')
         self.setSelectedEntry(self.root)
Ejemplo n.º 11
0
 def getRawImageFromPath(cls, aMediaCollection, path):
     """Return a raw image to represent the media content of the given file.
     
     Model.MediaCollection aMediaCollection
     String path 
     Return wx.Image or None
     """
     rawImage = None
     ffmpeg = aMediaCollection.getConfiguration(
         Movie.ConfigurationOptionFfmpeg)
     if (ffmpeg):
         try:
             Logger.debug('Movie.getRawImageFromPath(): Using "%s"' %
                          ffmpeg)
             duration = cls.getDurationFromPath(aMediaCollection, path)
             if (duration):
                 target = max(
                     0,
                     min(duration * Movie.CaptureFramePosition,
                         duration - 0.1))
             else:
                 target = 5
                 logging.warning(
                     'Movie.getRawImageFromPath(): Cannot determine duration, using %s secs as offset for "%s"'
                     % (target, path))
             targetString = "{:.3f}".format(target)
             logging.debug(
                 'Movie.getRawImageFromPath(): Duration is %s, target frame is %s'
                 % (duration, target))
             args = [
                 ffmpeg,
                 "-ss",
                 targetString,
                 "-i",
                 path,
                 "-map",
                 "v:0",  # first video stream
                 "-frames:v",
                 "1",  # 1 frame
                 "-f",
                 "mjpeg",  # motion jpeg (aka. jpeg since 1 frame) output
                 "pipe:"  # pipe output to stdout
             ]
             #                 proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             #                 (output, _) = proc.communicate()
             #                 if (proc.returncode):
             #                     raise subprocess.CalledProcessError(proc.returncode, args)
             cp = subprocess.run(args,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)  # Python 3
             if (cp.returncode):
                 raise subprocess.CalledProcessError(cp.returncode, args)
             if (not cp.stdout):
                 raise subprocess.CalledProcessError(-2, args)
             stream = BytesIO(cp.stdout)
             #                 rawImage = wx.ImageFromStream(stream, type=wx.BITMAP_TYPE_JPEG)
             rawImage = wx.Image(stream,
                                 type=wx.BITMAP_TYPE_JPEG)  # wxPython 4
         except Exception as e:
             Logger.error(
                 'Movie.getRawImageFromPath(): Cannot retrieve frame from "%s" due to error:\n%s'
                 % (path, e))
             rawImage = None
     else:
         Logger.warning(
             'Movie.getRawImageFromPath(): No ffmpeg specified with option "%s"'
             % Movie.ConfigurationOptionFfmpeg)
         rawImage = None
     if (rawImage == None):
         try:
             rawImage = wx.Image(
                 os.path.join(Installer.getLibraryPath(),
                              Movie.PreviewImageFilename),
                 wx.BITMAP_TYPE_JPEG)
         except Exception as exc:
             Logger.error(
                 'Movie.getRawImageFromPath(): Cannot load default movie image due to\n%s'
                 % exc)
             rawImage = None
     return (rawImage)
Ejemplo n.º 12
0
        #                 args = [ffmpeg,
        #                         '-i',
        #                         self.getPath()]
        #                 logging.debug('Movie.getDuration(): Calling "%s"' % args)
        # #                 proc = subprocess.Popen(args, stderr=subprocess.PIPE)
        # #                 (_, result) = proc.communicate()
        #                 output = subprocess.run(args, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout  # Python 3
        #                 m = re.search(r'Duration:\s*(\d+):(\d+):(\d+)\.(\d+)', output)
        #                 if (m == None):
        #                     logging.warning('Movie.getDuration(): Cannot determine duration for "%s"!' % self.getPath())
        #                 else:
        #                     # Avoiding strptime here because it has some issues handling milliseconds.
        #                     m = [int(m.group(i)) for i in range(1, 5)]
        #                     self.duration = datetime.timedelta(hours=m[0],
        #                                                        minutes=m[1],
        #                                                        seconds=m[2],
        #                                                        # * 10 because truncated to 2 decimal places
        #                                                        milliseconds=m[3] * 10
        #                                                        ).total_seconds()
        #             except Exception as e:
        #                 logging.warning('Movie.getDuration(): Cannot determine duration due to error:\n%s' % e)
        #         else:
        #             logging.warning('Movie.getDuration(): No ffmpeg specified with %s' % Movie.ConfigurationOptionFfmpeg)
        return (self.duration)


# Class Initialization
for extension in Movie.LegalExtensions:
    Installer.getProductTrader().registerClassFor(
        Movie, extension)  # register Movie to handle extension
Ejemplo n.º 13
0
        Logger.debug('Image.getRawImage(%s)' % self)
        if (self.rawImage):
            return (self.rawImage)
        result = super(Image, self).getRawImage()
        self.rotation = self.__class__.getRotationFromMetadata(
            self.getMetadata())
        if (self.rotation and (self.rotation != 'N')):
            self.changedAspect('name')
        return (result)

    def getMetadata(self):
        """Return image metadata, depending on image file type.
        
        Supported so far: 
        - JPG/EXIF
        
        Return dict (empty if no metadata available)
        """
        if ((self.getExtension() == 'jpg') or (self.getExtension() == 'jpeg')):
            if (self.metadataExif == None):
                self.metadataExif = self.__class__.getMetadataFromPath(
                    self.getPath())
            return (self.metadataExif)
        return ({})


# Internal - to change without notice
# Class Initialization
for extension in Image.LegalExtensions:
    Installer.getProductTrader().registerClassFor(Image, extension)