feat: 断点续传与色情识别提速/修复,支持 Linux 交叉编译
- feat: 新增续传表 scan_log,重扫跳过已归类文件(尺寸/头尾指纹校验) - fix: 色情识别记录批量入库超 SQLite 999 变量上限,改每 100 条一批 - perf: NudeNet 检测改为多线程推理池(每线程独立模型实例) - perf: 明暗分析 JPEG(YCbCr) 快路径;SQLite 读并发放开;加阶段耗时统计 - fix: 前端色情识别状态由后端如实上报(配置开关+检测服务是否起来) - feat: ffprobe 内嵌按平台拆分,Linux 构建回退系统 ffprobe,支持交叉编译 - docs: README 补充断点续传与 CentOS 交叉编译步骤 - chore: organize.workers 默认 8
This commit is contained in:
@@ -152,6 +152,23 @@ func analyzeBrightness(img image.Image) (darkScore float64, lightScore float64)
|
||||
offset++
|
||||
}
|
||||
}
|
||||
case *image.YCbCr:
|
||||
// JPEG 解码出来是 YCbCr:Y 平面就是亮度,直接翻数组。
|
||||
// 这是最常见的照片格式,走这分支能避开 default 里逐像素 img.At().RGBA() 的慢路径。
|
||||
pix := m.Y
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
offset := y*m.YStride + bounds.Min.X
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
v := float64(pix[offset])
|
||||
if v < 80 {
|
||||
darkCount++
|
||||
} else if v > 175 {
|
||||
lightCount++
|
||||
}
|
||||
sampleCount++
|
||||
offset++
|
||||
}
|
||||
}
|
||||
default:
|
||||
// 其他格式:用通用的读法
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
|
||||
@@ -3,15 +3,24 @@ package probe
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// FFprobeExeName 释放出来的解码器文件名。程序启动时扫到它要跳过,
|
||||
// 免得把自己人(ffprobe)当成媒体文件收走了。
|
||||
// 只在 Windows(有内嵌 ffprobe.exe)时才会真正释放出来。
|
||||
const FFprobeExeName = "ffprobe.exe"
|
||||
|
||||
// FFprobePath 返回当前目录下 ffprobe 的完整路径。
|
||||
// systemFFprobe 回退用的系统 ffprobe 路径(非 Windows 平台、没有内嵌时启用)。
|
||||
var systemFFprobe string
|
||||
|
||||
// FFprobePath 返回当前要用的 ffprobe 完整路径:
|
||||
// 有内嵌就先释放到当前目录用内嵌的;没有内嵌则用系统 PATH 里的那个。
|
||||
func FFprobePath() string {
|
||||
return "." + string(os.PathSeparator) + FFprobeExeName
|
||||
if len(embeddedFFprobe) > 0 {
|
||||
return "." + string(os.PathSeparator) + FFprobeExeName
|
||||
}
|
||||
return systemFFprobe
|
||||
}
|
||||
|
||||
// HasEmbeddedFFprobe 当前编译出的程序里有没有内嵌 ffprobe。
|
||||
@@ -20,15 +29,23 @@ func HasEmbeddedFFprobe() bool {
|
||||
return len(embeddedFFprobe) > 0
|
||||
}
|
||||
|
||||
// ReleaseFFprobe 把内嵌的 ffprobe 释放(写)到当前目录,才能当程序调用它。
|
||||
// ReleaseFFprobe 准备出一个可用的 ffprobe:
|
||||
// - 有内嵌 → 释放(写)到当前目录,才能当程序调用它;
|
||||
// - 没有内嵌(如 Linux 构建)→ 找系统 PATH 里的 ffprobe(如 /usr/bin/ffprobe)。
|
||||
//
|
||||
// 两者都拿不到才报错:调用方会跳过视频/音频整理,图片照常处理。
|
||||
func ReleaseFFprobe() error {
|
||||
if len(embeddedFFprobe) == 0 {
|
||||
return fmt.Errorf("当前系统没有内嵌的ffprobe")
|
||||
if len(embeddedFFprobe) > 0 {
|
||||
return os.WriteFile(FFprobeExeName, embeddedFFprobe, 0777)
|
||||
}
|
||||
return os.WriteFile(FFprobeExeName, embeddedFFprobe, 0777)
|
||||
if p, err := exec.LookPath("ffprobe"); err == nil {
|
||||
systemFFprobe = p
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("没有内嵌 ffprobe,系统 PATH 里也找不到 ffprobe(Linux 请先安装 ffmpeg)")
|
||||
}
|
||||
|
||||
// RemoveFFprobe 整理完把临时释放的 ffprobe 删掉,不留在目录里。
|
||||
func RemoveFFprobe() {
|
||||
_ = os.Remove(FFprobeExeName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
//go:build !windows
|
||||
|
||||
package probe
|
||||
|
||||
// 非 Windows 平台不在二进制里内嵌 ffprobe(仓库只带了 Windows 版)。
|
||||
// 运行时回退用系统 PATH 里的 ffprobe:如 CentOS 上 yum install ffmpeg 后
|
||||
// 就有 /usr/bin/ffprobe。找不到系统 ffprobe 时,视频/音频整理自动跳过,图片照常。
|
||||
var embeddedFFprobe []byte
|
||||
@@ -1,6 +1,8 @@
|
||||
//go:build windows
|
||||
|
||||
package probe
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed bin/ffprobe.exe
|
||||
var embeddedFFprobe []byte // Windows 版 ffprobe(未入库,见 .gitignore)
|
||||
var embeddedFFprobe []byte // Windows 版 ffprobe(未入库,见 .gitignore)
|
||||
Reference in New Issue
Block a user