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 # |