src/pyams_media/media.py
changeset 6 b78dab193043
parent 0 fd39db613f8b
child 22 b5da674fd06c
equal deleted inserted replaced
5:73e9b218db71 6:b78dab193043
    12 
    12 
    13 __docformat__ = 'restructuredtext'
    13 __docformat__ = 'restructuredtext'
    14 
    14 
    15 
    15 
    16 # import standard library
    16 # import standard library
       
    17 import re
       
    18 
    17 from mimetypes import guess_extension, guess_type
    19 from mimetypes import guess_extension, guess_type
    18 
    20 
    19 # import interfaces
    21 # import interfaces
    20 from pyams_file.interfaces import IFile
    22 from pyams_file.interfaces import IFile
    21 from pyams_media.interfaces import IMediaInfo, CUSTOM_AUDIO_TYPES, CUSTOM_VIDEO_TYPES, IMediaConversions, \
    23 from pyams_media.interfaces import IMediaInfo, CUSTOM_AUDIO_TYPES, CUSTOM_VIDEO_TYPES, IMediaConversions, \
    22     IMediaConversion, IMediaConversionUtility
    24     IMediaConversion, IMediaConversionUtility, VIDEO_FRAME_SIZE
       
    25 from pyams_utils.interfaces.tales import ITALESExtension
    23 from transaction.interfaces import ITransactionManager
    26 from transaction.interfaces import ITransactionManager
    24 from zope.annotation.interfaces import IAnnotations
    27 from zope.annotation.interfaces import IAnnotations
    25 from zope.lifecycleevent.interfaces import IObjectAddedEvent
    28 from zope.lifecycleevent.interfaces import IObjectAddedEvent
    26 
    29 
    27 # import packages
    30 # import packages
    28 from pyams_file.file import FileFactory
    31 from pyams_file.file import FileFactory
    29 from pyams_media.ffbase import FFmpeg
    32 from pyams_media.ffbase import FFmpeg
    30 from pyams_media.ffdocument import FFDocument
    33 from pyams_media.ffdocument import FFDocument
    31 from pyams_utils.adapter import adapter_config, ContextAdapter
    34 from pyams_utils.adapter import adapter_config, ContextAdapter, ContextRequestViewAdapter
    32 from pyams_utils.registry import query_utility
    35 from pyams_utils.registry import query_utility
    33 from pyramid.events import subscriber
    36 from pyramid.events import subscriber
    34 from pyramid.threadlocal import get_current_registry
    37 from zope.component.globalregistry import getGlobalSiteManager
    35 from zope.container.folder import Folder
    38 from zope.container.folder import Folder
    36 from zope.interface import implementer, alsoProvides
    39 from zope.interface import implementer, alsoProvides, Interface
    37 from zope.lifecycleevent import ObjectCreatedEvent
    40 from zope.lifecycleevent import ObjectCreatedEvent
    38 from zope.location import locate
    41 from zope.location import locate
    39 from zope.traversing.interfaces import ITraversable
    42 from zope.traversing.interfaces import ITraversable
    40 
    43 
    41 
    44 
    64 # Media conversions
    67 # Media conversions
    65 #
    68 #
    66 
    69 
    67 MEDIA_CONVERSIONS_KEY = 'pyams_media.media.conversions'
    70 MEDIA_CONVERSIONS_KEY = 'pyams_media.media.conversions'
    68 
    71 
       
    72 MEDIA_FRAME_SIZE = re.compile(".*-(.*)\..*")
       
    73 
    69 
    74 
    70 @implementer(IMediaConversions)
    75 @implementer(IMediaConversions)
    71 class MediaConversions(Folder):
    76 class MediaConversions(Folder):
    72     """Media conversions"""
    77     """Media conversions"""
    73 
    78 
    74     def add_conversion(self, conversion, format, extension=None, width=None):
    79     def add_conversion(self, conversion, format, extension=None, width=None):
    75         target = FileFactory(conversion)
    80         target = FileFactory(conversion)
    76         registry = get_current_registry()
    81         registry = getGlobalSiteManager()
    77         registry.notify(ObjectCreatedEvent(target))
    82         registry.notify(ObjectCreatedEvent(target))
    78         alsoProvides(target, IMediaConversion)
    83         alsoProvides(target, IMediaConversion)
    79         if extension is None:
    84         if extension is None:
    80             extension = guess_extension(format)
    85             extension = guess_extension(format)
    81         target_name = '{name}{width}.{extension}'.format(name=target.content_type.decode().split('/', 1)[0]
    86         target_name = '{name}{width}.{extension}'.format(name=target.content_type.decode().split('/', 1)[0]
    82                                                              if target.content_type else 'media',
    87                                                              if target.content_type else 'media',
    83                                                          width='-{0}'.format(width) if width else '',
    88                                                          width='-{0}'.format(width) if width else '',
    84                                                          extension=extension)
    89                                                          extension=extension)
       
    90         target.filename = target_name
    85         self[target_name] = target
    91         self[target_name] = target
    86 
    92 
    87     def get_conversions(self):
    93     def get_conversions(self, with_source=False, order=None):
    88         context = self.__parent__
    94         result = []
    89         return [context] + list(self.values())
    95         if with_source:
       
    96             result.append(self.__parent__)
       
    97         result.extend(list(self.values()))
       
    98         if order:
       
    99             order = tuple(map(lambda x: x.encode(), order))
       
   100             result.sort(key=lambda x: (order.index(x.content_type) if x.content_type in order else 999,
       
   101                                        self.get_conversion_width(x.filename) or 9999))
       
   102         return result
    90 
   103 
    91     def get_conversion(self, name):
   104     @staticmethod
    92         if '/' in name:
   105     def get_conversion_width(name):
    93             for conversion in self.get_conversions():
   106         match = MEDIA_FRAME_SIZE.match(name)
    94                 if conversion.content_type == name:
   107         if match:
    95                     return conversion
   108             return VIDEO_FRAME_SIZE.get(match.groups()[0])
    96         return self.get(name)
       
    97 
   109 
    98     def has_conversion(self, formats):
   110     def has_conversion(self, formats):
    99         for conversion in self.get_conversions():
   111         for conversion in self.get_conversions():
   100             if conversion.content_type in formats:
   112             if conversion.content_type in formats:
   101                 return True
   113                 return True
   117 class MediaConversionsTraverser(ContextAdapter):
   129 class MediaConversionsTraverser(ContextAdapter):
   118     """++conversions++ file traverser"""
   130     """++conversions++ file traverser"""
   119 
   131 
   120     def traverse(self, name, furtherpath=None):
   132     def traverse(self, name, furtherpath=None):
   121         return IMediaConversions(self.context)
   133         return IMediaConversions(self.context)
       
   134 
       
   135 
       
   136 @adapter_config(name='conversions', context=(IFile, Interface, Interface), provides=ITALESExtension)
       
   137 class ConversionsExtension(ContextRequestViewAdapter):
       
   138     """extension:conversions(media) TALES extension"""
       
   139 
       
   140     def render(self, context=None):
       
   141         if context is None:
       
   142             context = self.context
       
   143         return IMediaConversions(context)
   122 
   144 
   123 
   145 
   124 #
   146 #
   125 # Media files events
   147 # Media files events
   126 #
   148 #