From 33e05f02abc4871e6f19e7dac5912a4bbdfa6367 Mon Sep 17 00:00:00 2001 From: messense Date: Sat, 29 Dec 2012 21:01:07 +0800 Subject: [PATCH] release version v0.04 --- MANIFEST.in | 4 + README.md | 26 +- _posts | 1 + catsup | 8 - catsup.sh | 8 + catsup/.gitignore | 37 ++ catsup/__init__.py | 5 + catsup/app.py | 378 ++++++++++++++ catsup/template/feed.xml | 22 + catsup/template/sitemap.txt | 6 + .../themes/effector/static/css/effector.css | 424 +++++++++++++++ .../effector/static/css/pygments_style.css | 62 +++ catsup/themes/effector/static/robots.txt | 0 catsup/themes/effector/template/404.html | 18 + catsup/themes/effector/template/archive.html | 16 + catsup/themes/effector/template/archives.html | 15 + catsup/themes/effector/template/article.html | 66 +++ catsup/themes/effector/template/base.html | 47 ++ catsup/themes/effector/template/index.html | 34 ++ catsup/themes/effector/template/links.html | 21 + catsup/themes/effector/template/tag.html | 16 + catsup/themes/effector/template/tags.html | 15 + .../sealscript/static/css/pygments_style.css | 69 +++ catsup/themes/sealscript/static/css/style.css | 482 ++++++++++++++++++ catsup/themes/sealscript/static/favicon.ico | Bin 0 -> 1406 bytes .../static/image/background-stripes.png | Bin 0 -> 84 bytes .../sealscript/static/image/body_bg.png | Bin 0 -> 2198 bytes .../sealscript/static/image/body_dark_bg.png | Bin 0 -> 2092 bytes .../themes/sealscript/static/image/go_bg.png | Bin 0 -> 5417 bytes .../sealscript/static/image/ic16_github.png | Bin 0 -> 329 bytes .../sealscript/static/image/ic16_rss.png | Bin 0 -> 373 bytes .../sealscript/static/image/ic16_twitter.png | Bin 0 -> 216 bytes .../themes/sealscript/static/image/mask.png | Bin 0 -> 4441 bytes .../themes/sealscript/static/image/nav_bg.png | Bin 0 -> 2459 bytes catsup/themes/sealscript/static/robots.txt | 0 catsup/themes/sealscript/template/404.html | 33 ++ .../themes/sealscript/template/archive.html | 35 ++ .../themes/sealscript/template/archives.html | 0 .../themes/sealscript/template/article.html | 78 +++ catsup/themes/sealscript/template/base.html | 97 ++++ catsup/themes/sealscript/template/index.html | 53 ++ catsup/themes/sealscript/template/links.html | 0 catsup/themes/sealscript/template/tag.html | 38 ++ catsup/themes/sealscript/template/tags.html | 0 catsup/utils.py | 249 +++++++++ conf/nginx.conf | 20 + conf/supervisord.conf | 28 + setup.py | 21 + 48 files changed, 2419 insertions(+), 13 deletions(-) create mode 100644 MANIFEST.in create mode 160000 _posts delete mode 100755 catsup create mode 100755 catsup.sh create mode 100644 catsup/.gitignore create mode 100644 catsup/__init__.py create mode 100644 catsup/app.py create mode 100644 catsup/template/feed.xml create mode 100644 catsup/template/sitemap.txt create mode 100644 catsup/themes/effector/static/css/effector.css create mode 100644 catsup/themes/effector/static/css/pygments_style.css create mode 100644 catsup/themes/effector/static/robots.txt create mode 100644 catsup/themes/effector/template/404.html create mode 100644 catsup/themes/effector/template/archive.html create mode 100644 catsup/themes/effector/template/archives.html create mode 100644 catsup/themes/effector/template/article.html create mode 100644 catsup/themes/effector/template/base.html create mode 100644 catsup/themes/effector/template/index.html create mode 100644 catsup/themes/effector/template/links.html create mode 100644 catsup/themes/effector/template/tag.html create mode 100644 catsup/themes/effector/template/tags.html create mode 100644 catsup/themes/sealscript/static/css/pygments_style.css create mode 100755 catsup/themes/sealscript/static/css/style.css create mode 100644 catsup/themes/sealscript/static/favicon.ico create mode 100644 catsup/themes/sealscript/static/image/background-stripes.png create mode 100644 catsup/themes/sealscript/static/image/body_bg.png create mode 100644 catsup/themes/sealscript/static/image/body_dark_bg.png create mode 100644 catsup/themes/sealscript/static/image/go_bg.png create mode 100644 catsup/themes/sealscript/static/image/ic16_github.png create mode 100644 catsup/themes/sealscript/static/image/ic16_rss.png create mode 100644 catsup/themes/sealscript/static/image/ic16_twitter.png create mode 100644 catsup/themes/sealscript/static/image/mask.png create mode 100644 catsup/themes/sealscript/static/image/nav_bg.png create mode 100644 catsup/themes/sealscript/static/robots.txt create mode 100644 catsup/themes/sealscript/template/404.html create mode 100644 catsup/themes/sealscript/template/archive.html create mode 100644 catsup/themes/sealscript/template/archives.html create mode 100644 catsup/themes/sealscript/template/article.html create mode 100644 catsup/themes/sealscript/template/base.html create mode 100644 catsup/themes/sealscript/template/index.html create mode 100644 catsup/themes/sealscript/template/links.html create mode 100644 catsup/themes/sealscript/template/tag.html create mode 100644 catsup/themes/sealscript/template/tags.html create mode 100644 catsup/utils.py create mode 100644 conf/nginx.conf create mode 100644 conf/supervisord.conf create mode 100644 setup.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..d78a7a7 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,4 @@ +recursive-include catsup/template *.* +recursive-include catsup/themes *.* +include README.md +include LICENSE diff --git a/README.md b/README.md index e21b45d..7ae737f 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,30 @@ Licensed under the MIT License. ##Install + +Simple way using pip + +```bash +pip install catsup +``` + +Or another hard way to install + ```bash git clone git://github.com/whtsky/catsup.git cd catsup -pip install -r requirements.txt -cp config-sample.py config.py -vim config.py #Change it. -python catsup.py server --port=8888 +python setup.py install ``` + +##Settings + +The default settings file is at `~/.catsuprc`, you can specific it by passing `--settings=/path/to/settings` when executing `python -m catsup.app ` + +##Run +```bash +python -m catsup.app server --port=8888 +``` + Then go to http://localhost:8888 to take a look at your own catsup:) ##How to write @@ -50,5 +66,5 @@ The `comment` property defines whether the post can be commented or not. You can use `` to define an excerpt of a post. Any content before that will be used as excerpt of the post. And you can choose to display excerpt rather than full content on your homepage. ##Deploy a static blog -run`python catsup.py deploy` +run`python -m catsup.app deploy` And you can find your static blog in deploy/ . \ No newline at end of file diff --git a/_posts b/_posts new file mode 160000 index 0000000..2337bd9 --- /dev/null +++ b/_posts @@ -0,0 +1 @@ +Subproject commit 2337bd92f2644d59f7c6a32f67482b9d7da4b727 diff --git a/catsup b/catsup deleted file mode 100755 index f1615c8..0000000 --- a/catsup +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -case $1 in - server) python catsup.py server;; - deploy) python catsup.py deploy;; - webhook) python catsup.py webhook;; - *) echo "Usage: catsup ";; -esac diff --git a/catsup.sh b/catsup.sh new file mode 100755 index 0000000..cd8e67a --- /dev/null +++ b/catsup.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +case $1 in + server) python -m catsup.app server;; + deploy) python -m catsup.app deploy;; + webhook) python -m catsup.app webhook;; + *) echo "Usage: catsup ";; +esac diff --git a/catsup/.gitignore b/catsup/.gitignore new file mode 100644 index 0000000..6e47027 --- /dev/null +++ b/catsup/.gitignore @@ -0,0 +1,37 @@ +#catsup +_posts/* +deploy/* + +#PyCharm +.idea + +*.py[co] + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox + +#Translations +*.mo + +#Mr Developer +.mr.developer.cfg + +#OS X +.DS_Store diff --git a/catsup/__init__.py b/catsup/__init__.py new file mode 100644 index 0000000..7406589 --- /dev/null +++ b/catsup/__init__.py @@ -0,0 +1,5 @@ +""" +Catsup, a lightweight static blog generator +""" + +__version__ = '0.0.4' \ No newline at end of file diff --git a/catsup/app.py b/catsup/app.py new file mode 100644 index 0000000..1590172 --- /dev/null +++ b/catsup/app.py @@ -0,0 +1,378 @@ +#!/usr/bin/env python +#coding=utf-8 +import sys +default_encoding = 'utf-8' +if sys.getdefaultencoding() != default_encoding: + reload(sys) + sys.setdefaultencoding(default_encoding) + +import os +import shutil +import copy +import logging +import tornado.httpserver +import tornado.web +import tornado.ioloop +import tornado.options +import tornado.escape +import tornado.template + +from tornado.options import define, options +from tornado.util import ObjectDict + +try: + import catsup + print('Starting catsup version: %s' % catsup.__version__) +except ImportError: + import site + site.addsitedir(os.path.split(os.path.abspath(os.path.dirname(__file__)))[0]) +# import the config to define options, this only can be done once +from catsup import config +from catsup.utils import load_posts, get_infos, parse_config_file + +if len(sys.argv) > 1: + _args = copy.deepcopy(sys.argv) + del _args[1] + tornado.options.parse_command_line(_args) + del _args +if options.settings and os.path.exists(options.settings): + print('Parsing settings file: %s' % options.settings) + parse_config_file(options.settings) +else: + print('No settings file provided or it does not exists') + +if 'theme_path' not in options: + define('theme_path', os.path.join(options.themes_path, options.theme_name)) +if 'template_path' not in options: + define('template_path', os.path.join(options.theme_path, 'template')) +if 'static_path' not in options: + define('static_path', os.path.join(options.theme_path, 'static')) +if options.site_url.endswith('/'): + options.site_url = options.site_url[:-1] +if options.static_url.endswith('/'): + options.static_url = options.static_url[:-1] +if not (options.site_url == '' or options.site_url.startswith('http://') or options.site_url.startswith('https://') or options.site_url.startswith('//')): + options.site_url = "//%s" % options.site_url + +class BaseHandler(tornado.web.RequestHandler): + + def render_string(self, template_name, **kwargs): + options.tags = self.settings['tags'] + options.posts = self.settings['posts'] + options.archives = self.settings['archives'] + # access config directly + kwargs["config"] = options + return super(BaseHandler, self).render_string(template_name,**kwargs) + + def get_error_html(self, *args, **kwargs): + return self.render_string('404.html') + + +class MainHandler(BaseHandler): + def get(self, p=1): + if p == '1': # /page_1.html + self.redirect('/', status=301) + p = int(p) + self.render('index.html', posts=self.settings['posts'], p=p) + + +class ArticleHandler(BaseHandler): + def get(self, file_name): + posts = self.settings['posts'] + posts_num = len(posts) + prev = next = None + for i in range(posts_num): + post = posts[i] + if post.file_name == file_name: + if i: # i>0 + prev = posts[i - 1] + if (i + 1) < posts_num: + next = posts[i + 1] + return self.render('article.html', post=post, + prev=prev, next=next) + raise tornado.web.HTTPError(404) + + +class TagsHandler(BaseHandler): + def get(self): + self.render('tags.html') + + +class TagHandler(BaseHandler): + def get(self, tag_name): + tags = self.settings['tags'] + prev = next = None + for i, tag in enumerate(tags): + if tag[0] == tag_name: + i += 1 + if i < len(tags): + next = tags[i] + return self.render('tag.html', tag=tag, + prev=prev, next=next) + prev = tag + + raise tornado.web.HTTPError(404) + + +class ArchivesHandler(BaseHandler): + def get(self): + self.render('archives.html') + + +class ArchiveHandler(BaseHandler): + def get(self, archive_name): + archives = self.settings['archives'] + prev = next = None + for i, archive in enumerate(archives): + if archive[0] == archive_name: + i += 1 + if i < len(archives): + next = archives[i] + return self.render('archive.html', archive=archive, + prev=prev, next=next) + prev = archive + raise tornado.web.HTTPError(404) + + +class LinksHandler(BaseHandler): + def get(self): + self.render('links.html') + + +class FeedHandler(BaseHandler): + def get(self): + self.set_header("Content-Type", "application/atom+xml") + loader = tornado.template.Loader(options.common_template_path, + autoescape=None) + p = loader.load("feed.xml").generate(posts=self.settings['posts'], + config=options) + self.write(p) + + +class SitemapHandler(BaseHandler): + def get(self): + self.set_header("Content-Type", "text/plain") + loader = tornado.template.Loader(options.common_template_path, + autoescape=None) + p = loader.load("sitemap.txt").generate(posts=self.settings['posts'], + config=options, tags=self.settings['tags'], + archives=self.settings['archives']) + self.write(p) + + +class WebhookHandler(BaseHandler): + def get(self): + deploy() + + def post(self): + """Webhook support for GitHub and Bitbucket. + """ + logging.info('Updating posts...') + update_posts() + if 'tags' in self.settings: + posts = load_posts() + tags, archives = get_infos(posts) + self.settings['posts'] = posts + self.settings['tags'] = tags + self.settings['archives'] = archives + else: + deploy() + + +class ErrorHandler(BaseHandler): + def prepare(self): + raise tornado.web.HTTPError(404) + + +def write(file_name, page): + if not file_name.startswith(options.deploy_path): + file_path = os.path.join(options.deploy_path, file_name) + else: + file_path = file_name + open(file_path, 'w').write(page) + + +def deploy(): + logging.info('Starting deploy catsup') + posts = load_posts() + tags, archives = get_infos(posts) + posts_num = len(posts) + + options.tags = tags + options.posts = posts + options.archives = archives + + if os.path.exists(options.deploy_path): + shutil.rmtree(options.deploy_path) + + os.makedirs(options.deploy_path) + + loader = tornado.template.Loader(options.common_template_path, + autoescape=None) + + logging.info('Generating sitemap') + page = loader.load("sitemap.txt").generate(posts=posts, tags=tags, + archives=archives, config=options) + write('sitemap.txt', page) + + logging.info('Generating atom') + page = loader.load("feed.xml").generate(posts=posts, config=options) + write('feed.xml', page) + + loader = tornado.template.Loader(options.template_path, + autoescape=None) + + logging.info('Start generating index pages') + page_path = os.path.join(options.deploy_path, 'page') + if os.path.exists(page_path): + shutil.rmtree(page_path) + os.makedirs(page_path) + generator = loader.load("index.html") + p = 0 + while posts_num > p * options.post_per_page: + p += 1 + logging.info('Start generating page %s' % p) + page = generator.generate(posts=posts, p=p, config=options) + pager_file = os.path.join(page_path, "%s.html" % p) + write(pager_file, page) + + index_1 = os.path.join(page_path, '1.html') + index = os.path.join(options.deploy_path, 'index.html') + os.rename(index_1, index) + + logging.info('Start generating articles') + generator = loader.load("article.html") + posts.reverse() + prev = None + post = posts.pop() + next = len(posts) and posts.pop() or None + while post: + logging.info('Generating %s' % post.file_name) + page = generator.generate(post=post, prev=prev, + next=next, config=options) + write('%s.html' % post.file_name, page) + prev, post, next = post, next, len(posts) and posts.pop() or None + + logging.info('Start generating tag pages') + tag_path = os.path.join(options.deploy_path, 'tag') + if os.path.exists(tag_path): + shutil.rmtree(tag_path) + os.makedirs(tag_path) + generator = loader.load("tag.html") + prev = None + for i, tag in enumerate(tags): + logging.info('Generating tag %s' % tag[0]) + i += 1 + next = i < len(tags) and tags[i] or None + page = generator.generate(tag=tag, prev=prev, + next=next, config=options) + tag_file = os.path.join(tag_path, "%s.html" % tag[0].lower()) + write(tag_file, page) + prev = tag + + logging.info('Start generating archive pages') + archive_path = os.path.join(options.deploy_path, 'archive') + if os.path.exists(archive_path): + shutil.rmtree(archive_path) + os.makedirs(archive_path) + generator = loader.load("archive.html") + prev = None + for i, archive in enumerate(archives): + logging.info('Generating archive %s' % archive[0]) + i += 1 + next = i < len(archives) and archives[i] or None + page = generator.generate(archive=archive, prev=prev, + next=next, config=options) + archive_file = os.path.join(archive_path, "%s.html" % archive[0]) + write(archive_file, page) + prev = archive + + logging.info('Start generating other pages') + for p in ('404', 'tags', 'archives', 'links'): + page = loader.load("%s.html" % p).generate(config=options) + write('%s.html' % p, page) + + logging.info('Copying static files.') + deploy_static_dir = os.path.join(options.deploy_path, 'static') + if os.path.exists(deploy_static_dir): + shutil.rmtree(deploy_static_dir) + shutil.copytree(options.static_path, deploy_static_dir) + os.chdir(options.deploy_path) + # Favicon, use favicon.ico in _posts directory default or fallback to the one in static directory + favicon_file = os.path.join(options.posts_path, 'favicon.ico') + if os.path.exists(favicon_file): + os.system('cp %s ./' % favicon_file) + else: + os.system('cp static/favicon.ico ./') + # Robots.txt, use robots.txt in _posts directory default or fallback to the one in static directory + robots_file = os.path.join(options.posts_path, 'robots.txt') + if os.path.exists(robots_file): + os.system('cp %s ./' % robots_file) + else: + os.system('cp static/robots.txt ./') + + logging.info('Done.') + + +def update_posts(): + os.chdir(options.posts_path) + if os.path.isdir(os.path.join(options.posts_path, '.git')): + os.system('git pull') + elif os.path.isdir(os.path.join(options.posts_path, '.hg')): + os.system('hg pull') + + +def main(): + args = sys.argv + if len(args) < 2: + print('Useage: catsup.py server/deploy/webhook') + sys.exit(0) + cmd = args[1] + del args[1] + if cmd == 'server': + posts = load_posts() + tags, archives = get_infos(posts) + settings = dict( + autoescape=None, + static_path=options.static_path, + template_path=options.template_path, + ) + application = tornado.web.Application([ + (r'/', MainHandler), + (r'/page/(.*?).html', MainHandler), + (r'/archives.html', ArchivesHandler), + (r'/archive/(.*?).html', ArchiveHandler), + (r'/tags.html', TagsHandler), + (r'/tag/(.*?).html', TagHandler), + (r'/links.html', LinksHandler), + (r'/feed.xml', FeedHandler), + (r'/sitemap.txt', SitemapHandler), + (r'/webhook', WebhookHandler), + (r'/(.*).html', ArticleHandler), + (r'/.*', ErrorHandler), + ], posts=posts, tags=tags, archives=archives, **settings) + elif cmd == 'deploy': + deploy() + elif cmd == 'webhook': + application = tornado.web.Application([ + (r'/webhook', WebhookHandler), + ]) + else: + print('Unknow Command: %s' % cmd) + sys.exit(0) + + if 'application' in locals(): + if cmd == 'server': + print('Starting server at port %s' % options.port) + elif cmd == 'webhook': + print('Starting webhook at port %s' % options.port) + http_server = tornado.httpserver.HTTPServer(application, xheaders=True) + http_server.listen(options.port) + tornado.ioloop.IOLoop.instance().start() + +if __name__ == '__main__': + try: + main() + except (EOFError, KeyboardInterrupt): + print('Exiting catsup...') + sys.exit(0) \ No newline at end of file diff --git a/catsup/template/feed.xml b/catsup/template/feed.xml new file mode 100644 index 0000000..0abcaa7 --- /dev/null +++ b/catsup/template/feed.xml @@ -0,0 +1,22 @@ + + + {{ config.site_title }} + + + {{ posts and posts[0]['updated_xml'] }} + {{ config.site_url }} + {% for post in posts[:15] %} + + <![CDATA[{{ post.title }}]]> + + {{ post.updated_xml }} + {{ post.updated_xml }} + {{ post.permalink }} + + + + + {% end %} + \ No newline at end of file diff --git a/catsup/template/sitemap.txt b/catsup/template/sitemap.txt new file mode 100644 index 0000000..b10b306 --- /dev/null +++ b/catsup/template/sitemap.txt @@ -0,0 +1,6 @@ +{% for post in posts %}{{ post.permalink }}.html +{% end %}{% for tag in tags %}{{ config.site_url }}/tag_{{ tag[0] }}.html +{% end %}{% for av in archives %}{{ config.site_url }}/archive_{{ av[0] }}.html +{% end %}{{ config.site_url }}/index.html +{% for p in range(1, int((len(posts) + config.post_per_page - 1) / config.post_per_page)) %}{{ config.site_url }}/page_{{ p + 1 }}.html +{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/static/css/effector.css b/catsup/themes/effector/static/css/effector.css new file mode 100644 index 0000000..d05d340 --- /dev/null +++ b/catsup/themes/effector/static/css/effector.css @@ -0,0 +1,424 @@ +html, body { + background-color: #E6EBEA; +} +footer, header, nav { + display: block; +} +footer { + margin-top: 5px; + text-align: center; +} +.nav>a { + margin: 0px 20px 0px 0px; +} +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100% +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +a:hover, a:active { + outline: 0; +} +img { + max-width: 640px; + height: auto; + border: 0; + -ms-interpolation-mode: bicubic; +} +.wrapper p img { + clear: both; + display: block; + margin-left: -20px; + margin-right: -20px; +} + +body { + margin: 0; + font-family: 'Hiragino Sans GB', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-size: 15px; + line-height: 30px; + color: #555; +} +a { + color: #F95B1F; + text-decoration: none; +} +a:hover { + color: #A33B14; + text-decoration: none; +} +a.label:hover { + color: #fff; + background-color: #F95B1F; +} +p a { + border-bottom: 1px dashed #CED1D1; +} +.container { + width: 660px; + margin-left: auto; + margin-right: auto; + *zoom: 1; +} +p { + margin: 0 0 14px; + font-family: 'Hiragino Sans GB', 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-size: 15px; + line-height: 30px; + color: #555; +} +p small { + font-size: 13px; + color: #999; +} +.lead { + margin-bottom: 30px; + font-size: 20px; + font-weight: 200; + line-height: 45px; +} +h1, h2, h3, h4, h5, h6 { + font-weight: normal; + color: #555; + margin: 0; + text-rendering: optimizelegibility; +} +h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { + font-weight: normal; + color: #CED1D1; +} +h1 { + line-height: 60px; + font-size: 24px; +} +h1 small { + font-size: 16px;; +} +h2 { + color: #777; + background-color: #F2F8F7; + margin: 20px -20px; + font-size: 20px; + padding: 0px 20px; + line-height: 35px; +} +h2 small { + font-size: 18px; +} +h3 { + line-height: 18px; + font-size: 18px; +} +h3 small { + font-size: 14px; +} +h4, h5, h6 { + line-height: 15px; +} +h4 { + font-size: 14px; +} +h4 small { + font-size: 12px; +} +h5 { + font-size: 12px; +} +h6 { + font-size: 11px; + color: #999; + text-transform: uppercase; +} +ul, ol { + padding: 0; + margin: 0 0 0px 25px; +} +ul ul, ul ol, ol ol, ol ul { + margin-bottom: 0; +} +ul { + list-style: disc; +} +ol { + list-style: decimal; +} +li { + line-height: 30px; +} +ul.unstyled { + margin-left: 0; + list-style: none; +} +dl { + margin-bottom: 30px; +} +dt, dd { + line-height: 30px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 14px; +} +hr { + margin: 30px 0; + border: 0; + border-top: 1px solid #eee; +} +strong { + font-weight: bold; +} +em { + font-style: italic; +} +.muted { + color: #999; +} +abbr { + font-size: 90%; + text-transform: uppercase; + border-bottom: 1px dotted #ddd; + cursor: help; +} +blockquote { + padding: 0 0 0 14px; + margin: 0 0 30px; + border-left: 5px solid #eee; +} +blockquote p { + margin-bottom: 0; + font-size: 14px; + line-height: 34px; + font-weight: 300; + color: #777; +} +blockquote small { + display: block; + line-height: 30px; + color: #999; +} +blockquote small:before { + content: '\2014 \00A0'} +blockquote.pull-right { + float: right; + padding-left: 0; + padding-right: 14px; + border-left: 0; + border-right: 5px solid #eee; +} +blockquote.pull-right p, blockquote.pull-right small { + text-align: right; +} +q:before, q:after, blockquote:before, blockquote:after { + content: ""} +address { + display: block; + margin-bottom: 30px; + line-height: 30px; + font-style: normal; +} +small { + font-size: 100%} +cite { + font-style: normal; +} +code, pre { + font-family: Monaco, Menlo, "Courier New", monospace; + font-size: 12px; +} +code { + padding: 3px 4px; + color: #d14; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +pre code{ + border: 0; +} +pre { + display: block; + padding: 8px; + margin: 0 0 30px; + line-height: 20px; + background-color: #f7f7f9; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + white-space: pre; + white-space: pre-wrap; + word-break: break-all; +} +.prettyprint.linenums{ + -webkit-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0; + -moz-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0; + box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0 +} +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { +margin: 0 0 0 33px; /* IE indents via margin-left */ +} +ol.linenums li { +padding-left: 12px; +color: #bebec5; +line-height: 18px; +text-shadow: 0 1px 0 #fff; +} +.com { + color: #93a1a1; +} +.lit { + color: #195f91; +} +.pun, .opn, .clo { + color: #93a1a1; +} +.fun { + color: #dc322f; +} +.str, .atv { + color: #D14; +} +.kwd, .linenums .tag { + color: #1e347b; +} +.typ, .atn, .dec, .var { + color: teal; +} +.pln { + color: #48484c; +} + +.pager { + margin-left: 0; + margin-bottom: 10px; + list-style: none; + text-align: center; + *zoom: 1; +} +.pager:before, .pager:after { + display: table; + content: ""} +.pager:after { + clear: both; +} +.pager li { + display: inline; +} +.pager a { + display: inline-block; + padding: 5px 14px; + background-color: #f8f8f6; + border: 1px solid #ddd; + -webkit-border-radius: 14px; + -moz-border-radius: 14px; + border-radius: 14px; +} +.pager a:hover { + text-decoration: none; + background-color: #f5f5f5; +} +.pager .next a { + float: right; +} +.pager .previous a { + float: left; +} +.label { + padding: 3px 3px 2px; + font-size: 11.25px; + font-weight: bold; + color: #fff; + text-transform: uppercase; + background-color: #999; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.label-important { + background-color: #b94a48; +} +.label-warning { + background-color: #f89406; +} +.label-success { + background-color: #468847; +} +.label-info { + background-color: #3a87ad; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.hide { + display: none; +} +.show { + display: block; +} +.invisible { + visibility: hidden; +} +.sitename { + font-size: 40px; + font-weight: bold; + color: #333; +} +.wrapper { + background-color: #fff; + margin: 10px 0px 50px 0px; + padding: 10px 20px; + moz-border-radius: 5px; + webkit-moz-border-radius: 5px; + border-radius: 5px; + -webkit-box-shadow: 0px 1px 3px #A8ABAB; + -moz-box-shadow: 0px 1px 3px #A8ABAB; + box-shadow: 0px 1px 3px #A8ABAB; +} + +.postsList { + margin: 0px 0px 10px 0px; +} + +.postsList li{ + list-style: none; + padding: 5px 3px; + margin: 0; + border-bottom: 1px solid #eee; +} +.postsList li span{ + color: #bbb; + float: right; + font-size: 14px; +} + +@media (max-width:768px){ + .container { + width: auto; + padding: 20px; + } + .sitename { + font-size: 30px; + font-weight: bold; + } + + .sitename, .nav { + text-align: center; + } + + .wrapper { + background-color: #fff; + margin: 10px 0px 20px 0px; + } +} \ No newline at end of file diff --git a/catsup/themes/effector/static/css/pygments_style.css b/catsup/themes/effector/static/css/pygments_style.css new file mode 100644 index 0000000..eb1527a --- /dev/null +++ b/catsup/themes/effector/static/css/pygments_style.css @@ -0,0 +1,62 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f0f0; } +.highlight .c { color: #60a0b0; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #808080 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0040D0 } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #40a070 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #40a070 } /* Literal.Number.Float */ +.highlight .mh { color: #40a070 } /* Literal.Number.Hex */ +.highlight .mi { color: #40a070 } /* Literal.Number.Integer */ +.highlight .mo { color: #40a070 } /* Literal.Number.Oct */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .il { color: #40a070 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/catsup/themes/effector/static/robots.txt b/catsup/themes/effector/static/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/catsup/themes/effector/template/404.html b/catsup/themes/effector/template/404.html new file mode 100644 index 0000000..509937c --- /dev/null +++ b/catsup/themes/effector/template/404.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} + +{% block title %}404 NOT FOUND{% end %} + +{% block content %} +

Sorry, the page you were looking does not exist.

+What about... +
+ {% for archive in config.archives %} +

{{ archive[0] }}

+
    + {% for post in archive[1] %} +
  • {{ post.date }} {{ post.title }}
  • + {% end %} +
+ {% end %} +
+{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/archive.html b/catsup/themes/effector/template/archive.html new file mode 100644 index 0000000..18ffa37 --- /dev/null +++ b/catsup/themes/effector/template/archive.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} + +{% block title %} +{{ archive[0] }} | {{ config.site_title }} +{% end %} + +{% block content %} +
+

{{ archive[0] }}

+
    + {% for post in archive[1] %} +
  • {{ post.date }} {{ post.title }}
  • + {% end %} +
+
+{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/archives.html b/catsup/themes/effector/template/archives.html new file mode 100644 index 0000000..25ee034 --- /dev/null +++ b/catsup/themes/effector/template/archives.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block title %} +Archives | {{ config.site_title }} +{% end %} + +{% block content %} +
+ +
+{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/article.html b/catsup/themes/effector/template/article.html new file mode 100644 index 0000000..37b5a7e --- /dev/null +++ b/catsup/themes/effector/template/article.html @@ -0,0 +1,66 @@ +{% extends 'base.html' %} + +{% block head %} + + +{% end %} + +{% block title %} +{{ post.title }} | {{ config.site_title }} +{% end %} + +{% block content %} +
+ +
+ {% for tag in post.tags %} + {{ tag }} + {% end %} +
+
+ + +
+ {% if post.comment_open %} + {% if config.comment_system == 'disqus' and config.disqus_shortname %} +
+ + {% end %} + {% if config.comment_system == 'duoshuo' and config.duoshuo_shortname %} +
+ + {% end %} + {% end %} +
+{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/base.html b/catsup/themes/effector/template/base.html new file mode 100644 index 0000000..fff407a --- /dev/null +++ b/catsup/themes/effector/template/base.html @@ -0,0 +1,47 @@ + + + + + {% block head %}{% end %} + {% block title %}{{ config.site_title }}{% end %} + + + + + {% if config.google_analytics %} + + {% end %} + + +
+

{{ config.site_title }}

+ + +
+ + \ No newline at end of file diff --git a/catsup/themes/effector/template/index.html b/catsup/themes/effector/template/index.html new file mode 100644 index 0000000..fb662ba --- /dev/null +++ b/catsup/themes/effector/template/index.html @@ -0,0 +1,34 @@ +{% extends 'base.html' %} + +{% block content %} +{% for post in posts[(p-1)*config.post_per_page:p*config.post_per_page] %} +
+

{{ post.title }} {{ post.date }}

+ {% if config.excerpt_index and post.has_excerpt %} + {{ post.excerpt }} + {% else %} + {{ post.content }} + {% end %} + {% for tag in post.tags %} + {{ tag }} + {% end %} +
+{% end %} + +
+
    + {% if p > 1 %} + + {% end %} + + {% if len(posts) > p * config.post_per_page %} + + {% end %} +
+
+ +{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/links.html b/catsup/themes/effector/template/links.html new file mode 100644 index 0000000..1346e39 --- /dev/null +++ b/catsup/themes/effector/template/links.html @@ -0,0 +1,21 @@ +{% extends 'base.html' %} + +{% block title %} +Links | {{ config.site_title }} +{% end %} + +{% block content %} +
+
    + {% if config.twitter %} +
  • Twitter
  • + {% end %} + {% if config.github %} +
  • GitHub
  • + {% end %} + {% for link in config.links %} +
  • {{ link[0] }}
  • + {% end %} +
+
+{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/tag.html b/catsup/themes/effector/template/tag.html new file mode 100644 index 0000000..44e47b1 --- /dev/null +++ b/catsup/themes/effector/template/tag.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} + +{% block title %} +{{ tag[0] }} | {{ config.site_title }} +{% end %} + +{% block content %} +
+

{{ tag[0] }}

+ +
+{% end %} \ No newline at end of file diff --git a/catsup/themes/effector/template/tags.html b/catsup/themes/effector/template/tags.html new file mode 100644 index 0000000..1023440 --- /dev/null +++ b/catsup/themes/effector/template/tags.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block title %} +Tags | {{ config.site_title }} +{% end %} + +{% block content %} +
+ +
+{% end %} \ No newline at end of file diff --git a/catsup/themes/sealscript/static/css/pygments_style.css b/catsup/themes/sealscript/static/css/pygments_style.css new file mode 100644 index 0000000..90a9dd8 --- /dev/null +++ b/catsup/themes/sealscript/static/css/pygments_style.css @@ -0,0 +1,69 @@ +.highlight .hll { background-color: #404040 } +.highlight .c { color: #999999; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .g { color: #d0d0d0 } /* Generic */ +.highlight .k { color: #6ab825; font-weight: bold } /* Keyword */ +.highlight .l { color: #d0d0d0 } /* Literal */ +.highlight .n { color: #d0d0d0 } /* Name */ +.highlight .o { color: #d0d0d0 } /* Operator */ +.highlight .x { color: #d0d0d0 } /* Other */ +.highlight .p { color: #d0d0d0 } /* Punctuation */ +.highlight .cm { color: #999999; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999999; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */ +.highlight .gd { color: #d22323 } /* Generic.Deleted */ +.highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #d22323 } /* Generic.Error */ +.highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #589819 } /* Generic.Inserted */ +.highlight .go { color: #cccccc } /* Generic.Output */ +.highlight .gp { color: #aaaaaa } /* Generic.Prompt */ +.highlight .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */ +.highlight .gt { color: #d22323 } /* Generic.Traceback */ +.highlight .kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #6ab825 } /* Keyword.Pseudo */ +.highlight .kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #6ab825; font-weight: bold } /* Keyword.Type */ +.highlight .ld { color: #d0d0d0 } /* Literal.Date */ +.highlight .m { color: #3677a9 } /* Literal.Number */ +.highlight .s { color: #ed9d13 } /* Literal.String */ +.highlight .na { color: #bbbbbb } /* Name.Attribute */ +.highlight .nb { color: #24909d } /* Name.Builtin */ +.highlight .nc { color: #447fcf; text-decoration: underline } /* Name.Class */ +.highlight .no { color: #40ffff } /* Name.Constant */ +.highlight .nd { color: #ffa500 } /* Name.Decorator */ +.highlight .ni { color: #d0d0d0 } /* Name.Entity */ +.highlight .ne { color: #bbbbbb } /* Name.Exception */ +.highlight .nf { color: #447fcf } /* Name.Function */ +.highlight .nl { color: #d0d0d0 } /* Name.Label */ +.highlight .nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */ +.highlight .nx { color: #d0d0d0 } /* Name.Other */ +.highlight .py { color: #d0d0d0 } /* Name.Property */ +.highlight .nt { color: #6ab825; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #40ffff } /* Name.Variable */ +.highlight .ow { color: #6ab825; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #666666 } /* Text.Whitespace */ +.highlight .mf { color: #3677a9 } /* Literal.Number.Float */ +.highlight .mh { color: #3677a9 } /* Literal.Number.Hex */ +.highlight .mi { color: #3677a9 } /* Literal.Number.Integer */ +.highlight .mo { color: #3677a9 } /* Literal.Number.Oct */ +.highlight .sb { color: #ed9d13 } /* Literal.String.Backtick */ +.highlight .sc { color: #ed9d13 } /* Literal.String.Char */ +.highlight .sd { color: #ed9d13 } /* Literal.String.Doc */ +.highlight .s2 { color: #ed9d13 } /* Literal.String.Double */ +.highlight .se { color: #ed9d13 } /* Literal.String.Escape */ +.highlight .sh { color: #ed9d13 } /* Literal.String.Heredoc */ +.highlight .si { color: #ed9d13 } /* Literal.String.Interpol */ +.highlight .sx { color: #ffa500 } /* Literal.String.Other */ +.highlight .sr { color: #ed9d13 } /* Literal.String.Regex */ +.highlight .s1 { color: #ed9d13 } /* Literal.String.Single */ +.highlight .ss { color: #ed9d13 } /* Literal.String.Symbol */ +.highlight .bp { color: #24909d } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #40ffff } /* Name.Variable.Class */ +.highlight .vg { color: #40ffff } /* Name.Variable.Global */ +.highlight .vi { color: #40ffff } /* Name.Variable.Instance */ +.highlight .il { color: #3677a9 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/catsup/themes/sealscript/static/css/style.css b/catsup/themes/sealscript/static/css/style.css new file mode 100755 index 0000000..a3d012f --- /dev/null +++ b/catsup/themes/sealscript/static/css/style.css @@ -0,0 +1,482 @@ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + background: transparent; + border: 0; + margin: 0; + padding: 0; + vertical-align: baseline; +} + +body { + line-height: 1; + background: #fff; + background: transparent url(../image/body_bg.png) repeat fixed; + overflow: auto; + font: 14px 'Helvetica Neue',Helvetica,"Hiragino Sans GB","Hiragino Sans GB W3",Arial,sans-serif; + color: #494949; +} + +/* Common */ +h1, h2, h3, h4, h5, h6 { + margin: 0.5em 0; + font-weight: normal; + -webkit-font-smoothing: antialiased; +} +a { + color: #A0410D; + text-decoration: none; +} +a:active, a:hover { + color: #ff4b33; +} +.button { + border-radius: 2px; + border: 1px #ddd solid; + min-width: 80px; + height: 32px; + padding: 0px 12px; + display: inline-block; + text-align: center; + font-weight: bold; + color: #666; + text-shadow: 0 1px 1px white; + line-height: 32px; + cursor: pointer; + background: -webkit-gradient(linear, left top, left bottom, color-stop(2%, #FCFCFC), color-stop(4%,#F2F2F2), color-stop(100%,#EEE)); +} +.button:hover { + background: -webkit-gradient(linear, left top, left bottom, color-stop(2%, #FCFCFC), color-stop(4%,#F8F8F8), color-stop(100%,#F2f2f2)); +} +.button:active { + -webkit-box-shadow: inset #ccc 0 0 5px; + -moz-box-shadow: inset #ccc 0 0 5px; + box-shadow: inset #ccc 0 0 5px; +} +.title { + font-size: 30px; + line-height: 30px; + letter-spacing: -0.5px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + font-family: "Abel", "Helvetica Neue", Helvetica, Arial, Sans-serif; +} +.title:after, .big_sep { + display: block; + border-top: 1px solid #ececec; + border-bottom: 1px solid #ececec; + height: 1px; + width: 100%; + content: " "; + margin-top: 16px; +} +.sep { + background: transparent url(../image/background-stripes.png) repeat-x 0 0; + height: 5px; +} + +/* Header */ + +#nav { + height: 35px; + background: transparent url(../image/nav_bg.png) repeat-x 0 0; +} +#nav_wrapper { + height: 50px; + background: transparent url(../image/body_dark_bg.png) repeat-x; +} +#nav .inner { + width: 960px; + margin: 0 auto; +} +#nav .right { + float: right; + list-style: none; + font-size: 11px; + margin-top: 10px; +} +#nav .right li { + display: block; + float: left; + color: #ccc; +} +#nav .right a { + display: block; + color: #ccc; + padding: 0 10px; +} +#nav .right a:hover { + color: white; +} +#nav .right li:last-child{ + visibility:hidden; +} +#social { + right: 0; + top: 0; + margin-top: -15px; + height: 16px; + padding: 5px 10px 5px 5px; + position: absolute; + background: transparent url(../image/body_dark_bg.png) repeat-x; + border-radius: 3px; +} +#social a { + margin-left: 5px; +} +#header_inner { + width: 880px; + margin: 0 auto; + position: relative; + padding: 0; + text-align: center; +} +#title { + color: #ddd; + text-shadow: 0 1px 1px black; + font-size: 22px; + font-family: "Abel", "Helvetica Neue", Helvetica, Arial, Sans-serif; + float: left; + height: 32px; + line-height: 32px; + margin: 0; +} +#title a { + color: #ddd; +} +#title a:hover { + color: #fff; +} +#description { + padding: 3px 6px; + display: block; + float: left; + height: 32px; + line-height: 32px; + font-size: 11px; + font-family: "Abel", "Helvetica Neue", Helvetica, Arial, Sans-serif; + color: #ddd; + margin-left: 5px; +} +#content { + width: 960px; + margin: 40px auto 0 auto; +} +#article_list { + list-style-type: none; +} +#article_list .list_item:last-child .sep{ + display: none; +} +.article { + font-size: 16px; + padding: 15px; + background: #F2F2F2; + margin: 40px auto; + width: 660px; + border: 1px white solid; + -webkit-box-shadow: 0 1px 10px #A8B1B9; + -moz-box-shadow: 0 1px 10px #A8B1B9; + box-shadow: 0 1px 10px #58B1B9; + text-shadow: 0 1px 1px white; +} + +.article_title { + margin: 0; + text-align: center; +} +.article .title a { + color: #444; + -moz-transition: color 0.2s ease-in; + -webkit-transition: color 0.2s ease-in; +} +.article .title a:hover { + color: #A0410D; + text-shadow: 0 0 1px rgba(200, 200, 200, 0.8); +} +.article_meta { + height: 20px; + line-height: 20px; + padding: 10px 0; + font-size: 10px; + color: #777; + text-transform: uppercase; + margin-bottom: 15px; +} +.article_meta > span { + font-family: Georgia, serif; + font-style: italic; + text-transform: lowercase; + color: #AAA; +} +.article .inner, .tag_box .inner { + background-color: #F8F8F8; + border: 1px #F2F3F3 solid; + padding: 20px; +} +.article .tag:hover { + color: #ff4b33 +} +.article .text { + margin: 20px 0px; + line-height: 1.5em; +} +.article strong { + background: #FEF6A8; + color: #533B18; + border: 1px #fcfc91 solid; + padding: 1px 3px; + font-weight: normal; +} +.article p { + margin: 0 0 24px 0; + line-height: 1.5em; +} +.article .text h1, .article .text h2, .article .text h3, .article .text h4, .article .text h5, .article .text h6 { + font-weight: bold; + margin: 0.75em 0; +} +.article .text h1 { + font-size: 1.8em; +} +.article .text h2 { + font-size: 1.6em; +} +.article .text h3 { + font-size: 1.4em; +} +.article .text h4 { + font-size: 1.2em; +} +.article .text h5 { + font-size: 1.0em; +} +.article .text h6 { + font-size: 1.0em; +} +.article .text blockquote { + margin: 10px 0; + padding: 5px 0 5px 40px; + border-left: 5px #7d7d7d solid; +} +.article .text ul, .article .text ol { + margin: 10px 0 10px 20px; +} +.article .text li { + margin-bottom: 5px; +} +.article .text img { + text-align: center; + display: block; + margin: 0 auto; + border: 5px white solid; + -webkit-box-shadow: 0 1px 3px #333; + -moz-box-shadow: 0 1px 3px #333; + box-shadow: 0 1px 3px #333; + max-width: 570px; +} +.article pre { + margin: 10px -37px; + background: #222; + color: white; + font: 12px Monaco,monospace; + overflow-x: auto; + padding: 20px 37px; + white-space: pre; + word-wrap: normal; + text-shadow: 0 -1px 1px #000; + box-shadow: inset 0 0 10px #000; +} +.article code { + color: #000; + background: #f8f8ff; + padding: 0.5em; + font-size: 14px; + font-family: 'Monaco', 'monospace'; + text-shadow: none; +} +.article pre code{ + padding: 0; + background: #222; + color: white; +} +.article .share { + float: right; +} + +.article .gist-syntax { + font-size: 80% !important; +} + +.article .gist-syntax pre { + text-shadow: none; + box-shadow: none; +} + +/* Nav */ + +.v_nav { + position: fixed; + display: block; + background: transparent url(../image/body_dark_bg.png); + outline: none; + color: #6D6E71; + font-size: 20px; + font-weight: bold; + display: block; + height: 64px; + width: 64px; + text-indent: -9999px; +} +.v_nav .icon { + background: transparent url(../image/go_bg.png) no-repeat 0 0; + height: 64px; + width: 64px; + display: block; + content: " "; + float: left; +} +.v_nav:hover { + color: #A0410D +} +@-webkit-keyframes ani_go_loading { + from { + -webkit-transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + } +} +#prev { + top: 50%; + left: 0; + padding: 10px 10px 10px 20px; + margin-top: -100px; + border-bottom-right-radius: 42px; + border-top-right-radius: 42px; +} +#prev .icon{ + background-position: 0 0; +} +#prev:hover .icon{ + background-position: 0 -64px; +} +#next { + top: 50%; + right: 0; + padding: 10px 20px 10px 10px; + margin-top: -100px; + border-bottom-left-radius: 42px; + border-top-left-radius: 42px; +} +#next .icon{ + background-position: 0 -128px; +} +#next:hover .icon{ + background-position: 0 -192px; +} +#next .loading, #prev .loading { + background-position: 0 -256px !important; + -webkit-animation-name: ani_go_loading; + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; +} +/* Footer */ +#footer_wrapper { + padding-top: 15px; + background: transparent url(../image/body_dark_bg.png) repeat-x; +} + +#footer { + background: #333 url(../image/mask.png) 0 0 repeat; + padding: 30px 0 0 0; + -webkit-box-shadow: inset 0 -1px 3px #111; + -moz-box-shadow: inset 0 -1px 3px #111; + box-shadow: inset 0 -1px 3px #111; + text-shadow: 0 1px 1px #111; + color: #ddd; +} + +#footer_inner { + margin: 0 auto; + width: 960px; +} + +#footer .copyright { + clear: both; + padding: 80px 0 20px 0; + text-align: center; + text-transform: uppercase; + font-size: 11px; +} + +#footer .copyright span { + margin: 0 5px; +} + +#footer a { + color: #A0927F; +} + +#footer a:hover { + color: #ddd; +} + +#footer_inner ul { + list-style:none; +} +#footer_inner li { + display: block; + float: left; + width: 130px; + height: 20px; + margin: 0 20px 10px 0; +} +#footer_inner li:after { + display: block; + content: " "; + border-top: 1px #2d2d2d solid; + border-bottom: 1px #4e4e4e solid; +} +#footer_inner li a { + height: 20px; + line-height: 20px; + display: block; + width: 120px; + font-size: 11px; + padding-left: 10px; +} + +#footer_inner > .col { + width: 300px; + float: left; + margin: 0 0 0 20px; +} + +#footer_inner h2 { + font-size: 14px; + font-weight: bold; + font-family: "Abel", "Helvetica Neue", Helvetica, Arial, Sans-serif; + padding-left: 10px; +} + +#footer .tag_cloud { + line-height: 2em; +} + +#footer .tag { + padding: 2px 3px; + margin: 2px 3px; + font-size: 11px; +} +::selection { + background: #ccc; + color: #333; +} + diff --git a/catsup/themes/sealscript/static/favicon.ico b/catsup/themes/sealscript/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..2a350955115559bbe5b825292731a6fa49fb1edf GIT binary patch literal 1406 zcmZQzU<5(|0R|w+!H~hqz#zuJz@P!dKp_SNAO?x!0-ADi4Ca~|3>I3N3^qF240d|D z4DO~T48E2Y459XR42d3Y3~4^z40%C;3!|T^EoY=CN;lhFa43`fdVz_qVIK%Dp=NKMdzsB(9=~ITc&z~{8d-0s% z-OHB@KfZot`1SKAF0YJ=kA}c#2v8aVN-9V|k%2**pBD~<)PZ~!VRb%7 literal 0 HcmV?d00001 diff --git a/catsup/themes/sealscript/static/image/body_bg.png b/catsup/themes/sealscript/static/image/body_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..444f7c24f331f12b71195bcb546ff534c4cf17f3 GIT binary patch literal 2198 zcmV;H2x<3;P)E-3+=H}+;=;-I?=i=hx;o;%x>gwz3>ktksivR!!FiAu~RA}D4TFatc$BGk3 z0#yJ1!97U2J9eDh`13D>mg?V&r<#T0QTE$}6fYvWE3~yLg7S$XTW!?UH;($Z9wk z&zdH)nvSh$Ek;p@MpZMIzNC6Wm)oR#PG*@~VR&C&?&t9P4qL;Pi%lsW%`r*QB$!N;6wG&VQgQOI<#3$K2mD>^@3Wy@-1R`6y3^R?0{+S?3nvZb*{l7Q^G@@ zU$r>hkAUj#u|{~b`TUrD2B+i}3xRSH^`1rU%=o-UQ718-4k@)7=f&$ub*5G}$;Gjs z%IRL!^?TNIr$H~>O!u*d>_k8{S)`jIYNoT*DjH&)H&aP&#~x2 z#Bwp-r;dcEI4#2$Zp0?wBWnA_P0o^h-Atvk!)0POhXZ5^7<)@oYAt(?kE`Zmeyhn} zofpuYqV3W4Of5%cXC1I3$~f3b^@6S=)z(lARE<`LBimM_iYa-5Ae3YU`Yc)f2Rsta6AXNd;?w4(4CZ2$I` za3o%{s&;DZN|PFJwp(mtkMV7~JOK56x>xXj6XRxz;uJ{kWJ&5Un{I91IFG-btwsI> z1Htib3hQOOU6PQUYu2(K!rJY7Ta81L=^370mYpsOuxd%MZ?>|iY;Vx^&0H;hh|T0N z#R#k}4lANFy|1D|h9^`#biHkuwSimOxfk+rb}4qAtMTVgGmUW|b3>-Qoh6u>69a~j z&Qu-y4K+`dZ!?okp)gA!#p$bl zWK`iw&vO@Jo*9$HS;JwY!Lboq)u=5$;%$huijU})Jfi(@wa$n=J&;w%Z8wKvP^ zeYFu;yN8YMesxFsq%fjn`qit< zd(94s*@4LIA2CvZqOu?ID_#8Z zQ%nlKN)rBwV8xddeaEmpw zLG@0RN(K57)O0vkcw82>xAg3I9pN*w$7OP>Im05{TWHT6O+M;Y>gS}Iqje}sZ}ae) zg$1_JjIXN~V&4edfYi-Aqp>SduvXwN&T_S5f-i39&9UREnp(T7o0lTKQnuMH55e)P z?xD9P@9-fc`KGDywd?7}q#8d|_Z-O6=l9ObR##`GXY#=F!_>X)!4li?MhrRQ_R8FT z3LgpZ;XgNE-e!u`T^f~$rmwKPbYsQLW8JeR%q5(AWNk#7xPM2Vd{konj-If%=iTbh z86fyemi(%!yqAXOj9^~gY!&Zqk>`hQR#>BS6`K_uX|B1~EwB&7Pb>emhQon)Sccn6 z9SHUNF^l^(7vLWXZhRiOnqV_MT=R3h1s_}Ne{iDlE12|82MeFwRs{-&GQby^LzPe> zDxzq<X^plUALbm(^`fz(^Y8z#c=1TM=g39AK-F-ng@K(k#=STn4DU$ z$j%mjNx)*xL(!+^8y-6{;ji>2@v95TGsE?6b>T_as?^G9%&fu!J|8x1@JTrNUnoIi zchkUZ$QQLrc(YxM#GWP>TR^FYoYLsERdkHaJRwSFGH450qTZO2atCQgz~!sWtH-LQJ;jcJ;i z9IxVOza-DzEWac`{!iVA53!(c1{n7*z%V}Ua#kB3Qq|u!N$QQo-QL$7Q&2ER%-b3H z1q?N)R!8&}r|Sl7-8B(b%HW8orvH>+;S+hu_ue?ZD(3q;2*O9-lKlR1=8K{5$L~e( z$*^HLT)_B9%<#Qg{;zl||H6tl66EdBd#DUY$TnDNs_j=Whu$t@i13+AJ-s*o@cGXF Y0QCm1#XS;Xz5oCK07*qoM6N<$f-J3Pwg3PC literal 0 HcmV?d00001 diff --git a/catsup/themes/sealscript/static/image/body_dark_bg.png b/catsup/themes/sealscript/static/image/body_dark_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..1dba9616b2164a47c5d5def08bbb36aba52fd854 GIT binary patch literal 2092 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 literal 0 HcmV?d00001 diff --git a/catsup/themes/sealscript/static/image/ic16_github.png b/catsup/themes/sealscript/static/image/ic16_github.png new file mode 100644 index 0000000000000000000000000000000000000000..495bd1c7f43a6965b61b47561d258ec2a07ed7b3 GIT binary patch literal 329 zcmV-P0k-~$P)As=7{+l|LFm*ekVze@!*GY_uL!b%h_ogd7j5IK2G!L2 z^Gx<6(X~J#6~$f%g(PGvN&EsmDqBG86{uTaAq%weL8fkj2`A%gKr)KX#jyN+8iTC! zU*myS^d+Ti#jvTf{%d5gY0cAzTr7hl6Ok#~u5!uUpK@glmAtW5a9+)WGjRR^GMD-J byZ_D?7SuSJi9dKX00000NkvXXu0mjfsXdQe literal 0 HcmV?d00001 diff --git a/catsup/themes/sealscript/static/image/ic16_rss.png b/catsup/themes/sealscript/static/image/ic16_rss.png new file mode 100644 index 0000000000000000000000000000000000000000..da666de82a64ea9edaaf7bacf775290341a746ad GIT binary patch literal 373 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 Z{{c$z=D^VH_=f-h002ovPDHLkV1jP6Y8U_j literal 0 HcmV?d00001 diff --git a/catsup/themes/sealscript/static/robots.txt b/catsup/themes/sealscript/static/robots.txt new file mode 100644 index 0000000..e69de29 diff --git a/catsup/themes/sealscript/template/404.html b/catsup/themes/sealscript/template/404.html new file mode 100644 index 0000000..7008c2c --- /dev/null +++ b/catsup/themes/sealscript/template/404.html @@ -0,0 +1,33 @@ + + + + + 404 NOT FOUND + + + + +
+
+
+

Hey!

+

Sorry, the page you were looking does not exist.

+

+

+ Bring me back to earth! +

+
+
+
+ + + + diff --git a/catsup/themes/sealscript/template/archive.html b/catsup/themes/sealscript/template/archive.html new file mode 100644 index 0000000..4895e63 --- /dev/null +++ b/catsup/themes/sealscript/template/archive.html @@ -0,0 +1,35 @@ +{% extends 'base.html' %} + +{% block title %} +{{ archive[0] }} | {{ config.site_title }} +{% end %} + +{% block content %} +
+
+

Articles posted in "{{ archive[0] }}"

+
+
    + {% for post in archive[1] %} +
  • + {{ post.date }} + {{ post.title }} +
  • + {% end %} +
+
+
+
+{% if prev %} + +{% end %} + +{% if next %} + +{% end %} + +{% end %} \ No newline at end of file diff --git a/catsup/themes/sealscript/template/archives.html b/catsup/themes/sealscript/template/archives.html new file mode 100644 index 0000000..e69de29 diff --git a/catsup/themes/sealscript/template/article.html b/catsup/themes/sealscript/template/article.html new file mode 100644 index 0000000..6b5b420 --- /dev/null +++ b/catsup/themes/sealscript/template/article.html @@ -0,0 +1,78 @@ +{% extends 'base.html' %} + +{% block head %} + + +{% end %} + +{% block title %} +{{ post.title }} | {{ config.site_title }} +{% end %} + +{% block content %} +
+
+

{{ post.title }}

+ + +
+ {{ post.content }} +
+ {% if post.tags %} +
+ + {% end %} +
+ + {% if post.comment_open %} + {% if config.comment_system == 'disqus' and config.disqus_shortname %} +
+ + {% end %} + {% if config.comment_system == 'duoshuo' and config.duoshuo_shortname %} +
+ + {% end %} + {% end %} +
+
+{% if prev %} + +{% end %} + +{% if next %} + +{% end %} +{% end %} \ No newline at end of file diff --git a/catsup/themes/sealscript/template/base.html b/catsup/themes/sealscript/template/base.html new file mode 100644 index 0000000..bbe6dc6 --- /dev/null +++ b/catsup/themes/sealscript/template/base.html @@ -0,0 +1,97 @@ + + + + + {% block head %}{% end %} + {% block title %}{{ config.site_title }}{% end %} + + + + + {% if config.google_analytics %} + + {% end %} + + + +
+ {% block content %} + {% end %} +
+ + + + + + diff --git a/catsup/themes/sealscript/template/index.html b/catsup/themes/sealscript/template/index.html new file mode 100644 index 0000000..4ddbc1e --- /dev/null +++ b/catsup/themes/sealscript/template/index.html @@ -0,0 +1,53 @@ +{% extends 'base.html' %} + +{% block content %} +
    + {% for post in posts[(p-1)*config.post_per_page:p*config.post_per_page] %} +
  • +
    +
    +

    {{ post.title }}

    + + +
    + {% if config.excerpt_index and post.has_excerpt %} + {{ post.excerpt }} + {% else %} + {{ post.content }} + {% end %} +
    + +
    +
    +
    +
  • + {% end %} +
+ +{% if p > 1 %} + +{% end %} + +{% if len(posts) > p * config.post_per_page %} + +{% end %} + +{% end %} \ No newline at end of file diff --git a/catsup/themes/sealscript/template/links.html b/catsup/themes/sealscript/template/links.html new file mode 100644 index 0000000..e69de29 diff --git a/catsup/themes/sealscript/template/tag.html b/catsup/themes/sealscript/template/tag.html new file mode 100644 index 0000000..fb67514 --- /dev/null +++ b/catsup/themes/sealscript/template/tag.html @@ -0,0 +1,38 @@ +{% extends 'base.html' %} + +{% block head %} + +{% end %} + +{% block title %} +{{ tag[0] }} | {{ config.site_title }} +{% end %} + +{% block content %} +
+
+

Articles Tagged as "{{ tag[0] }}"

+
+
    + {% for post in tag[1] %} +
  • + {{ post.date }} + {{ post.title }} +
  • + {% end %} +
+
+
+
+{% if prev %} + +{% end %} + +{% if next %} + +{% end %} +{% end %} \ No newline at end of file diff --git a/catsup/themes/sealscript/template/tags.html b/catsup/themes/sealscript/template/tags.html new file mode 100644 index 0000000..e69de29 diff --git a/catsup/utils.py b/catsup/utils.py new file mode 100644 index 0000000..db5eb60 --- /dev/null +++ b/catsup/utils.py @@ -0,0 +1,249 @@ +from __future__ import with_statement + +import os +import time +import re +import misaka as m + +import logging +from tornado.escape import xhtml_escape +from tornado.util import ObjectDict +from tornado.options import options, define + +from pygments import highlight +from pygments.formatters import HtmlFormatter +from pygments.lexers import get_lexer_by_name + +def parse_config_file(path): + if not path: + return + config = {} + exec(compile(open(path).read(), path, 'exec'), config, config) + for name in config: + if name in options: + options[name].set(config[name]) + else: + define(name, config[name]) + +class Post(ObjectDict): + """Post object""" + def has_format(self, format): + if not hasattr(self, 'format'): + return False + if self['format'] == format.lower(): + return True + + @property + def is_regular(self): + return self.has_format('regular') + + @property + def is_aside(self): + return self.has_format('aside') + + @property + def is_gallery(self): + return self.has_format('gallery') + + @property + def is_link(self): + return self.has_format('link') + + @property + def is_status(self): + return self.has_format('status') + + @property + def is_image(self): + return self.has_format('image') + + @property + def is_video(self): + return self.has_format('video') + + @property + def is_audio(self): + return self.has_format('audio') + + @property + def is_chat(self): + return self.has_format('chat') + + @property + def is_quote(self): + return self.has_format('quote') + + +class CatsupRender(m.HtmlRenderer, m.SmartyPants): + def block_code(self, text, lang): + if not lang: + text = xhtml_escape(text.strip()) + return '\n
%s
\n' % text + lexer = get_lexer_by_name(lang, stripall=True) + formatter = HtmlFormatter() + return highlight(text, lexer, formatter) + + def autolink(self, link, is_email): + if is_email: + return '%(link)s' % {'link': link} + + if '.' in link: + name_extension = link.split('.')[-1].lower() + if name_extension in ('jpg', 'png', 'git', 'jpeg'): + return '' % link + + return '%s' % (link, link) + +# Allow use raw html in .md files +md = m.Markdown(CatsupRender(flags=m.HTML_USE_XHTML), + extensions=m.EXT_FENCED_CODE | m.EXT_NO_INTRA_EMPHASIS | m.EXT_AUTOLINK | + m.EXT_STRIKETHROUGH | m.EXT_SUPERSCRIPT) + + +def load_post(file_name): + '''Load a post.return a dict. + ''' + def _highlightcode(m): + '''Function for replace liquid style code highlight to github style + ''' + return "```%s\n%s\n```" % (m.group(1), m.group(2)) + + pattern = re.compile('\{%\s?highlight ([\w\-\+]+)\s?%\}\n*(.+?)\n*\{%\s?endhighlight\s?%\}', re.I | re.S) + + path = os.path.join(options.posts_path, file_name) + logging.info('Loading file %s' % path) + post_permalink = file_name[:-3].lower() + if not options.date_in_permalink: + post_permalink = file_name[11:-3] + post = Post( + file_name = post_permalink, + tags = [], + date = file_name[:10], + comment_open = True, + has_excerpt = False, + excerpt = '', + format = 'regular', + category = '', + permalink = '%s/%s.html' % (options.site_url, post_permalink) + ) + try: + with open(path, 'r') as f: + # test if the post includes a string --- + fcontent = f.read() + if fcontent.find("\n---") == -1: + logging.warning('The format of post %s is illegal, ignore it.' % path) + return None + else: + # fallback to the file's beginning + f.seek(0, os.SEEK_SET) + del fcontent + while True: + line = f.readline() + line_lower = line.lower() + # Post title + if line.startswith('#'): + post.title = xhtml_escape(line[1:].strip()) + # Yet another post title property for compatibility of jekyll + elif 'title' in line_lower: + post.title = xhtml_escape(line.split(':')[-1].strip()) + # Post format + elif 'format' in line_lower: + post_format = line_lower.split(':')[-1].strip() + if post_format not in ('regular', 'aside', 'gallery', 'link', 'image', 'quote', 'status', 'video', 'audio', 'chat'): + post_format = 'regular' + post.format = post_format + # Post category(unused) + elif 'category' in line_lower: + post.category = xhtml_escape(line.split(':')[-1].strip()) + # Post tags + elif 'tags' in line_lower: + for tag in line.split(':')[-1].strip().split(','): + post.tags.append(xhtml_escape(tag.strip().lower())) + # Post date specificed + elif 'date' in line_lower: + post.date = xhtml_escape(line.split(':')[-1].strip()) + # Allow comment of not + elif 'comment' in line_lower: + status = line_lower.split(':')[-1].strip() + if status in ['no', 'false', '0', 'close']: + post.comment_open = False + # Here many cause an infinite loop if the post has no --- in it + elif line.startswith('---'): + content = '\n'.join(f.readlines()) + if isinstance(content, str): + content = content.decode('utf-8') + # Provide compatibility for liquid style code highlight + content = pattern.sub(_highlightcode, content) + # Post excerpt support, use as flag + if content.lower().find(u''): + post.excerpt = md.render(content.split(u'')[0]) + post.has_excerpt = True + content = content.replace(u'', '') + post.content = md.render(content) + post.updated = os.stat(path).st_ctime + updated_xml = time.gmtime(post['updated']) + post.updated_xml = time.strftime('%Y-%m-%dT%H:%M:%SZ', + updated_xml) + break; # exit the infinite loop + except IOError: + logging.error('Open file %s failed.' % path) + return post + +def load_posts(): + '''load all the posts.return a list. + Sort with filename. + ''' + def _cmp_post(p1, p2): + """ + Post sort compare function + """ + if p1[:10] == p2[:10]: + # Posts in the same day + p1_updated = os.stat(os.path.join(options.posts_path, p1)).st_ctime + p2_updated = os.stat(os.path.join(options.posts_path, p2)).st_ctime + if p1_updated > p2_updated: + return 1 + elif p1_updated < p2_updated: + return -1 + else: + return 0 + else: + if p1 > p2: + return 1 + elif p1 < p2: + return -1 + else: + return 0 + + # Post file name must match style 2012-12-24-title.md + pattern = re.compile('^\d{4}\-\d{2}\-\d{2}\-.+\.md$', re.I) + post_files = os.listdir(options.posts_path) + post_files.sort(reverse=True, cmp=_cmp_post) + posts = [] + for file_name in post_files: + if pattern.match(file_name): + post = load_post(file_name) + if post: + posts.append(post) + return posts + + +def get_infos(posts): + """return the tag list and archive list. + """ + tags = {} + archives = {} + for post in posts: + for tag in post['tags']: + if tag in tags: + tags[tag].append(post) + else: + tags[tag] = [post] + year = post['date'][:4] + if year in archives: + archives[year].append(post) + else: + archives[year] = [post] + + return sorted(tags.items(), key=lambda x: len(x[1]), reverse=True),\ + sorted(archives.items(), key=lambda x: x[0], reverse=True) diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 0000000..8eddf03 --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,20 @@ +server { + listen 80; + server_name yourdomain.com; + + gzip on; + gzip_static on; + gzip_min_length 500; + gzip_proxied any; + gzip_types text/plain application/xml application/x-javascript text/css text/xml application/atom+xml application/rss+xml; + + root /path/to/catsup/deploy/; + index index.html index.htm; + + access_log /path/to/catsup.access.log; + error_log /path/to/catsup.error.log; + + location = /feed { + rewrite (.*) /feed.xml; + } +} \ No newline at end of file diff --git a/conf/supervisord.conf b/conf/supervisord.conf new file mode 100644 index 0000000..3fb68e2 --- /dev/null +++ b/conf/supervisord.conf @@ -0,0 +1,28 @@ +[unix_http_server] +file=/tmp/supervisor.sock ; path to your socket file + +[supervisord] +logfile=/tmp/supervisord.log ; supervisord log file +logfile_maxbytes=50MB ; maximum size of logfile before rotation +logfile_backups=10 ; number of backed up logfiles +loglevel=warn ; info, debug, warn, trace +pidfile=/tmp/supervisord.pid ; pidfile location +nodaemon=false ; run supervisord as a daemon +minfds=1024 ; number of startup file descriptors +minprocs=200 +user=root +childlogdir=/path/to/logs + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket + +[program:catsup_webhook] +command=python -m catsup.app webhook --port=5555 +user=your_username +process_name=catsup_webhook +numproc=1 +autostart=true +autorestart=true diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..6a19752 --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from setuptools import setup, find_packages + +setup( + name='catsup', + version='0.0.4', + author='whtsky, messense', + author_email='whtsky@me.com, wapdevelop@gmail.com', + url='https://github.com/whtsky/catsup', + packages=find_packages(), + description='Catsup: a lightweight static blog generator', + install_requires=[ + 'tornado', + 'misaka', + 'pygments', + ], + include_package_data=True, + license='MIT License', +) \ No newline at end of file