zoukankan      html  css  js  c++  java
  • 利用GitHook实现博客园文章的备份和自动发布

    在使用vscode中的writecnblog插件时有所启发,链接: 用vscode写博客和发布,大家可以看看。
    我们在本地可以利用git轻松实现博客园文章的历史记录管理,利用博客园的MetaWeblog API 别人的介绍编写小程序来自动化上传文章(参考插件)。
    更进一步,将这个程序放到githook里,每次commit时自动执行,就实现了现博客园文章的备份和自动发布。
    这样,你每次发布文章的步骤就简化为:

    1. 编写本地一个Git仓库内的xx.md文件
    2. commit更改
      程序会自动获取diff,然后editPost或newPost到博客园,同时git记录了更改历史。

    详细代码放github上了cnblogs_githook,这里发个python脚本文件。

    #! /usr/bin/env python
    # coding=utf-8
    
    # 使用python xmlrpc 发送内容到博客园
    # http://rpc.cnblogs.com/metaweblog/WeyneChen 从链接可以看到支持的metaweblog API
    import xmlrpc.client as xmlrpclib
    import glob
    import os
    import sys
    import json
    import time
    import datetime
    
    # 发布文章路径(article path)
    art_path = "./articles/"
    # 不发布文章路径(unpublished article path)
    unp_path = "./unpublished/"
    # 博客配置路径(config path)
    cfg_path = "blog_config.json"
    # 备份路径(backup path)
    bak_path = "./backup/"
    # 获取文章篇数
    recentnum = 99999
    
    # 创建路径
    for path in [art_path, unp_path, bak_path]:
        if not os.path.exists(path):
            os.makedirs(path)
    
    # -----配置读写操作-----
    '''
    配置字典:
    type | description(example)
    str  | metaWeblog url, 博客设置中有('https://rpc.cnblogs.com/metaweblog/1024th')
    str  | appkey, Blog地址名('1024th')
    str  | blogid, 这个无需手动输入,通过getUsersBlogs得到
    str  | usr, 登录用户名
    str  | passwd, 登录密码
    '''
    
    
    def exist_cfg():
        '''
        返回配置是否存在
        '''
        try:
            with open(cfg_path, "r", encoding="utf-8") as f:
                try:
                    cfg = json.load(f)
                    if cfg == {}:
                        return False
                    else:
                        return True
                except json.decoder.JSONDecodeError:  # 文件为空
                    return False
        except:
            with open(cfg_path, "w", encoding="utf-8") as f:
                json.dump({}, f)
                return False
    
    
    def create_cfg():
        '''
        创建配置
        '''
        while True:
            cfg = {}
            for item in [("url", "metaWeblog url, 博客设置中有\
                ('https://rpc.cnblogs.com/metaweblog/blogaddress')"),
                         ("appkey", "Blog地址名('blogaddress')"),
                         ("usr", "登录用户名"),
                         ("passwd", "登录密码")]:
                cfg[item[0]] = input("输入"+item[1])
            try:
                server = xmlrpclib.ServerProxy(cfg["url"])
                userInfo = server.blogger.getUsersBlogs(
                    cfg["appkey"], cfg["usr"], cfg["passwd"])
                print(userInfo[0])
                # {'blogid': 'xxx', 'url': 'xxx', 'blogName': 'xxx'}
                cfg["blogid"] = userInfo[0]["blogid"]
                break
            except:
                print("发生错误!")
        with open(cfg_path, "w", encoding="utf-8") as f:
            json.dump(cfg, f, indent=4, ensure_ascii=False)
    
    
    url = appkey = blogid = usr = passwd = ""
    server = None
    mwb = None
    title2id = {}
    
    
    def get_cfg():
        global url, appkey, blogid, usr, passwd, server, mwb, title2id
        with open(cfg_path, "r", encoding="utf-8") as f:
            cfg = json.load(f)
            url = cfg["url"]
            appkey = cfg["appkey"]
            blogid = cfg["blogid"]
            usr = cfg["usr"]
            passwd = cfg["passwd"]
            server = xmlrpclib.ServerProxy(cfg["url"])
            mwb = server.metaWeblog
            # title2id[title]=postid  储存博客中文章标题对应的postid
            recentPost = mwb.getRecentPosts(
                cfg["blogid"], cfg["usr"], cfg["passwd"], recentnum)
            for post in recentPost:
                # 1.把datetime转成字符串
                dt = post["dateCreated"]
                # post["dateCreated"] = dt.strftime("%Y%m%dT%H:%M:%S")
                post["dateCreated"] = dt.__str__()
                # 2.把字符串转成datetime
                # datetime.datetime.strptime(st, "%Y%m%dT%H:%M:%S")
                # datetime.datetime.fromisoformat(str)
                title2id[post["title"]] = post["postid"]
            # 格式化成20160320-114539形式
            filename = time.strftime("%Y%m%d-%H%M%S", time.localtime())
            with open(bak_path+filename+".json", "w", encoding="utf-8") as f:
                json.dump(recentPost, f, indent=4)
    
    
    # server = xmlrpclib.ServerProxy(url)
    # userInfo = server.blogger.getUsersBlogs(appkey, usr, passwd)
    # recentPost = mwb.getRecentPosts(blogid, usr, passwd, 9)
    def newPost(blogid, usr, passwd, post, publish):
        while True:
            try:
                postid = mwb.newPost(blogid, usr, passwd, post, publish)
                break
            except:
                time.sleep(5)
        return postid
    
    
    def post_art(path, publish=True):
        title = os.path.basename(path)  # 获取文件名做博客文章标题
        [title, fename] = os.path.splitext(title)  # 去除扩展名
        with open(mdfile, "r", encoding="utf-8") as f:
            post = dict(description=f.read(), title=title)
            post["categories"] = ["[Markdown]"]
            # 不发布
            if not publish:
                # 对于已经发布的文章,直接修改为未发布会报错:
                # xmlrpc.client.Fault: <'published post can not be saved as draft'>
                # 所以先删除这个文章
                # if title in title2id.keys():
                #     server.blogger.deletePost(
                #         appkey, title2id[title], usr, passwd, True)
                if title not in title2id.keys():
                    post["categories"].append('[随笔分类]unpublished')  # 标记未发布
                    # post["postid"] = title2id[title]
                    postid = newPost(blogid, usr, passwd, post, publish)
                    print("New:[title=%s][postid=%s][publish=%r]" %
                          (title, postid, publish))
            # 发布
            else:
                if title in title2id.keys():  # 博客里已经存在这篇文章
                    mwb.editPost(title2id[title], usr, passwd, post, publish)
                    print("Update:[title=%s][postid=%s][publish=%r]" %
                          (title, title2id[title], publish))
                else:  # 博客里还不存在这篇文章
                    postid = newPost(blogid, usr, passwd, post, publish)
                    print("New:[title=%s][postid=%s][publish=%r]" %
                          (title, postid, publish))
    
    
    def download_art():
        recentPost = mwb.getRecentPosts(blogid, usr, passwd, recentnum)
        for post in recentPost:
            if "categories" in post.keys():
                if '[随笔分类]unpublished' in post["categories"]:
                    with open(unp_path+post["title"]+".md",
                              "w", encoding="utf-8") as f:
                        f.write(post["description"])
            else:
                with open(art_path+post["title"]+".md",
                          "w", encoding="utf-8") as f:
                    f.write(post["description"])
    
    
    if __name__ == "__main__":
        if not exist_cfg():
            create_cfg()
        get_cfg()
        if len(sys.argv) > 1:
            if sys.argv[1] == "download":
                download_art()
            elif sys.argv[1] == "config":
                create_cfg()
                get_cfg()
        for mdfile in glob.glob(art_path+"*.md"):
            post_art(mdfile, True)
        for mdfile in glob.glob(unp_path+"*.md"):
            post_art(mdfile, False)
    

    然后编写.git/hooks/commit-msg,加入

    chmod +x ./cnblog.py
    ./cnblog.py
    
  • 相关阅读:
    Editor REST Client
    log配置
    spring-boot-configuration-processor
    http请求
    做项目用到的一些正则表达式,贴出来共享
    批量插入的实现
    sql执行顺序对比
    Java常用的并发工具类:CountDownLatch、CyclicBarrier、Semaphore、Exchanger
    spring中bean的生命周期
    多属性的对象列表的两种排序方法
  • 原文地址:https://www.cnblogs.com/1024th/p/10360719.html
Copyright © 2011-2022 走看看