diff --git a/README.rst b/README.rst
index f4b54f428..49231a78c 100644
--- a/README.rst
+++ b/README.rst
@@ -1,8 +1,21 @@
Wagtail CMS
===========
-Wagtail is a Django content management system focused on flexibility and user experience. Find out more at `wagtail.io `_
-and `torchbox.github.io/wagtail `_.
+Wagtail is a Django content management system built originally for the `Royal College of Art `_ and focused on flexibility and user experience. Its features include:
+
+* A fast, attractive editor interface
+* Complete control over design with standard Django templates
+* Configure content types through standard Django models
+* Tightly integrated search (with an `Elasticsearch `_ backend for production)
+* Strong document and image management
+* Wide support for embedded content
+* Simple, configurable permissions
+* Support for tree-based content organisation
+* Optional preview->submit->approve workflow
+* Fast out of the box. `Varnish `_-friendly if you need it
+* Tests! But not enough; we're working hard to improve this
+
+Find out more at `wagtail.io `_.
Getting started
~~~~~~~~~~~~~~~
@@ -10,4 +23,4 @@ To get you up and running quickly, we've provided a demonstration site with all
Contributing
~~~~~~~~~~~~
-If you're a Python or Django developer, fork the repo and get stuck in! Send us a useful pull request and we'll post you a `t-shirt `_.
+If you're a Python or Django developer, fork the repo and get stuck in! Send us a useful pull request and we'll post you a `t-shirt `_. Our immediate priorities are better docs, more tests, internationalisation and localisation.
diff --git a/setup.py b/setup.py
index 74da04225..e92d9df23 100644
--- a/setup.py
+++ b/setup.py
@@ -43,7 +43,6 @@ setup(
"South>=0.8.4",
"django-compressor>=1.3",
"django-modelcluster>=0.1",
- "Embedly>=0.5.0",
"django-taggit>=0.11.2",
"Pillow>=2.3.0",
"beautifulsoup4>=4.3.2",
diff --git a/wagtail/wagtailcore/rich_text.py b/wagtail/wagtailcore/rich_text.py
index bd00ee503..aa8f25336 100644
--- a/wagtail/wagtailcore/rich_text.py
+++ b/wagtail/wagtailcore/rich_text.py
@@ -52,7 +52,10 @@ class ImageEmbedHandler(object):
format = get_image_format(attrs['format'])
if for_editor:
- return format.image_to_editor_html(image, attrs['alt'])
+ try:
+ return format.image_to_editor_html(image, attrs['alt'])
+ except:
+ return ''
else:
return format.image_to_html(image, attrs['alt'])
diff --git a/wagtail/wagtailembeds/__init__.py b/wagtail/wagtailembeds/__init__.py
index b75cbc491..8e3708ca9 100644
--- a/wagtail/wagtailembeds/__init__.py
+++ b/wagtail/wagtailembeds/__init__.py
@@ -1,2 +1,2 @@
from .models import Embed
-from .embeds import get_embed
+from .embeds.embed import get_embed
diff --git a/wagtail/wagtailembeds/embeds.py b/wagtail/wagtailembeds/embeds.py
index 59d349a26..a2cff4d62 100644
--- a/wagtail/wagtailembeds/embeds.py
+++ b/wagtail/wagtailembeds/embeds.py
@@ -1,12 +1,18 @@
from datetime import datetime
-from embedly import Embedly
+
from django.conf import settings
from .models import Embed
+import os
+module_dir = os.path.dirname(__file__) # get current directory
+file_path = os.path.join(module_dir, 'endpoints.json')
+print file_path
+print open(file_path).read()
-def get_embed(url, max_width=None):
+
+def get_embed_embedly(url, max_width=None):
# Check database
try:
return Embed.objects.get(url=url, max_width=max_width)
@@ -52,3 +58,18 @@ def get_embed(url, max_width=None):
# Return new embed
return row
+
+def get_embed_oembed(url, max_width=None):
+ pass
+
+get_embed = get_embed_oembed
+try:
+ from embedly import Embedly
+ if hasattr(settings,'EMBEDLY_KEY'):
+ get_embed = get_embed_embedly
+except:
+ pass
+
+print get_embed
+
+
\ No newline at end of file
diff --git a/wagtail/wagtailembeds/embeds/__init__.py b/wagtail/wagtailembeds/embeds/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/wagtailembeds/embeds/embed.py b/wagtail/wagtailembeds/embeds/embed.py
new file mode 100644
index 000000000..3d91a7fae
--- /dev/null
+++ b/wagtail/wagtailembeds/embeds/embed.py
@@ -0,0 +1,80 @@
+from datetime import datetime
+from django.conf import settings
+from ..models import Embed
+import oembed_api
+
+class EmbedlyException(Exception): pass
+class AccessDeniedEmbedlyException(Exception): pass
+class NotFoundEmbedlyException(Exception): pass
+
+def get_embed_embedly(url, max_width=None):
+ # Check database
+ try:
+ return Embed.objects.get(url=url, max_width=max_width)
+ except Embed.DoesNotExist:
+ pass
+
+ client = Embedly(key=settings.EMBEDLY_KEY)
+
+ if max_width is not None:
+ oembed = client.oembed(url, maxwidth=max_width, better=False)
+ else:
+ oembed = client.oembed(url, better=False)
+
+ # Check for error
+ if oembed.get('error'):
+ if oembed['error_code'] in [401,403]:
+ raise AccessDeniedEmbedlyException
+ elif oembed['error_code'] == 404:
+ raise NotFoundEmbedlyException
+ else:
+ raise EmbedlyException
+
+ return save_embed(url, max_width, oembed)
+
+
+def get_embed_oembed(url, max_width=None):
+ # Check database
+ try:
+ return Embed.objects.get(url=url, max_width=max_width)
+ except Embed.DoesNotExist:
+ pass
+
+ oembed = oembed_api.get_embed_oembed(url, max_width)
+ return save_embed(url, max_width, oembed)
+
+
+def save_embed(url, max_width, oembed):
+ row, created = Embed.objects.get_or_create(
+ url=url,
+ max_width=max_width,
+ defaults={
+ 'type': oembed['type'],
+ 'title': oembed['title'],
+ 'thumbnail_url': oembed.get('thumbnail_url'),
+ 'width': oembed.get('width'),
+ 'height': oembed.get('height')
+ }
+ )
+
+ if oembed['type'] == 'photo':
+ html = '
' % (oembed['url'], )
+ else:
+ html = oembed.get('html')
+
+ if html:
+ row.html = html
+ row.last_updated = datetime.now()
+ row.save()
+
+ return row
+
+# As a default use oembed
+get_embed = get_embed_oembed
+try:
+ from embedly import Embedly
+ # if EMBEDLY_KEY is set and embedly library found the use embedly
+ if hasattr(settings,'EMBEDLY_KEY'):
+ get_embed = get_embed_embedly
+except:
+ pass
diff --git a/wagtail/wagtailembeds/embeds/endpoints.json b/wagtail/wagtailembeds/embeds/endpoints.json
new file mode 100644
index 000000000..c289b7183
--- /dev/null
+++ b/wagtail/wagtailembeds/embeds/endpoints.json
@@ -0,0 +1,295 @@
+{
+ "https://speakerdeck.com/oembed.{format}": [
+ "^http(?:s)?://speakerdeck\\.com/.+$"
+ ],
+ "https://alpha-api.app.net/oembed": [
+ "^http(?:s)?://alpha\\.app\\.net/[^#?/]+/post/.+$",
+ "^http(?:s)?://photos\\.app\\.net/[^#?/]+/.+$"
+ ],
+ "http://www.youtube.com/oembed": [
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/watch.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/v/.+$",
+ "^http(?:s)?://youtu\\.be/.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/user/.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/[^#?/]+#[^#?/]+/.+$",
+ "^http(?:s)?://m\\.youtube\\.com/index.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/profile.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/view_play_list.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?youtube\\.com/playlist.+$"
+ ],
+ "http://backend.deviantart.com/oembed": [
+ "^http://(?:[-\\w]+\\.)?deviantart\\.com/art/.+$",
+ "^http://fav\\.me/.+$",
+ "^http://sta\\.sh/.+$",
+ "^http://(?:[-\\w]+\\.)?deviantart\\.com/[^#?/]+#/d.+$"
+ ],
+ "http://blip.tv/oembed/": [
+ "^http://[-\\w]+\\.blip\\.tv/.+$"
+ ],
+ "http://www.dailymotion.com/api/oembed/": [
+ "^http://[-\\w]+\\.dailymotion\\.com/.+$"
+ ],
+ "http://www.flickr.com/services/oembed/": [
+ "^http://[-\\w]+\\.flickr\\.com/photos/.+$",
+ "^http://flic\\.kr\\.com/.+$"
+ ],
+ "http://www.hulu.com/api/oembed.{format}": [
+ "^http://www\\.hulu\\.com/watch/.+$"
+ ],
+ "http://www.nfb.ca/remote/services/oembed/": [
+ "^http://(?:[-\\w]+\\.)?nfb\\.ca/film/.+$"
+ ],
+ "http://qik.com/api/oembed.{format}": [
+ "^http://qik\\.com/.+$",
+ "^http://qik\\.ly/.+$"
+ ],
+ "http://revision3.com/api/oembed/": [
+ "^http://[-\\w]+\\.revision3\\.com/.+$"
+ ],
+ "http://www.scribd.com/services/oembed": [
+ "^http://[-\\w]+\\.scribd\\.com/.+$"
+ ],
+ "http://www.viddler.com/oembed/": [
+ "^http://[-\\w]+\\.viddler\\.com/v/.+$",
+ "^http://[-\\w]+\\.viddler\\.com/explore/.+$"
+ ],
+ "http://www.vimeo.com/api/oembed.{format}": [
+ "^http(?:s)?://(?:www\\.)?vimeo\\.com/.+$",
+ "^http(?:s)?://player\\.vimeo\\.com/.+$"
+ ],
+ "http://dotsub.com/services/oembed": [
+ "^http://dotsub\\.com/view/.+$"
+ ],
+ "http://www.yfrog.com/api/oembed": [
+ "^http(?:s)?://(?:www\\.)?yfrog\\.com/.+$",
+ "^http(?:s)?://(?:www\\.)?yfrog\\.us/.+$"
+ ],
+ "http://clikthrough.com/services/oembed": [
+ "^http(?:s)?://(?:[-\\w]+\\.)?clikthrough\\.com/.+$"
+ ],
+ "http://www.kinomap.com/oembed": [
+ "^http://[-\\w]+\\.kinomap\\.com/.+$"
+ ],
+ "https://photobucket.com/oembed": [
+ "^http://(?:[-\\w]+\\.)?photobucket\\.com/albums/.+$",
+ "^http://(?:[-\\w]+\\.)?photobucket\\.com/groups/.+$"
+ ],
+ "http://api.instagram.com/oembed": [
+ "^http://instagr\\.am/p/.+$",
+ "^http://instagram\\.com/p/.+$"
+ ],
+ "https://www.slideshare.net/api/oembed/2": [
+ "^http://www\\.slideshare\\.net/.+$"
+ ],
+ "http://tv.majorleaguegaming.com/oembed": [
+ "^http://mlg\\.tv/.+$",
+ "^http://tv\\.majorleaguegaming\\.com/.+$"
+ ],
+ "http://my.opera.com/service/oembed": [
+ "^http://my\\.opera\\.com/.+$"
+ ],
+ "http://skitch.com/oembed": [
+ "^http(?:s)?://(?:www\\.)?skitch\\.com/.+$",
+ "^http://skit\\.ch/.+$"
+ ],
+ "https://api.twitter.com/1/statuses/oembed.{format}": [
+ "^http(?:s)?://twitter\\.com/(?:#!)?[^#?/]+/status/.+$"
+ ],
+ "https://soundcloud.com/oembed": [
+ "^https://soundcloud\\.com/[^#?/]+/.+$"
+ ],
+ "http://www.collegehumor.com/oembed.{format}": [
+ "^http://(?:www\\.)?collegehumor\\.com/video/.+$",
+ "^http://(?:www\\.)?collegehumor\\.com/video:.+$"
+ ],
+ "http://www.polleverywhere.com/services/oembed/": [
+ "^http://www\\.polleverywhere\\.com/polls/.+$",
+ "^http://www\\.polleverywhere\\.com/multiple_choice_polls/.+$",
+ "^http://www\\.polleverywhere\\.com/free_text_polls/.+$"
+ ],
+ "http://www.ifixit.com/Embed": [
+ "^http://www\\.ifixit\\.com/[^#?/]+/[^#?/]+/.+$"
+ ],
+ "http://api.smugmug.com/services/oembed/": [
+ "^http(?:s)?://(?:www\\.)?smugmug\\.com/[^#?/]+/.+$"
+ ],
+ "https://github.com/api/oembed": [
+ "^http(?:s)?://gist\\.github\\.com/.+$"
+ ],
+ "http://animoto.com/services/oembed": [
+ "^http://animoto\\.com/play/.+$"
+ ],
+ "http://www.rdio.com/api/oembed": [
+ "^http://(?:wwww\\.)?rdio\\.com/people/[^#?/]+/playlists/.+$",
+ "^http://[-\\w]+\\.rdio\\.com/artist/[^#?/]+/album/.+$"
+ ],
+ "http://api.5min.com/oembed.{format}": [
+ "^http://www\\.5min\\.com/video/.+$"
+ ],
+ "http://500px.com/photo/{1}/oembed.{format}": [
+ "^http://500px\\.com/photo/([^#?/]+)(?:.+)?$"
+ ],
+ "http://api.dipdive.com/oembed.{format}": [
+ "^http://[-\\w]+\\.dipdive\\.com/media/.+$"
+ ],
+ "http://video.yandex.ru/oembed.{format}": [
+ "^http://video\\.yandex\\.ru/users/[^#?/]+/view/.+$"
+ ],
+ "http://www.mixcloud.com/oembed/": [
+ "^http://www\\.mixcloud\\.com/oembed/[^#?/]+/.+$"
+ ],
+ "http://www.kickstarter.com/services/oembed": [
+ "^http(?:s)://[-\\w]+\\.kickstarter\\.com/projects/.+$"
+ ],
+ "http://coub.com/api/oembed.{format}": [
+ "^http(?:s)?://coub\\.com/view/.+$",
+ "^http(?:s)?://coub\\.com/embed/.+$"
+ ],
+ "http://www.screenr.com/api/oembed.{format}": [
+ "^http://www\\.screenr\\.com/.+$"
+ ],
+ "http://www.funnyordie.com/oembed.{format}": [
+ "^http://www\\.funnyordie\\.com/videos/.+$"
+ ],
+ "http://fast.wistia.com/oembed.{format}": [
+ "^http://[-\\w]+\\.wista\\.com/medias/.+$"
+ ],
+ "http://www.ustream.tv/oembed": [
+ "^http(?:s)?://(?:www\\.)?ustream\\.tv/.+$",
+ "^http(?:s)?://(?:www\\.)?ustream\\.com/.+$",
+ "^http://ustre\\.am/.+$"
+ ],
+ "http://wordpress.tv/oembed/": [
+ "^http://wordpress\\.tv/.+$"
+ ],
+ "http://polldaddy.com/oembed/": [
+ "^http(?:s)?://(?:[-\\w]+\\.)?polldaddy\\.com/.+$"
+ ],
+ "http://api.bambuser.com/oembed.{format}": [
+ "^http://bambuser\\.com/channel/[^#?/]+/broadcast/.+$",
+ "^http://bambuser\\.com/channel/.+$",
+ "^http://bambuser\\.com/v/.+$"
+ ],
+ "http://www.ted.com/talks/oembed.{format}": [
+ "^http(?:s)?://(?:www\\.)?ted\\.com/talks/.+$",
+ "^http(?:s)?://(?:www\\.)?ted\\.com/talks/lang/[^#?/]+/.+$",
+ "^http(?:s)?://(?:www\\.)?ted\\.com/index\\.php/talks/.+$",
+ "^http(?:s)?://(?:www\\.)?ted\\.com/index\\.php/talks/lang/[^#?/]+/.+$"
+ ],
+ "http://chirb.it/oembed.{format}": [
+ "^http://chirb\\.it/.+$"
+ ],
+ "https://www.circuitlab.com/circuit/oembed/": [
+ "^http(?:s)?://(?:www\\.)?circuitlab\\.com/circuit/.+$"
+ ],
+ "http://api.geograph.org.uk/api/oembed": [
+ "^http://(?:[-\\w]+\\.)?geograph\\.org\\.uk/.+$",
+ "^http://(?:[-\\w]+\\.)?geograph\\.co\\.uk/.+$",
+ "^http://(?:[-\\w]+\\.)?geograph\\.ie/.+$"
+ ],
+ "http://geo.hlipp.de/restapi.php/api/oembed": [
+ "^http://geo-en\\.hlipp\\.de/.+$",
+ "^http://geo\\.hlipp\\.de/.+$",
+ "^http://germany\\.geograph\\.org/.+$"
+ ],
+ "http://www.geograph.org.gg/api/oembed": [
+ "^http://(?:[-\\w]+\\.)?geograph\\.org\\.gg/.+$",
+ "^http://(?:[-\\w]+\\.)?geograph\\.org\\.je/.+$",
+ "^http://channel-islands\\.geograph\\.org/.+$",
+ "^http://channel-islands\\.geographs\\.org/.+$",
+ "^http://(?:[-\\w]+\\.)?channel\\.geographs\\.org/.+$"
+ ],
+ "http://vzaar.com/api/videos/{1}.{format}": [
+ "^http://(?:www\\.)?vzaar\\.com/videos/([^#?/]+)(?:.+)?$",
+ "^http://www\\.vzaar\\.tv/([^#?/]+)(?:.+)?$",
+ "^http://vzaar\\.tv/([^#?/]+)(?:.+)?$",
+ "^http://vzaar\\.me/([^#?/]+)(?:.+)?$",
+ "^http://[-\\w]+\\.vzaar\\.me/([^#?/]+)(?:.+)?$"
+ ],
+ "http://api.minoto-video.com/services/oembed.{format}": [
+ "^http://api\\.minoto-video\\.com/publishers/[^#?/]+/videos/.+$",
+ "^http://dashboard\\.minoto-video\\.com/main/video/details/.+$",
+ "^http://embed\\.minoto-video\\.com/.+$"
+ ],
+ "http://www.videojug.com/oembed.{format}": [
+ "^http(?:s)?://(?:[-\\w]+\\.)?videojug\\.com/film/.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?videojug\\.com/payer/.+$",
+ "^http(?:s)?://(?:[-\\w]+\\.)?videojug\\.com/interview/.+$"
+ ],
+ "http://videos.sapo.pt/oembed": [
+ "^http(?:s)?://videos\\.sapo\\.pt/.+$"
+ ],
+ "http://vhx.tv/services/oembed.{format}": [
+ "^http(?:s)?://(?:www\\.)?vhx\\.tv/.+$"
+ ],
+ "http://api.justin.tv/api/embed/from_url.{format}": [
+ "^http(?:s)?://(?:www\\.)?justin\\.tv/.+$"
+ ],
+ "http://official.fm/services/oembed.{format}": [
+ "^http(?:s)?://official\\.fm/.+$"
+ ],
+ "http://huffduffer.com/oembed": [
+ "^http(?:s)?://(?:www\\.)?huffduffer\\.com/[^#?/]+/.+$"
+ ],
+ "https://embed.spotify.com/oembed/": [
+ "^http(?:s)?://open\\.spotify\\.com/.+$",
+ "^http(?:s)?://spoti\\.fi/.+$"
+ ],
+ "http://shoudio.com/api/oembed": [
+ "^http://shoudio\\.com/.+$",
+ "^http://shoud\\.io/.+$"
+ ],
+ "http://api.mobypicture.com/oEmbed": [
+ "^http(?:s)?://(?:www\\.)?mobypicture\\.com/user/[^#?/]+/view/.+$",
+ "^http(?:s)?://(?:www\\.)?moby\\.to/.+$"
+ ],
+ "http://www.23hq.com/23/oembed": [
+ "^http(?:s)?://(?:www\\.)?23hq\\.com/[^#?/]+/photo/.+$"
+ ],
+ "http://gmep.org/oembed.{format}": [
+ "^http(?:s)?://(?:www\\.)?gmep\\.org/.+$",
+ "^http(?:s)?://gmep\\.imeducate\\.com/.+$"
+ ],
+ "http://oembed.urtak.com/1/oembed": [
+ "^http(?:s)?://(?:[-\\w]+\\.)?urtak\\.com/.+$"
+ ],
+ "http://cacoo.com/oembed.{format}": [
+ "^http(?:s)?://cacoo\\.com/.+$"
+ ],
+ "http://api.dailymile.com/oembed": [
+ "^http(?:s)?://(?:www\\.)?dailymile\\.com/people/[^#?/]+/entries/.+$"
+ ],
+ "http://www.dipity.com/oembed/timeline/": [
+ "^http(?:s)?://(?:www\\.)?dipity\\.com/timeline/.+$",
+ "^http(?:s)?://(?:www\\.)?dipity\\.com/voaweb/.+$"
+ ],
+ "https://sketchfab.com/oembed": [
+ "^http(?:s)?://sketchfab\\.com/show/.+$"
+ ],
+ "https://api.meetup.com/oembed": [
+ "^http(?:s)?://(?:www\\.)?meetup\\.com/.+$",
+ "^http(?:s)?://(?:www\\.)?meetup\\.ps/.+$"
+ ],
+ "https://roomshare.jp/oembed.{format}": [
+ "^http(?:s)?://(?:www\\.)?roomshare\\.jp/(?:en/)?post/.+$"
+ ],
+ "http://crowdranking.com/api/oembed.{format}": [
+ "^http(?:s)?://crowdranking\\.com/crowdrankings/.+$",
+ "^http(?:s)?://crowdranking\\.com/rankings/.+$",
+ "^http(?:s)?://crowdranking\\.com/topics/.+$",
+ "^http(?:s)?://crowdranking\\.com/widgets/.+$",
+ "^http(?:s)?://crowdranking\\.com/r/.+$"
+ ],
+ "http://openapi.etsy.com/svc/oembed/": [
+ "^http(?:s)?://(?:www\\.)?etsy\\.com/listing/.+$"
+ ],
+ "https://audioboo.fm/publishing/oembed.{format}": [
+ "^http(?:s)?://audioboo\\.fm/boos/.+$"
+ ],
+ "http://demo.clikthrough.com/services/oembed/": [
+ "^http(?:s)?://demo\\.clikthrough\\.com/theater/video/.+$"
+ ],
+ "http://www.ifttt.com/oembed/": [
+ "^http(?:s)?://ifttt\\.com/recipes/.+$"
+ ]
+}
\ No newline at end of file
diff --git a/wagtail/wagtailembeds/embeds/oembed_api.py b/wagtail/wagtailembeds/embeds/oembed_api.py
new file mode 100644
index 000000000..8f7945577
--- /dev/null
+++ b/wagtail/wagtailembeds/embeds/oembed_api.py
@@ -0,0 +1,52 @@
+import os, re
+import urllib2, urllib
+from datetime import datetime
+import json
+
+class NotImplementedOembedException(Exception):
+ pass
+
+ENDPOINTS = {}
+
+def get_embed_oembed(url, max_width=None):
+ provider = None
+ for endpoint in ENDPOINTS.keys():
+ for pattern in ENDPOINTS[endpoint]:
+ if re.match(pattern, url):
+ provider = endpoint
+ break
+ if not provider:
+ raise NotImplementedOembedException
+ params = {'url': url, 'format': 'json', }
+ if max_width:
+ params['maxwidth'] = max_width
+ req = provider+'?' +urllib.urlencode(params)
+ request = urllib2.Request(req)
+ opener = urllib2.build_opener()
+ # Some provicers were not working without a user agent
+ request.add_header('User-Agent','Mozilla/5.0')
+ return json.loads(opener.open(request).read())
+
+
+# Uses the public domain collection of oembed endpoints by Mathias Panzenbpeck (panzi)
+# at https://github.com/panzi/oembedendpoints/blob/master/endpoints-regexp.json
+
+def load_oembed_endpoints():
+ module_dir = os.path.dirname(__file__)
+ endpoints_path = os.path.join(module_dir, 'endpoints.json')
+ with open( endpoints_path) as f:
+ endpoints = json.loads(f.read())
+
+ for endpoint in endpoints.keys():
+ endpoint_key = endpoint.replace('{format}', 'json')
+
+ ENDPOINTS[endpoint_key]=[]
+ for pattern in endpoints[endpoint]:
+ ENDPOINTS[endpoint_key].append(re.compile(pattern))
+
+
+
+load_oembed_endpoints()
+
+
+
\ No newline at end of file
diff --git a/wagtail/wagtailembeds/embeds/unittests.py b/wagtail/wagtailembeds/embeds/unittests.py
new file mode 100644
index 000000000..4c7653b99
--- /dev/null
+++ b/wagtail/wagtailembeds/embeds/unittests.py
@@ -0,0 +1,66 @@
+import unittest
+import oembed
+
+# Test that a bunch of oembed examples is working
+# If any of these is removed or changed then the unit test will fail
+# This is a unittest TestCase (and not a django.test one) since django
+# database is not actually needed for these tests
+
+TEST_DATA = [
+ {
+ 'url':'http://www.youtube.com/watch?v=S3xAeTmsJfg',
+ 'title':'Animation: Ferret dance (A series of tubes)'
+ },
+ {
+ 'url':'http://vimeo.com/86036070',
+ 'title':'Wagtail: A new Django CMS'
+ },
+ {
+ 'url':'https://speakerdeck.com/harmstyler/an-introduction-to-django',
+ 'title':'An Introduction to Django'
+ },
+ {
+ 'url':'https://ifttt.com/recipes/144705-new-twitter-followers-in-a-google-spreadsheet',
+ 'title':'New Twitter followers in a Google spreadsheet'
+ },
+ {
+ 'url':'http://www.hulu.com/watch/20807/late-night-with-conan-obrien-wed-may-21-2008',
+ 'title':'Wed, May 21, 2008 (Late Night With Conan O\'Brien)'
+ },
+ {
+ 'url':'http://www.flickr.com/photos/dfluke/5995957175/',
+ 'title':'Django pony!?'
+ },
+ {
+ 'url':'http://www.slideshare.net/simon/the-django-web-application-framework',
+ 'title':'The Django Web Application Framework'
+ },
+ {
+ 'url':'http://www.rdio.com/artist/The_Black_Keys/album/Brothers/',
+ 'title':'Brothers'
+ },
+ {
+ 'url':'http://instagram.com/p/kFKCcEKmBq/',
+ 'title':'Family holidays in #Greece!'
+ },
+ {
+ 'url':'https://www.kickstarter.com/projects/noujaimfilms/the-square-a-film-about-the-egyptian-revolution',
+ 'title':'Sundance Award Winning Film on the Egyptian Revolution'
+ },
+ {
+ 'url':'http://www.dailymotion.com/video/xoxulz_babysitter_animals',
+ 'title':'Babysitter!'
+ }
+]
+
+class TestEmbeds(unittest.TestCase):
+ def test_get_embed_oembed(self):
+ for td in TEST_DATA:
+ embed = oembed.get_embed_oembed_low(td['url'])
+ self.assertEqual(embed['title'], td['title'] )
+ self.assertIsNotNone(embed['type'] )
+ self.assertIsNotNone(embed['width'] )
+ self.assertIsNotNone(embed['height'] )
+
+if __name__ == '__main__':
+ unittest.main()
\ No newline at end of file
diff --git a/wagtail/wagtailembeds/endpoints.json b/wagtail/wagtailembeds/endpoints.json
new file mode 100644
index 000000000..7cee0cec7
--- /dev/null
+++ b/wagtail/wagtailembeds/endpoints.json
@@ -0,0 +1,114 @@
+[
+{
+"url": "http://*.blip.tv/*",
+"url_re": "blip\\.tv/.+",
+"example_url": "http://pycon.blip.tv/file/2058801/",
+"endpoint_url": "http://blip.tv/oembed/",
+"title": "blip.tv"
+},
+{
+"url": "http://*.dailymotion.com/*",
+"url_re": "dailymotion\\.com/.+",
+"example_url": "http://www.dailymotion.com/video/x5ioet_phoenix-mars-lander_tech",
+"endpoint_url": "http://www.dailymotion.com/api/oembed/",
+"title": "Dailymotion"
+},
+{
+"url": "http://*.flickr.com/photos/*",
+"url_re": "flickr\\.com/photos/[-.\\w@]+/\\d+/?",
+"example_url": "http://www.flickr.com/photos/fuffer2005/2435339994/",
+"endpoint_url": "http://www.flickr.com/services/oembed/",
+"title": "Flickr Photos"
+},
+{
+"url": "http://www.hulu.com/watch/*",
+"url_re": "hulu\\.com/watch/.*",
+"example_url": "http://www.hulu.com/watch/20807/late-night-with-conan",
+"endpoint_url": "http://www.hulu.com/api/oembed.json",
+"title": "Hulu"
+},
+{
+"url": "http://*.nfb.ca/film/*",
+"url_re": "nfb\\.ca/film/[-\\w]+/?",
+"example_url": "http://www.nfb.ca/film/blackfly/",
+"endpoint_url": "http://www.nfb.ca/remote/services/oembed/",
+"title": "National Film Board of Canada"
+},
+{
+"url": "http://qik.com/*",
+"url_re": "qik\\.com/\\w+",
+"example_url": "http://qik.com/video/86776",
+"endpoint_url": "http://qik.com/api/oembed.json",
+"title": "Qik Video"
+},
+{
+"url": "http://*.revision3.com/*",
+"url_re": "revision3\\.com/.+",
+"example_url": "http://revision3.com/diggnation/2008-04-17xsanned/",
+"endpoint_url": "http://revision3.com/api/oembed/",
+"title": "Revision3"
+},
+{
+"url": "http://*.scribd.com/*",
+"url_re": "scribd\\.com/.+",
+"example_url": "http://www.scribd.com/doc/17896323/Indian-Automobile-industryPEST",
+"endpoint_url": "http://www.scribd.com/services/oembed",
+"title": "Scribd"
+},
+{
+"url": "http://*.viddler.com/explore/*",
+"url_re": "viddler\\.com/explore/.*/videos/\\w+/?",
+"example_url": "http://www.viddler.com/explore/engadget/videos/14/",
+"endpoint_url": "http://lab.viddler.com/services/oembed/",
+"title": "Viddler Video"
+},
+{
+"url": "http://www.vimeo.com/* and http://www.vimeo.com/groups/*/videos/*",
+"url_re": "vimeo\\.com/.*",
+"example_url": "http://www.vimeo.com/1211060",
+"endpoint_url": "http://www.vimeo.com/api/oembed.json",
+"title": "Vimeo"
+},
+{
+"url": "http://*.youtube.com/watch*",
+"url_re": "youtube\\.com/watch.+v=[\\w-]+&?",
+"example_url": "http://www.youtube.com/watch?v=vk1HvP7NO5w",
+"endpoint_url": "http://www.youtube.com/oembed",
+"title": "YouTube"
+},
+{
+"url": "http://dotsub.com/view/*",
+"url_re": "dotsub\\.com/view/[-\\da-zA-Z]+$",
+"example_url": "http://dotsub.com/view/10e3cb5e-96c7-4cfb-bcea-8ab11e04e090",
+"endpoint_url": "http://dotsub.com/services/oembed",
+"title": "dotSUB.com"
+},
+{
+"url": "http://yfrog.(com|ru|com.tr|it|fr|co.il|co.uk|com.pl|pl|eu|us)/*",
+"url_re": "yfrog\\.(com|ru|com\\.tr|it|fr|co\\.il|co\\.uk|com\\.pl|pl|eu|us)/[a-zA-Z0-9]+$",
+"example_url": "http://yfrog.com/0wgvcpj",
+"endpoint_url": "http://www.yfrog.com/api/oembed",
+"title": "YFrog"
+},
+{
+"url": "http://*.clikthrough.com/theater/video/*",
+"url_re": "clikthrough\\.com/theater/video/\\d+$",
+"example_url": "http://www.clikthrough.com/theater/video/55",
+"endpoint_url": "http://clikthrough.com/services/oembed",
+"title": "Clikthrough"
+},
+{
+"url": "http://*.kinomap.com/*",
+"url_re": "kinomap\\.com/.+",
+"example_url": "http://www.kinomap.com/kms-vzkpc7",
+"endpoint_url": "http://www.kinomap.com/oembed",
+"title": "Kinomap"
+},
+{
+"url": "http://*.photobucket.com/albums/*|http://*.photobucket.com/groups/*",
+"url_re": "photobucket\\.com/(albums|groups)/.+$",
+"example_url": "http://img.photobucket.com/albums/v211/JAV123/Michael%20Holland%20Candle%20Burning/_MG_5661.jpg",
+"endpoint_url": "http://photobucket.com/oembed",
+"title": "Photobucket"
+}
+]
diff --git a/wagtail/wagtailembeds/format.py b/wagtail/wagtailembeds/format.py
index 3c050a83d..6fac83bb3 100644
--- a/wagtail/wagtailembeds/format.py
+++ b/wagtail/wagtailembeds/format.py
@@ -2,21 +2,24 @@ from __future__ import division # Use true division
from django.utils.html import escape
-from .embeds import get_embed
+from .embeds.embed import get_embed
def embed_to_frontend_html(url):
- embed = get_embed(url)
- if embed is not None:
- # Work out ratio
- if embed.width and embed.height:
- ratio = str(embed.height / embed.width * 100) + "%"
- else:
- ratio = "0"
+ try:
+ embed = get_embed(url)
+ if embed is not None:
+ # Work out ratio
+ if embed.width and embed.height:
+ ratio = str(embed.height / embed.width * 100) + "%"
+ else:
+ ratio = "0"
- # Build html
- return '%s
' % (ratio, embed.html)
- else:
+ # Build html
+ return '%s
' % (ratio, embed.html)
+ else:
+ return ''
+ except:
return ''
diff --git a/wagtail/wagtailembeds/templatetags/embed_filters.py b/wagtail/wagtailembeds/templatetags/embed_filters.py
index e526bb9b6..dac91cda0 100644
--- a/wagtail/wagtailembeds/templatetags/embed_filters.py
+++ b/wagtail/wagtailembeds/templatetags/embed_filters.py
@@ -1,7 +1,7 @@
from django import template
from django.utils.safestring import mark_safe
-from wagtail.wagtailembeds.embeds import get_embed
+from wagtail.wagtailembeds.embed.embeds import get_embed
register = template.Library()
@@ -10,9 +10,12 @@ register = template.Library()
@register.filter
def embed(url, max_width=None):
embed = get_embed(url, max_width=max_width)
- if embed is not None:
- return mark_safe(embed.html)
- else:
+ try:
+ if embed is not None:
+ return mark_safe(embed.html)
+ else:
+ return ''
+ except:
return ''
diff --git a/wagtail/wagtailembeds/tests.py b/wagtail/wagtailembeds/tests.py
index ab3aa3271..1470f05ef 100644
--- a/wagtail/wagtailembeds/tests.py
+++ b/wagtail/wagtailembeds/tests.py
@@ -1,4 +1,4 @@
-from django.test import TestCase
+from django.test import TestCasez
from .embeds import get_embed
diff --git a/wagtail/wagtailembeds/views/chooser.py b/wagtail/wagtailembeds/views/chooser.py
index 13a835acb..94695f1a3 100644
--- a/wagtail/wagtailembeds/views/chooser.py
+++ b/wagtail/wagtailembeds/views/chooser.py
@@ -5,6 +5,10 @@ from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
from wagtail.wagtailembeds.forms import EmbedForm
from wagtail.wagtailembeds.format import embed_to_editor_html
+from wagtail.wagtailembeds.embeds.oembed_api import NotImplementedOembedException
+from wagtail.wagtailembeds.embeds.embed import EmbedlyException, AccessDeniedEmbedlyException, NotFoundEmbedlyException
+
+
def chooser(request):
form = EmbedForm()
@@ -19,18 +23,27 @@ def chooser_upload(request):
form = EmbedForm(request.POST, request.FILES)
if form.is_valid():
- embed_html = embed_to_editor_html(form.cleaned_data['url'])
- if embed_html != "":
+ try:
+ embed_html = embed_to_editor_html(form.cleaned_data['url'])
return render_modal_workflow(
request, None, 'wagtailembeds/chooser/embed_chosen.js',
{'embed_html': embed_html}
)
- else:
+ except Exception as e :
+ #print e
+ #import traceback
+ #traceback.print_exc()
errors = form._errors.setdefault('url', ErrorList())
- if not hasattr(settings, 'EMBEDLY_KEY'):
- errors.append('Please set EMBEDLY_KEY in your settings')
+ if type(e) == NotImplementedOembedException:
+ errors.append("This URL is not supported by an oembed provider. You may try embedding it using Embedly by setting a propery EMBEDLY_KEY in your settings.")
+ elif type(e) == AccessDeniedEmbedlyException:
+ errors.append("There seems to be a problem with your embedly API key. Please check your settings.")
+ elif type(e) == NotFoundEmbedlyException:
+ errors.append("The URL you are trying to embed cannot be found.")
+ elif type(e) == EmbedlyException:
+ errors.append("There seems to be an error with Embedly while trying to embed this URL. Please try again later.")
else:
- errors.append('This URL is not recognised')
+ errors.append(str(e) )
return render_modal_workflow(request, 'wagtailembeds/chooser/chooser.html', 'wagtailembeds/chooser/chooser.js', {
'form': form,
})