TOPO.TW

使用 Google Photos 當作圖床

引子

撰寫部落格,沒有圖床怎麼行呢?

目前本站搭建在 Vultr 提供的 VPS 服務上。 基本方案下,這台主機有 25GB 的 SSD 可供使用。 雖然目前可用空間還有 14 GB , 但是時候先想好圖片的儲存方案了, 總不能一直把圖片往這部主機塞。

好在目前我的手機是 PIXEL 5, 享有無限量上傳的 Google Photos 服務。 所以只要能夠接受一點點壓縮圖片的代價, 無限空間的圖床理論上是沒問題。

動手開工

目前部落格的各個頁面是用 Hugo 搭建的。 在每則文章的 markdown 檔案中, 可以使用絕對路徑或相對路徑來指定圖片連結。例如:

![](https://topo.tw/photos/foo.jpg)
![](../../photos/foo.jpg)

但不管怎樣,都要讓 VPS 先有一個 /photos/ 的 path 來提供圖片。 因此,我們會需要有一個圖片的專屬目錄供 Nginx 使用。

要如何把 Google Photos API 轉換為可掛載到檔案系統的目錄呢? 嘿嘿,要把各種雲端儲存服務掛載到檔案系統, 早就有大名鼎鼎的 rclone 可供使用啦。

設定

網路上有關 rclone 的教學資源相當豐富, 官方也有提供 docker image,所以這邊我就不多作贅述了。 只把目前情境下需要的設定紀錄下來:

IMAGE=rclone/rclone:1.58.0

# 使用 docker 執行 rclone
# 進入 config 模式
docker run \
    --rm -it \
    --name rclone \
    --user `id -u`:`id -g` \
    --volume ~/.config/rclone:/config/rclone \
    --volume ~/rclone:/data \
    --network host \
    $IMAGE \
    config
    
# 依照提示,新增一個指向 Google Photos 的 Remote
# 大部分的設定使用預設選項即可
...
    
# 掛載相關的 Remote 到目錄 ~/data/photos/
# 為了不要在檔案權限上太花時間,這邊我們把 /etc/passwd 和 /etc/group 傳進去
# 讓 docker container 內的使用者和目前使用者一模一樣
mkdir -p ~/data/photos
docker run \
    --name rclone \
    --rm --detach \
    --user `id -u`:`id -g` \
    --volume ~/.config/rclone:/config/rclone \
    --volume ~/data:/data:shared \
    --volume /etc/passwd:/etc/passwd:ro --volume /etc/group:/etc/group:ro \
    --device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor:unconfined \
    $IMAGE \
    mount photos:media/by-day /data/photos --gphotos-read-size --allow-other

值得注意的是:預設情況下,掛載的目錄只可以顯示檔名而無法取得圖片內容

根據官方文件1,這是因為讀取圖片需要知道圖片的 size, 而用 Google Photos API 取得 size 需要額外的 transaction , 會大大拖慢同步的速度。

不過因為我們的目的就是要取得圖片內容,因此參數需要加上 gphotos-read-size。 執行指令後,我們就完成掛載啦。

Google Photos 類型的目錄下有不同的圖片分類方式: 例如 all/, by-year/, by-month/, by-day/等。

因為我們僅掛載 media/by-day,所以目錄結構會長這樣:

~/data/photos/2022
├── 2022-01-01
│   ├── PXL_20220101_055706343.jpg
│   ├── PXL_20220101_060221557.jpg
│   ├── PXL_20220101_060725049.jpg
│   ├── PXL_20220101_064911561.jpg
│   └── PXL_20220101_065919363.MP.jpg

接著,就只要把 Nginx 調整好就完成圖床服務啦!