基于CF-workers和Github-actions的lsky图床随机API

MIKU 发布于 21 天前 50 次阅读


本地版:https://blog.mikulab.com/archives/20
由于服务器物理位置限制,导致该API请求时耗时经常超过1000ms,因此考虑将请求程序存放于CF/GitHub仓库中,通过CF提供的边缘计算加快访问速度,减少不必要的物理传输时间。

追加支持:通过增加域名后缀实现对不同相册的访问,需更改CF worker及GitHub sync 脚本。

1.创建CF-KV存储用于储存图床中相册特定内的所有图片链接,以在后续请求中直接调用,加快访问速度的同时减少服务器资源消耗,将KV命名为IMG_LIST_KV,帮记录其ID。随后登录控制台,创建API Tokens,选择Custom Token,设置如下:

Token name: GitHub_Sync_KV

Permissions:

Account | Worker KV Storage | Edit

Account Resources: 选择 Include | Your Account

记录该Token。

2.创建CF-Worker,并将KV与其绑定。

export default {
  async fetch(request, env) {
    // 1. 从 KV 数据库读取名为 "images" 的键值对
    const listStr = await env.IMG_LIST_KV.get("images");
    
    if (!listStr) {
      return new Response("列表尚未同步,请运行 GitHub Actions", { status: 404 });
    }

    const imgList = JSON.parse(listStr);
    
    // 2. 本地随机算法 
    const randomUrl = imgList[Math.floor(Math.random() * imgList.length)];

    // 3. 返回 302 重定向
    return Response.redirect(randomUrl, 302);
  }
};

多相册版:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    // 获取路径并去掉斜杠,例如 "/6" 变成 "6"
    let albumId = url.pathname.replace(/\//g, '');

    // 如果直接访问根域名没有带路径,默认指向相册 5
    if (!albumId) {
      albumId = "5";
    }

    // 从 KV 数据库中读取对应相册 ID 的列表
    const listStr = await env.IMG_LIST_KV.get(albumId);
    
    if (!listStr) {
      return new Response(`未找到相册 ID ${albumId} 的同步数据。请确认 GitHub Actions 已运行并同步了此 ID。`, { 
        status: 404,
        headers: { "Content-Type": "text/plain;charset=UTF-8" }
      });
    }

    const imgList = JSON.parse(listStr);
    const randomUrl = imgList[Math.floor(Math.random() * imgList.length)];

    // 执行重定向
    return Response.redirect(randomUrl, 302);
  }
};

3.创建新的Github仓库,并在根目录创建同步脚本sync.py。

import requests
import json
import os

# 环境变量 (在 GitHub Secrets 中配置)
LSKY_API = "https://image.mikulab.com/api/v1/images?album_id=5"
LSKY_TOKEN = os.getenv("LSKY_TOKEN")
CF_ACCOUNT_ID = os.getenv("CF_ACCOUNT_ID")
CF_KV_ID = os.getenv("CF_KV_ID")
CF_API_TOKEN = os.getenv("CF_API_TOKEN")

def sync():
    # 1. 获取兰空图床相册数据
    headers = {"Authorization": LSKY_TOKEN, "Accept": "application/json"}
    try:
        response = requests.get(LSKY_API, headers=headers)
        res = response.json()
        
        if res.get('status'):
            # 提取所有图片链接
            urls = [img['links']['url'] for img in res['data']['data']]
            
            # 2. 推送到 Cloudflare KV (Key 为 "images")
            kv_url = f"https://api.cloudflare.com/client/v4/accounts/{CF_ACCOUNT_ID}/storage/kv/namespaces/{CF_KV_ID}/values/images"
            kv_headers = {
                "Authorization": f"Bearer {CF_API_TOKEN}",
                "Content-Type": "text/plain"
            }
            
            put_res = requests.put(kv_url, headers=kv_headers, data=json.dumps(urls))
            if put_res.status_code == 200:
                print(f"同步成功!已同步 {len(urls)} 张图片。")
            else:
                print(f"KV 更新失败: {put_res.text}")
    except Exception as e:
        print(f"运行出错: {e}")

if __name__ == "__main__":
    sync()

随后在Secrets and variables 中选取Actions,创建四个变量:

Secret 名称获取值的方法
LSKY_TOKEN兰空图床 Token(格式:Bearer x|...
CF_ACCOUNT_IDCloudflare 仪表板首页右下角看到的 Account ID
CF_KV_ID KV Namespace 的 ID
CF_API_TOKENCloudflare API Token

多相册版:

import requests
import json
import os

# --- 唯一需要手动维护的地方:在列表里增加相册 ID ---
ALBUM_IDS = [5, 6, 7, 8] 

LSKY_TOKEN = os.getenv("LSKY_TOKEN")
CF_ACCOUNT_ID = os.getenv("CF_ACCOUNT_ID")
CF_KV_ID = os.getenv("CF_KV_ID")
CF_API_TOKEN = os.getenv("CF_API_TOKEN")

def sync():
    headers = {"Authorization": LSKY_TOKEN, "Accept": "application/json"}
    
    for album_id in ALBUM_IDS:
        print(f"正在同步相册 {album_id}...")
        api_url = f"https://image.mikulab.com/api/v1/images?album_id={album_id}"
        
        try:
            res = requests.get(api_url, headers=headers).json()
            if res.get('status'):
                # 提取图片 URL
                urls = [img['links']['url'] for img in res['data']['data']]
                
                # 使用相册 ID 作为 KV 的 Key
                kv_endpoint = f"https://api.cloudflare.com/client/v4/accounts/{CF_ACCOUNT_ID}/storage/kv/namespaces/{CF_KV_ID}/values/{album_id}"
                
                kv_headers = {
                    "Authorization": f"Bearer {CF_API_TOKEN}",
                    "Content-Type": "text/plain"
                }
                
                requests.put(kv_endpoint, headers=kv_headers, data=json.dumps(urls))
                print(f"相册 {album_id} 同步成功,共 {len(urls)} 张图片。")
        except Exception as e:
            print(f"相册 {album_id} 同步失败: {e}")

if __name__ == "__main__":
    sync()

4.配置Github actions定时任务:

在Actions中手动创建文件sync.yml

name: Hourly Sync API Cache

on:
  schedule:
    - cron: '0 * * * *'  # 每小时的第 0 分钟执行一次
  workflow_dispatch:      # 允许你在 GitHub 页面上点击按钮手动执行

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Setup Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10'

      - name: Install Requests
        run: pip install requests

      - name: Run Sync Script
        env:
          LSKY_TOKEN: ${{ secrets.LSKY_TOKEN }}
          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
          CF_KV_ID: ${{ secrets.CF_KV_ID }}
          CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
        run: python sync.py

手动执行Actions,并在CF中绑定自定义域名,如 rdapi1.mikulab.com

默认域名将会随机返回相册5中图片,如需访问其他相册,仅需添加对应相册编号如rdapi1.mikulab.com/6

此作者没有提供个人介绍。
最后更新于 2026-01-23