Post

自動備份 Medium 文章到 Github Pages (Jekyll) 的那些事

個人 Medium 文章備份鏡像站搭建、維護、升級、客製化的一些紀錄

自動備份 Medium 文章到 Github Pages (Jekyll) 的那些事

自動備份 Medium 文章到 Github Pages (Jekyll) 的那些事

個人 Medium 文章備份鏡像站搭建、維護、升級、客製化的一些紀錄

前言

經營 Medium 來到了第 6 年,文章總數在去年突破 100 篇;隨著經營時間越長、文章越多,越怕哪天 Medium 突然關閉或是帳號異常造成所有文章心血付之一炬,有的文章含金量不高道無妨,但更多的是記錄技術架構跟當時的解題思維,我時常也會回來看之前寫的文章,重新複習知識;另外後面幾年也開始記錄出國旅遊遊記,都是回憶並且流量表現不錯;這些內容一但遺失就不可能再重新撰寫了。

自行開發備份工具

我習慣都是直接在 Medium 平台上撰寫文章,沒有自己的備份,因此在 2022 年過年期間花時間開發了一個 Medium 文章下載&轉換成 Markdown 文件(包含文章圖片、文章內嵌的程式碼…等內容) 的工具 ZMediumToMarkdown

並延伸使用此工具將下載下來的 Markdown 使用 Jekyll (Chirpy Theme) 做為靜態備份鏡像網站部署在 Github Pages 上 — https://zhgchg.li/

[https://zhgchg.li/](https://zhgchg.li/){:target="_blank"}

https://zhgchg.li/

那時候把這整套整合成一個 Github Template Repo 給有同樣需求的朋友可以快速部署使用 — ZMediumToJekyll ,在此之後(2022),我就沒有再更新過 Jekyll (Chirpy Theme) 的版本跟設定了; ZMediumToMarkdown 持續有在維護,偶爾會發現格式解析錯誤就會立刻修正,目前趨於穩定。

那時候使用的 Jekyll (Chirpy Theme) 版本是 v5.x 沒有太大的問題,該有的功能也都有(e.g. 置頂、分類、標籤、封面圖、留言…);只有在畫面滾動時很常會出現無法滾動問題,但是在滑個幾下又正常,一個操作體驗缺憾,曾經嘗試升級到 v6.x 還是有、回報給官方也沒得到回應;再加上隨著版本提升升級會遇到的衝突就越多,因此後來完全放棄升級這個念頭。

近期才下定決心要解決 Jekyll (Chirpy Theme) 問題、升級版本、順手重新優化快速部署工具 ZMediumToJekyll

New! medium-to-jekyll-starter 🎉🎉

medium-to-jekyll-starter.github.io

我將 Jekyll (Chirpy Theme) 最新版 v7.x 加上我的 ZMediumToMarkdown Medium 文章下載轉換工具重新整合成新的 — medium-to-jekyll-starter.github.io Github Template Repo。

大家可以直接使用這個範本 Repo 快速設定搭建自己的 Medium 鏡像內容備份網站, 一次設定永久持續自動備份、部署在 Github Pages 上完全免費

手把手設定教學請參考此篇文章: https://zhgchg.li/posts/zh-TW-medium-to-jekyll/

成果

[https://zhgchg.li/](https://zhgchg.li/){:target="_blank"}

https://zhgchg.li/

*上面的所有文章都是 自動 從我的 Medium 下載所有內容&轉換成 Markdown 格式&重新上傳。

附上隨便一篇文章的轉換成果作為比較範例:

Medium 上的原始內容 / 轉換後在個人網站的結果

升級後沒再出現滾動卡住的問題了,藉由這次升級也多加上了客製化動態內容 (顯示 Medium 追蹤人數)。

一些技術紀錄

Jekyll (Chirpy Theme) 在 Github Pages 上的部署設定方式主要是直接參考官方 Start Repo:

上個月也參考這個專案的方式,做了一個新的開源專案 — Linkyee 開源版的 Link Tree 個人連結頁面。

[https://link.zhgchg.li/](https://link.zhgchg.li/){:target="_blank"}

https://link.zhgchg.li/

Jekyll 客製化方式 (1) — Override HTML

Jekyll 是一套很強大的 Ruby 靜態內容網站生成引擎, Jekyll (Chirpy Theme) 只是一套基於 Jekyll 的主題,比較過其他主題還是 Chirpy Theme 最有質感跟操作體驗優異、功能俱全。

Jekyll 的頁面具有繼承性,我們可以在 ./_layouts 新增 與 Jekyll 相同的頁面檔案名 ,引擎在產生網站內容時就會使用你自訂的頁面內容取代掉原本的。

例如我希望在每個文章頁末尾加上一行文字,我先把原本的文章頁面檔案( post.html )複製出來,放到 ./_layouts 目錄下:

使用編輯器打開 post.html 在相應的位置加上文字或客製化,重新部署網站就能看到客製化結果。

也可以建立一個 ./_include 目錄,放一些想要共用的頁面內容檔案:

然後再 post.html 中我們就可以直接使用 {% include buymeacoffee.html %} 引入剛檔案的 HTML 內容重複使用。

複寫 HTML Layout 檔案的優點是 100% 客製化,頁面內容、排版要怎麼呈現都可以隨意調整;缺點是這次在升級的過程就會遇到衝突或是預期外結果,要自己重新檢視一次客製化的內容。

Jekyll 客製化方式 (2) — Plugin

第二種方式是使用 Plugin 中的 Hook 方法,在 Jekyll 產生靜態內容階段注入自己想要的客製化內容。

[Built-in Hook Owners and Events](https://jekyllrb.com/docs/plugins/hooks/#built-in-hook-owners-and-events){:target="_blank"}

Built-in Hook Owners and Events

Hook 事件 有很多,這邊只附上我用到的 site:pre_renderpost:pre_render

新增方式也很簡單,只要在 ./_plugins 新增一個 Ruby 檔案即可。

posts-lastmod-hook.rb 是原本就有的 Plugin

posts-lastmod-hook.rb 是原本就有的 Plugin

我想要幾個「偽」動態內容功能,第一個是在個人資料下顯示 Medium 追蹤人數還有在頁底顯示頁面內容最後更新時間。

./_plugins 下建立了一個 zhgchgli-customize.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/env ruby
#
require 'net/http'
require 'nokogiri'
require 'uri'
require 'date'


def load_medium_followers(url, limit = 10)
  return 0 if limit.zero?

  uri = URI(url)
  response = Net::HTTP.get_response(uri)
  case response
  when Net::HTTPSuccess then
      document = Nokogiri::HTML(response.body)

      follower_count_element = document.at('span.pw-follower-count > a')
      follower_count = follower_count_element&.text&.split(' ')&.first

      return follower_count || 0
  when Net::HTTPRedirection then
    location = response['location']
    return load_medium_followers(location, limit - 1)
  else
      return 0
  end
end

$medium_url = "https://medium.com/@zhgchgli"
# could also define in _config.yml and retrieve in Jekyll::Hooks.register :site, :pre_render do |site| site.config

$medium_followers = load_medium_followers($medium_url)

$medium_followers = 1000 if $medium_followers == 0
$medium_followers = $medium_followers.to_s.reverse.scan(/\d{1,3}/).join(',').reverse


Jekyll::Hooks.register :site, :pre_render do |site|

  tagline = site.config['tagline']
  
  followMe = <<-HTML
  <a href="#{$medium_url}" target="_blank" style="display: block;text-align: center;font-style: normal;/* text-decoration: underline; */font-size: 1.2em;color: var(--heading-color);">#{$medium_followers}+ Followers on Medium</a>
  HTML

  site.config['tagline'] = "#{followMe}";
  site.config['tagline'] += tagline;

  meta_data = site.data.dig('locales', 'en', 'meta');
  # only impletation in en, could impletation to all langs.

  if meta_data
    gmt_plus_8 = Time.now.getlocal("+08:00")
    formatted_time = gmt_plus_8.strftime("%Y-%m-%d %H:%M:%S")
    site.data['locales']['en']['meta'] += "<br/>Last updated: #{formatted_time} +08:00"
  end
end
  • 原理是註冊一個 Hook 在網站 Render 前,對 config 中的 tagline 個人資料下方介紹內容區塊,多塞上 Medium 追蹤人數顯示 HTML。
  • Medium 追蹤人數會在每次執行都去爬取拿到最新數字
  • 頁底最後更新時間邏輯也差不多,就是對 locales->en->meta 在產生網站時多塞上最後更新時間字串
  • 補充如果是 Hook 文章產生前,可以拿到 Markdown、Hook 文章產生後,可以拿到產生後的 HTML

儲存後可以先在本機下 bundle exec jekyll s 測試結果:

用瀏覽器打開 127.0.0.1:4000 查看結果。

最後在 Github Pages Repo 上的 Actions 加上排程定時自動重新產生網站,就完成了:

Jekyll (Chirpy Theme) Repo 專案中的 Actions 找到「 pages-deploy.yml 」在 on: 新增:

1
2
  schedule:
    - cron: "10 1 * * *" # 每天 UTC 01:10 自動執行一次, https://crontab.guru

Plugin 的優點是可以達到動態內容效果(排程更新內容)、不影響網站架構不會在升級時遇到衝突;缺點就是能調整的內容、顯示位置有局限。

Jekyll (Chirpy Theme) v7.x 後的 Github Pages 部署問題

除了網站架構的調整外,v.7.x 的部署腳本也有改變;移除了原本的 deploy.sh 部署腳本,直接使用 Github Actions 的部署步驟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# build:
# ...
      - name: Upload site artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: "_site${{ steps.pages.outputs.base_path }}"

  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4

但是我在部署的過程遇到了問題:

Uploaded artifact size of 1737778940 bytes exceeds the allowed size of 1 GB 因為我的網站內容太大了,導致 Upload Artifact 失敗;但是之前的部署腳本是可以的,所以只好退回去用原本的 deploy.sh註解掉上面這一段

Github Pages 部署時 Test Site 步驟一直不通過

Jekyll (Chirpy Theme) 部署有一個步驟是 Test Site 自檢測網頁內容是否正確,例如連結是否正常、HTML 標籤是否有缺漏…等等

1
2
3
4
5
6
7
8
9
# build:
# ...
      - name: Test site
        run: |
          bundle exec htmlproofer _site \
            \-\-disable-external \
            \-\-no-enforce-https \
            \-\-ignore-empty-alt \
            \-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"

我自己多加了 --no-enforce-https --ignore-empty-alt 忽略 https、html tag沒有 alt 的檢查, 忽略這兩條讓檢查通過(因為暫時無法去改內容)

htmlproofer 的 CLI 指令官方文件沒有提,翻了好久才在某個 Issue 的 Comment 找到規則:

[https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268](https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268){:target="_blank"}

https://github.com/gjtorikian/html-proofer/issues/727#issuecomment-1334430268

其他文章補充

有任何問題及指教歡迎 與我聯絡

===

本文首次發表於 Medium ➡️ 前往查看

Buy me a beer

This post is licensed under CC BY 4.0 by the author.