Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff0beb0f34 | ||
|
|
09a3637b56 | ||
|
|
7d48ea50b4 | ||
|
|
4807b81dd5 | ||
|
|
ffad253390 | ||
|
|
07b7b5b4f7 | ||
|
|
d31b1afb50 | ||
|
|
2d475743f7 | ||
|
|
e21d4773d2 | ||
|
|
4ded242e66 | ||
|
|
a3b8005175 | ||
|
|
90627ac258 | ||
|
|
ecde6c9fdc | ||
|
|
632aa00a3e |
@@ -0,0 +1 @@
|
|||||||
|
.git
|
||||||
+7
-3
@@ -37,15 +37,19 @@ RUN apk add --no-cache py3-opencv
|
|||||||
|
|
||||||
# 预装 PySceneDetect(--no-deps: scenedetect 强依赖 opencv-python 会触发源码编译)
|
# 预装 PySceneDetect(--no-deps: scenedetect 强依赖 opencv-python 会触发源码编译)
|
||||||
# opencv 已由 apk 的 py3-opencv 提供,无需 pip 重复安装
|
# opencv 已由 apk 的 py3-opencv 提供,无需 pip 重复安装
|
||||||
RUN pip3 install --break-system-packages --no-deps -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com scenedetect \
|
# pip 24+ 扫描系统包元数据时崩溃(python-4.10.0 版本号无效)
|
||||||
&& pip3 install --break-system-packages -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com click platformdirs tqdm
|
# 用虚拟环境隔离
|
||||||
|
RUN python3 -m venv --system-site-packages /opt/venv \
|
||||||
|
&& /opt/venv/bin/pip install --no-deps -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com scenedetect \
|
||||||
|
&& /opt/venv/bin/pip install -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com click platformdirs tqdm
|
||||||
|
ENV PATH=/opt/venv/bin:$PATH
|
||||||
|
|
||||||
# 验证 PySceneDetect 安装
|
# 验证 PySceneDetect 安装
|
||||||
RUN python3 -c "import scenedetect; print(f'scenedetect {scenedetect.__version__} installed')"
|
RUN python3 -c "import scenedetect; print(f'scenedetect {scenedetect.__version__} installed')"
|
||||||
|
|
||||||
# 预装 HyperFrames(全局安装)
|
# 预装 HyperFrames(全局安装)
|
||||||
# 使用 npmmirror 镜像加速
|
# 使用 npmmirror 镜像加速
|
||||||
RUN npm install -g hyperframes --registry=https://registry.npmmirror.com/ --ignore-scripts
|
RUN npm install -g hyperframes --ignore-scripts
|
||||||
|
|
||||||
# HyperFrames 渲染需要 Chromium/Chrome
|
# HyperFrames 渲染需要 Chromium/Chrome
|
||||||
# 安装 Chromium(提供系统级共享库依赖)和中文字体
|
# 安装 Chromium(提供系统级共享库依赖)和中文字体
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# 阶段1: 构建
|
||||||
|
FROM golang:alpine AS builder
|
||||||
|
|
||||||
|
RUN apk add --no-cache git ca-certificates tzdata
|
||||||
|
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
ENV GO111MODULE=on
|
||||||
|
ENV GOPROXY=https://goproxy.cn,direct
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
ENV GOTOOLCHAIN=auto
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN go mod download && go mod tidy
|
||||||
|
|
||||||
|
RUN go build -ldflags="-s -w" -o main ./main.go
|
||||||
|
|
||||||
|
|
||||||
|
# 阶段2: 运行时(继承 media-deps 基础镜像)
|
||||||
|
FROM redfuture-media-deps:latest
|
||||||
|
|
||||||
|
# 复制二进制和运行时必需的文件
|
||||||
|
COPY --from=builder /build/main .
|
||||||
|
COPY --from=builder /build/config.yml .
|
||||||
|
COPY --from=builder /build/scripts ./scripts
|
||||||
|
EXPOSE 3010
|
||||||
|
|
||||||
|
CMD ["./main"]
|
||||||
@@ -87,3 +87,8 @@ hyperframes:
|
|||||||
# 是否启用 headless 模式
|
# 是否启用 headless 模式
|
||||||
headless: true
|
headless: true
|
||||||
|
|
||||||
|
# HyperFrames 远程渲染服务配置(独立微服务)
|
||||||
|
hyperframes_service:
|
||||||
|
# 服务地址,留空则使用默认服务名 (http://127.0.0.1:3029)
|
||||||
|
address: "http://127.0.0.1:3029"
|
||||||
|
|
||||||
|
|||||||
@@ -3,43 +3,46 @@ module media
|
|||||||
go 1.26.1
|
go 1.26.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gitea.redpowerfuture.com/red-future/common v0.0.23
|
gitea.redpowerfuture.com/red-future/common v0.0.26
|
||||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2
|
||||||
github.com/gogf/gf/v2 v2.10.2
|
github.com/gogf/gf/v2 v2.10.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
github.com/BurntSushi/toml v1.6.0 // indirect
|
||||||
github.com/armon/go-metrics v0.4.1 // indirect
|
github.com/armon/go-metrics v0.4.1 // indirect
|
||||||
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
github.com/bwmarrin/snowflake v0.3.0 // indirect
|
||||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||||
|
github.com/clipperhouse/displaywidth v0.11.0 // indirect
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
|
||||||
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
|
github.com/dgraph-io/badger/v4 v4.2.0 // indirect
|
||||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.19.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||||
github.com/go-ego/gse v1.0.2 // indirect
|
github.com/go-ego/gse v1.0.2 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.1 // indirect
|
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.6 // indirect
|
||||||
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 // indirect
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 // indirect
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 // indirect
|
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect
|
||||||
github.com/golang/glog v1.2.5 // indirect
|
github.com/golang/glog v1.2.5 // indirect
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/golang/snappy v1.0.0 // indirect
|
github.com/golang/snappy v1.0.0 // indirect
|
||||||
github.com/google/flatbuffers v1.12.1 // indirect
|
github.com/google/btree v1.1.3 // indirect
|
||||||
|
github.com/google/flatbuffers v25.12.19+incompatible // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
|
||||||
github.com/hashicorp/consul/api v1.26.1 // indirect
|
github.com/hashicorp/consul/api v1.33.5 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
github.com/hashicorp/go-hclog v1.5.0 // indirect
|
||||||
@@ -48,42 +51,43 @@ require (
|
|||||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
github.com/hashicorp/serf v0.10.1 // indirect
|
github.com/hashicorp/serf v0.10.1 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.6 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.12.3 // indirect
|
||||||
github.com/magiconair/properties v1.8.10 // indirect
|
github.com/magiconair/properties v1.8.10 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.15 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.22 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.24 // indirect
|
||||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
|
||||||
github.com/olekukonko/errors v1.1.0 // indirect
|
github.com/olekukonko/errors v1.3.0 // indirect
|
||||||
github.com/olekukonko/ll v0.0.9 // indirect
|
github.com/olekukonko/ll v0.1.8 // indirect
|
||||||
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
github.com/olekukonko/tablewriter v1.1.4 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/r3labs/diff/v2 v2.15.1 // indirect
|
github.com/r3labs/diff/v2 v2.15.1 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.12.1 // indirect
|
github.com/redis/go-redis/v9 v9.21.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/tiger1103/gfast-token v1.0.10 // indirect
|
github.com/tiger1103/gfast-token v1.0.10 // indirect
|
||||||
github.com/vcaesar/cedar v0.30.0 // indirect
|
github.com/vcaesar/cedar v0.30.0 // indirect
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
|
||||||
go.mongodb.org/mongo-driver/v2 v2.4.0 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
go.opentelemetry.io/otel v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.44.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
go.opentelemetry.io/otel/trace v1.44.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
golang.org/x/net v0.47.0 // indirect
|
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 // indirect
|
||||||
golang.org/x/sys v0.38.0 // indirect
|
golang.org/x/net v0.56.0 // indirect
|
||||||
golang.org/x/text v0.31.0 // indirect
|
golang.org/x/sys v0.46.0 // indirect
|
||||||
|
golang.org/x/text v0.38.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
|
||||||
google.golang.org/grpc v1.75.0 // indirect
|
google.golang.org/grpc v1.79.3 // indirect
|
||||||
google.golang.org/protobuf v1.36.8 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
gitea.redpowerfuture.com/red-future/common v0.0.23 h1:xieoA00iKOCDm5SO9iXn+cSyMKBAlZwI0fuEVPWrHLg=
|
gitea.redpowerfuture.com/red-future/common v0.0.26 h1:C4V2Y6XbzMRttajoVFlc6MyXBER3fYhg1XOUq2wl9Uo=
|
||||||
gitea.redpowerfuture.com/red-future/common v0.0.23/go.mod h1:50U1Xi+Ie56z09S5LQbZvaken0Mxv3OeS9LgR7U/ZRY=
|
gitea.redpowerfuture.com/red-future/common v0.0.26/go.mod h1:Og3l2TFq10ICcbtc6JRsou17+MsEiXz4m2Ir7A0ODtQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
@@ -36,6 +36,10 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
|
|||||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||||
|
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||||
|
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -47,8 +51,6 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa
|
|||||||
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
@@ -61,10 +63,10 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||||
github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4=
|
github.com/go-ego/gse v1.0.2 h1:+27lYFPhQEhA9igtdOsJPRKYL/k3TwYsxBF5jr6KFv4=
|
||||||
github.com/go-ego/gse v1.0.2/go.mod h1:Fy35G+q7VV7Et1zIKO8o/sW1kkugV3znXap/lF/11zc=
|
github.com/go-ego/gse v1.0.2/go.mod h1:Fy35G+q7VV7Et1zIKO8o/sW1kkugV3znXap/lF/11zc=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
@@ -77,14 +79,16 @@ github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4
|
|||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
|
github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
|
||||||
|
github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 h1:u8EpP24GkprogROnJ7htMov9Fc66pTP1eVYrWxiCYOs=
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2 h1:u8EpP24GkprogROnJ7htMov9Fc66pTP1eVYrWxiCYOs=
|
||||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2/go.mod h1:GmvM3r8GVByVMi4RD2+MCs5+CfxVXPMeT8mVDkAaAXE=
|
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.2/go.mod h1:GmvM3r8GVByVMi4RD2+MCs5+CfxVXPMeT8mVDkAaAXE=
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.1 h1:egobo4YfQX3C4NtrEFunBqMX3jsddagklgut9u91+BM=
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2 h1:iTQegT+lEg/wDKvj2mi3W1wrdrwFarjokf88EXVVgu4=
|
||||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.9.1/go.mod h1:YQ+u5Cs5N2ETCeQaLbv29z/UWYuxw27mJpUkOLj0kJ8=
|
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.2/go.mod h1:ZRw3GNz5cq4uYrW4TPSVyrYWaoqzujKdWro/AOcGBaE=
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5 h1:eUqwJ/qNH8lJ6yssiqskazgp1ACQuNU6zXlLOZVuXTQ=
|
||||||
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
|
github.com/gogf/gf/contrib/registry/consul/v2 v2.9.5/go.mod h1:sjQyMry9+0POYZCA6lHXBxO77WoNKkruJpRB4xKqk5k=
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5 h1:tHUEZYB5GTqEYYVDYnlGobf1xISARKDE4KHVlgjwTec=
|
|
||||||
github.com/gogf/gf/contrib/trace/otlphttp/v2 v2.9.5/go.mod h1:cfzTn2HS9RDX8f5pUVkbGxUWcSosouqfNQ1G6cY0V88=
|
|
||||||
github.com/gogf/gf/v2 v2.10.2 h1:46IO0Uc8e85/FqdftJFskfDejJLBL0JBnGS5qOftUu8=
|
github.com/gogf/gf/v2 v2.10.2 h1:46IO0Uc8e85/FqdftJFskfDejJLBL0JBnGS5qOftUu8=
|
||||||
github.com/gogf/gf/v2 v2.10.2/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
github.com/gogf/gf/v2 v2.10.2/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
@@ -114,10 +118,10 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
|
|||||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
|
||||||
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
|
github.com/google/flatbuffers v25.12.19+incompatible h1:haMV2JRRJCe1998HeW/p0X9UaMTK6SDo0ffLn2+DbLs=
|
||||||
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
github.com/google/flatbuffers v25.12.19+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -134,12 +138,12 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5T
|
|||||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
||||||
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
|
||||||
github.com/hashicorp/consul/api v1.26.1 h1:5oSXOO5fboPZeW5SN+TdGFP/BILDgBm19OrPZ/pICIM=
|
github.com/hashicorp/consul/api v1.33.5 h1:Nn6q87zudRU1rLBTJEgaWxz9STCNadilLCD7B8OA5aI=
|
||||||
github.com/hashicorp/consul/api v1.26.1/go.mod h1:B4sQTeaSO16NtynqrAdwOlahJ7IUDZM9cj2420xYL8A=
|
github.com/hashicorp/consul/api v1.33.5/go.mod h1:pa6fJOSHKLOzNHpUVeqLDtxA5+J1D7NNzLasuk8eRXA=
|
||||||
github.com/hashicorp/consul/sdk v0.15.0 h1:2qK9nDrr4tiJKRoxPGhm6B7xJjLVIQqkjiab2M4aKjU=
|
github.com/hashicorp/consul/sdk v0.17.3 h1:oZMMxzQGSsiT+ToOH50y3Qcs0nc9Ud+7L5lRx+EmMU0=
|
||||||
github.com/hashicorp/consul/sdk v0.15.0/go.mod h1:r/OmRRPbHOe0yxNahLw7G9x5WG17E1BIECMtCjcPSNo=
|
github.com/hashicorp/consul/sdk v0.17.3/go.mod h1:jnOmYjiNfVRpBaujQ1DFFVs0N6g3S1y6wygSjLTzYfc=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
@@ -169,8 +173,8 @@ github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA=
|
||||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
@@ -185,8 +189,10 @@ github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -196,8 +202,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.12.3 h1:tTWxr2YLKwIvK90ZXEw8GP7UFHtcbTtty8zsI+YjrfQ=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.12.3/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA=
|
||||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
@@ -205,39 +211,39 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc
|
|||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
|
github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI=
|
||||||
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
|
github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs=
|
||||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 h1:zrbMGy9YXpIeTnGj4EljqMiZsIcE09mmF8XsD5AYOJc=
|
||||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6/go.mod h1:rEKTHC9roVVicUIfZK7DYrdIoM0EOr8mK1Hj5s3JjH0=
|
||||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
github.com/olekukonko/errors v1.3.0 h1:teJvgLGUEqMzBUms+Dj3/3szNqCG/Jdw9iDbum8fR6U=
|
||||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
github.com/olekukonko/errors v1.3.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||||
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
github.com/olekukonko/ll v0.1.8 h1:ysHCJRGHYKzmBSdz9w5AySztx7lG8SQY+naTGYUbsz8=
|
||||||
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
github.com/olekukonko/ll v0.1.8/go.mod h1:RPRC6UcscfFZgjo1nulkfMH5IM0QAYim0LfnMvUuozw=
|
||||||
|
github.com/olekukonko/tablewriter v1.1.4 h1:ORUMI3dXbMnRlRggJX3+q7OzQFDdvgbN9nVWj1drm6I=
|
||||||
|
github.com/olekukonko/tablewriter v1.1.4/go.mod h1:+kedxuyTtgoZLwif3P1Em4hARJs+mVnzKxmsCL/C5RY=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
@@ -264,13 +270,10 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
|
|||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg=
|
github.com/r3labs/diff/v2 v2.15.1 h1:EOrVqPUzi+njlumoqJwiS/TgGgmZo83619FNDB9xQUg=
|
||||||
github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc=
|
github.com/r3labs/diff/v2 v2.15.1/go.mod h1:I8noH9Fc2fjSaMxqF3G2lhDdC0b+JXCfyx85tWFM9kc=
|
||||||
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
|
github.com/redis/go-redis/v9 v9.21.0 h1:FPBE4hhbAke+TLmcY3WkpbDffJEomdqPn3HYiqAtL9E=
|
||||||
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
github.com/redis/go-redis/v9 v9.21.0/go.mod h1:v/M13XI1PVCDcm01VtPFOADfZtHf8YW3baQf57KlIkA=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
@@ -278,14 +281,18 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
|
github.com/tiger1103/gfast-token v1.0.10 h1:fNiBE/Dq5iTHvTGlCx3DmXa2o4hr0NtumFpffZ39k6s=
|
||||||
@@ -299,28 +306,32 @@ github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaU
|
|||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.4.0 h1:Oq6BmUAAFTzMeh6AonuDlgZMuAuEiUxoAD1koK5MuFo=
|
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
|
||||||
go.mongodb.org/mongo-driver/v2 v2.4.0/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI=
|
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
|
||||||
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
|
go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8=
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
go.mongodb.org/mongo-driver/v2 v2.6.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@@ -329,15 +340,15 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
golang.org/x/exp v0.0.0-20260611194520-c48552f49976 h1:X8Hz2ImujgbmetVuW+w2YkyZChE3cBpZi2P158rTG9M=
|
||||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
golang.org/x/exp v0.0.0-20260611194520-c48552f49976/go.mod h1:vnf4pv9iKZXY58sQE1L86zmNWJ4159e1RkcWiLCkeEY=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -353,8 +364,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||||
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -363,8 +374,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
|
||||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -388,16 +399,15 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE=
|
||||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -407,8 +417,8 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -423,17 +433,17 @@ google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
|
|||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0=
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -443,8 +453,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
|||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ type SubtitleSegment struct {
|
|||||||
|
|
||||||
// SubtitleStyle 字幕样式配置
|
// SubtitleStyle 字幕样式配置
|
||||||
type SubtitleStyle struct {
|
type SubtitleStyle struct {
|
||||||
FontSize int `json:"fontSize" d:"28" dc:"字号(默认28)"`
|
FontSize int `json:"fontSize" d:"48" dc:"字号(默认48)"`
|
||||||
FontColor string `json:"fontColor" d:"#FFFFFF" dc:"字体颜色(默认白色)"`
|
FontColor string `json:"fontColor" d:"#FFFFFF" dc:"字体颜色(默认白色)"`
|
||||||
BgColor *string `json:"bgColor" dc:"背景色,空字符串=透明(默认#000000)。传空字符串 '' 可去掉背景色"`
|
BgColor *string `json:"bgColor" dc:"背景色,空字符串=透明(默认#000000)。传空字符串 '' 可去掉背景色"`
|
||||||
BgOpacity *float64 `json:"bgOpacity" dc:"背景透明度0-1(默认0.6)。传0可使背景完全透明"`
|
BgOpacity *float64 `json:"bgOpacity" dc:"背景透明度0-1(默认0.4)。传0可使背景完全透明"`
|
||||||
X string `json:"x" d:"center" dc:"水平位置:left/center/right或像素值(默认center)"`
|
X string `json:"x" d:"center" dc:"水平位置:left/center/right或像素值(默认center)"`
|
||||||
Y string `json:"y" d:"bottom" dc:"垂直位置:top/center/bottom或像素值(默认bottom)"`
|
Y string `json:"y" d:"65%" dc:"垂直位置:top/center/bottom或像素值或百分比(默认65%)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- 创建字幕任务 ----------
|
// ---------- 创建字幕任务 ----------
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ def detect_scenes(video_path: str, threshold: float) -> list[dict]:
|
|||||||
scenes = []
|
scenes = []
|
||||||
for start, end in scene_list:
|
for start, end in scene_list:
|
||||||
scenes.append({
|
scenes.append({
|
||||||
"start_time": start.seconds,
|
"start_time": start.get_seconds(),
|
||||||
"end_time": end.seconds,
|
"end_time": end.get_seconds(),
|
||||||
})
|
})
|
||||||
return scenes
|
return scenes
|
||||||
|
|
||||||
|
|||||||
@@ -53,8 +53,14 @@ func (s *audioTaskService) Create(ctx context.Context, params *CreateTaskParams)
|
|||||||
params.Threshold = 0.3
|
params.Threshold = 0.3
|
||||||
}
|
}
|
||||||
|
|
||||||
inputBytes, _ := json.Marshal(params.InputData)
|
inputBytes, err := json.Marshal(params.InputData)
|
||||||
fnBytes, _ := json.Marshal(params.FileNames)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("序列化输入数据失败: %v", err)
|
||||||
|
}
|
||||||
|
fnBytes, err := json.Marshal(params.FileNames)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("序列化文件名列表失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
task := &entity.TranscribeTask{
|
task := &entity.TranscribeTask{
|
||||||
@@ -229,18 +235,30 @@ func (s *audioTaskService) callback(ctx context.Context, taskID, status, errMsg,
|
|||||||
DetailList: detailItems,
|
DetailList: detailItems,
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[回调 %s] 序列化payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[回调 %s] 触发回调, 状态=%s, 成功=%d 失败=%d, 错误=%s, 目标=%s",
|
g.Log().Infof(ctx, "[回调 %s] 触发回调, 状态=%s, 成功=%d 失败=%d, 错误=%s, 目标=%s",
|
||||||
taskID, taskInfo.Status, taskInfo.SuccessFiles, taskInfo.FailFiles, errMsg, callbackURL)
|
taskID, taskInfo.Status, taskInfo.SuccessFiles, taskInfo.FailFiles, errMsg, callbackURL)
|
||||||
g.Log().Debugf(ctx, "[回调 %s] 回调载荷长度=%d字节, 明细条数=%d",
|
g.Log().Debugf(ctx, "[回调 %s] 回调载荷长度=%d字节, 明细条数=%d",
|
||||||
taskID, len(body), len(detailItems))
|
taskID, len(body), len(detailItems))
|
||||||
// 透传调用方的用户信息,供回调方 GetUserInfo 从 X-User-Info 头获取
|
// 透传调用方的用户信息,供回调方 GetUserInfo 从 X-User-Info 头获取
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[回调 %s] curl -X POST '%s' -H 'Content-Type: application/json' -H 'X-User-Info: %s' -d '%s'",
|
g.Log().Infof(ctx, "[回调 %s] curl -X POST '%s' -H 'Content-Type: application/json' -H 'X-User-Info: %s' -d '%s'",
|
||||||
taskID, callbackURL, string(userJSON), strings.ReplaceAll(string(body), "'", "'\\''"))
|
taskID, callbackURL, string(userJSON), strings.ReplaceAll(string(body), "'", "'\\''"))
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
req, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("X-User-Info", string(userJSON))
|
req.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
@@ -251,7 +269,11 @@ func (s *audioTaskService) callback(ctx context.Context, taskID, status, errMsg,
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,9 +322,13 @@ func (s *audioTaskService) processSingleVideo(ctx context.Context, taskID, saveP
|
|||||||
|
|
||||||
var scenesJSON string
|
var scenesJSON string
|
||||||
if scenes != nil {
|
if scenes != nil {
|
||||||
sb, _ := json.Marshal(scenes)
|
sb, je := json.Marshal(scenes)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Warningf(ctx, "[任务 %s] 序列化场景信息失败: %v", taskID, je)
|
||||||
|
} else {
|
||||||
scenesJSON = string(sb)
|
scenesJSON = string(sb)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.saveDetail(ctx, taskID, fileIndex, fileName,
|
s.saveDetail(ctx, taskID, fileIndex, fileName,
|
||||||
transRes.Text, scenesJSON, transRes.AudioSize, transRes.AudioDuration, model, language, "")
|
transRes.Text, scenesJSON, transRes.AudioSize, transRes.AudioDuration, model, language, "")
|
||||||
@@ -414,8 +440,12 @@ func enrichDetailsFromResult(resultJSON string, details []dto.TranscribeTaskDeta
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r.FileName == d.FileName {
|
if r.FileName == d.FileName {
|
||||||
sb, _ := json.Marshal(r.Result.Scenes)
|
sb, je := json.Marshal(r.Result.Scenes)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Warningf(context.TODO(), "[回调] 序列化场景信息失败: %v", je)
|
||||||
|
} else {
|
||||||
details[i].Scenes = string(sb)
|
details[i].Scenes = string(sb)
|
||||||
|
}
|
||||||
// 同时补全其他可能缺失的字段
|
// 同时补全其他可能缺失的字段
|
||||||
if d.AudioDuration == "" {
|
if d.AudioDuration == "" {
|
||||||
details[i].AudioDuration = r.Result.AudioDuration
|
details[i].AudioDuration = r.Result.AudioDuration
|
||||||
|
|||||||
@@ -92,7 +92,9 @@ func (s *analysisService) processAsyncTask(user *beans.User, taskID string, vide
|
|||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
errMsg := fmt.Sprintf("视频分析异常: %v", r)
|
errMsg := fmt.Sprintf("视频分析异常: %v", r)
|
||||||
g.Log().Errorf(bgCtx, "[视频分析 %s] %s", taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[视频分析 %s] %s", taskID, errMsg)
|
||||||
analysisDao.AnalysisTask.UpdateError(bgCtx, taskID, errMsg)
|
if err := analysisDao.AnalysisTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[视频分析 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.analysisCallback(bgCtx, taskID, callbackURL)
|
s.analysisCallback(bgCtx, taskID, callbackURL)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -109,7 +111,9 @@ func (s *analysisService) processAsyncTask(user *beans.User, taskID string, vide
|
|||||||
if dlErr != nil {
|
if dlErr != nil {
|
||||||
errMsg := fmt.Sprintf("下载视频失败 %s: %v", videoURL, dlErr)
|
errMsg := fmt.Sprintf("下载视频失败 %s: %v", videoURL, dlErr)
|
||||||
g.Log().Errorf(bgCtx, "[视频分析 %s] %s", taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[视频分析 %s] %s", taskID, errMsg)
|
||||||
analysisDao.AnalysisTaskDetail.UpdateError(bgCtx, taskID, videoURL, errMsg)
|
if err := analysisDao.AnalysisTaskDetail.UpdateError(bgCtx, taskID, videoURL, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[视频分析 %s] 更新明细失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
failedCount++
|
failedCount++
|
||||||
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
||||||
continue
|
continue
|
||||||
@@ -122,7 +126,9 @@ func (s *analysisService) processAsyncTask(user *beans.User, taskID string, vide
|
|||||||
if cpErr != nil {
|
if cpErr != nil {
|
||||||
errMsg := fmt.Sprintf("调用Caption接口失败 %s: %v", videoURL, cpErr)
|
errMsg := fmt.Sprintf("调用Caption接口失败 %s: %v", videoURL, cpErr)
|
||||||
g.Log().Errorf(bgCtx, "[视频分析 %s] %s", taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[视频分析 %s] %s", taskID, errMsg)
|
||||||
analysisDao.AnalysisTaskDetail.UpdateError(bgCtx, taskID, videoURL, errMsg)
|
if err := analysisDao.AnalysisTaskDetail.UpdateError(bgCtx, taskID, videoURL, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[视频分析 %s] 更新明细失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
failedCount++
|
failedCount++
|
||||||
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
||||||
continue
|
continue
|
||||||
@@ -131,7 +137,13 @@ func (s *analysisService) processAsyncTask(user *beans.User, taskID string, vide
|
|||||||
g.Log().Infof(bgCtx, "[视频分析 %s] Caption接口调用成功: %s", taskID, videoURL)
|
g.Log().Infof(bgCtx, "[视频分析 %s] Caption接口调用成功: %s", taskID, videoURL)
|
||||||
|
|
||||||
// 3. 保存结果到数据库(视频不删除,永久保留)
|
// 3. 保存结果到数据库(视频不删除,永久保留)
|
||||||
captionJSON, _ := json.Marshal(captionResult)
|
captionJSON, je := json.Marshal(captionResult)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[视频分析 %s] 序列化结果失败: %v", taskID, je)
|
||||||
|
failedCount++
|
||||||
|
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
||||||
|
continue
|
||||||
|
}
|
||||||
analysisDao.AnalysisTaskDetail.UpdateSuccess(bgCtx, taskID, videoURL, savePath, string(captionJSON))
|
analysisDao.AnalysisTaskDetail.UpdateSuccess(bgCtx, taskID, videoURL, savePath, string(captionJSON))
|
||||||
successCount++
|
successCount++
|
||||||
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
analysisDao.AnalysisTask.UpdateProgress(bgCtx, taskID, successCount, failedCount)
|
||||||
@@ -143,7 +155,10 @@ func (s *analysisService) processAsyncTask(user *beans.User, taskID string, vide
|
|||||||
if failedCount == 0 {
|
if failedCount == 0 {
|
||||||
analysisDao.AnalysisTask.UpdateSuccess(bgCtx, taskID, successCount, failedCount)
|
analysisDao.AnalysisTask.UpdateSuccess(bgCtx, taskID, successCount, failedCount)
|
||||||
} else if successCount == 0 {
|
} else if successCount == 0 {
|
||||||
analysisDao.AnalysisTask.UpdateError(bgCtx, taskID, fmt.Sprintf("所有视频处理失败(共%d个)", len(videoURLs)))
|
g.Log().Errorf(bgCtx, "[视频分析 %s] 所有视频处理失败(共%d个)", taskID, len(videoURLs))
|
||||||
|
if err := analysisDao.AnalysisTask.UpdateError(bgCtx, taskID, fmt.Sprintf("所有视频处理失败(共%d个)", len(videoURLs))); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[视频分析 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
analysisDao.AnalysisTask.UpdateSuccess(bgCtx, taskID, successCount, failedCount)
|
analysisDao.AnalysisTask.UpdateSuccess(bgCtx, taskID, successCount, failedCount)
|
||||||
}
|
}
|
||||||
@@ -355,14 +370,26 @@ func (s *analysisService) analysisCallback(ctx context.Context, taskID, callback
|
|||||||
"results": results,
|
"results": results,
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[视频分析回调 %s] 序列化payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[视频分析回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
g.Log().Infof(ctx, "[视频分析回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
||||||
|
|
||||||
cbReq, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
cbReq, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[视频分析回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
cbReq.Header.Set("Content-Type", "application/json")
|
cbReq.Header.Set("Content-Type", "application/json")
|
||||||
// 透传调用方用户信息
|
// 透传调用方用户信息
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[视频分析回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
cbReq.Header.Set("X-User-Info", string(userJSON))
|
cbReq.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
// 打印 curl 命令方便调试
|
// 打印 curl 命令方便调试
|
||||||
@@ -377,6 +404,10 @@ func (s *analysisService) analysisCallback(ctx context.Context, taskID, callback
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[视频分析回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[视频分析回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[视频分析回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package video
|
package video
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"io"
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -46,8 +48,14 @@ func (s *captionService) CreateAsyncTask(ctx context.Context, videoURLs []string
|
|||||||
subtitles = []dto.SubtitleSegment{}
|
subtitles = []dto.SubtitleSegment{}
|
||||||
}
|
}
|
||||||
|
|
||||||
videoURLsJSON, _ := json.Marshal(videoURLs)
|
videoURLsJSON, err := json.Marshal(videoURLs)
|
||||||
elementsJSON, _ := json.Marshal(elements)
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("序列化视频URL失败: %v", err)
|
||||||
|
}
|
||||||
|
elementsJSON, err := json.Marshal(elements)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("序列化元素失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
taskID := "cap_" + guid.S()
|
taskID := "cap_" + guid.S()
|
||||||
task := &entity.VideoCaptionTask{
|
task := &entity.VideoCaptionTask{
|
||||||
@@ -107,7 +115,10 @@ func (s *captionService) processTask(user *beans.User, taskID string, videoURLs
|
|||||||
}
|
}
|
||||||
if len(videoPaths) < 1 {
|
if len(videoPaths) < 1 {
|
||||||
errMsg := fmt.Sprintf("所有视频下载失败(共%d个)", len(videoURLs))
|
errMsg := fmt.Sprintf("所有视频下载失败(共%d个)", len(videoURLs))
|
||||||
dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[字幕 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[字幕 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL, nil)
|
s.callback(bgCtx, taskID, callbackURL, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -187,17 +198,23 @@ func (s *captionService) processTask(user *beans.User, taskID string, videoURLs
|
|||||||
htmlPath := filepath.Join(projectDir, "index.html")
|
htmlPath := filepath.Join(projectDir, "index.html")
|
||||||
if err := os.WriteFile(htmlPath, []byte(htmlContent), 0644); err != nil {
|
if err := os.WriteFile(htmlPath, []byte(htmlContent), 0644); err != nil {
|
||||||
errMsg := fmt.Sprintf("生成HTML失败: %v", err)
|
errMsg := fmt.Sprintf("生成HTML失败: %v", err)
|
||||||
dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[字幕 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[字幕 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL, nil)
|
s.callback(bgCtx, taskID, callbackURL, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
g.Log().Infof(bgCtx, "[字幕 %s] HTML生成完成: %s", taskID, htmlPath)
|
g.Log().Infof(bgCtx, "[字幕 %s] HTML生成完成: %s", taskID, htmlPath)
|
||||||
|
|
||||||
// 10. 执行 HyperFrames 渲染
|
// 10. 远程渲染:打包项目 → 上传 OSS → 调用 hyperframes-service → 下载结果
|
||||||
outputPath := filepath.Join(projectDir, "output.mp4")
|
outputPath := filepath.Join(projectDir, "hf_output.mp4")
|
||||||
if err := s.runHyperFramesRender(bgCtx, projectDir, outputPath); err != nil {
|
if err := s.renderViaRemoteService(bgCtx, taskID, projectDir, outputPath); err != nil {
|
||||||
errMsg := fmt.Sprintf("视频渲染失败: %v", err)
|
errMsg := fmt.Sprintf("远程渲染失败: %v", err)
|
||||||
dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[字幕 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[字幕 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL, nil)
|
s.callback(bgCtx, taskID, callbackURL, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -206,7 +223,10 @@ func (s *captionService) processTask(user *beans.User, taskID string, videoURLs
|
|||||||
stat, statErr := os.Stat(outputPath)
|
stat, statErr := os.Stat(outputPath)
|
||||||
if statErr != nil {
|
if statErr != nil {
|
||||||
errMsg := fmt.Sprintf("输出文件不存在: %v", statErr)
|
errMsg := fmt.Sprintf("输出文件不存在: %v", statErr)
|
||||||
dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[字幕 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[字幕 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL, nil)
|
s.callback(bgCtx, taskID, callbackURL, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -218,7 +238,11 @@ func (s *captionService) processTask(user *beans.User, taskID string, videoURLs
|
|||||||
uploadCtx := context.WithValue(context.Background(), "user", user)
|
uploadCtx := context.WithValue(context.Background(), "user", user)
|
||||||
uploadRes, uploadErr := uploadToMinIO(uploadCtx, outputPath)
|
uploadRes, uploadErr := uploadToMinIO(uploadCtx, outputPath)
|
||||||
if uploadErr != nil {
|
if uploadErr != nil {
|
||||||
dao.CaptionTask.UpdateError(bgCtx, taskID, fmt.Sprintf("上传失败: %v", uploadErr))
|
errMsg := fmt.Sprintf("上传失败: %v", uploadErr)
|
||||||
|
g.Log().Errorf(bgCtx, "[字幕 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.CaptionTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[字幕 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL, nil)
|
s.callback(bgCtx, taskID, callbackURL, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -244,56 +268,128 @@ func (s *captionService) processTask(user *beans.User, taskID string, videoURLs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// runHyperFramesRender 执行 HyperFrames 渲染
|
// ---------- 远程渲染(通过 hyperframes-service 微服务) ----------
|
||||||
func (s *captionService) runHyperFramesRender(ctx context.Context, projectDir, outputPath string) error {
|
|
||||||
ctxWithTimeout, cancel := context.WithTimeout(ctx, 30*time.Minute)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
// 使用全局 hyperframes 命令(已在 setup 中安装检查)
|
// renderViaRemoteService 通过远程 hyperframes-service 执行渲染
|
||||||
hyperframesPath, lookErr := exec.LookPath("hyperframes")
|
// 流程:打包项目 ZIP → 直接 POST 给 hyperframes-service(multipart)→ 保存返回的 MP4
|
||||||
if lookErr != nil {
|
func (s *captionService) renderViaRemoteService(ctx context.Context, taskID, projectDir, outputPath string) error {
|
||||||
return fmt.Errorf("hyperframes 未安装, 请运行: npm install -g hyperframes")
|
// 1. 打包项目目录为 ZIP
|
||||||
|
zipPath := filepath.Join(projectDir, "project.zip")
|
||||||
|
if err := s.zipProjectDir(projectDir, zipPath); err != nil {
|
||||||
|
return fmt.Errorf("打包项目文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(zipPath)
|
||||||
|
|
||||||
|
// 2. 获取 hyperframes-service 地址
|
||||||
|
serviceAddr := g.Cfg().MustGet(ctx, "hyperframes_service.address", "").String()
|
||||||
|
if serviceAddr == "" {
|
||||||
|
serviceAddr = "http://127.0.0.1:3029"
|
||||||
}
|
}
|
||||||
|
|
||||||
// 直接在工作目录运行 hyperframes render,输出默认 output.mp4
|
// 3. 将 ZIP 作为 multipart 发送到渲染服务(同步渲染)
|
||||||
cmd := exec.CommandContext(ctxWithTimeout, hyperframesPath, "render")
|
var reqBuf bytes.Buffer
|
||||||
cmd.Dir = projectDir
|
mw := multipart.NewWriter(&reqBuf)
|
||||||
cmd.Env = append(os.Environ(),
|
|
||||||
"HYPERFRAMES_HEADLESS=true",
|
|
||||||
"HYPERFRAMES_BROWSER_PATH=/usr/bin/chromium",
|
|
||||||
)
|
|
||||||
|
|
||||||
output, err := cmd.CombinedOutput()
|
fw, err := mw.CreateFormFile("file", "project.zip")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("hyperframes render 失败: %v\n%s", err, string(output))
|
return fmt.Errorf("创建表单文件字段失败: %v", err)
|
||||||
}
|
|
||||||
g.Log().Infof(ctx, "[HyperFrames] render 完成: %s", strings.TrimSpace(string(output)))
|
|
||||||
|
|
||||||
// 查找输出文件:优先 renders/ 目录(HyperFrames 默认输出位置)
|
|
||||||
rendersDir := filepath.Join(projectDir, "renders")
|
|
||||||
if entries, readErr := os.ReadDir(rendersDir); readErr == nil {
|
|
||||||
for _, entry := range entries {
|
|
||||||
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".mp4") {
|
|
||||||
src := filepath.Join(rendersDir, entry.Name())
|
|
||||||
if err := os.Rename(src, outputPath); err != nil {
|
|
||||||
return fmt.Errorf("移动输出文件失败: %v", err)
|
|
||||||
}
|
|
||||||
g.Log().Infof(ctx, "[HyperFrames] 找到输出文件: %s", entry.Name())
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回退:检查 projectDir 下的 output.mp4
|
zipFile, err := os.Open(zipPath)
|
||||||
fallback := filepath.Join(projectDir, "output.mp4")
|
if err != nil {
|
||||||
if _, statErr := os.Stat(fallback); statErr == nil {
|
return fmt.Errorf("打开ZIP文件失败: %v", err)
|
||||||
if err := os.Rename(fallback, outputPath); err != nil {
|
|
||||||
return fmt.Errorf("移动输出文件失败: %v", err)
|
|
||||||
}
|
}
|
||||||
|
if _, err = io.Copy(fw, zipFile); err != nil {
|
||||||
|
zipFile.Close()
|
||||||
|
mw.Close()
|
||||||
|
return fmt.Errorf("写入ZIP内容失败: %v", err)
|
||||||
|
}
|
||||||
|
zipFile.Close()
|
||||||
|
mw.Close()
|
||||||
|
|
||||||
|
g.Log().Infof(ctx, "[字幕 %s] 发送渲染请求, ZIP大小=%d", taskID, reqBuf.Len())
|
||||||
|
|
||||||
|
client := &http.Client{Timeout: 60 * time.Minute}
|
||||||
|
resp, err := client.Post(serviceAddr+"/render", mw.FormDataContentType(), &reqBuf)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("调用渲染服务失败: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return fmt.Errorf("渲染服务返回错误(%d): %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 保存响应体(MP4)到本地
|
||||||
|
outFile, err := os.Create(outputPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("创建输出文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
written, err := io.Copy(outFile, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("保存渲染结果失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Log().Infof(ctx, "[字幕 %s] ✅ 远程渲染完成, 输出=%s (%d bytes)", taskID, outputPath, written)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("未找到输出文件(已在 %s 和 %s 中查找)", rendersDir, fallback)
|
// zipProjectDir 将项目目录打包为 ZIP 文件
|
||||||
|
func (s *captionService) zipProjectDir(sourceDir, targetPath string) error {
|
||||||
|
zipFile, err := os.Create(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("创建ZIP文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer zipFile.Close()
|
||||||
|
|
||||||
|
writer := zip.NewWriter(zipFile)
|
||||||
|
defer writer.Close()
|
||||||
|
|
||||||
|
return filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 跳过 ZIP 文件自身
|
||||||
|
if path == targetPath {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算相对路径
|
||||||
|
relPath, err := filepath.Rel(sourceDir, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.IsDir() {
|
||||||
|
// 跳过空目录(HyperFrames 渲染只需要文件)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
header, err := zip.FileInfoHeader(info)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("创建ZIP头失败: %v", err)
|
||||||
|
}
|
||||||
|
header.Name = relPath
|
||||||
|
header.Method = zip.Deflate
|
||||||
|
|
||||||
|
fw, err := writer.CreateHeader(header)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("创建ZIP条目失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("打开文件失败: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(fw, file)
|
||||||
|
return err
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildHTML 生成 HyperFrames HTML 模板
|
// buildHTML 生成 HyperFrames HTML 模板
|
||||||
@@ -309,7 +405,7 @@ func (s *captionService) buildHTML(taskID, videoPath, audioPath string, elements
|
|||||||
sb.WriteString("* { margin: 0; padding: 0; box-sizing: border-box; }\n")
|
sb.WriteString("* { margin: 0; padding: 0; box-sizing: border-box; }\n")
|
||||||
sb.WriteString(fmt.Sprintf("body { width: %dpx; height: %dpx; overflow: hidden; background: #000; }\n", width, height))
|
sb.WriteString(fmt.Sprintf("body { width: %dpx; height: %dpx; overflow: hidden; background: #000; }\n", width, height))
|
||||||
sb.WriteString(".clip { position: absolute; }\n")
|
sb.WriteString(".clip { position: absolute; }\n")
|
||||||
sb.WriteString(".text-element { font-family: \"Noto Sans SC\", \"Noto Sans CJK SC\", \"PingFang SC\", \"Microsoft YaHei\", Arial, sans-serif; text-align: center; display: flex; align-items: center; justify-content: center; white-space: pre-wrap; word-break: break-word; }\n")
|
sb.WriteString(".text-element { font-family: Arial, Helvetica, sans-serif; text-align: center; display: flex; align-items: center; justify-content: center; white-space: pre-wrap; word-break: break-word; }\n")
|
||||||
sb.WriteString("@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n")
|
sb.WriteString("@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n")
|
||||||
sb.WriteString("@keyframes slideUp { from { opacity: 0; transform: translateY(40px); } to { opacity: 1; transform: translateY(0); } }\n")
|
sb.WriteString("@keyframes slideUp { from { opacity: 0; transform: translateY(40px); } to { opacity: 1; transform: translateY(0); } }\n")
|
||||||
sb.WriteString("@keyframes slideLeft { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: translateX(0); } }\n")
|
sb.WriteString("@keyframes slideLeft { from { opacity: 0; transform: translateX(40px); } to { opacity: 1; transform: translateX(0); } }\n")
|
||||||
@@ -321,7 +417,6 @@ func (s *captionService) buildHTML(taskID, videoPath, audioPath string, elements
|
|||||||
sb.WriteString(".anim-scaleIn { animation: scaleIn 0.5s ease-out; }\n")
|
sb.WriteString(".anim-scaleIn { animation: scaleIn 0.5s ease-out; }\n")
|
||||||
sb.WriteString(".anim-pulse { animation: pulse 1.5s ease-in-out infinite; }\n")
|
sb.WriteString(".anim-pulse { animation: pulse 1.5s ease-in-out infinite; }\n")
|
||||||
sb.WriteString("</style>\n")
|
sb.WriteString("</style>\n")
|
||||||
sb.WriteString("<link href=\"https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;700&display=swap\" rel=\"stylesheet\">\n")
|
|
||||||
sb.WriteString("<script src=\"https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js\"></script>\n")
|
sb.WriteString("<script src=\"https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js\"></script>\n")
|
||||||
sb.WriteString("</head>\n<body>\n")
|
sb.WriteString("</head>\n<body>\n")
|
||||||
|
|
||||||
@@ -367,15 +462,22 @@ func (s *captionService) buildHTML(taskID, videoPath, audioPath string, elements
|
|||||||
elemID, animClass, elem.StartTime, elemDuration, trackIdx, html.EscapeString(elem.ImageURL), imgStyle))
|
elemID, animClass, elem.StartTime, elemDuration, trackIdx, html.EscapeString(elem.ImageURL), imgStyle))
|
||||||
} else {
|
} else {
|
||||||
bgStyle := ""
|
bgStyle := ""
|
||||||
|
hasBg := false
|
||||||
if elem.BgColor != "" {
|
if elem.BgColor != "" {
|
||||||
|
hasBg = true
|
||||||
if elem.BgOpacity > 0 && elem.BgOpacity < 1 {
|
if elem.BgOpacity > 0 && elem.BgOpacity < 1 {
|
||||||
bgStyle = fmt.Sprintf("background:%s;padding:12px 24px;border-radius:8px;", hexToRGBA(elem.BgColor, elem.BgOpacity))
|
bgStyle = fmt.Sprintf("background:%s;padding:12px 24px;border-radius:8px;", hexToRGBA(elem.BgColor, elem.BgOpacity))
|
||||||
} else {
|
} else {
|
||||||
bgStyle = fmt.Sprintf("background:%s;padding:12px 24px;border-radius:8px;", elem.BgColor)
|
bgStyle = fmt.Sprintf("background:%s;padding:12px 24px;border-radius:8px;", elem.BgColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.WriteString(fmt.Sprintf(" <div id=\"%s\" class=\"clip text-element %s\" data-start=\"%.3f\" data-duration=\"%.3f\" data-track-index=\"%d\" style=\"%s%s\">%s</div>\n",
|
if hasBg {
|
||||||
|
sb.WriteString(fmt.Sprintf(" <div id=\"%s\" class=\"clip text-element %s\" data-start=\"%.3f\" data-duration=\"%.3f\" data-track-index=\"%d\" style=\"%s\"><span style=\"%s\">%s</span></div>\n",
|
||||||
elemID, animClass, elem.StartTime, elemDuration, trackIdx, style, bgStyle, html.EscapeString(elem.Text)))
|
elemID, animClass, elem.StartTime, elemDuration, trackIdx, style, bgStyle, html.EscapeString(elem.Text)))
|
||||||
|
} else {
|
||||||
|
sb.WriteString(fmt.Sprintf(" <div id=\"%s\" class=\"clip text-element %s\" data-start=\"%.3f\" data-duration=\"%.3f\" data-track-index=\"%d\" style=\"%s\">%s</div>\n",
|
||||||
|
elemID, animClass, elem.StartTime, elemDuration, trackIdx, style, html.EscapeString(elem.Text)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
clipIndex++
|
clipIndex++
|
||||||
}
|
}
|
||||||
@@ -464,6 +566,7 @@ func (s *captionService) buildElemStyle(elem dto.CaptionElement, canvasWidth, ca
|
|||||||
maxWidthPct = 90
|
maxWidthPct = 90
|
||||||
}
|
}
|
||||||
maxWidth := int(float64(canvasWidth) * float64(maxWidthPct) / 100.0)
|
maxWidth := int(float64(canvasWidth) * float64(maxWidthPct) / 100.0)
|
||||||
|
parts = append(parts, fmt.Sprintf("width:%dpx;", maxWidth))
|
||||||
parts = append(parts, fmt.Sprintf("max-width:%dpx;", maxWidth))
|
parts = append(parts, fmt.Sprintf("max-width:%dpx;", maxWidth))
|
||||||
|
|
||||||
if elem.FontSize > 0 {
|
if elem.FontSize > 0 {
|
||||||
@@ -705,10 +808,10 @@ func hexToRGBA(hex string, alpha float64) string {
|
|||||||
// subtitlesToElements 将外部传入的字幕时间线转为底部字幕元素
|
// subtitlesToElements 将外部传入的字幕时间线转为底部字幕元素
|
||||||
func subtitlesToElements(subtitles []dto.SubtitleSegment, style *dto.SubtitleStyle) []dto.CaptionElement {
|
func subtitlesToElements(subtitles []dto.SubtitleSegment, style *dto.SubtitleStyle) []dto.CaptionElement {
|
||||||
// 应用默认值
|
// 应用默认值
|
||||||
fontSize := 28
|
fontSize := 48
|
||||||
fontColor := "#FFFFFF"
|
fontColor := "#FFFFFF"
|
||||||
bgColor := "#000000"
|
bgColor := "#000000"
|
||||||
bgOpacity := 0.6
|
bgOpacity := 0.4
|
||||||
if style != nil {
|
if style != nil {
|
||||||
if style.FontSize > 0 {
|
if style.FontSize > 0 {
|
||||||
fontSize = style.FontSize
|
fontSize = style.FontSize
|
||||||
@@ -729,7 +832,7 @@ func subtitlesToElements(subtitles []dto.SubtitleSegment, style *dto.SubtitleSty
|
|||||||
|
|
||||||
// 从样式配置中读取字幕位置
|
// 从样式配置中读取字幕位置
|
||||||
subtitleX := "center"
|
subtitleX := "center"
|
||||||
subtitleY := "bottom"
|
subtitleY := "65%"
|
||||||
if style != nil {
|
if style != nil {
|
||||||
if style.X != "" {
|
if style.X != "" {
|
||||||
subtitleX = style.X
|
subtitleX = style.X
|
||||||
@@ -812,13 +915,25 @@ func (s *captionService) callback(ctx context.Context, taskID, callbackURL strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[字幕回调 %s] 序列化回调payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[字幕回调 %s] 状态=%s, 目标=%s, body=%s", taskID, task.Status, callbackURL, string(body))
|
g.Log().Infof(ctx, "[字幕回调 %s] 状态=%s, 目标=%s, body=%s", taskID, task.Status, callbackURL, string(body))
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
req, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[字幕回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[字幕回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("X-User-Info", string(userJSON))
|
req.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
client := &http.Client{Timeout: 2 * time.Minute}
|
client := &http.Client{Timeout: 2 * time.Minute}
|
||||||
@@ -828,7 +943,11 @@ func (s *captionService) callback(ctx context.Context, taskID, callbackURL strin
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[字幕回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[字幕回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[字幕回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -702,14 +702,26 @@ func (s *concatService) concatCallback(ctx context.Context, taskID, callbackURL
|
|||||||
payload["errorMessage"] = task.ErrorMessage
|
payload["errorMessage"] = task.ErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步拼接回调 %s] 序列化payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[异步拼接回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
g.Log().Infof(ctx, "[异步拼接回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
req, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步拼接回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
// 透传调用方用户信息
|
// 透传调用方用户信息
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步拼接回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("X-User-Info", string(userJSON))
|
req.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
client := &http.Client{Timeout: 2 * time.Minute}
|
client := &http.Client{Timeout: 2 * time.Minute}
|
||||||
@@ -719,7 +731,11 @@ func (s *concatService) concatCallback(ctx context.Context, taskID, callbackURL
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步拼接回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[异步拼接回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[异步拼接回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -757,7 +773,10 @@ func downloadFile(ctx context.Context, rawURL, tempDir string) (string, error) {
|
|||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
// 读取响应体用于错误诊断
|
// 读取响应体用于错误诊断
|
||||||
bodyBytes, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
|
bodyBytes, readErr := io.ReadAll(io.LimitReader(resp.Body, 1024))
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Warningf(ctx, "[下载] 读取HTTP错误响应失败: %v", readErr)
|
||||||
|
}
|
||||||
// 尝试检测签名 URL 是否过期
|
// 尝试检测签名 URL 是否过期
|
||||||
if parsedURL.Query().Get("x-expires") != "" || parsedURL.Query().Get("expires") != "" {
|
if parsedURL.Query().Get("x-expires") != "" || parsedURL.Query().Get("expires") != "" {
|
||||||
return "", fmt.Errorf("HTTP %d (签名URL可能已过期,请使用新鲜地址) body=%s", resp.StatusCode, string(bodyBytes))
|
return "", fmt.Errorf("HTTP %d (签名URL可能已过期,请使用新鲜地址) body=%s", resp.StatusCode, string(bodyBytes))
|
||||||
@@ -765,16 +784,23 @@ func downloadFile(ctx context.Context, rawURL, tempDir string) (string, error) {
|
|||||||
return "", fmt.Errorf("HTTP %d body=%s", resp.StatusCode, string(bodyBytes))
|
return "", fmt.Errorf("HTTP %d body=%s", resp.StatusCode, string(bodyBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedSize := resp.ContentLength
|
||||||
out, err := os.Create(savePath)
|
out, err := os.Create(savePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer out.Close()
|
defer out.Close()
|
||||||
|
|
||||||
_, err = io.Copy(out, resp.Body)
|
written, err := io.Copy(out, resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Remove(savePath)
|
os.Remove(savePath)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 验证下载完整性:检查文件大小是否匹配 Content-Length
|
||||||
|
if expectedSize > 0 && written != expectedSize {
|
||||||
|
os.Remove(savePath)
|
||||||
|
return "", fmt.Errorf("下载不完整: 期望 %d 字节, 实际 %d 字节", expectedSize, written)
|
||||||
|
}
|
||||||
return savePath, nil
|
return savePath, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -442,9 +442,13 @@ func (s *cutService) UploadToMinIO(ctx context.Context, localFilePath string) (*
|
|||||||
// 无 HTTP 请求时(异步 goroutine),从 context 的用户信息构造 header
|
// 无 HTTP 请求时(异步 goroutine),从 context 的用户信息构造 header
|
||||||
if !hasAuthHeader {
|
if !hasAuthHeader {
|
||||||
uploadUser := getUserFromCtx(ctx)
|
uploadUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(uploadUser)
|
userJSON, je := json.Marshal(uploadUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[UploadToMinIO] 序列化用户信息失败: %v", je)
|
||||||
|
} else {
|
||||||
client.SetHeader("X-User-Info", string(userJSON))
|
client.SetHeader("X-User-Info", string(userJSON))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 设置 multipart Content-Type(含 boundary)
|
// 设置 multipart Content-Type(含 boundary)
|
||||||
contentType := mw.FormDataContentType()
|
contentType := mw.FormDataContentType()
|
||||||
@@ -568,7 +572,10 @@ func (s *cutService) processAsyncTask(user *beans.User, taskID string, videoURL
|
|||||||
savePath, dlErr := downloadFile(bgCtx, videoURL, tempDir)
|
savePath, dlErr := downloadFile(bgCtx, videoURL, tempDir)
|
||||||
if dlErr != nil {
|
if dlErr != nil {
|
||||||
errMsg := fmt.Sprintf("下载视频失败: %v", dlErr)
|
errMsg := fmt.Sprintf("下载视频失败: %v", dlErr)
|
||||||
dao.CutTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[异步剪切 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.CutTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[异步剪切 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.cutCallback(bgCtx, taskID, callbackURL)
|
s.cutCallback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -577,7 +584,10 @@ func (s *cutService) processAsyncTask(user *beans.User, taskID string, videoURL
|
|||||||
// 执行剪切
|
// 执行剪切
|
||||||
cutErr := s.executeCut(bgCtx, taskID, savePath, shots, upload)
|
cutErr := s.executeCut(bgCtx, taskID, savePath, shots, upload)
|
||||||
if cutErr != nil {
|
if cutErr != nil {
|
||||||
dao.CutTask.UpdateError(bgCtx, taskID, cutErr.Error())
|
g.Log().Errorf(bgCtx, "[异步剪切 %s] %v", taskID, cutErr)
|
||||||
|
if err := dao.CutTask.UpdateError(bgCtx, taskID, cutErr.Error()); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[异步剪切 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.cutCallback(bgCtx, taskID, callbackURL)
|
s.cutCallback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -644,14 +654,26 @@ func (s *cutService) cutCallback(ctx context.Context, taskID, callbackURL string
|
|||||||
payload["errorMessage"] = task.ErrorMessage
|
payload["errorMessage"] = task.ErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步剪切回调 %s] 序列化payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[异步剪切回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
g.Log().Infof(ctx, "[异步剪切回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
req, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步剪切回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
// 透传调用方用户信息
|
// 透传调用方用户信息
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步剪切回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("X-User-Info", string(userJSON))
|
req.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
client := &http.Client{Timeout: 2 * time.Minute}
|
client := &http.Client{Timeout: 2 * time.Minute}
|
||||||
@@ -661,6 +683,10 @@ func (s *cutService) cutCallback(ctx context.Context, taskID, callbackURL string
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[异步剪切回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[异步剪切回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[异步剪切回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,8 +47,14 @@ func (s *mergeService) CreateAsyncTask(ctx context.Context, videoURLs, audioURLs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将 videoURLs/audioURLs 序列化为 JSON 存入数据库
|
// 将 videoURLs/audioURLs 序列化为 JSON 存入数据库
|
||||||
videoURLsJSON, _ := json.Marshal(videoURLs)
|
videoURLsJSON, err := json.Marshal(videoURLs)
|
||||||
audioURLsJSON, _ := json.Marshal(audioURLs)
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("序列化视频URL失败: %v", err)
|
||||||
|
}
|
||||||
|
audioURLsJSON, err := json.Marshal(audioURLs)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("序列化音频URL失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
taskID := "merge_" + guid.S()
|
taskID := "merge_" + guid.S()
|
||||||
task := &entity.VideoAudioMergeTask{
|
task := &entity.VideoAudioMergeTask{
|
||||||
@@ -85,7 +91,9 @@ func (s *mergeService) processAsyncTask(user *beans.User, taskID string, videoUR
|
|||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
errMsg := fmt.Sprintf("异步拼接混音异常: %v", r)
|
errMsg := fmt.Sprintf("异步拼接混音异常: %v", r)
|
||||||
g.Log().Errorf(bgCtx, "[拼接混音 %s] %s", taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] %s", taskID, errMsg)
|
||||||
dao.MergeTask.UpdateError(bgCtx, taskID, errMsg)
|
if err := dao.MergeTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -106,7 +114,10 @@ func (s *mergeService) processAsyncTask(user *beans.User, taskID string, videoUR
|
|||||||
|
|
||||||
if len(videoPaths) < 1 {
|
if len(videoPaths) < 1 {
|
||||||
errMsg := fmt.Sprintf("所有视频下载失败(共%d个)", len(videoURLs))
|
errMsg := fmt.Sprintf("所有视频下载失败(共%d个)", len(videoURLs))
|
||||||
dao.MergeTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.MergeTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
cleanupFiles(videoPaths)
|
cleanupFiles(videoPaths)
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
@@ -125,7 +136,10 @@ func (s *mergeService) processAsyncTask(user *beans.User, taskID string, videoUR
|
|||||||
|
|
||||||
if len(audioPaths) < 1 {
|
if len(audioPaths) < 1 {
|
||||||
errMsg := fmt.Sprintf("所有音频下载失败(共%d个)", len(audioURLs))
|
errMsg := fmt.Sprintf("所有音频下载失败(共%d个)", len(audioURLs))
|
||||||
dao.MergeTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.MergeTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
cleanupFiles(videoPaths)
|
cleanupFiles(videoPaths)
|
||||||
cleanupFiles(audioPaths)
|
cleanupFiles(audioPaths)
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
@@ -141,7 +155,10 @@ func (s *mergeService) processAsyncTask(user *beans.User, taskID string, videoUR
|
|||||||
cleanupFiles(audioPaths)
|
cleanupFiles(audioPaths)
|
||||||
|
|
||||||
if mergeErr != nil {
|
if mergeErr != nil {
|
||||||
dao.MergeTask.UpdateError(bgCtx, taskID, mergeErr.Error())
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] %v", taskID, mergeErr)
|
||||||
|
if err := dao.MergeTask.UpdateError(bgCtx, taskID, mergeErr.Error()); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[拼接混音 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -303,13 +320,25 @@ func (s *mergeService) callback(ctx context.Context, taskID, callbackURL string)
|
|||||||
payload["errorMessage"] = task.ErrorMessage
|
payload["errorMessage"] = task.ErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[拼接混音回调 %s] 序列化payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[拼接混音回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
g.Log().Infof(ctx, "[拼接混音回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
req, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[拼接混音回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[拼接混音回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("X-User-Info", string(userJSON))
|
req.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
client := &http.Client{Timeout: 2 * time.Minute}
|
client := &http.Client{Timeout: 2 * time.Minute}
|
||||||
@@ -319,7 +348,11 @@ func (s *mergeService) callback(ctx context.Context, taskID, callbackURL string)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[拼接混音回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[拼接混音回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[拼接混音回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,9 +395,13 @@ func uploadToMinIO(ctx context.Context, localFilePath string) (*uploadFileRes, e
|
|||||||
}
|
}
|
||||||
if !hasAuthHeader {
|
if !hasAuthHeader {
|
||||||
uploadUser := getUserFromCtx(ctx)
|
uploadUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(uploadUser)
|
userJSON, je := json.Marshal(uploadUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[上传MinIO] 序列化用户信息失败: %v", je)
|
||||||
|
} else {
|
||||||
client.SetHeader("X-User-Info", string(userJSON))
|
client.SetHeader("X-User-Info", string(userJSON))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
contentType := mw.FormDataContentType()
|
contentType := mw.FormDataContentType()
|
||||||
client.SetHeader("Content-Type", contentType)
|
client.SetHeader("Content-Type", contentType)
|
||||||
|
|||||||
@@ -82,7 +82,10 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
videoPath, dlErr := downloadFile(bgCtx, videoURL, workDir)
|
videoPath, dlErr := downloadFile(bgCtx, videoURL, workDir)
|
||||||
if dlErr != nil {
|
if dlErr != nil {
|
||||||
errMsg := fmt.Sprintf("视频下载失败: %v", dlErr)
|
errMsg := fmt.Sprintf("视频下载失败: %v", dlErr)
|
||||||
dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[场景分割 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -105,7 +108,10 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
scenesJSONPath := filepath.Join(workDir, "scenes.json")
|
scenesJSONPath := filepath.Join(workDir, "scenes.json")
|
||||||
if err := s.detectScenes(bgCtx, videoPath, scenesJSONPath, threshold); err != nil {
|
if err := s.detectScenes(bgCtx, videoPath, scenesJSONPath, threshold); err != nil {
|
||||||
errMsg := fmt.Sprintf("场景检测失败: %v", err)
|
errMsg := fmt.Sprintf("场景检测失败: %v", err)
|
||||||
dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[场景分割 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -114,7 +120,10 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
scenes, parseErr := s.parseScenes(scenesJSONPath)
|
scenes, parseErr := s.parseScenes(scenesJSONPath)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
errMsg := fmt.Sprintf("解析场景结果失败: %v", parseErr)
|
errMsg := fmt.Sprintf("解析场景结果失败: %v", parseErr)
|
||||||
dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[场景分割 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -122,7 +131,10 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
|
|
||||||
if len(scenes) == 0 {
|
if len(scenes) == 0 {
|
||||||
errMsg := "未检测到任何场景"
|
errMsg := "未检测到任何场景"
|
||||||
dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[场景分割 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -132,7 +144,10 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
results, splitErr := s.splitVideo(bgCtx, videoPath, scenes, workDir, taskID)
|
results, splitErr := s.splitVideo(bgCtx, videoPath, scenes, workDir, taskID)
|
||||||
if splitErr != nil {
|
if splitErr != nil {
|
||||||
errMsg := fmt.Sprintf("视频分割失败: %v", splitErr)
|
errMsg := fmt.Sprintf("视频分割失败: %v", splitErr)
|
||||||
dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[场景分割 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -146,7 +161,10 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
uploadRes, uploadErr := uploadToMinIO(uploadCtx, r.Path)
|
uploadRes, uploadErr := uploadToMinIO(uploadCtx, r.Path)
|
||||||
if uploadErr != nil {
|
if uploadErr != nil {
|
||||||
errMsg := fmt.Sprintf("上传分片%d(%s)到MinIO失败: %v", i+1, r.Timeline, uploadErr)
|
errMsg := fmt.Sprintf("上传分片%d(%s)到MinIO失败: %v", i+1, r.Timeline, uploadErr)
|
||||||
dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg)
|
g.Log().Errorf(bgCtx, "[场景分割 %s] %s", taskID, errMsg)
|
||||||
|
if err := dao.SceneSplitTask.UpdateError(bgCtx, taskID, errMsg); err != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 更新失败状态到数据库出错: %v", taskID, err)
|
||||||
|
}
|
||||||
s.callback(bgCtx, taskID, callbackURL)
|
s.callback(bgCtx, taskID, callbackURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -172,8 +190,12 @@ func (s *sceneSplitService) processTask(user *beans.User, taskID, videoURL strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 9. 更新数据库为成功
|
// 9. 更新数据库为成功
|
||||||
segmentsJSON, _ := json.Marshal(segments)
|
segmentsJSON, je := json.Marshal(segments)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(bgCtx, "[场景分割 %s] 序列化分片信息失败: %v", taskID, je)
|
||||||
|
} else {
|
||||||
dao.SceneSplitTask.UpdateSuccess(bgCtx, taskID, string(segmentsJSON), audioURL, len(segments), audioDuration, videoDuration)
|
dao.SceneSplitTask.UpdateSuccess(bgCtx, taskID, string(segmentsJSON), audioURL, len(segments), audioDuration, videoDuration)
|
||||||
|
}
|
||||||
|
|
||||||
g.Log().Infof(bgCtx, "[场景分割 %s] 完成! 分片数=%d, 音频=%s", taskID, len(segments), audioURL)
|
g.Log().Infof(bgCtx, "[场景分割 %s] 完成! 分片数=%d, 音频=%s", taskID, len(segments), audioURL)
|
||||||
|
|
||||||
@@ -409,15 +431,27 @@ func (s *sceneSplitService) callback(ctx context.Context, taskID, callbackURL st
|
|||||||
payload["errorMessage"] = task.ErrorMessage
|
payload["errorMessage"] = task.ErrorMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
body, _ := json.Marshal(payload)
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
g.Log().Errorf(ctx, "[场景分割回调 %s] 序列化payload失败: %v", taskID, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
cbUser := getUserFromCtx(ctx)
|
cbUser := getUserFromCtx(ctx)
|
||||||
userJSON, _ := json.Marshal(cbUser)
|
userJSON, je := json.Marshal(cbUser)
|
||||||
|
if je != nil {
|
||||||
|
g.Log().Errorf(ctx, "[场景分割回调 %s] 序列化用户信息失败: %v", taskID, je)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
g.Log().Infof(ctx, "[场景分割回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
g.Log().Infof(ctx, "[场景分割回调 %s] 状态=%s, 目标=%s", taskID, task.Status, callbackURL)
|
||||||
g.Log().Infof(ctx, "[场景分割回调 %s] curl: curl -X POST '%s' -H 'Content-Type: application/json' -H 'X-User-Info: %s' -d '%s'",
|
g.Log().Infof(ctx, "[场景分割回调 %s] curl: curl -X POST '%s' -H 'Content-Type: application/json' -H 'X-User-Info: %s' -d '%s'",
|
||||||
taskID, callbackURL, string(userJSON), string(body))
|
taskID, callbackURL, string(userJSON), string(body))
|
||||||
|
|
||||||
req, _ := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
req, reqErr := http.NewRequest("POST", callbackURL, bytes.NewReader(body))
|
||||||
|
if reqErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[场景分割回调 %s] 创建请求失败: %v", taskID, reqErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("X-User-Info", string(userJSON))
|
req.Header.Set("X-User-Info", string(userJSON))
|
||||||
|
|
||||||
@@ -428,6 +462,10 @@ func (s *sceneSplitService) callback(ctx context.Context, taskID, callbackURL st
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
respBody, _ := io.ReadAll(resp.Body)
|
respBody, readErr := io.ReadAll(resp.Body)
|
||||||
|
if readErr != nil {
|
||||||
|
g.Log().Errorf(ctx, "[场景分割回调 %s] 读取响应失败: %v", taskID, readErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
g.Log().Infof(ctx, "[场景分割回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
g.Log().Infof(ctx, "[场景分割回调 %s] 响应 status=%d, body=%s", taskID, resp.StatusCode, string(respBody))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user