halo博客自动备份到GitHub

halo博客自动备份到GitHub

该功能可自定义每隔N小时备份博客到GitHub仓库,显示效果如下,也可以点击这里浏览详细页面:

环境准备

  • Java
  • GitHub
  • 准备与GitHub相关的环境

  • Settings---->Personal access tokens--------->public_repo

  • 记住上一步的token

  • 代码部分

  • GitHub项目地址:https://github.com/chenguod/halo-executor
  • Gitee项目地址:https://gitee.com/cgd0526/halo-executor
  • 详细代码

    package com.cgd.xxljobexecutor.utils;import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONException;import com.alibaba.fastjson.JSONObject;import jodd.http.HttpRequest;import jodd.http.HttpResponse;import lombok.extern.slf4j.Slf4j;import javax.servlet.http.HttpServletResponse;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Base64;import java.util.Objects;import java.util.TimeZone;/** * @author 晓果冻 * @version 1.0 * @date 2021/11/24 22:32 */@Slf4jpublic class GitHubUtil { private final static String USER_AGENT = "https://www.chenmx.net"; private GitHubUtil() { } public static JSONArray getGitHubRepos(String githubUserId) { try { HttpResponse res = HttpRequest.get("https://api.github.com/users/" + githubUserId + "/repos"). connectionTimeout(20000).timeout(60000).header("User-Agent", USER_AGENT).send(); if (HttpServletResponse.SC_OK != res.statusCode()) { return null; } res.charset("UTF-8"); JSONArray result = JSONArray.parseArray(res.bodyText()); String pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); JSONArray compatibleResult = new JSONArray(); for (int i = 0; i < result.size(); i++) { JSONObject resultObject = result.getJSONObject(i); JSONObject compatibleObject = new JSONObject(); compatibleObject.put("githubrepoId", resultObject.getString("id")); compatibleObject.put("githubrepoStatus", 0); compatibleObject.put("oId", "" + System.currentTimeMillis()); compatibleObject.put("githubrepoDescription", resultObject.getString("description")); compatibleObject.put("githubrepoHomepage", resultObject.getString("homepage")); compatibleObject.put("githubrepoForksCount", resultObject.getLong("forks_count")); compatibleObject.put("githubrepoOwnerId", resultObject.getJSONObject("owner").getString("id")); compatibleObject.put("githubrepoStargazersCount", resultObject.getLong("stargazers_count")); compatibleObject.put("githubrepoWatchersCount", resultObject.getLong("watchers_count")); compatibleObject.put("githubrepoOwnerLogin", resultObject.getJSONObject("owner").getString("login")); compatibleObject.put("githubrepoHTMLURL", resultObject.getString("html_url")); compatibleObject.put("githubrepoLanguage", resultObject.getString("language")); compatibleObject.put("githubrepoUpdated", simpleDateFormat.parse(resultObject.getString("updated_at")).getTime()); compatibleObject.put("githubrepoName", resultObject.getString("name")); compatibleObject.put("githubrepoFullName", resultObject.getString("full_name")); compatibleResult.add(compatibleObject); } // 排序 ArrayList<String> tempResultList = new ArrayList<>(); for (int i = 0; i < compatibleResult.size(); i++) { JSONObject compatibleObject = compatibleResult.getJSONObject(i); tempResultList.add(compatibleObject.toString()); } tempResultList.sort((o1, o2) -> { int o1star = JSONObject.parseObject(o1).getInteger("githubrepoStargazersCount"); int o2star = JSONObject.parseObject(o2).getInteger("githubrepoStargazersCount"); return o2star - o1star; }); JSONArray sortedCompatibleResult = new JSONArray(); for (String json : tempResultList) { sortedCompatibleResult.add(JSONObject.parseObject(json)); } return sortedCompatibleResult; } catch (JSONException e) { log.error("Gets GitHub repos failed because the request has been reached GitHub's limit, try again at later."); return null; } catch (Exception e) { log.error("Gets GitHub repos failed, please check your network connection to github.com"); return null; } } public static boolean updateFile(String pat, String loginName, String repoName, String filePath, byte[] content) { String fullRepoName = loginName + "/" + repoName; try { HttpResponse response = HttpRequest.get("https://api.github.com/repos/" + fullRepoName + "/git/trees/main").header("Authorization", "token " + pat). connectionTimeout(7000).timeout(60000).header("User-Agent", USER_AGENT).send(); int statusCode = response.statusCode(); response.charset("UTF-8"); String responseBody = response.bodyText(); if (200 != statusCode && 409 != statusCode) { log.error("Get git tree of file [" + filePath + "] failed: " + responseBody); return false; } JSONObject body = new JSONObject(); body.put("message", ":memo: 更新博客"); body.put("content", Base64.getEncoder().encodeToString(content)); if (200 == statusCode) { JSONObject responseData = JSONObject.parseObject(responseBody); JSONArray tree = responseData.getJSONArray("tree"); for (int i = 0; i < tree.size(); i++) { JSONObject file = tree.getJSONObject(i); if (Objects.equals(filePath, file.getString("path"))) { body.put("sha", file.getString("sha")); break; } } } response = HttpRequest.put("https://api.github.com/repos/" + fullRepoName + "/contents/" + filePath).header("Authorization", "token " + pat). connectionTimeout(7000).timeout(60000 * 2).header("User-Agent", USER_AGENT).bodyText(body.toString()).send(); statusCode = response.statusCode(); response.charset("UTF-8"); responseBody = response.bodyText(); if (200 != statusCode && 201 != statusCode) { log.error("Updates repo [" + repoName + "] file [" + filePath + "] failed: " + responseBody); return false; } return true; } catch (Exception e) { log.error("Updates repo [" + repoName + "] file [" + filePath + "] failed: " + e.getMessage()); return false; } } public static boolean createOrUpdateGitHubRepo(String pat, String loginName, String repoName, String repoDesc, String repoHomepage) { try { JSONObject body = new JSONObject(); body.put("name", repoName); body.put("description", repoDesc); body.put("homepage", repoHomepage); body.put("has_wiki", false); body.put("has_projects", false); HttpResponse response = HttpRequest.post("https://api.github.com/user/repos").header("Authorization", "token " + pat). connectionTimeout(7000).timeout(30000).header("User-Agent", USER_AGENT).bodyText(body.toString()).send(); int statusCode = response.statusCode(); response.charset("UTF-8"); String responseBody = response.bodyText(); if (201 != statusCode && 422 != statusCode) { log.error("Creates GitHub repo [" + repoName + "] failed: " + responseBody); return false; } if (201 == statusCode) { return true; } response = HttpRequest.patch("https://api.github.com/repos/" + loginName + "/" + repoName).header("Authorization", "token " + pat). connectionTimeout(7000).timeout(30000).header("User-Agent", USER_AGENT).bodyText(body.toString()).send(); statusCode = response.statusCode(); responseBody = response.bodyText(); if (200 != statusCode) { log.error("Updates GitHub repo [" + repoName + "] failed: " + responseBody); return false; } return true; } catch (Exception e) { log.error("Creates or updates GitHub repo failed: " + e.getMessage()); return false; } } public static JSONObject getGitHubUser(String pat) { try { HttpResponse response = HttpRequest.get("https://api.github.com/user").header("Authorization", "token " + pat). connectionTimeout(7000).timeout(30000).header("User-Agent", USER_AGENT).send(); if (200 != response.statusCode()) { return null; } response.charset("UTF-8"); return JSONObject.parseObject(response.bodyText()); } catch (Exception e) { log.error("Gets GitHub user info failed: " + e.getMessage()); return null; } }}
    @ApiOperation("测试") @RequestMapping(value = "/test", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"}) @ResponseBody public void test(String param) { String site = "https://www.chenmx.net"; JSONObject gitHubUser = GitHubUtil.getGitHubUser(param); String loginName = gitHubUser.getString("login"); String repository = "halo-blog"; String repositoryDesc = "✍️ 晓果冻的个人博客 - 一个热爱生活的90后"; GitHubUtil.createOrUpdateGitHubRepo(param, loginName, repository, repositoryDesc, site); List<String> list = postsDao.getPosts("'"+site+"?p='"); StringBuilder sb = new StringBuilder(); list.stream().forEach(e -> { sb.append(e); }); String readme = "<p align=\"center\"><img alt=\"晓果冻的个人博客\" src=\"https://cdn.jsdelivr.net/gh/chenguod/picture/202111251402173.jpg\" width=\"130\"></p><h2 align=\"center\">\n" + "\n" + "晓果冻的个人博客\n" + "</h2>\n" + "\n" + "<h4 align=\"center\">一个热爱生活的90后</h4>\n" + "<p align=\"center\"><a title=\"晓果冻的个人博客\" target=\"_blank\" href=\"https://github.com/chenguod/halo-blog\"><img src=\"https://img.shields.io/github/last-commit/chenguod/halo-blog.svg?style=flat-square&color=FF9900\"></a>\n" + "<a title=\"GitHub repo size in bytes\" target=\"_blank\" href=\"https://github.com/chenguod/halo-blog\"><img src=\"https://img.shields.io/github/repo-size/chenguod/halo-blog.svg?style=flat-square\"></a>\n" + "<a title=\"由halo驱动\" target=\"_blank\" href=\"https://github.com/halo-dev/halo\"><img src=\"https://img.shields.io/badge/halo-1.4.13-f1e05a.svg?style=flat-square&color=blueviolet\"></a>\n" + "<a title=\"Hits\" target=\"_blank\" href=\"https://github.com/dwyl/hits\"><img src=\"http://hits.dwyl.com/chengd/halo-blog.svg\"></a></p>\n" + "\n" + "### 最新\n" + "\n" + sb + "\n" + "\n" + "\n" + "---\n" + "\n" + "本仓库通过 [halo-executor](https://github.com/chenguod/halo-executor) 自动进行同步更新 ❤️ \n" + "\n"; Boolean ok = GitHubUtil.updateFile(param, loginName, repository, "README.md", readme.getBytes(Charset.forName("UTF-8"))); }

    注意,此方案需要使用halo的数据库。至于定时任务可以换成quartz,xxl-job是因为有可视化界面,操作比较方便。

    博文markdown备份到GitHub我后续继续研究下。

    感谢bolo博客提供的备份思路

    欢迎大家访问我的个人小站:https://www.chenmx.net,获取更多有趣的博文!

    ©著作权归作者所有,转载或内容合作请联系作者
    【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
    平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

    相关阅读更多精彩内容

    友情链接更多精彩内容