暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

DIY自己的gitbook文章阅读量统计插件

奥思立方 2021-07-30
671

背景

个人开发者普遍拥有属于自己的个人博客站点。常见的框架无论是Hexo、Gitbook,亦或是Docsify,这些框架本身并不支持文章阅读量或者站点访问量的功能,需要各种对应的插件支持 目前市面上这些插件基本上是基于busuanzi,LeanCloud实现的,而MemFireDB Cloud[1]旨在提供数据库服务,若后续提供sdk功能,能够实现对应框架的插件供个人开发者使用,并提供相关文章,也能吸引很多个人开发者(因为我本身也是基于使用插件的需要,才在LeanCloud上注册了账户。)

概述

基本上述背景,尝试着基于memfire去实现一个统计gitbook文章访问量的插件

实现

建库建表

登录MemFireDB Cloud

需要在MemFireDB Cloud[2]上注册账户,并创建自己的数据库

进入在线编辑器

点击SQL查询进入在线编辑器

建表

CREATE TABLE counter (
id serial NOT NULL,
url varchar(500),
time int,
title varchar(200),
PRIMARY KEY (id)
)

复制

数据库连接

因为目前MemFireDB Cloud[3]还不提供sdk等功能,所以先自己简单写一个中间服务,便于插件访问。

package main

import (
"database/sql"
"fmt"
"log"
"net/http"

"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
)

const (
host = "<db ip>"
port = <db port>
user = "<your db user>"
password = "<your db password>"
dbname = "<your db name>"
)

func main() {
r := gin.Default()
r.Use(Cors()) //开启中间件 允许使用跨域请求
r.GET("/counter", GetCount) // 获取文章访问量
r.POST("/counter", AddCount) // 创建文章访问量
r.PUT("/counter", UpdateCount) // 更新文章访问量
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

func Cors() gin.HandlerFunc {
return func(c *gin.Context) {
method := c.Request.Method
origin := c.Request.Header.Get("Origin") //请求头部
if origin != "" {
c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
c.Header("Access-Control-Max-Age", "172800")
c.Header("Access-Control-Allow-Credentials", "true")
}

//允许类型校验
if method == "OPTIONS" {
c.JSON(http.StatusOK, "ok!")
}
defer func() {
if err := recover(); err != nil {
log.Printf("Panic info is: %v", err)
}
}()
c.Next()
}
}

func GetCount(c *gin.Context) {
url := c.Query("url")
if url == "" {
url = "#"
}

psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("SELECT time FROM counter WHERE url = $1", url)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
var time int
for rows.Next() {
err := rows.Scan(&time)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Row[%d]\n", time)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}

defer db.Close()
c.JSON(200, gin.H{
"time":time,
})
return
}

func AddCount(c *gin.Context) {
url := c.PostForm("url")
if url == "" {
url = "#"
}

psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}

insert := "INSERT INTO counter(url, time) VALUES ("
insert += "'" + url + "', 1)"
fmt.Println("insert statement: ", insert)

if _, err := db.Exec(insert); err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted data: %s\n", insert)
defer db.Close()
return
}

func UpdateCount(c *gin.Context) {
url := c.PostForm("url")
if url == "" {
url = "#"
}
time := c.PostForm("time")
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
update := "UPDATE counter SET time=" + time + " Where url= '" + url + "'"
if _, err := db.Exec(update); err != nil {
log.Fatal(err)
}
fmt.Printf("update data: %s\n", update)
defer db.Close()
return
}

复制

构建gitbook插件

仿造其他插件,建立代码仓库

修改book下plugin.js

var gitbook = window.gitbook;

/*
<!-- Start of CuterCounter Code -->
<a href="http://www.cutercounter.com/" target="_blank"><img src="http://www.cutercounter.com/hit.php?id=gmvufxqck&nd=1&style=116" border="0" alt="visitor counter"></a>
<!-- End of CuterCounter Code -->
*/

var iconSVg = '<svg t="1543310294340" \
class="icon" style="" viewBox="0 0 1024 1024" version="1.1" \
xmlns="http://www.w3.org/2000/svg" p-id="1104" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14"><defs><style type="text/css"></style></defs>\
<path d="M512 416a96 96 0 1 0 0 192 96 96 0 0 0 0-192z m511.952 102.064c-0.016-0.448-0.064-0.864-0.096-1.296a8.16 8.16 0 0 0-0.08-0.656c0-0.32-0.064-0.624-0.128-0.928-0.032-0.368-0.064-0.736-0.128-1.088-0.032-0.048-0.032-0.096-0.032-0.144a39.488 39.488 0 0 0-10.704-21.536c-32.672-39.616-71.536-74.88-111.04-107.072-85.088-69.392-182.432-127.424-289.856-150.8-62.112-13.504-124.576-14.064-187.008-2.64-56.784 10.384-111.504 32-162.72 58.784-80.176 41.92-153.392 99.696-217.184 164.48-11.808 11.984-23.552 24.224-34.288 37.248-14.288 17.328-14.288 37.872 0 55.216 32.672 39.616 71.52 74.848 111.04 107.056 85.12 69.392 182.448 127.408 289.888 150.784 62.096 13.504 124.608 14.096 187.008 2.656 56.768-10.4 111.488-32 162.736-58.768 80.176-41.936 153.376-99.696 217.184-164.48 11.792-12 23.536-24.224 34.288-37.248 5.712-5.872 9.456-13.44 10.704-21.568l0.032-0.128a12.592 12.592 0 0 0 0.128-1.088c0.064-0.304 0.096-0.624 0.128-0.928l0.08-0.656 0.096-1.28c0.032-0.656 0.048-1.296 0.048-1.952l-0.096-1.968zM512 704c-106.032 0-192-85.952-192-192s85.952-192 192-192 192 85.968 192 192c0 106.048-85.968 192-192 192z"\
fill="#CCC" p-id="1105"></path></svg>'

require(["gitbook", "jQuery"], function (gitbook, $) {
gitbook.events.bind("page.change", function() {
var bookHeader = $('.book-header')
var lastChild = bookHeader.children().last()

var renderWrapper = $('<div class="page-view-wrapper dropdown pull-left">\
<span class="btn toggle-dropdown">'+ iconSVg + '</span>\
<span class="page-view-counter" title="阅读数">-</span>\
</div>')

if(lastChild.length){
renderWrapper.insertBefore(lastChild)
}else{
bookHeader.append(renderWrapper)
}

var Counter = function (method, url, data) {
return $.ajax({
method: method,
url : `http://127.0.0.1:8080${url}`,
data: data,
});
};

var url = location.href.replace(/^http:\/\/[^/]+/, "").trim();
url = decodeURI(url);
var s = url.split("/").pop();
var title = s.replace(".html", "");
var time = 0;

Counter('get', '/counter', { url: url }).done(function (results ) {
console.log(results)
if (results.time > 0) {
time = results.time+1;
Counter('put', `/counter`, {url: url, time: time }).done(function () {
console.log(time);
renderWrapper.find('.page-view-counter').html(time)
})
} else {
Counter('post', '/counter', { title: title, url: url, time: 1}).done(function ({ results }) {
renderWrapper.find('.page-view-counter').html(1)
})
}
});

})
});

复制

仓库地址:https://github.com/TiannV/gitbook-plugin-mf-pageview npm publish发布到npm市场

使用

添加插件

在自己的gitbook仓库的book.json文件添加插件

执行gitbook install即可将应用市场上的插件下载到gitbook项目中 gitboolk build 执行编译

运行数据库连接服务

go run mf.go

启动gitbook

gitbook serve

查看界面:

成功~

代码仓库

TiannV/gitbook-plugin-mf-pageview

References

[1]
 MemFireDB Cloud: https://memfiredb.com/


文章转载自奥思立方,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论