-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathembedutils.py
142 lines (109 loc) · 4.23 KB
/
embedutils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""
Quick and mostly dirty model utils for embedded media fields in Django with Jinja2.
Currently just YouTube and Vimeo video.
Blame [email protected] for this mess.
see also: https://gist.github.com/796214
@@TODO:liberate
@@TODO: Allow definition of default iframe width/height in VideoEmbedURLField
@@TODO: Add more video services / find a safe way to use embed.ly?
"""
import re
from django.db import models
from django.utils.translation import ugettext_lazy as _
from jinja2.utils import Markup
from django.core.exceptions import ValidationError
YOUTUBE_URL_RE = re.compile('''
^ # start
http:// # schema
(?:www\\.)? # optional www.
youtube\\.com/watch\? # domain + path
(?:.*?&)*? # optional leading params (except v=)
v=(?P<id>\w+) # v=<video id>
(&.*)? # optional trailing params
$ # end
''', re.VERBOSE)
YOUTUBE_EMBED_URL = 'http://www.youtube.com/embed/%(id)s'
VIMEO_URL_RE = re.compile('''
^ # start
http:// # schema
(?:www\\.)? # optional www.
vimeo\\.com/ # domain + path
(?P<id>\d+) # <video id>
(\?.*)? # optional params
$ # end
''', re.VERBOSE)
VIMEO_EMBED_URL = 'http://player.vimeo.com/video/%(id)s'
EMBED_PATTERNS = (
(YOUTUBE_URL_RE, YOUTUBE_EMBED_URL),
(VIMEO_URL_RE, VIMEO_EMBED_URL)
)
EMBED_CODE = (
'<iframe type="text/html" width="%(width)d" height="%(height)d" ' +
' src="%(url)s" frameborder="0"></iframe>'
)
DEFAULT_ARGS = { 'width': 480, 'height': 360 }
def build_video_embed(url, **kwargs):
for regex, embed_url in EMBED_PATTERNS:
m = regex.match(url)
if m:
args = dict(DEFAULT_ARGS)
args.update(kwargs)
args['url'] = embed_url % m.groupdict()
return EMBED_CODE % args
return None
class VideoEmbedURL(object):
"""Proxy for access on a VideoEmbedURLField, offers embed_html property"""
def __init__(self, instance, field, value):
self.instance = instance
self.field = field
self.value = value
def __unicode__(self):
return self.value
def _get_embed_html(self):
return Markup(build_video_embed(self.value))
embed_html = property(_get_embed_html)
class VideoEmbedURLDescriptor(object):
"""Transforms a plain URL into VideoEmbedURL on field access
see also: django.db.models.fields.files.FileField"""
def __init__(self, field):
self.field = field
def __set__(self, instance, value):
instance.__dict__[self.field.name] = value
def __get__(self, instance=None, owner=None):
if instance is None:
raise AttributeError(
"The '%s' attribute can only be accessed from %s instances."
% (self.field.name, owner.__name__))
veurl = instance.__dict__[self.field.name]
if isinstance(veurl, basestring) or veurl is None:
attr = self.field.attr_class(instance, self.field, veurl)
instance.__dict__[self.field.name] = attr
elif isinstance(veurl, VideoEmbedURL) and not hasattr(veurl, 'field'):
veurl.instance = instance
veurl.field = self.field
out = instance.__dict__[self.field.name]
if not out or not out.value:
return None
return out
class VideoEmbedURLField(models.URLField):
"""URL field with the magical ability to enable media embedding via the
embed_html property"""
attr_class = VideoEmbedURL
descriptor_class = VideoEmbedURLDescriptor
def validate(self, value, model_instance):
super(VideoEmbedURLField, self).validate(value, model_instance)
if not build_video_embed(value):
raise ValidationError(_('Not an URL from a supported video service'))
def get_prep_value(self, field_value):
"Returns field's value prepared for saving into a database."
if field_value is None or field_value.value is None:
return ''
return unicode(field_value)
def contribute_to_class(self, cls, name):
super(VideoEmbedURLField, self).contribute_to_class(cls, name)
setattr(cls, self.name, self.descriptor_class(self))
try:
import south.modelsinspector
south.modelsinspector.add_introspection_rules([ ], ["^embedutils.VideoEmbedURLField"])
except ImportError:
pass