Skip to content
Snippets Groups Projects
Commit 4df946e9 authored by mazenovi's avatar mazenovi
Browse files

first full funcitonal release

parent 4b8abd04
No related branches found
No related tags found
No related merge requests found
Showing
with 401 additions and 0 deletions
'''
tag_cloud
===================================
This plugin generates a tag cloud from available tags
'''
from __future__ import unicode_literals
from collections import defaultdict
from operator import itemgetter
import logging
import math
import random
from pelican import signals
logger = logging.getLogger(__name__)
def set_default_settings(settings):
settings.setdefault('TAG_CLOUD_STEPS', 4)
settings.setdefault('TAG_CLOUD_MAX_ITEMS', 100)
settings.setdefault('TAG_CLOUD_SORTING', 'random')
settings.setdefault('TAG_CLOUD_BADGE', False)
def init_default_config(pelican):
from pelican.settings import DEFAULT_CONFIG
set_default_settings(DEFAULT_CONFIG)
if(pelican):
set_default_settings(pelican.settings)
def generate_tag_cloud(generator):
tag_cloud = defaultdict(int)
for article in generator.articles:
for tag in getattr(article, 'tags', []):
tag_cloud[tag] += 1
tag_cloud = sorted(tag_cloud.items(), key=itemgetter(1), reverse=True)
tag_cloud = tag_cloud[:generator.settings.get('TAG_CLOUD_MAX_ITEMS')]
tags = list(map(itemgetter(1), tag_cloud))
if tags:
max_count = max(tags)
steps = generator.settings.get('TAG_CLOUD_STEPS')
# calculate word sizes
def generate_tag(tag, count):
tag = (
tag,
int(math.floor(steps - (steps - 1) * math.log(count)
/ (math.log(max_count)or 1)))
)
if generator.settings.get('TAG_CLOUD_BADGE'):
tag += (count,)
return tag
tag_cloud = [
generate_tag(tag, count)
for tag, count in tag_cloud
]
sorting = generator.settings.get('TAG_CLOUD_SORTING')
if sorting == 'alphabetically':
tag_cloud.sort(key=lambda elem: elem[0].name)
elif sorting == 'alphabetically-rev':
tag_cloud.sort(key=lambda elem: elem[0].name, reverse=True)
elif sorting == 'size':
tag_cloud.sort(key=lambda elem: elem[1])
elif sorting == 'size-rev':
tag_cloud.sort(key=lambda elem: elem[1], reverse=True)
elif sorting == 'random':
random.shuffle(tag_cloud)
else:
logger.warning("setting for TAG_CLOUD_SORTING not recognized: %s, "
"falling back to 'random'", sorting)
random.shuffle(tag_cloud)
# make available in context
generator.tag_cloud = tag_cloud
generator._update_context(['tag_cloud'])
def register():
signals.initialized.connect(init_default_config)
signals.article_generator_finalized.connect(generate_tag_cloud)
Title: Article1
tags: fun, pelican, plugins
content, yeah!
\ No newline at end of file
Title: Article2
tags: pelican, plugins, python
content2, yeah!
Title: Article3
tags: pelican, plugins
content3, yeah!
Title: Article4
tags: pelican, fun
content4, yeah!
Title: Article5
tags: plugins, pelican, fun
content5, yeah!
import unittest
import os
import six
import tag_cloud
from pelican.generators import ArticlesGenerator
from pelican.tests.support import get_settings
from pelican.urlwrappers import Tag
CUR_DIR = os.path.dirname(__file__)
CONTENT_DIR = os.path.join(CUR_DIR, 'test_data')
class TestTagCloudGeneration(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls._settings = get_settings(filenames={})
cls._settings['DEFAULT_CATEGORY'] = 'Default'
cls._settings['DEFAULT_DATE'] = (1970, 1, 1)
cls._settings['READERS'] = {'asc': None}
cls._settings['CACHE_CONTENT'] = False
tag_cloud.set_default_settings(cls._settings)
cls.generator = ArticlesGenerator(
context=cls._settings.copy(), settings=cls._settings,
path=CONTENT_DIR, theme=cls._settings['THEME'], output_path=None)
cls.generator.generate_context()
def test_tag_cloud_random(self):
self.generator.settings['TAG_CLOUD_STEPS'] = 10
self.generator.settings['TAG_CLOUD_BADGE'] = False
tag_cloud.generate_tag_cloud(self.generator)
expected = [
(Tag('pelican', self._settings), 1),
(Tag('plugins', self._settings), 2),
(Tag('fun', self._settings), 3),
(Tag('python', self._settings), 10)
]
six.assertCountEqual(self, self.generator.tag_cloud, expected)
def test_tag_cloud_badge(self):
self.generator.settings['TAG_CLOUD_STEPS'] = 10
self.generator.settings['TAG_CLOUD_BADGE'] = True
tag_cloud.generate_tag_cloud(self.generator)
expected = [
(Tag('pelican', self._settings), 1, 5),
(Tag('plugins', self._settings), 2, 4),
(Tag('fun', self._settings), 3, 3),
(Tag('python', self._settings), 10, 1)
]
six.assertCountEqual(self, self.generator.tag_cloud, expected)
def test_tag_cloud_alphabetical(self):
self.generator.settings['TAG_CLOUD_STEPS'] = 10
self.generator.settings['TAG_CLOUD_SORTING'] = 'alphabetically'
tag_cloud.generate_tag_cloud(self.generator)
expected = [
(Tag('fun', self._settings), 3),
(Tag('pelican', self._settings), 1),
(Tag('plugins', self._settings), 2),
(Tag('python', self._settings), 10)
]
self.assertEqual(self.generator.tag_cloud, expected)
def test_tag_cloud_alphabetical_rev(self):
self.generator.settings['TAG_CLOUD_STEPS'] = 10
self.generator.settings['TAG_CLOUD_SORTING'] = 'alphabetically-rev'
tag_cloud.generate_tag_cloud(self.generator)
expected = [
(Tag('python', self._settings), 10),
(Tag('plugins', self._settings), 2),
(Tag('pelican', self._settings), 1),
(Tag('fun', self._settings), 3)
]
self.assertEqual(self.generator.tag_cloud, expected)
def test_tag_cloud_size(self):
self.generator.settings['TAG_CLOUD_STEPS'] = 10
self.generator.settings['TAG_CLOUD_SORTING'] = 'size'
tag_cloud.generate_tag_cloud(self.generator)
expected = [
(Tag('pelican', self._settings), 1),
(Tag('plugins', self._settings), 2),
(Tag('fun', self._settings), 3),
(Tag('python', self._settings), 10)
]
self.assertEqual(self.generator.tag_cloud, expected)
def test_tag_cloud_size_rev(self):
self.generator.settings['TAG_CLOUD_STEPS'] = 10
self.generator.settings['TAG_CLOUD_SORTING'] = 'size-rev'
tag_cloud.generate_tag_cloud(self.generator)
expected = [
(Tag('python', self._settings), 10),
(Tag('fun', self._settings), 3),
(Tag('plugins', self._settings), 2),
(Tag('pelican', self._settings), 1)
]
self.assertEqual(self.generator.tag_cloud, expected)
if __name__ == "__main__":
unittest.main()
Tipue Search
============
A Pelican plugin to serialize generated HTML to JSON that can be used by jQuery plugin - Tipue Search.
Copyright (c) Talha Mansoor
Author | Talha Mansoor
----------------|-----
Author Email | talha131@gmail.com
Author Homepage | http://onCrashReboot.com
Github Account | https://github.com/talha131
Why do you need it?
===================
Static sites do not offer search feature out of the box. [Tipue Search](http://www.tipue.com/search/)
is a jQuery plugin that search the static site without using any third party service, like DuckDuckGo or Google.
Tipue Search offers 4 search modes. Its [JSON search mode](http://www.tipue.com/search/docs/json/) is the best search mode
especially for large sites.
Tipue's JSON search mode requires the textual content of site in JSON format.
Requirements
============
Tipue Search requires BeautifulSoup.
```bash
pip install beautifulsoup4
```
How Tipue Search works
=========================
Tipue Search serializes the generated HTML into JSON. Format of JSON is as follows
```python
{
"pages": [
{
"text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero.",
"tags": "Example Category",
"url" : "http://oncrashreboot.com/plugin-example.html",
"title": "Everything you want to know about Lorem Ipsum"
},
{
"text": "Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh.",
"tags": "Example Category",
"url" : "http://oncrashreboot.com/plugin-example-2.html",
"title": "Review of the book Lorem Ipsum"
}
]
}
```
JSON is written to file `tipuesearch_content.json` which is created in the root of `output` directory.
How to use
==========
To utilize JSON Search mode, your theme needs to have Tipue Search properly configured in it. [Official documentation](http://www.tipue.com/search/docs/#json) has the required details.
Pelican [Elegant Theme](https://github.com/talha131/pelican-elegant) and [Plumage
theme](https://github.com/kdeldycke/plumage) have Tipue Search configured. You can view their
code to understand the configuration.
from .tipue_search import *
# -*- coding: utf-8 -*-
"""
Tipue Search
============
A Pelican plugin to serialize generated HTML to JSON
that can be used by jQuery plugin - Tipue Search.
Copyright (c) Talha Mansoor
"""
from __future__ import unicode_literals
import os.path
import json
from bs4 import BeautifulSoup
from codecs import open
try:
from urlparse import urljoin
except ImportError:
from urllib.parse import urljoin
from pelican import signals
class Tipue_Search_JSON_Generator(object):
def __init__(self, context, settings, path, theme, output_path, *null):
self.output_path = output_path
self.context = context
self.siteurl = settings.get('SITEURL')
self.tpages = settings.get('TEMPLATE_PAGES')
self.output_path = output_path
self.json_nodes = []
def create_json_node(self, page):
if getattr(page, 'status', 'published') != 'published':
return
soup_title = BeautifulSoup(page.title.replace(' ', ' '), 'html.parser')
page_title = soup_title.get_text(' ', strip=True).replace('', '"').replace('', '"').replace('', "'").replace('^', '^')
soup_text = BeautifulSoup(page.content, 'html.parser')
page_text = soup_text.get_text(' ', strip=True).replace('', '"').replace('', '"').replace('', "'").replace('', ' ').replace('^', '^')
page_text = ' '.join(page_text.split())
page_category = page.category.name if getattr(page, 'category', 'None') != 'None' else ''
page_url = page.url if page.url else '.'
node = {'title': page_title,
'text': page_text,
'tags': page_category,
'url': page_url}
self.json_nodes.append(node)
def create_tpage_node(self, srclink):
srcfile = open(os.path.join(self.output_path, self.tpages[srclink]), encoding='utf-8')
soup = BeautifulSoup(srcfile, 'html.parser')
page_title = soup.title.string if soup.title is not None else ''
page_text = soup.get_text()
# Should set default category?
page_category = ''
page_url = urljoin(self.siteurl, self.tpages[srclink])
node = {'title': page_title,
'text': page_text,
'tags': page_category,
'url': page_url}
self.json_nodes.append(node)
def generate_output(self, writer):
path = os.path.join(self.output_path, 'tipuesearch_content.json')
pages = self.context['pages'] + self.context['articles']
for article in self.context['articles']:
pages += article.translations
for srclink in self.tpages:
self.create_tpage_node(srclink)
for page in pages:
self.create_json_node(page)
root_node = {'pages': self.json_nodes}
with open(path, 'w', encoding='utf-8') as fd:
json.dump(root_node, fd, separators=(',', ':'), ensure_ascii=False)
def get_generators(generators):
return Tipue_Search_JSON_Generator
def register():
signals.get_generators.connect(get_generators)
setup.py 0 → 100644
from setuptools import setup
setup(
name='blog-limos',
version='1.0',
include_package_data=True,
install_requires=[
'pelican',
'markdown',
'beautifulsoup4'
]
)
File moved
File moved
File moved
File moved
File moved
File moved
File moved
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment