Question

J'ai écrit une extension Nautilus qui lit les métadonnées de l'image (exécution généracodagcode), mais lorsque j'ouvre des dossiers avec de nombreux fichiers, il ralentit vraiment le gestionnaire de fichiers et se bloque jusqu'à ce qu'il finit la lecture des données du fichier.

Y a-t-il un moyen de faire de Nautilus garder son travail pendant qu'il court mon poste?Peut-être que les données EXIF peuvent apparaître progressivement dans les colonnes pendant que je continue avec mon travail.

#!/usr/bin/python

# Richiede:
# nautilus-python
# exiftool
# gconf-python

# Versione 0.15

import gobject
import nautilus
from subprocess import Popen, PIPE
from urllib import unquote
import gconf

def getexiftool(filename):
    options = '-fast2 -f -m -q -q -s3 -ExifIFD:DateTimeOriginal -IFD0:Software -ExifIFD:Flash -Composite:ImageSize -IFD0:Model'
    exiftool=Popen(['/usr/bin/exiftool'] + options.split() + [filename],stdout=PIPE,stderr=PIPE)
    #'-Nikon:ShutterCount' non utilizzabile con l'argomento -fast2
    output,errors=exiftool.communicate()
    return output.split('\n')

class ColumnExtension(nautilus.ColumnProvider, nautilus.InfoProvider, gobject.GObject):
    def __init__(self):
        pass

    def get_columns(self):
        return (
            nautilus.Column("NautilusPython::ExifIFD:DateTimeOriginal","ExifIFD:DateTimeOriginal","Data (ExifIFD)","Data di scatto"),
            nautilus.Column("NautilusPython::IFD0:Software","IFD0:Software","Software (IFD0)","Software utilizzato"),
            nautilus.Column("NautilusPython::ExifIFD:Flash","ExifIFD:Flash","Flash (ExifIFD)","Modalit\u00e0 del flash"),
            nautilus.Column("NautilusPython::Composite:ImageSize","Composite:ImageSize","Risoluzione (Exif)","Risoluzione dell'immagine"),
            nautilus.Column("NautilusPython::IFD0:Model","IFD0:Model","Fotocamera (IFD0)","Modello fotocamera"),
            #nautilus.Column("NautilusPython::Nikon:ShutterCount","Nikon:ShutterCount","Contatore scatti (Nikon)","Numero di scatti effettuati dalla macchina a questo file"),
            nautilus.Column("NautilusPython::Mp","Mp","Megapixel (Exif)","Dimensione dell'immagine in megapixel"),
        )

    def update_file_info_full(self, provider, handle, closure, file):
        client = gconf.client_get_default()

        if not client.get_bool('/apps/nautilus/nautilus-metadata/enable'):
            client.set_bool('/apps/nautilus/nautilus-metadata/enable',0)
            return

        if file.get_uri_scheme() != 'file':
            return

        if file.get_mime_type() in ('image/jpeg', 'image/png', 'image/gif', 'image/bmp', 'image/x-nikon-nef', 'image/x-xcf', 'image/vnd.adobe.photoshop'):
            gobject.timeout_add_seconds(1, self.update_exif, provider, handle, closure, file)
            return Nautilus.OperationResult.IN_PROGRESS

        file.add_string_attribute('ExifIFD:DateTimeOriginal','')
        file.add_string_attribute('IFD0:Software','')
        file.add_string_attribute('ExifIFD:Flash','')
        file.add_string_attribute('Composite:ImageSize','')
        file.add_string_attribute('IFD0:Model','')
        file.add_string_attribute('Nikon:ShutterCount','')
        file.add_string_attribute('Mp','')

        return Nautilus.OperationResult.COMPLETE

    def update_exif(self, provider, handle, closure, file):
        filename = unquote(file.get_uri()[7:])

        data = getexiftool(filename)

        file.add_string_attribute('ExifIFD:DateTimeOriginal',data[0].replace(':','-',2))
        file.add_string_attribute('IFD0:Software',data[1])
        file.add_string_attribute('ExifIFD:Flash',data[2])
        file.add_string_attribute('Composite:ImageSize',data[3])
        file.add_string_attribute('IFD0:Model',data[4])
        #file.add_string_attribute('Nikon:ShutterCount',data[5])
        width, height = data[3].split('x')
        mp = float(width) * float(height) / 1000000
        mp = "%.2f" % mp
        file.add_string_attribute('Mp',str(mp) + ' Mp')

        Nautilus.info_provider_update_complete_invoke(closure, provider, handle, Nautilus.OperationResult.COMPLETE)

        return false

Était-ce utile?

La solution

Cela se produit parce que vous invoquez update_file_info , qui fait partie du système IO asynchrone de Nautilus. Par conséquent, il bloque Nautilus si les opérations ne sont pas assez rapides.

Dans votre cas, il est exacerbé parce que vous appelez un programme externe, et c'est une opération coûteuse. Notez que update_file_info est appelé une fois par fichier. Si vous avez 100 fichiers, vous appellerez 100 fois le programme externe et Nautilus devra attendre chacun avant de traiter le prochain.

Etant donné que Nautilus-Python 0.7 est disponible update_file_info_full et annule_update , ce qui vous permet de programmer des appels asynchronisés. Vous pouvez vérifier le Documentation de Nautilus 0.7 pour Plus de détails .

Cela vaut la peine de mentionner que c'était une limitation de Nautilus-Python uniquement, ce qui n'exposé pas ces méthodes disponibles en c.

Modifier : Ajout d'un couple d'exemples.

Le truc est de rendre le processus aussi vite que possible ou de la rendre asynchrone.

Exemple 1: Invoquant un programme externe

Utilisation d'une version simplifiée de votre code, nous faisons de l'utilisation asynchrone gobject.timeout_add_seconds dans update_file_info_full .

from gi.repository import Nautilus, GObject
from urllib import unquote
from subprocess import Popen, PIPE

def getexiftool(filename):
    options = '-fast2 -f -m -q -q -s3 -ExifIFD:DateTimeOriginal'
    exiftool = Popen(['/usr/bin/exiftool'] + options.split() + [filename],
                     stdout=PIPE, stderr=PIPE)
    output, errors = exiftool.communicate()
    return output.split('\n')

class MyExtension(Nautilus.ColumnProvider, Nautilus.InfoProvider, GObject.GObject):
    def __init__(self):
        pass

    def get_columns(self):
        return (
            Nautilus.Column(name='MyExif::DateTime',
                            attribute='Exif:Image:DateTime',
                            label='Date Original',
                            description='Data time original'
            ),
        )

    def update_file_info_full(self, provider, handle, closure, file_info):
        if file_info.get_uri_scheme() != 'file':
            return

        filename = unquote(file_info.get_uri()[7:])
        attr = ''

        if file_info.get_mime_type() in ('image/jpeg', 'image/png'):
            GObject.timeout_add_seconds(1, self.update_exif, 
                                        provider, handle, closure, file_info)
            return Nautilus.OperationResult.IN_PROGRESS

        file_info.add_string_attribute('Exif:Image:DateTime', attr)

        return Nautilus.OperationResult.COMPLETE

    def update_exif(self, provider, handle, closure, file_info):
        filename = unquote(file_info.get_uri()[7:])

        try:
            data = getexiftool(filename)
            attr = data[0]
        except:
            attr = ''

        file_info.add_string_attribute('Exif:Image:DateTime', attr)

        Nautilus.info_provider_update_complete_invoke(closure, provider, 
                               handle, Nautilus.OperationResult.COMPLETE)
        return False

Le code ci-dessus ne bloque pas Nautilus, et si l'original de la colonne 'Date d'origine' est disponible dans la vue de colonne, les images JPEG et PNG afficheront la valeur ' inconnue ' et ils seront lentement être mis à jour (le sous-processus est appelé après 1 seconde).

Exemples 2: Utilisation d'une bibliothèque

Plutôt que d'invoquer un programme externe, il pourrait être préférable d'utiliser une bibliothèque. Comme exemple ci-dessous:

from gi.repository import Nautilus, GObject
from urllib import unquote
import pyexiv2

class MyExtension(Nautilus.ColumnProvider, Nautilus.InfoProvider, GObject.GObject):
    def __init__(self):
        pass

    def get_columns(self):
        return (
            Nautilus.Column(name='MyExif::DateTime',
                            attribute='Exif:Image:DateTime',
                            label='Date Original',
                            description='Data time original'
            ),
        )

    def update_file_info_full(self, provider, handle, closure, file_info):
        if file_info.get_uri_scheme() != 'file':
            return

        filename = unquote(file_info.get_uri()[7:])
        attr = ''

        if file_info.get_mime_type() in ('image/jpeg', 'image/png'):
            metadata = pyexiv2.ImageMetadata(filename)
            metadata.read()

            try:
                tag = metadata['Exif.Image.DateTime'].value
                attr = tag.strftime('%Y-%m-%d %H:%M')
            except:
                attr = ''

        file_info.add_string_attribute('Exif:Image:DateTime', attr)

        return Nautilus.OperationResult.COMPLETE

Finalement, si la routine est lente, vous auriez besoin de le rendre asynchrone (peut-être utiliser quelque chose de mieux que gobject.timeout_add_secondes . . .

enfin mais non le moindre, dans mes exemples, j'ai utilisé gobject introspection (typiquement pour Nautilus 3), mais il est facile de le changer pour utiliser le module Nautilus directement.

Autres conseils

La solution ci-dessus n'est que partiellement correcte.

entre les modifications de l'état pour File_info métadonnées, l'utilisateur doit appeler file_info.invalidate_extension_info () pour notifier Nautilus de la modification. Omettant de le faire pourrait se retrouver avec ' inconnu "apparaissant dans vos colonnes.

file_info.add_string_attribute('video_width', video_width)
file_info.add_string_attribute('video_height', video_height)
file_info.add_string_attribute('name_suggestion', name_suggestion)   

file_info.invalidate_extension_info()

Nautilus.info_provider_update_complete_invoke(closure, provider, handle, Nautilus.OperationResult.COMPLETE)

Exemple de travail complet ici:

Exemple de travail entièrement

Documentation API

Merci à Dave!

Je cherchais une solution au texte « inconnu » dans la colonne pour les âges

file_info.invalidate_extension_info() 

Correction du problème pour moi tout de suite :)

par la documentation API API

https://projects-old.gnome.org/nautilus-python/documentation/html/class-nautilus-pyThon-file-info.html#method-nautilus-Python-File-Info - Invalidate-Extension-Info

nautilus.fileinfo.invalidate_extension_info

def invalidate_extension_info()

invalide les informations Nautilus sur ce fichier, ce qui lui permet de demander de nouvelles informations à partir de ses fournisseurs Nautilus.infoprovider.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top