闽公网安备 35020302035485号
本文介绍如何基于 GitHub 为图片存储,通过 API 随机返回可用的图片地址。
常用的桌面壁纸、终端背景图片,亦或是博客背景或文章封面,这些都离不开图片。于是,就想如何免费管理图片,同时又能轻松共享他人。在网上找了一些免费的随机图片 API,大部分处于不可用的状态,或者是需要注册登录,创建 API Token。作为一名老年程序员,自然就想能通过编程实现,实现图片自由。虽然也可以通过类似爬虫的思路实现,但还是希望都在自己的控制中,万一出现不好的图片就不好了。
https://github.com/poloxue/public_images/default/0001.webp -> https://cdn.jsdelivr.net/gh/poloxue/public_images@latest/default/0001.webp现在如果能顺利获取到仓库的图片文件列表,即可将 github 作为我们的图片图片存储,而无需花钱购买云存储实现。
如何获得 GitHub 文件列表呢?
https ://api.github.com/repos/{user}/{repo}/branches/{branch}。
JSON 返回体中,通过访问路径 .commit.commit.tree.url 拿到获取仓库文件列表的接口地址。其实主要是获取该分支最近的 commit hash。https ://api.github.com/repos/poloxue/public_images/branches/main
{
// ...
"commit": {
"commit": {
"tree": {
"sha": "3859a482b15ed41bfb86ce073d6c500fef36910c",
"url": "https://api.github.com/repos/poloxue/public_images/git/trees/3859a482b15ed41bfb86ce073d6c500fef36910c"
}
}
}
}
通过 jq 解析请求结果,再次通过 httpie 请求,命令如下:https $(https ://api.github.com/repos/poloxue/public_images/branches/main | jq -r '.commit.commit.tree.url+"?recursive=1"') | jq '.tree[].path'如上的命令中通过 ?recursive=1 实现遍历子目录,通过 '.tree[].path' 返回所有文件和目录。
.gitignore README.md beauties beauties/0001.jpeg beauties/0002.jpeg beauties/0003.jpeg beauties/0004.webp beauties/0005.jpg beauties/0006.webp default default/0001.webp default/0002.webp default/0003.webp scenes scenes/0001.webp scenes/0002.webp scenes/0003.webp scenes/0004.webp scenes/0005.webp
特别说明:接口的返回其实有数量限制,但这个限制并不是很大,个人使用无需担心。
import time
import random
import requests
from collections import defaultdict
# 堆代码 duidaima.com
class ImageService:
def __init__(self):
self._sha = None
self._images = defaultdict(list)
self._timeout = 60
self._timestamp = 0
def last_sha(self):
last_timestamp = time.time()
if last_timestamp - self._timestamp < self._timeout:
return self._sha
self._timestamp = last_timestamp
data = requests.get(
"https://api.github.com/repos/poloxue/public_images/branches/main"
).json()
return data["commit"]["commit"]["tree"]["sha"]
def get_images(self, category):
last_sha = self.last_sha()
if self._sha == last_sha:
return self._images[category]
self._images[category] = []
self._sha = last_sha
data = requests.get(
f"https://api.github.com/repos/poloxue/public_images/git/trees/{last_sha}?recursive=1"
).json()
for file in data["tree"]:
fpath = file["path"]
subdir = fpath.split("/")[0]
if fpath.lower().endswith((".png", "jpg", "jpeg", "webp")):
self._images[subdir].append(
f"https://cdn.jsdelivr.net/gh/poloxue/public_images@latest/{file['path']}"
)
return self._images[category]
def random_image(self, category):
images = self.get_images(category)
if images:
return random.choice(images)
如上方法,random_image 可提供给接口调用,从 GitHub 仓库返回一个随机图片。https ://api.poloxue.com/image/random/scenes输出结果:
{
"image": "https://cdn.jsdelivr.net/gh/poloxue/public_images@latest/scenes/0005.webp"
}
这只是服务的最小版本,还可以继续扩展,提供更多接口能力,如基于 Python 实现简单的裁剪缩放,皆是可行。另外,这个 service 中还实现了简单的基于时间的缓存方案,另外当请求到分支最后的 hash 变化时才会更新 self._images。唯一的遗憾就是,因为要提升共享能力,开发了一个简单的后端服务,没有免费云服务可用。还有就是,没有自动更新图片机制,有机会看看补齐吧。