diff --git a/liquid_tags/Readme.md b/liquid_tags/Readme.md index 5c4446b96..3b6871c58 100644 --- a/liquid_tags/Readme.md +++ b/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: diff --git a/liquid_tags/giphy.py b/liquid_tags/giphy.py new file mode 100644 index 000000000..c61b305d9 --- /dev/null +++ b/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 `. +For the first runs you could also use the public beta key you can get `here `. + +Syntax +------ +{% giphy gif_id ["alt text"|'alt text'] %} + +Example +------- +{% giphy aMSJFS6oFX0fC 'ive had some free time' %} + +Output +------ +ive had some free time +""" +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[\S+]+)(?:\s+(['"]{0,1})(?P.+)(\\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 = ''.format(gif['data']['url']) + html_out += '{}'.format( + gif['data']['images']['original']['url'], + attrs['alt']) + html_out += '' + + 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 diff --git a/liquid_tags/mdx_liquid_tags.py b/liquid_tags/mdx_liquid_tags.py index 5a2b0ee2b..60edf5e21 100644 --- a/liquid_tags/mdx_liquid_tags.py +++ b/liquid_tags/mdx_liquid_tags.py @@ -21,11 +21,13 @@ 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): diff --git a/liquid_tags/test_data/giphy.json b/liquid_tags/test_data/giphy.json new file mode 100644 index 000000000..8a2d5e11f --- /dev/null +++ b/liquid_tags/test_data/giphy.json @@ -0,0 +1,2 @@ + +{"data":{"type":"gif","id":"aMSJFS6oFX0fC","url":"http:\/\/giphy.com\/gifs\/veronica-mars-aMSJFS6oFX0fC","bitly_gif_url":"http:\/\/gph.is\/1hcFOSo","bitly_url":"http:\/\/gph.is\/1hcFOSo","embed_url":"http:\/\/giphy.com\/embed\/aMSJFS6oFX0fC","username":"","source":"http:\/\/www.tumblr.com","rating":"pg","caption":"","content_url":"","import_datetime":"2014-02-21 04:43:11","trending_datetime":"1970-01-01 00:00:00","images":{"fixed_height":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200.gif","width":"350","height":"200","size":"296611","mp4":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200.mp4","mp4_size":"64850","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200.webp","webp_size":"529942"},"fixed_height_still":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200_s.gif","width":"350","height":"200"},"fixed_height_downsampled":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200_d.gif","width":"350","height":"200","size":"243264","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200_d.webp","webp_size":"138300"},"fixed_width":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200w.gif","width":"200","height":"114","size":"120246","mp4":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200w.mp4","mp4_size":"96166","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200w.webp","webp_size":"210140"},"fixed_width_still":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200w_s.gif","width":"200","height":"114"},"fixed_width_downsampled":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200w_d.gif","width":"200","height":"114","size":"113909","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/200w_d.webp","webp_size":"55084"},"fixed_height_small":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100.gif","width":"175","height":"100","size":"296611","mp4":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100.mp4","mp4_size":"243931","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100.webp","webp_size":"136098"},"fixed_height_small_still":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100_s.gif","width":"175","height":"100"},"fixed_width_small":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100w.gif","width":"100","height":"57","size":"120246","mp4":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100w.mp4","mp4_size":"101604","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100w.webp","webp_size":"55480"},"fixed_width_small_still":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/100w_s.gif","width":"100","height":"57"},"downsized":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy.gif","width":"245","height":"140","size":"487767"},"downsized_still":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy_s.gif","width":"245","height":"140"},"downsized_large":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy.gif","width":"245","height":"140","size":"487767"},"original":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy.gif","width":"245","height":"140","size":"487767","frames":"23","mp4":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy.mp4","mp4_size":"219528","webp":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy.webp","webp_size":"272262"},"original_still":{"url":"http:\/\/media2.giphy.com\/media\/aMSJFS6oFX0fC\/giphy_s.gif","width":"245","height":"140"}}},"meta":{"status":200,"msg":"OK"}} \ No newline at end of file diff --git a/liquid_tags/test_giphy.py b/liquid_tags/test_giphy.py new file mode 100644 index 000000000..1ce80c131 --- /dev/null +++ b/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'), + ('' + 'source: http://www.tumblr.com')), + (dict(gif_id='abc123', alt='ive had some free time'), + ('' + 'ive had some free time')) +]) +@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