11
11
from django .utils import simplejson
12
12
from django .conf import settings
13
13
from django .utils .safestring import mark_safe
14
- #from django.utils.html import conditional_escape
15
14
from oembed .models import ProviderRule , StoredOEmbed
16
15
from django .template .loader import render_to_string
17
16
18
- conditional_escape = lambda x : x
19
-
20
17
END_OVERRIDES = (')' , ',' , '.' , '>' , ']' , ';' )
21
18
MAX_WIDTH = getattr (settings , "OEMBED_MAX_WIDTH" , 320 )
22
19
MAX_HEIGHT = getattr (settings , "OEMBED_MAX_HEIGHT" , 240 )
23
20
FORMAT = getattr (settings , "OEMBED_FORMAT" , "json" )
24
21
25
- def fetch (url , user_agent = "django-oembed" ):
26
- request = urllib2 .Request (url )
27
- request .add_header ('User-Agent' , user_agent )
28
- request .add_header ('Accept-Encoding' , 'gzip' )
29
- opener = urllib2 .build_opener ()
30
- f = opener .open (request )
31
- result = f .read ()
32
- if f .headers .get ('content-encoding' , '' ) == 'gzip' :
33
- result = gzip .GzipFile (fileobj = StringIO (result )).read ()
34
- f .close ()
35
- return result
22
+ def fetch (url , user_agent = "django-oembed/0.1" ):
23
+ """
24
+ Fetches from a URL, respecting GZip encoding, etc.
25
+ """
26
+ request = urllib2 .Request (url )
27
+ request .add_header ('User-Agent' , user_agent )
28
+ request .add_header ('Accept-Encoding' , 'gzip' )
29
+ opener = urllib2 .build_opener ()
30
+ f = opener .open (request )
31
+ result = f .read ()
32
+ if f .headers .get ('content-encoding' , '' ) == 'gzip' :
33
+ result = gzip .GzipFile (fileobj = StringIO (result )).read ()
34
+ f .close ()
35
+ return result
36
36
37
37
def re_parts (regex_list , text ):
38
38
"""
@@ -83,6 +83,17 @@ def match_compare(x, y):
83
83
yield (- 1 , last_bit )
84
84
85
85
def replace (text , max_width = MAX_WIDTH , max_height = MAX_HEIGHT ):
86
+ """
87
+ Scans a block of text, replacing anything matched by a ``ProviderRule``
88
+ pattern with an OEmbed html snippet, if possible.
89
+
90
+ Templates should be stored at oembed/{format}.html, so for example:
91
+
92
+ oembed/video.html
93
+
94
+ These templates are passed a context variable, ``response``, which is a
95
+ dictionary representation of the response.
96
+ """
86
97
rules = list (ProviderRule .objects .all ())
87
98
patterns = [re .compile (r .regex ) for r in rules ] # Compiled patterns from the rules
88
99
parts = [] # The parts that we will assemble into the final return value.
@@ -91,10 +102,10 @@ def replace(text, max_width=MAX_WIDTH, max_height=MAX_HEIGHT):
91
102
urls = set () # A set of URLs to try to lookup from the database.
92
103
stored = {} # A mapping of URLs to StoredOEmbed objects.
93
104
index = 0
94
- # First let's pass through the text, populating our data structures.
105
+ # First we pass through the text, populating our data structures.
95
106
for i , part in re_parts (patterns , text ):
96
107
if i == - 1 :
97
- parts .append (conditional_escape ( part ) )
108
+ parts .append (part )
98
109
index += 1
99
110
else :
100
111
to_append = ""
@@ -110,19 +121,28 @@ def replace(text, max_width=MAX_WIDTH, max_height=MAX_HEIGHT):
110
121
if to_append :
111
122
parts .append (to_append )
112
123
index += 1
124
+ # Now we fetch a list of all stored patterns, and put it in a dictionary
125
+ # mapping the URL to to the stored model instance.
113
126
for stored_embed in StoredOEmbed .objects .filter (match__in = urls , max_width = max_width , max_height = max_height ):
114
127
stored [stored_embed .match ] = stored_embed
128
+ # Now we're going to do the actual replacement of URL to embed.
115
129
for i , id_to_replace in enumerate (indices ):
116
130
rule = rules [indices_rules [i ]]
117
131
part = parts [id_to_replace ]
118
132
try :
133
+ # Try to grab the stored model instance from our dictionary, and
134
+ # use the stored HTML fragment as a replacement.
119
135
parts [id_to_replace ] = stored [part ].html
120
136
except KeyError :
121
137
try :
138
+ # Build the URL based on the properties defined in the OEmbed spec.
122
139
url = u"%s?url=%s&maxwidth=%s&maxheight=%s&format=%s" % (
123
140
rule .endpoint , part , max_width , max_height , FORMAT
124
141
)
142
+ # Fetch the link and parse the JSON.
125
143
resp = simplejson .loads (fetch (url ))
144
+ # Depending on the embed type, grab the associated template and
145
+ # pass it the parsed JSON response as context.
126
146
replacement = render_to_string ('oembed/%s.html' % resp ['type' ], {'response' : resp })
127
147
if replacement :
128
148
stored_embed = StoredOEmbed .objects .create (
@@ -136,7 +156,8 @@ def replace(text, max_width=MAX_WIDTH, max_height=MAX_HEIGHT):
136
156
else :
137
157
raise ValueError
138
158
except ValueError :
139
- parts [id_to_replace ] = conditional_escape ( part )
159
+ parts [id_to_replace ] = part
140
160
except KeyError :
141
- parts [id_to_replace ] = conditional_escape (part )
161
+ parts [id_to_replace ] = part
162
+ # Combine the list into one string and return it.
142
163
return mark_safe (u'' .join (parts ))
0 commit comments