Git Product home page Git Product logo

blog_content's Introduction

基于org和Flask的纯文本博客系统

简介

将org文件转化为博客是我期待以久的事情,之前看过使用Hexo此类的博客系统,但是一直不想搭,最近学完了整套Flask,觉得用Flask框架配合org导出(org-export)的html文件搭一个静态博客应当是一件非常容易的事情,于是这个博客系统的方案诞生了。

博客地址为:http://lantianzero.club

博客系统方案

这个方案是因Emacs的org-mode而生的,org-mode和Emacs的配置是必须的;另外,它还依赖于nginx和Python及其安装包[包括Flask、uwsgi及supervisor等]

  • 博客的文本内容由Emacs内置的org-mode生成,文本内容在org文件中编写并整理,配置org-export选项后经org-publish的方式发布,形成html文档;
  • 博客应用服务的基础http服务由uwsgi和nginx支撑,内部逻辑基于Flask框架编写,主要使用其中的Jinja2模板和Flask提供的hook
  • 前端使用uikit作为框架基础,由于我并不怎么了解css,所以这部分不在博客中介绍
  • 应用扫描指定博客目录的html文件,提取为博客索引,根据索引访问某篇博客时,通过正则表达式解析html内容,填充入Jinja2模板中,经前端渲染后反馈用户

选择的理由

  • 优点:
    1. 依赖极少配置简单:org博客方案有许多成熟的例子,虽然我没有逐一使用,但就我了解,这些东西都有相当的依赖,要么需要进行一些繁杂的配置;
    2. 没有重复造轮子:org文体的转化由org-mode自带的org-export完成,不需要第三方工具解析,也不需要进行多次转换,org-export支持的特性都能得到有效保证;
    3. 对页面拥有绝对的控制力,界面的效果完全取决于你的前端水平
  • 缺点:
    1. 非开箱及用,需要个人理解–50行python代码
    2. 界面效果完全取决于前端水平,如果追求界面精致美观,那么需要更多的前端知识,否则可能造成用户体验较差(比如我)
    3. 如果需求诸如评论类的交互功能,需要更多的Flask基础,不过对于静态博客而言,了解Jinja2和Flask提供的hook已经足够;

配置说明

org-mode配置

org-mode的配置主要是防止使用org-html-publish-to-html使加入内嵌的css和javascript,这样方便我们处理样式,尤其是导出的源码

;; 导出的源代码内容使用单独的css文件控制样式
(setq org-html-htmlize-output-type 'css)
;; 不生成默认的css及javascript内容
(setq org-html-head-include-default-style nil)
(setq org-html-head-include-scripts nil)

(setq org-publish-project-alist
      '(("pre_pub"                          ;; project的名称
         :base-directory "path/of/org/file" ;; org文件的目录
         :base-extension "org"              ;; 扩展名称
         :publishing-directory "path/to/publish" ;; 导出目录
         :publishing-function org-html-publish-to-html  ;; 导出函数
         ;; :auto-sitemap t                                ; 自动生成网站地图,暂不需要
         )))

python代码

  1. 使用before_request这个hook以更新索引列表 这个函数获取blog所在目录的所有文件,然后生成html文件来表并绑定至g对象
    @app.before_request
    def get_static_html_list():
        static_html_dir = os.path.join(os.getcwd(), 'static', config.BLOG_DIR)
        if os.path.isdir(static_html_dir):
            static_html_list = os.listdir(static_html_dir)
            try:
                # 删除.gitkeep
                static_html_list.remove(".gitkeep")
            except ValueError:
                logging.info(f"don't have .gitkeep")
            finally:
                g.HTML_LIST = static_html_list
        else:
            g.HTML_LIST = ""
        
  2. 解析org生成的html文件 因为org-mode生成的html极为规则,这些直接使用正则表达式抽取其中的title和body,以便于后面Jinja2填充;
    title_re = re.compile(r'<title>([\s\S]*)<\/title>')
    body_re = re.compile(r'<body>([\s\S]*)<\/body>')
    
    
    class OrgBlog():
        """解析传入的ox-html文件,匹配其title和body
        如果title不存在,则返回""
        如果body不存在,则返回ox-html文件的所有内容
        """
    
        def __init__(self, oxhtml):
            with open(oxhtml, 'r', encoding='utf-8') as fp:
                try:
                    html_context = fp.read()
                except IOError as ioerr:
                    raise f"Read orghtml Failed, Error: {ioerr}"
                else:
                    title_ma = title_re.search(html_context)
                    body_ma = body_re.search(html_context)
                finally:
                    self.org_title = title_ma.group(1) if title_ma else ""
                    self.org_content = body_ma.group(1) \
                        if body_ma else html_context
        
  3. 博客索引的过滤器 这里使用template_filter类自定义Jinja2过滤器,从g对象中获取文件,通过OrgBlog类获取其title
    @app.template_filter('html_title')
    def get_static_title(ox_html):
        """函数以启动文件为根目录,ox_html为其在static/static_html/下的相对位置"""
        file_path = os.path.join(os.getcwd(), "static", config.BLOG_DIR, ox_html)
        title = OrgBlog(file_path).org_title
        return title
        
  4. Jinja2模板内容
    1. 抽取title内容生成索引
      {%- for html in g.HTML_LIST %}
      <li><a href="{{ url_for('show_blog', blog_file=html) }}">{{html|html_title}}</a></li>
      {% endfor %}
              
    2. 抽取文件内容填充模板
      {% block title %}{{ title }}{% endblock %}
      {% block content %}{{ content|safe }}{% endblock %}
              
  5. 根据选择的索引返回文件由Jinja2渲染
    @app.route('/blog/<path:blog_file>')
    def show_blog(blog_file):
        """函数以启动文件为根目录,blog_file为其在static/static_html下的相对位置"""
        file_path = os.path.join(os.getcwd(), "static", config.BLOG_DIR, blog_file)
        org_blog = OrgBlog(file_path)
    
        title = org_blog.org_title
        content = org_blog.org_content
        return render_template("blog_detail.html", title=title, content=content)
        
  6. uwsgi及supervisor将在其它博客中说明,完成后于此处增加链接

文件同步命令

静态文件使用rsync进行同步

rsync -avz /path/to/static/html xxxx@ipv4/ipv6:path/to/static/

图片上传及源码

博客需要进一步完善对图片和二进制文件的支持

目前已有两种方案可以用于支持图片,一是将图片编码为base64,直接插入网页中;另外一种是将图片的链接进行转换和转移,博文上传到个人网站时同步将这些静态文件上传;

两种实现需要的elisp代码均已合在init-org中

Note

  1. 设置org-publish-use-timestamps-flag以忽略文件是否改动,将文件重新publish至新目录
    (setq org-publish-use-timestamps-flag nil)
        

blog_content's People

Contributors

gaeric avatar

Stargazers

 avatar

Watchers

 avatar  avatar

blog_content's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.