mirror of
https://github.com/Hopiu/python-markdown-oembed.git
synced 2026-04-17 05:10:58 +00:00
initial commit
Functional beta
This commit is contained in:
commit
e4ec8a72fb
9 changed files with 234 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.DS_Store
|
||||||
|
.idea
|
||||||
|
*.pyc
|
||||||
|
*.egg-info
|
||||||
9
README.markdown
Normal file
9
README.markdown
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Python Markdown oEmbed
|
||||||
|
|
||||||
|
Markdown extension to allow media embedding using the oEmbed standard.
|
||||||
|
|
||||||
|
# Links
|
||||||
|
|
||||||
|
- [Markdown](http://daringfireball.net/projects/markdown/)
|
||||||
|
- [oEmbed](http://www.oembed.com/)
|
||||||
|
- [python-oembed](https://github.com/abarmat/python-oembed)
|
||||||
6
mdx_oembed/__init__.py
Normal file
6
mdx_oembed/__init__.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from mdx_oembed.extension import OEmbedExtension
|
||||||
|
|
||||||
|
|
||||||
|
def makeExtension(configs=None):
|
||||||
|
return OEmbedExtension(configs=configs)
|
||||||
16
mdx_oembed/endpoints.py
Normal file
16
mdx_oembed/endpoints.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import oembed
|
||||||
|
|
||||||
|
|
||||||
|
ENDPOINTS = {
|
||||||
|
'youtube': oembed.OEmbedEndpoint('http://www.youtube.com/oembed', [
|
||||||
|
'http://(*.)?youtube.com/*',
|
||||||
|
'http://youtu.be/*',
|
||||||
|
]),
|
||||||
|
'flickr': oembed.OEmbedEndpoint('http://www.flickr.com/services/oembed/', [
|
||||||
|
'http://*.flickr.com/*',
|
||||||
|
]),
|
||||||
|
'vimeo': oembed.OEmbedEndpoint('http://vimeo.com/api/oembed.json', [
|
||||||
|
'http://vimeo.com/*',
|
||||||
|
]),
|
||||||
|
}
|
||||||
22
mdx_oembed/extension.py
Normal file
22
mdx_oembed/extension.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from markdown import Extension
|
||||||
|
import oembed
|
||||||
|
from mdx_oembed.endpoints import ENDPOINTS
|
||||||
|
from mdx_oembed.inlinepatterns import OEmbedLinkPattern, OEMBED_LINK_RE
|
||||||
|
|
||||||
|
|
||||||
|
class OEmbedExtension(Extension):
|
||||||
|
|
||||||
|
def extendMarkdown(self, md, md_globals):
|
||||||
|
self.oembed_consumer = self.prepare_oembed_consumer()
|
||||||
|
pattern = OEmbedLinkPattern(OEMBED_LINK_RE, md, self.oembed_consumer)
|
||||||
|
md.inlinePatterns.add('oembed_link', pattern, '<image_link')
|
||||||
|
|
||||||
|
def prepare_oembed_consumer(self):
|
||||||
|
allowed_endpoints = self.getConfig('allowed_endpoints',
|
||||||
|
ENDPOINTS.keys())
|
||||||
|
consumer = oembed.OEmbedConsumer()
|
||||||
|
[consumer.addEndpoint(v)
|
||||||
|
for k,v in ENDPOINTS.items()
|
||||||
|
if k in allowed_endpoints]
|
||||||
|
return consumer
|
||||||
23
mdx_oembed/inlinepatterns.py
Normal file
23
mdx_oembed/inlinepatterns.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import logging
|
||||||
|
from markdown.inlinepatterns import Pattern
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
OEMBED_LINK_RE = r'\!\[([^\]]*)\]\((https?://[^\)]*)' \
|
||||||
|
r'(?<!png)(?<!jpg)(?<!jpeg)(?<!gif)\)'
|
||||||
|
|
||||||
|
|
||||||
|
class OEmbedLinkPattern(Pattern):
|
||||||
|
|
||||||
|
def __init__(self, pattern, markdown_instance=None, oembed_consumer=None):
|
||||||
|
Pattern.__init__(self, pattern, markdown_instance)
|
||||||
|
self.consumer = oembed_consumer
|
||||||
|
|
||||||
|
def handleMatch(self, match):
|
||||||
|
url = match.group(3).strip()
|
||||||
|
response = self.consumer.embed(url)
|
||||||
|
placeholder = self.markdown.htmlStash.store(response['html'])
|
||||||
|
return placeholder
|
||||||
0
mdx_oembed/version.py
Normal file
0
mdx_oembed/version.py
Normal file
40
setup.py
Normal file
40
setup.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
try:
|
||||||
|
from setuptools import setup
|
||||||
|
except ImportError:
|
||||||
|
from distutils.core import setup
|
||||||
|
|
||||||
|
|
||||||
|
VERSION = '0.0b'
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='python-markdown-oembed',
|
||||||
|
version=VERSION,
|
||||||
|
description="",
|
||||||
|
long_description=open('README.markdown').read(),
|
||||||
|
author='Tanner Netterville',
|
||||||
|
author_email='tannern@gmail.com',
|
||||||
|
url='http://tannern.com',
|
||||||
|
license='MIT',
|
||||||
|
classifiers=(
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Programming Language :: Python",
|
||||||
|
"Programming Language :: Python :: 2.5",
|
||||||
|
"Programming Language :: Python :: 2.6",
|
||||||
|
),
|
||||||
|
keywords='markdown oembed',
|
||||||
|
|
||||||
|
packages=[
|
||||||
|
'mdx_oembed',
|
||||||
|
],
|
||||||
|
install_requires=[
|
||||||
|
"python-oembed >= 0.2.1",
|
||||||
|
"Markdown >= 2.2.0",
|
||||||
|
],
|
||||||
|
|
||||||
|
test_suite='nose.collector',
|
||||||
|
tests_require=['WebTest >= 1.2', 'BeautifulSoup', 'pytidylib', 'poster']
|
||||||
|
)
|
||||||
114
tests.py
Normal file
114
tests.py
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import re
|
||||||
|
import unittest
|
||||||
|
import markdown
|
||||||
|
from mdx_oembed.extension import OEMBED_LINK_RE
|
||||||
|
|
||||||
|
|
||||||
|
class OEmbedPatternRegexTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.re = re.compile(OEMBED_LINK_RE)
|
||||||
|
|
||||||
|
def test_ignore_relative_image_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNone(match)
|
||||||
|
|
||||||
|
def test_ignore_absolute_image_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNone(match)
|
||||||
|
|
||||||
|
def test_ignore_png_image_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNone(match)
|
||||||
|
|
||||||
|
def test_ignore_jpg_image_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNone(match)
|
||||||
|
|
||||||
|
def test_ignore_gif_image_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNone(match)
|
||||||
|
|
||||||
|
def test_find_youtube_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNotNone(match)
|
||||||
|
|
||||||
|
def test_find_youtube_short_link(self):
|
||||||
|
text = ''
|
||||||
|
match = self.re.match(text)
|
||||||
|
self.assertIsNotNone(match)
|
||||||
|
|
||||||
|
|
||||||
|
class OEmbedExtensionTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
md_params = {
|
||||||
|
'extensions': [
|
||||||
|
'oembed',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
self.markdown = markdown.Markdown(**md_params)
|
||||||
|
|
||||||
|
|
||||||
|
class IgnoredTestCase(OEmbedExtensionTestCase):
|
||||||
|
"""
|
||||||
|
The OEmbedExtension should ignore these tags allowing markdown's image
|
||||||
|
processor to find and handle them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_relative(self):
|
||||||
|
text = ''
|
||||||
|
expected = '<p><img alt="alt" src="image.png" /></p>'
|
||||||
|
output = self.markdown.convert(text)
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_slash_relative(self):
|
||||||
|
text = ''
|
||||||
|
expected = '<p><img alt="alt" src="/image.png" /></p>'
|
||||||
|
output = self.markdown.convert(text)
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_absolute(self):
|
||||||
|
text = ''
|
||||||
|
expected = '<p><img alt="Mumbo Jumbo" src="http://tannern.com/mumbo-jumbo.jpg" /></p>'
|
||||||
|
output = self.markdown.convert(text)
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
|
||||||
|
class YoutubeTestCase(OEmbedExtensionTestCase):
|
||||||
|
"""
|
||||||
|
The OEmbedExtension should handle embedding for these cases.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_youtube_link(self):
|
||||||
|
"""
|
||||||
|
YouTube video link.
|
||||||
|
"""
|
||||||
|
text = ''
|
||||||
|
expected = '<iframe width="459" height="344" src="http://www.youtube.com/embed/zqnh_YJBvOI?fs=1&feature=oembed" frameborder="0" allowfullscreen></iframe>'
|
||||||
|
output = self.markdown.convert(text)
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_youtube_short_link(self):
|
||||||
|
"""
|
||||||
|
Short format YouTube video link.
|
||||||
|
"""
|
||||||
|
text = ''
|
||||||
|
expected = '<iframe width="459" height="344" src="http://www.youtube.com/embed/zqnh_YJBvOI?fs=1&feature=oembed" frameborder="0" allowfullscreen></iframe>'
|
||||||
|
output = self.markdown.convert(text)
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
|
def test_vimeio_link(self):
|
||||||
|
"""
|
||||||
|
Vimeo video link.
|
||||||
|
"""
|
||||||
|
text = ''
|
||||||
|
expected = '<iframe src="http://player.vimeo.com/video/52970271" width="1280" height="720" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>'
|
||||||
|
output = self.markdown.convert(text)
|
||||||
|
self.assertEqual(output, expected)
|
||||||
|
|
||||||
Loading…
Reference in a new issue