10 # FOR A PARTICULAR PURPOSE. |
10 # FOR A PARTICULAR PURPOSE. |
11 # |
11 # |
12 |
12 |
13 __docformat__ = 'restructuredtext' |
13 __docformat__ = 'restructuredtext' |
14 |
14 |
|
15 import json |
15 import re |
16 import re |
|
17 from collections import OrderedDict |
16 from mimetypes import guess_extension, guess_type |
18 from mimetypes import guess_extension, guess_type |
17 |
19 |
18 from pyramid.events import subscriber |
20 from pyramid.events import subscriber |
19 from transaction.interfaces import ITransactionManager |
21 from transaction.interfaces import ITransactionManager |
20 from zope.container.folder import Folder |
22 from zope.container.folder import Folder |
25 |
27 |
26 from pyams_file.file import FileFactory |
28 from pyams_file.file import FileFactory |
27 from pyams_file.interfaces import IFile |
29 from pyams_file.interfaces import IFile |
28 from pyams_media.ffbase import FFmpeg |
30 from pyams_media.ffbase import FFmpeg |
29 from pyams_media.ffdocument import FFDocument |
31 from pyams_media.ffdocument import FFDocument |
30 from pyams_media.interfaces import CUSTOM_AUDIO_TYPES, CUSTOM_VIDEO_TYPES, IMediaConversion, IMediaConversionUtility, \ |
32 from pyams_media.interfaces import CUSTOM_AUDIO_TYPES, CUSTOM_VIDEO_TYPES, IMediaConversion, \ |
31 IMediaConversions, IMediaInfo, MEDIA_CONVERSIONS_KEY, VIDEO_FRAME_SIZE |
33 IMediaConversionUtility, IMediaConversions, IMediaInfo, MEDIA_CONVERSIONS_KEY, \ |
32 from pyams_utils.adapter import ContextAdapter, ContextRequestViewAdapter, adapter_config, get_annotation_adapter |
34 VIDEO_FRAME_SIZE |
|
35 from pyams_media.video import get_video_type |
|
36 from pyams_utils.adapter import ContextAdapter, ContextRequestViewAdapter, adapter_config, \ |
|
37 get_annotation_adapter |
|
38 from pyams_utils.date import get_timestamp |
33 from pyams_utils.factory import factory_config |
39 from pyams_utils.factory import factory_config |
34 from pyams_utils.interfaces.tales import ITALESExtension |
40 from pyams_utils.interfaces.tales import ITALESExtension |
35 from pyams_utils.registry import get_global_registry, query_utility |
41 from pyams_utils.registry import get_global_registry, query_utility |
|
42 from pyams_utils.url import absolute_url |
|
43 |
36 |
44 |
37 # |
45 # |
38 # Media infos |
46 # Media infos |
39 # |
47 # |
40 |
48 |
78 if extension is None: |
86 if extension is None: |
79 extension = guess_extension(format) |
87 extension = guess_extension(format) |
80 content_type = target.content_type |
88 content_type = target.content_type |
81 if isinstance(content_type, bytes): |
89 if isinstance(content_type, bytes): |
82 content_type = content_type.decode() |
90 content_type = content_type.decode() |
83 target_name = '{name}{width}.{extension}'.format(name=content_type.split('/', 1)[0] |
91 target_name = '{name}{width}.{extension}'.format( |
84 if content_type else 'media', |
92 name=content_type.split('/', 1)[0] if content_type else 'media', |
85 width='-{0}'.format(width) if width else '', |
93 width='-{0}'.format(width) if width else '', |
86 extension=extension) |
94 extension=extension) |
87 if target_name in self: |
95 if target_name in self: |
88 del self[target_name] |
96 del self[target_name] |
89 target.filename = target_name |
97 target.filename = target_name |
90 self[target_name] = target |
98 self[target_name] = target |
91 return target |
99 return target |
111 for conversion in self.get_conversions(): |
119 for conversion in self.get_conversions(): |
112 if conversion.content_type in formats: |
120 if conversion.content_type in formats: |
113 return True |
121 return True |
114 return False |
122 return False |
115 |
123 |
|
124 def get_sources(self, request): |
|
125 sources = [] |
|
126 types_order = ('video/mp4','video/webm','video/ogg','video/x-flv') |
|
127 media_width = 0 |
|
128 previous_type = None |
|
129 for conversion in self.get_conversions(order=types_order): |
|
130 video_type = get_video_type(conversion, request.registry) |
|
131 min_width = ((media_width or 0) + 1) if (video_type == previous_type) else 0 |
|
132 media_width = self.get_conversion_width(conversion.__name__) |
|
133 media_src = '{0}?_={1}'.format(absolute_url(conversion, request), |
|
134 get_timestamp(conversion)) |
|
135 sources.append({'type': video_type, |
|
136 'min': min_width, |
|
137 'max': media_width, |
|
138 'src': media_src}) |
|
139 previous_type = video_type |
|
140 return json.dumps(sources) |
|
141 |
116 |
142 |
117 @adapter_config(context=IFile, provides=IMediaConversions) |
143 @adapter_config(context=IFile, provides=IMediaConversions) |
118 def media_conversions_factory(context): |
144 def media_conversions_factory(context): |
119 """Media conversions factory""" |
145 """Media conversions factory""" |
120 return get_annotation_adapter(context, MEDIA_CONVERSIONS_KEY, IMediaConversions, |
146 return get_annotation_adapter(context, MEDIA_CONVERSIONS_KEY, IMediaConversions, |
127 |
153 |
128 def traverse(self, name, furtherpath=None): |
154 def traverse(self, name, furtherpath=None): |
129 return IMediaConversions(self.context) |
155 return IMediaConversions(self.context) |
130 |
156 |
131 |
157 |
132 @adapter_config(name='conversions', context=(Interface, Interface, Interface), provides=ITALESExtension) |
158 @adapter_config(name='conversions', |
|
159 context=(Interface, Interface, Interface), |
|
160 provides=ITALESExtension) |
133 class ConversionsExtension(ContextRequestViewAdapter): |
161 class ConversionsExtension(ContextRequestViewAdapter): |
134 """extension:conversions(media) TALES extension""" |
162 """extension:conversions(media) TALES extension""" |
135 |
163 |
136 def render(self, context=None): |
164 def render(self, context=None): |
137 if context is None: |
165 if context is None: |