From 2b373628738c9f053a8574f2080ca4379e55b7d0 Mon Sep 17 00:00:00 2001 From: Khue Vu Date: Tue, 6 May 2014 00:27:42 +0800 Subject: [PATCH 1/3] add the plugin to extract representative image for article and assign to an article's property --- representative_image/Readme.md | 8 +++ representative_image/__init__.py | 1 + representative_image/representative_image.py | 31 +++++++++++ .../test_representative_image.py | 54 +++++++++++++++++++ 4 files changed, 94 insertions(+) create mode 100644 representative_image/Readme.md create mode 100644 representative_image/__init__.py create mode 100644 representative_image/representative_image.py create mode 100644 representative_image/test_representative_image.py diff --git a/representative_image/Readme.md b/representative_image/Readme.md new file mode 100644 index 0000000..a26c5f2 --- /dev/null +++ b/representative_image/Readme.md @@ -0,0 +1,8 @@ +# Summary + +This plugin extracts a presentative image from the article's summary or article's content. The image can be access at `article.repImage`. + +The plugin also remove any images from the summary after extraction to avoid duplication. + +It allows the flexibility on where and how to display the representative image of an article together with its summary in a template page. For example, the article metadata can be displayed in thumbnail format, in which there is a short summary and an image. The layout of the summary and the image can be varied for aesthetical purpose. It doesn't have to depend on article's content format. + diff --git a/representative_image/__init__.py b/representative_image/__init__.py new file mode 100644 index 0000000..f52720f --- /dev/null +++ b/representative_image/__init__.py @@ -0,0 +1 @@ +from .representative_image import * diff --git a/representative_image/representative_image.py b/representative_image/representative_image.py new file mode 100644 index 0000000..7d5d61c --- /dev/null +++ b/representative_image/representative_image.py @@ -0,0 +1,31 @@ +from pelican import signals +from pelican.contents import Content, Article +from bs4 import BeautifulSoup + +def images_extraction(instance): + representativeImage = None + if type(instance) == Article: + # Process Summary: + # If summary contains images, extract one to be the representativeImage and remove images from summary + soup = BeautifulSoup(instance.summary, 'html.parser') + images = soup.find_all('img') + for i in images: + if not representativeImage: + representativeImage = i['src'] + i.extract() + if len(images) > 0: + # set _summary field which is based on metadata. summary field is only based on article's content and not settable + instance._summary = unicode(soup) + + # If there are no image in summary, look for it in the content body + if not representativeImage: + soup = BeautifulSoup(instance.content, 'html.parser') + imageTag = soup.find('img') + if imageTag: + representativeImage = imageTag['src'] + + # Set the attribute to content instance + instance.repImage = representativeImage + +def register(): + signals.content_object_init.connect(images_extraction) diff --git a/representative_image/test_representative_image.py b/representative_image/test_representative_image.py new file mode 100644 index 0000000..60efa8b --- /dev/null +++ b/representative_image/test_representative_image.py @@ -0,0 +1,54 @@ +#!/bin/sh +import unittest + +from jinja2.utils import generate_lorem_ipsum + +# Generate content with image +TEST_CONTENT_IMAGE_URL = 'https://testimage.com/test.jpg' +TEST_CONTENT = str(generate_lorem_ipsum(n=3, html=True)) + ''+ str(generate_lorem_ipsum(n=2,html=True)) +TEST_SUMMARY_IMAGE_URL = 'https://testimage.com/summary.jpg' +TEST_SUMMARY_WITHOUTIMAGE = str(generate_lorem_ipsum(n=1, html=True)) +TEST_SUMMARY_WITHIMAGE = TEST_SUMMARY_WITHOUTIMAGE + '' + + +from pelican.contents import Article +import representative_image + +class TestRepresentativeImage(unittest.TestCase): + + def setUp(self): + super(TestRepresentativeImage, self).setUp() + representative_image.register() + + def test_extract_image_from_content(self): + args = { + 'content': TEST_CONTENT, + 'metadata': { + 'summary': TEST_SUMMARY_WITHOUTIMAGE, + }, + } + + article = Article(**args) + self.assertEqual(article.repImage, TEST_CONTENT_IMAGE_URL) + + def test_extract_image_from_summary(self): + args = { + 'content': TEST_CONTENT, + 'metadata': { + 'summary': TEST_SUMMARY_WITHIMAGE, + }, + } + + article = Article(**args) + self.assertEqual(article.repImage, TEST_SUMMARY_IMAGE_URL) + self.assertEqual(article.summary, TEST_SUMMARY_WITHOUTIMAGE) + +if __name__ == '__main__': + unittest.main() + + + + + + + From c15a9dc250961f5696a3aad639729d7e439560a5 Mon Sep 17 00:00:00 2001 From: Khue Vu Date: Tue, 6 May 2014 09:20:30 +0800 Subject: [PATCH 2/3] change image property name to featured_image --- representative_image/representative_image.py | 2 +- representative_image/test_representative_image.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/representative_image/representative_image.py b/representative_image/representative_image.py index 7d5d61c..3d91d36 100644 --- a/representative_image/representative_image.py +++ b/representative_image/representative_image.py @@ -25,7 +25,7 @@ def images_extraction(instance): representativeImage = imageTag['src'] # Set the attribute to content instance - instance.repImage = representativeImage + instance.featured_image = representativeImage def register(): signals.content_object_init.connect(images_extraction) diff --git a/representative_image/test_representative_image.py b/representative_image/test_representative_image.py index 60efa8b..4e65c5d 100644 --- a/representative_image/test_representative_image.py +++ b/representative_image/test_representative_image.py @@ -29,7 +29,7 @@ class TestRepresentativeImage(unittest.TestCase): } article = Article(**args) - self.assertEqual(article.repImage, TEST_CONTENT_IMAGE_URL) + self.assertEqual(article.featured_image, TEST_CONTENT_IMAGE_URL) def test_extract_image_from_summary(self): args = { @@ -40,7 +40,7 @@ class TestRepresentativeImage(unittest.TestCase): } article = Article(**args) - self.assertEqual(article.repImage, TEST_SUMMARY_IMAGE_URL) + self.assertEqual(article.featured_image, TEST_SUMMARY_IMAGE_URL) self.assertEqual(article.summary, TEST_SUMMARY_WITHOUTIMAGE) if __name__ == '__main__': From 624734724b3c52fd85cb8fbc915e862a145b7a70 Mon Sep 17 00:00:00 2001 From: Khue Vu Date: Wed, 7 May 2014 00:40:00 +0800 Subject: [PATCH 3/3] update Readme.md --- representative_image/Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/representative_image/Readme.md b/representative_image/Readme.md index a26c5f2..390a216 100644 --- a/representative_image/Readme.md +++ b/representative_image/Readme.md @@ -1,8 +1,8 @@ # Summary -This plugin extracts a presentative image from the article's summary or article's content. The image can be access at `article.repImage`. +This plugin extracts a representative image (i.e, featured image) from the article's summary or article's content. The image can be access at `article.featured_image`. The plugin also remove any images from the summary after extraction to avoid duplication. -It allows the flexibility on where and how to display the representative image of an article together with its summary in a template page. For example, the article metadata can be displayed in thumbnail format, in which there is a short summary and an image. The layout of the summary and the image can be varied for aesthetical purpose. It doesn't have to depend on article's content format. +It allows the flexibility on where and how to display the featured image of an article together with its summary in a template page. For example, the article metadata can be displayed in thumbnail format, in which there is a short summary and an image. The layout of the summary and the image can be varied for aesthetical purpose. It doesn't have to depend on article's content format.