Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3f7380341 | ||
|
|
6c6ee77067 | ||
|
|
f00aa189e3 | ||
|
|
48ceb87e29 | ||
|
|
cd663d05ca | ||
|
|
a778b0fa8c |
60
.github/workflows/build-docker.yml
vendored
Normal file
60
.github/workflows/build-docker.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Build and Publish Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=sha
|
||||
type=raw,value=latest
|
||||
type=ref,event=branch
|
||||
type=ref,event=tag
|
||||
labels: |
|
||||
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
|
||||
org.opencontainers.image.source=https://github.com/krau/SaveAny-Bot
|
||||
org.opencontainers.image.url=https://github.com/krau/SaveAny-Bot
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 22
|
||||
|
||||
- run: npx changelogithub
|
||||
env:
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM golang:alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.* ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o saveany-bot .
|
||||
|
||||
FROM alpine:latest
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /app/saveany-bot .
|
||||
|
||||
CMD ["./saveany-bot"]
|
||||
25
README.md
25
README.md
@@ -29,6 +29,31 @@ chmod +x saveany-bot
|
||||
./saveany-bot
|
||||
```
|
||||
|
||||
### 添加为 systemd 服务
|
||||
|
||||
创建文件 `/etc/systemd/system/saveany-bot.service` 并写入以下内容:
|
||||
|
||||
```
|
||||
[Unit]
|
||||
Description=SaveAnyBot
|
||||
After=systemd-user-sessions.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/yourpath/
|
||||
ExecStart=/yourpath/saveany-bot
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
设为开机启动并启动服务:
|
||||
|
||||
```bash
|
||||
systemctl enable --now saveany-bot
|
||||
```
|
||||
|
||||
## 更新
|
||||
|
||||
使用 `upgrade` 或 `up` 升级到最新版
|
||||
|
||||
@@ -18,5 +18,5 @@ func Run(_ *cobra.Command, _ []string) {
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
sig := <-quit
|
||||
logger.L.Info(sig, "exit")
|
||||
logger.L.Info(sig, ", exit")
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ package config
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Workers int `toml:"workers" mapstructure:"workers"`
|
||||
Retry int `toml:"retry" mapstructure:"retry"` // Retry times for failed tasks
|
||||
Retry int `toml:"retry" mapstructure:"retry"`
|
||||
|
||||
Temp tempConfig `toml:"temp" mapstructure:"temp"`
|
||||
Log logConfig `toml:"log" mapstructure:"log"`
|
||||
@@ -79,7 +80,12 @@ var Cfg *Config
|
||||
func Init() {
|
||||
viper.SetConfigName("config")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("/etc/saveany/")
|
||||
viper.SetConfigType("toml")
|
||||
viper.SetEnvPrefix("SAVEANY")
|
||||
viper.AutomaticEnv()
|
||||
replacer := strings.NewReplacer(".", "_")
|
||||
viper.SetEnvKeyReplacer(replacer)
|
||||
|
||||
viper.SetDefault("workers", 3)
|
||||
viper.SetDefault("retry", 3)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -86,17 +87,36 @@ func (a *Alist) Init() {
|
||||
go refreshToken(reqClient)
|
||||
}
|
||||
|
||||
type putResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data struct {
|
||||
Task struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
State int `json:"state"`
|
||||
Status string `json:"status"`
|
||||
Progress int `json:"progress"`
|
||||
Error string `json:"error"`
|
||||
} `json:"task"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (a *Alist) Save(ctx context.Context, filePath, storagePath string) error {
|
||||
storagePath = path.Join(basePath, storagePath)
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fileBytes, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := reqClient.R().
|
||||
SetContext(ctx).
|
||||
SetBody(file).
|
||||
SetBodyBytes(fileBytes).
|
||||
SetHeaders(map[string]string{
|
||||
"File-Path": url.PathEscape(storagePath),
|
||||
"File-Path": url.QueryEscape(storagePath),
|
||||
"As-Task": "true",
|
||||
}).Put("/api/fs/put")
|
||||
if err != nil {
|
||||
@@ -105,5 +125,12 @@ func (a *Alist) Save(ctx context.Context, filePath, storagePath string) error {
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("failed to save file to Alist: %s", resp.Status)
|
||||
}
|
||||
var putResp putResponse
|
||||
if err := json.Unmarshal(resp.Bytes(), &putResp); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal put response: %v", err)
|
||||
}
|
||||
if putResp.Code != http.StatusOK {
|
||||
return fmt.Errorf("failed to save file to Alist: %d, %s", putResp.Code, putResp.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user