Kaynağa Gözat

Merge pull request #562 from xsteadfastx/master

liquid_tags: Add audio and giphy plugins
Justin Mayer 9 yıl önce
ebeveyn
işleme
8e4b9eaa34

+ 21 - 0
liquid_tags/Readme.md

@@ -53,6 +53,14 @@ To insert a Flickr image to a post, follow these steps:
 
     ``{% flickr image_id [small|medium|large] ["alt text"|'alt text'] %}``
 
+## Giphy Tag
+To insert a gif from Giphy in your document by its id (such as ``aMSJFS6oFX0fC``), enable the ``liquid_tags.giphy`` plugin and use the following:
+
+    {% giphy gif_id ["alt text"|'alt text'] %}
+
+IMPORTANT: You have to request a production API key from giphy [here](https://api.giphy.com/submit).
+For the first runs you could also use the public beta key you can get [here](https://github.com/giphy/GiphyAPI).
+
 ## Soundcloud Tag
 To insert a Soundcloud Widget to a post, follow these steps:
 
@@ -96,6 +104,19 @@ which is used as a preview of the video.
 To use a video from file, make sure it's in a static directory and put in
 the appropriate url.
 
+## Audio Tag
+To insert HTML5 audio into a post, enable the ``liquid_tags.audio`` plugin,
+and add to your document:
+
+    {% audio url/to/audio [url/to/audio] [url/to/audio] %}
+
+Up to 3 audio urls are possible. So you can add different versions of
+the audio file you want to post because not every browser support every
+file format.
+
+To use a audio from file, make sure it's in a static directory and put in
+the appropriate url.
+
 ## Include Code
 To include code from a file in your document with a link to the original
 file, enable the ``liquid_tags.include_code`` plugin, and add to your

+ 74 - 0
liquid_tags/audio.py

@@ -0,0 +1,74 @@
+"""
+Audio Tag
+---------
+This implements a Liquid-style audio tag for Pelican,
+based on the pelican video plugin [1]_
+
+Syntax
+------
+{% audio url/to/audio [url/to/audio] [/url/to/audio] %}
+
+Example
+-------
+{% audio http://example.tld/foo.mp3 http://example.tld/foo.ogg %}
+
+Output
+------
+<audio controls><source src="http://example.tld/foo.mp3" type="audio/mpeg"><source src="http://example.tld/foo.ogg" type="audio/ogg">Your browser does not support the audio element.</audio>
+
+[1] https://github.com/getpelican/pelican-plugins/blob/master/liquid_tags/video.py
+"""
+import os
+import re
+from .mdx_liquid_tags import LiquidTags
+
+SYNTAX = "{% audio url/to/audio [url/to/audio] [/url/to/audio] %}"
+AUDIO = re.compile(r'(/\S+|https?:\S+)(?:\s+(/\S+|https?:\S+))?(?:\s+(/\S+|https?:\S+))?')
+
+AUDIO_TYPEDICT = {'.mp3': 'audio/mpeg',
+                  '.ogg': 'audio/ogg',
+                  '.opus': 'audio/ogg',
+                  '.wav': 'audio/wav',
+                  '.mp4': 'audio/mp4'}
+
+
+def create_html(markup):
+    match = AUDIO.search(markup)
+    if match:
+        groups = match.groups()
+        audio_files = [g for g in groups if g]
+
+    if any(audio_files):
+        audio_out = '<audio controls>'
+
+        for audio_file in audio_files:
+
+            base, ext = os.path.splitext(audio_file)
+
+            if ext not in AUDIO_TYPEDICT:
+                raise ValueError("Unrecognized audio extension: "
+                                 "{0}".format(ext))
+
+            # add audio source
+            audio_out += '<source src="{}" type="{}">'.format(
+                audio_file, AUDIO_TYPEDICT[ext])
+
+        # close audio tag
+        audio_out += 'Your browser does not support the audio element.'
+        audio_out += '</audio>'
+
+    else:
+        raise ValueError("Error processing input, "
+                         "expected syntax: {0}".format(SYNTAX))
+
+    return audio_out
+
+
+@LiquidTags.register('audio')
+def audio(preprocessor, tag, markup):
+    return create_html(markup)
+
+
+# ---------------------------------------------------
+# This import allows image tag to be a Pelican plugin
+from liquid_tags import register

+ 89 - 0
liquid_tags/giphy.py

@@ -0,0 +1,89 @@
+"""
+Giphy Tag
+---------
+
+This implements a Liquid-style Giphy tag for Pelican.
+
+IMPORTANT: You have to request a production API key from giphy `here <https://api.giphy.com/submit>`.
+For the first runs you could also use the public beta key you can get `here <https://github.com/giphy/GiphyAPI>`.
+
+Syntax
+------
+{% giphy gif_id ["alt text"|'alt text'] %}
+
+Example
+-------
+{% giphy aMSJFS6oFX0fC 'ive had some free time' %}
+
+Output
+------
+<a href="http://giphy.com/gifs/veronica-mars-aMSJFS6oFX0fC"><img src="http://media4.giphy.com/media/aMSJFS6oFX0fC/giphy.gif" alt="ive had some free time"></a>
+"""
+import json
+import re
+try:
+    from urllib.request import urlopen
+except ImportError:
+    from urllib import urlopen
+from .mdx_liquid_tags import LiquidTags
+
+
+SYNTAX = '''{% giphy gif_id ["alt text"|'alt text'] %}'''
+GIPHY = re.compile('''(?P<gif_id>[\S+]+)(?:\s+(['"]{0,1})(?P<alt>.+)(\\2))?''')
+
+
+def get_gif(api_key, gif_id):
+    '''Returns dict with gif informations from the API.'''
+    url = 'http://api.giphy.com/v1/gifs/{}?api_key={}'.format(gif_id, api_key)
+    r = urlopen(url)
+
+    return json.loads(r.read().decode('utf-8'))
+
+
+def create_html(api_key, attrs):
+    '''Returns complete html tag string.'''
+    gif = get_gif(api_key, attrs['gif_id'])
+
+    if 'alt' not in attrs.keys():
+        attrs['alt'] = 'source: {}'.format(gif['data']['source'])
+
+    html_out = '<a href="{}">'.format(gif['data']['url'])
+    html_out += '<img src="{}" alt="{}">'.format(
+        gif['data']['images']['original']['url'],
+        attrs['alt'])
+    html_out += '</a>'
+
+    return html_out
+
+
+def main(api_key, markup):
+    '''Doing the regex parsing and running the create_html function.'''
+    match = GIPHY.search(markup)
+
+    attrs = None
+
+    if match:
+        attrs = dict(
+            [(key, value.strip())
+             for (key, value) in match.groupdict().items() if value])
+
+    else:
+        raise ValueError('Error processing input. '
+                         'Expected syntax: {}'.format(SYNTAX))
+
+    return create_html(api_key, attrs)
+
+
+@LiquidTags.register('giphy')
+def giphy(preprocessor, tag, markup):
+    api_key = preprocessor.configs.getConfig('GIPHY_API_KEY')
+
+    if api_key is None:
+        raise ValueError('Please set GIPHY_API_KEY.')
+
+    return main(api_key, markup)
+
+
+# ---------------------------------------------------
+# This import allows image tag to be a Pelican plugin
+from liquid_tags import register

+ 4 - 2
liquid_tags/mdx_liquid_tags.py

@@ -21,11 +21,13 @@ LIQUID_TAG = re.compile(r'\{%.*?%\}', re.MULTILINE | re.DOTALL)
 EXTRACT_TAG = re.compile(r'(?:\s*)(\S+)(?:\s*)')
 LT_CONFIG = { 'CODE_DIR': 'code',
               'NOTEBOOK_DIR': 'notebooks',
-              'FLICKR_API_KEY': 'flickr'
+              'FLICKR_API_KEY': 'flickr',
+              'GIPHY_API_KEY': 'giphy'
 }
 LT_HELP = { 'CODE_DIR' : 'Code directory for include_code subplugin',
             'NOTEBOOK_DIR' : 'Notebook directory for notebook subplugin',
-            'FLICKR_API_KEY': 'Flickr key for accessing the API'
+            'FLICKR_API_KEY': 'Flickr key for accessing the API',
+            'GIPHY_API_KEY': 'Giphy key for accessing the API'
 }
 
 class _LiquidTagsPreprocessor(markdown.preprocessors.Preprocessor):

+ 38 - 0
liquid_tags/test_audio.py

@@ -0,0 +1,38 @@
+from . import audio
+import pytest
+import re
+
+
+@pytest.mark.parametrize('input,expected', [
+    ('http://foo.bar https://bar.foo',
+     ('http://foo.bar', 'https://bar.foo', None)),
+    ('http://test.foo',
+     ('http://test.foo', None, None)),
+    ('https://test.foo',
+     ('https://test.foo', None, None)),
+    ('http://foo.foo https://bar.bar http://zonk.zonk',
+     ('http://foo.foo', 'https://bar.bar', 'http://zonk.zonk'))
+])
+def test_regex(input, expected):
+    assert re.match(audio.AUDIO, input).groups() == expected
+
+
+@pytest.mark.parametrize('input,expected', [
+    ('http://foo.foo/foo.mp3',
+     ('<audio controls>'
+      '<source src="http://foo.foo/foo.mp3" type="audio/mpeg">'
+      'Your browser does not support the audio element.</audio>')),
+    ('https://foo.foo/foo.ogg http://bar.bar/bar.opus',
+     ('<audio controls>'
+      '<source src="https://foo.foo/foo.ogg" type="audio/ogg">'
+      '<source src="http://bar.bar/bar.opus" type="audio/ogg">'
+      'Your browser does not support the audio element.</audio>')),
+    ('http://1.de/1.wav http://2.de/2.mp4 http://3.de/3.ogg',
+     ('<audio controls>'
+      '<source src="http://1.de/1.wav" type="audio/wav">'
+      '<source src="http://2.de/2.mp4" type="audio/mp4">'
+      '<source src="http://3.de/3.ogg" type="audio/ogg">'
+      'Your browser does not support the audio element.</audio>'))
+])
+def test_create_html(input, expected):
+    assert audio.create_html(input) == expected

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 0
liquid_tags/test_data/giphy.json


+ 29 - 0
liquid_tags/test_giphy.py

@@ -0,0 +1,29 @@
+from . import giphy
+try:
+    from unittest.mock import patch
+except ImportError:
+    from mock import patch
+import os
+import pytest
+
+
+PLUGIN_DIR = os.path.dirname(__file__)
+TEST_DATA_DIR = os.path.join(PLUGIN_DIR, 'test_data')
+
+
+@pytest.mark.parametrize('input,expected', [
+    (dict(gif_id='abc123'),
+     ('<a href="http://giphy.com/gifs/veronica-mars-aMSJFS6oFX0fC">'
+      '<img src="http://media2.giphy.com/media/'
+      'aMSJFS6oFX0fC/giphy.gif" alt="source: http://www.tumblr.com"></a>')),
+    (dict(gif_id='abc123', alt='ive had some free time'),
+     ('<a href="http://giphy.com/gifs/veronica-mars-aMSJFS6oFX0fC">'
+      '<img src="http://media2.giphy.com/media/'
+      'aMSJFS6oFX0fC/giphy.gif" alt="ive had some free time"></a>'))
+])
+@patch('liquid_tags.giphy.urlopen')
+def test_create_html(mock_urlopen, input, expected):
+    with open(TEST_DATA_DIR + '/giphy.json', 'rb') as f:
+        mock_urlopen.return_value.read.return_value = f.read()
+
+        assert giphy.create_html('test_api_key', input) == expected