deepin优雅地创作和分享技术博客


1. 闲言碎语

好记性不如烂笔头。我们很多人喜欢写技术博客,构建知识库,然后把它们分享到网络平台,比如自建博客,主流博客平台,又或者记录在自己的笔记软件。

以下是我个人观点:

写技术博客,博文格式首选markdown。写makrdown,博文内容所见即所得比预览或者人脑渲染更爽。

博客发布平台,首选比较干净整洁的博客园。其他比如CSDN,简书,开源中国。很多人喜欢多平台一起发布,也没啥问题。

把博客当作代码,托管在github/gitee。把博客当作知识库,放在个人博客网站,笔记软件,导图软件,都是主流选择。

实际上我也想这么做,还没有付出更多的实际行动。

有人说,使用windowns系列操作系统+写作或者笔记软件来写,或者在线写不香吗?或者离线写好,同步软件同步,粘贴到在线平台不香吗?

实话说,挺香。

选择【创作】【保存】【同步】【分享】的组合方式很多,但是我还是喜欢找到适合自己的舒服的方式。

用typora写好了,右键分享一下,就能发布到博客,也挺香

我个人的组合方式:deepin+typora+cnblogs+wiznote

当然typora已经收费,wiznote已经发布Linux版本。更多更好的替代,都在排着队......

===================================================================

着重和正式强调:不要拿博客平台当图床用,后果自负!!!

===================================================================

2. 正式入题

之前也写过一篇比较全面的博客

在上面这篇博客中,你能在deepin上,用快捷键,用命令行,用右键三种姿势,来分享你的博客

但是今天,我把代码改了改,2.0版本出来了。最重要的就是,能够上传图片了,香不香?

2.1 python3+xmrpc.client实现代码

以下是主要的代码:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# ***************************************************************************
# * 
# * @file:send_to_cnblogs.py 
# * @author:liwanliang 
# * @date:2021-12-08
# * @version 2.0  
# * @description: Python Script 
# * @Copyright (c)  all right reserved 
# * 
# ***************************************************************************
# 本脚本发送博客至www.cnblogs.com
# --file 指定要上传的markdown博客文件
# --upload 指定要上传的(多个)图片
# ***************************************************************************

import sys
import xmlrpc.client #{'python3':"xmlrpc.client",'python2':"xmlrpclib"}
import mimetypes
import os
import json
import subprocess
from optparse import OptionParser

class CnblogsAPI():
    """
    从配置文件读取用户的:url,帐号,密码
    """
    def __init__(self,config_json):
        self.__url,self.__user,self.__password = self.__read_config(config_json)
        self.__cnblogs_api = xmlrpc.client.ServerProxy(self.__url)
        self.__user_info = self.__cnblogs_api.blogger.getUsersBlogs('',self.__user,self.__password)
        self.__user_blogid = self.__user_info[0].get('blogid')

    def __read_config(self,config):
        try:
            with open(config,'r') as f:
                data = json.load(f)
                url = data.get('url')
                user = data.get('user')
                password = data.get('password')
                if not all([url,user,password]):
                    print("配置文件未正确指定:url,user,password")
                    sys.exit(0)
        except IOError:
            print("未指定配置文件")
            sys.exit(0)
        return (url,user,password)
                
    def get_all_blogs(self):
        """
        获取全部博客:{title:postid}
        """
        blogs_title_postid = {}
        all_blogs = self.__cnblogs_api.metaWeblog.getRecentPosts(self.__user_blogid,self.__user,self.__password,0)
        for blog in all_blogs:
            blogs_title_postid.update({blog.get('title'):blog.get('postid')})
        return blogs_title_postid

    def __get_post_id(self,post_name):
        """
        通过博客标题获取博客的post_id
        """
        return self.get_all_blogs().get(post_name)

    def upload_image_get_url(self,image):
        """
        指定图片上传图片,返回图片的url
        """
        with open(image,'rb') as f:
            image_bits = xmlrpc.client.Binary(f.read())
        image_type = mimetypes.guess_type(image)[0]
        image_name = os.path.basename(image)
        url = self.__cnblogs_api.metaWeblog.newMediaObject(
            	self.__user_blogid,
            	self.__user,
            	self.__password,
            	dict(bits=image_bits,name=image_name,type=image_type))
        return url.get('url')

    def edit_post(self,blog_file):
        """
        指定博客文件上传,发送通知到操作系统
        """
        with open(blog_file,'r') as blog:
            blog_content = blog.read()

        post_name = os.path.basename(blog_file)
        post_id = self.__get_post_id(post_name)
        post_info = {
            'title':post_name,
            'description':blog_content,
            'categories':['[]','[Markdown]'],#默认不发送到博客园首页候选区,默认markdown格式
        }

        if post_id:
            return self.__cnblogs_api.metaWeblog.editPost(
                	post_id,
                	self.__user,
                	self.__password,
                	post_info,True)
        else:
            return self.__cnblogs_api.metaWeblog.newPost(
                	self.__user_blogid,
                	self.__user,
                	self.__password,
                	post_info,True)

#****************************************************************************#
#上面的代码,主要是封装接口,复用性很强,ctrl+c,ctrl+v拿走就行。
# 下面的代码,就是个性化功能配置了
# 我个人的配置文件:
# 帐号密码配置文件,/home/liwl/.liwl/deepin/scripts/cnblogs.json
# conblogs.json内容:
#{
#	"url":xxxx,
#	"user":xxxx,
#	"password":xxxx,
#}
# deepin分享博客成功后,发送一个系统通知,其icon图片
# /home/liwl/.liwl/deepin/picture/cnblogs.png
#****************************************************************************#
if __name__ == "__main__":
    #脚本参数
    parser = OptionParser()
    parser.add_option("-f","--file",dest="filename")
    parser.add_option("-u","--upload",dest="image",action="append")
    (options,args) = parser.parse_args()

    #加载配置文件
    liwl_cnblogs = CnblogsAPI('/home/liwl/.liwl/deepin/scripts/cnblogs.json')

    #获取markdown博客
    markdown_blog = options.filename
    if options.filename:
        if liwl_cnblogs.edit_post(markdown_blog):
            subprocess.run('notify-send -i /home/liwl/.liwl/deepin/picture/cnblogs.png "创建/更新博客,成功"',shell=True)
        else:
            subprocess.run('notify-send -i /home/liwl/.liwl/deepin/picture/cnblogs.png "创建/更新博客,失败"',shell=True)

    #以下适合命令行发送
    #else:
        #subprocess.run('notify-send -i /home/liwl/.liwl/deepin/picture/cnblogs.png "未指定博客文件"',shell=True)
        

    #获取多个图片
    if options.image:
        for img in options.image + args:
            print(liwl_cnblogs.upload_image_get_url(img))
    #以下代码适合命令行发送
    #else:
        #subprocess.run('notify-send -i /home/liwl/.liwl/deepin/picture/cnblogs.png "未指定(多个)图片"',shell=True)

上面的代码,保存到一个路径下:/home/liwl/.liwl/deepin/scripts/send_to_cnblogs.py

注意赋予一个执行权限:chmod +x /home/liwl/.liwl/deepin/scripts/send_to_cnblogs.py

2.2 deepin配置右键发送

创建一个desktop文件:

sudo vim /usr/share/deepin/dde-file-manager/oem-menuextensions/deepin-send.desktop

内容如下:

[Desktop Entry]
Type=Application
Name=发布文档到
Actions=SendTocnblogs;SendTonsccwx;SendTowiznote
X-DFM-MenuTypes=SingleFile
MimeType=text/markdown

[Desktop Action SendTocnblogs]
Name=博客园
Exec=python3 /home/liwl/.liwl/deepin/scripts/send_to_cnblogs.py --file %U
Icon=send-to

2.3 Typora配置上传图片

如下图配置即可

需要注意的是,【上传服务设定】-【命令】要写脚本绝对路径和参数,如下:

python3 /home/liwl/.liwl/deepin/scripts/send_to_cnblogs.py --upload

下面这张图,就是我截图之后,粘贴在typora,自动上传的哦

3. 原理分析

其实也没啥原理,主要是以前没有注意到metaWeblog.newMediaObject这个接口,这两天研究了一下,发现这个接口,就把这个脚本重新修改了一下

简单理解:xmlrpc是一个协议,python实现了这个协议接口

python2的协议接口为:xmlrpclib,python3的协议接口包为:xmlrpc.client

博客园允许你使用这个协议来使用他们提供的接口,而且有个前提,你需要在自己的博客设置里面启用这个功能

博客设置——其他设置——勾选允许MetaWeblog博客客户端访问

Typora又恰好提供了使用命令或者脚本的方式来获取图片的url

所以,一切都是那么顺其自然,挺幸运

本篇博客就是在deepin系统下,写完了以后,右键发送到博客园的呢,右键

发送成功后,deepin上方会有如下图提示:


最后还是强调,不要把博客平台当作图床来用,否则后果自负