fix(promotion-import): 实例(一)(二)多备选源路径;目录内唯一 mov/jpg 自动匹配
Made-with: Cursor
This commit is contained in:
@@ -6,26 +6,40 @@ $Src = Join-Path $Root "web\promotion\视频发布"
|
||||
$Dst = Join-Path $Root "web\promotion\social"
|
||||
New-Item -ItemType Directory -Force -Path $Dst | Out-Null
|
||||
|
||||
function Copy-IfExists($fromRel, $toName) {
|
||||
$from = Join-Path $Src $fromRel
|
||||
function Copy-First($toName, [string[]]$fromRels) {
|
||||
$to = Join-Path $Dst $toName
|
||||
if (Test-Path -LiteralPath $from) {
|
||||
Copy-Item -LiteralPath $from -Destination $to -Force
|
||||
Write-Host "OK $toName"
|
||||
} else {
|
||||
Write-Warning "SKIP (缺失): $from"
|
||||
foreach ($rel in $fromRels) {
|
||||
$from = Join-Path $Src $rel
|
||||
if (Test-Path -LiteralPath $from) {
|
||||
Copy-Item -LiteralPath $from -Destination $to -Force
|
||||
Write-Host "OK $toName <= $rel"
|
||||
return
|
||||
}
|
||||
}
|
||||
Write-Warning "SKIP (均未找到): -> $toName"
|
||||
}
|
||||
|
||||
Copy-IfExists "宇恒一号操作计算软件实例(一)\宣传片-封面.jpg" "video-calc-demo-1-cover.jpg"
|
||||
Copy-IfExists "宇恒一号操作计算软件实例(一)\宣传片.mov" "video-calc-demo-1.mov"
|
||||
Copy-IfExists "宇恒一号操作计算软件实例(二)\宇恒一号操作计算软件实例(二)-封面.jpg" "video-calc-demo-2-cover.jpg"
|
||||
Copy-IfExists "宇恒一号操作计算软件实例(二)\宇恒一号操作计算软件实例(二).mov" "video-calc-demo-2.mov"
|
||||
Copy-IfExists "宇恒一号AIWord简介\宇恒一号AIWord简介-封面.jpg" "video-aiword-cover.jpg"
|
||||
Copy-IfExists "宇恒一号AIWord简介\宇恒一号AIWord简介.mov" "video-aiword.mov"
|
||||
Copy-IfExists "宇恒一号语音办公实例\宇恒一号语音办公实例-封面.jpg" "video-voice-office-cover.jpg"
|
||||
Copy-IfExists "宇恒一号语音办公实例\宇恒一号语音办公实例.mov" "video-voice-office.mov"
|
||||
Copy-IfExists "宇恒一号,AI 全自动办发票\宇恒一号,AI 全自动办发票-封面.jpg" "video-invoice-ai-cover.jpg"
|
||||
Copy-IfExists "宇恒一号,AI 全自动办发票\宇恒一号,AI 全自动办发票.mov" "video-invoice-ai.mov"
|
||||
Copy-First "video-calc-demo-1-cover.jpg" @(
|
||||
"宇恒一号操作计算软件实例(一)\宣传片-封面.jpg",
|
||||
"宇恒一号操作计算软件实例(一)\宇恒一号操作计算软件实例(一)-封面.jpg"
|
||||
)
|
||||
Copy-First "video-calc-demo-1.mov" @(
|
||||
"宇恒一号操作计算软件实例(一)\宣传片.mov",
|
||||
"宇恒一号操作计算软件实例(一)\宇恒一号操作计算软件实例(一).mov"
|
||||
)
|
||||
Copy-First "video-calc-demo-2-cover.jpg" @(
|
||||
"宇恒一号操作计算软件实例(二)\宇恒一号操作计算软件实例(二)-封面.jpg",
|
||||
"宇恒一号操作计算软件实例(二)\宣传片-封面.jpg"
|
||||
)
|
||||
Copy-First "video-calc-demo-2.mov" @(
|
||||
"宇恒一号操作计算软件实例(二)\宇恒一号操作计算软件实例(二).mov",
|
||||
"宇恒一号操作计算软件实例(二)\宣传片.mov"
|
||||
)
|
||||
Copy-First "video-aiword-cover.jpg" @("宇恒一号AIWord简介\宇恒一号AIWord简介-封面.jpg")
|
||||
Copy-First "video-aiword.mov" @("宇恒一号AIWord简介\宇恒一号AIWord简介.mov")
|
||||
Copy-First "video-voice-office-cover.jpg" @("宇恒一号语音办公实例\宇恒一号语音办公实例-封面.jpg")
|
||||
Copy-First "video-voice-office.mov" @("宇恒一号语音办公实例\宇恒一号语音办公实例.mov")
|
||||
Copy-First "video-invoice-ai-cover.jpg" @("宇恒一号,AI 全自动办发票\宇恒一号,AI 全自动办发票-封面.jpg")
|
||||
Copy-First "video-invoice-ai.mov" @("宇恒一号,AI 全自动办发票\宇恒一号,AI 全自动办发票.mov")
|
||||
|
||||
Write-Host "完成。Linux 服务器上建议在 social 目录执行: chmod -R a+rX ."
|
||||
|
||||
@@ -8,35 +8,48 @@ SRC="$ROOT/web/promotion/视频发布"
|
||||
DST="$ROOT/web/promotion/social"
|
||||
mkdir -p "$DST"
|
||||
|
||||
copy_if () {
|
||||
local from="$1" to="$2"
|
||||
if [[ -f "$from" ]]; then
|
||||
cp -f "$from" "$to"
|
||||
echo "OK $to"
|
||||
else
|
||||
echo "SKIP (缺失): $from" >&2
|
||||
fi
|
||||
# 按顺序使用第一个存在的源文件
|
||||
copy_first() {
|
||||
local dest="$1"
|
||||
shift
|
||||
for from in "$@"; do
|
||||
if [[ -f "$from" ]]; then
|
||||
cp -f "$from" "$dest"
|
||||
echo "OK $(basename "$dest") <= $from"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
echo "SKIP (均未找到): -> $dest" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# 操作与计算软件实例(一)
|
||||
copy_if "$SRC/宇恒一号操作计算软件实例(一)/宣传片-封面.jpg" "$DST/video-calc-demo-1-cover.jpg"
|
||||
copy_if "$SRC/宇恒一号操作计算软件实例(一)/宣传片.mov" "$DST/video-calc-demo-1.mov"
|
||||
copy_first "$DST/video-calc-demo-1-cover.jpg" \
|
||||
"$SRC/宇恒一号操作计算软件实例(一)/宣传片-封面.jpg" \
|
||||
"$SRC/宇恒一号操作计算软件实例(一)/宇恒一号操作计算软件实例(一)-封面.jpg" || true
|
||||
copy_first "$DST/video-calc-demo-1.mov" \
|
||||
"$SRC/宇恒一号操作计算软件实例(一)/宣传片.mov" \
|
||||
"$SRC/宇恒一号操作计算软件实例(一)/宇恒一号操作计算软件实例(一).mov" || true
|
||||
|
||||
# 操作与计算软件实例(二)
|
||||
copy_if "$SRC/宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二)-封面.jpg" "$DST/video-calc-demo-2-cover.jpg"
|
||||
copy_if "$SRC/宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二).mov" "$DST/video-calc-demo-2.mov"
|
||||
copy_first "$DST/video-calc-demo-2-cover.jpg" \
|
||||
"$SRC/宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二)-封面.jpg" \
|
||||
"$SRC/宇恒一号操作计算软件实例(二)/宣传片-封面.jpg" || true
|
||||
copy_first "$DST/video-calc-demo-2.mov" \
|
||||
"$SRC/宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二).mov" \
|
||||
"$SRC/宇恒一号操作计算软件实例(二)/宣传片.mov" || true
|
||||
|
||||
# AI Word
|
||||
copy_if "$SRC/宇恒一号AIWord简介/宇恒一号AIWord简介-封面.jpg" "$DST/video-aiword-cover.jpg"
|
||||
copy_if "$SRC/宇恒一号AIWord简介/宇恒一号AIWord简介.mov" "$DST/video-aiword.mov"
|
||||
copy_first "$DST/video-aiword-cover.jpg" "$SRC/宇恒一号AIWord简介/宇恒一号AIWord简介-封面.jpg" || true
|
||||
copy_first "$DST/video-aiword.mov" "$SRC/宇恒一号AIWord简介/宇恒一号AIWord简介.mov" || true
|
||||
|
||||
# 语音办公
|
||||
copy_if "$SRC/宇恒一号语音办公实例/宇恒一号语音办公实例-封面.jpg" "$DST/video-voice-office-cover.jpg"
|
||||
copy_if "$SRC/宇恒一号语音办公实例/宇恒一号语音办公实例.mov" "$DST/video-voice-office.mov"
|
||||
copy_first "$DST/video-voice-office-cover.jpg" "$SRC/宇恒一号语音办公实例/宇恒一号语音办公实例-封面.jpg" || true
|
||||
copy_first "$DST/video-voice-office.mov" "$SRC/宇恒一号语音办公实例/宇恒一号语音办公实例.mov" || true
|
||||
|
||||
# 办发票(目录名含全角逗号)
|
||||
copy_if "$SRC/宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票-封面.jpg" "$DST/video-invoice-ai-cover.jpg"
|
||||
copy_if "$SRC/宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票.mov" "$DST/video-invoice-ai.mov"
|
||||
copy_first "$DST/video-invoice-ai-cover.jpg" "$SRC/宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票-封面.jpg" || true
|
||||
copy_first "$DST/video-invoice-ai.mov" "$SRC/宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票.mov" || true
|
||||
|
||||
if command -v chmod >/dev/null 2>&1; then
|
||||
chmod -R a+rX "$DST" 2>/dev/null || true
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
将 `web/promotion/视频发布/` 下映射表中的文件复制到 **`{upload}/sites/{site_id}/promotion/social/`**,并在 **`site_assets`** 集合插入记录(与后台「保留原文件名」上传到 `promotion/social` 一致)。
|
||||
|
||||
对「操作与计算(一)(二)」等条目会**按顺序尝试多个源文件名**;若仍找不到且子目录内**恰好只有一个** `.mov` 或 `.jpg`,会自动选用(解决「有些视频有、有些 404」多为源文件名与映射不一致)。
|
||||
|
||||
## 参数
|
||||
|
||||
| 参数 | 说明 |
|
||||
|
||||
@@ -57,21 +57,77 @@ func mimeForExt(ext string) string {
|
||||
}
|
||||
}
|
||||
|
||||
// 与 scripts/sync-video-assets-to-social.sh 一致:源相对「视频发布」目录,目标为 promotion/social 下英文名
|
||||
var mappings = []struct {
|
||||
SrcRel string // 相对 视频发布/
|
||||
Dst string // 仅文件名,落在 promotion/social/
|
||||
}{
|
||||
{"宇恒一号操作计算软件实例(一)/宣传片-封面.jpg", "video-calc-demo-1-cover.jpg"},
|
||||
{"宇恒一号操作计算软件实例(一)/宣传片.mov", "video-calc-demo-1.mov"},
|
||||
{"宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二)-封面.jpg", "video-calc-demo-2-cover.jpg"},
|
||||
{"宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二).mov", "video-calc-demo-2.mov"},
|
||||
{"宇恒一号AIWord简介/宇恒一号AIWord简介-封面.jpg", "video-aiword-cover.jpg"},
|
||||
{"宇恒一号AIWord简介/宇恒一号AIWord简介.mov", "video-aiword.mov"},
|
||||
{"宇恒一号语音办公实例/宇恒一号语音办公实例-封面.jpg", "video-voice-office-cover.jpg"},
|
||||
{"宇恒一号语音办公实例/宇恒一号语音办公实例.mov", "video-voice-office.mov"},
|
||||
{"宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票-封面.jpg", "video-invoice-ai-cover.jpg"},
|
||||
{"宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票.mov", "video-invoice-ai.mov"},
|
||||
// importRule:按顺序尝试 SrcRels;若均不存在且 FallbackScanDir 非空,则在该子目录下「仅一个 .mov/.jpg 时」自动选用(兼容实际文件夹命名与文件名不一致)
|
||||
type importRule struct {
|
||||
SrcRels []string
|
||||
Dst string
|
||||
FallbackScanDir string // 相对 视频发布/,仅当目标为视频时用 .mov;封面用 .jpg
|
||||
}
|
||||
|
||||
// 与 sync-video-assets-to-social.sh 对齐,并增加备选路径(线上常见「实例(一)」内不叫宣传片.mov 的情况)
|
||||
var mappings = []importRule{
|
||||
{[]string{
|
||||
"宇恒一号操作计算软件实例(一)/宣传片-封面.jpg",
|
||||
"宇恒一号操作计算软件实例(一)/宇恒一号操作计算软件实例(一)-封面.jpg",
|
||||
}, "video-calc-demo-1-cover.jpg", "宇恒一号操作计算软件实例(一)"},
|
||||
{[]string{
|
||||
"宇恒一号操作计算软件实例(一)/宣传片.mov",
|
||||
"宇恒一号操作计算软件实例(一)/宇恒一号操作计算软件实例(一).mov",
|
||||
}, "video-calc-demo-1.mov", "宇恒一号操作计算软件实例(一)"},
|
||||
{[]string{
|
||||
"宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二)-封面.jpg",
|
||||
"宇恒一号操作计算软件实例(二)/宣传片-封面.jpg",
|
||||
}, "video-calc-demo-2-cover.jpg", "宇恒一号操作计算软件实例(二)"},
|
||||
{[]string{
|
||||
"宇恒一号操作计算软件实例(二)/宇恒一号操作计算软件实例(二).mov",
|
||||
"宇恒一号操作计算软件实例(二)/宣传片.mov",
|
||||
}, "video-calc-demo-2.mov", "宇恒一号操作计算软件实例(二)"},
|
||||
{[]string{"宇恒一号AIWord简介/宇恒一号AIWord简介-封面.jpg"}, "video-aiword-cover.jpg", "宇恒一号AIWord简介"},
|
||||
{[]string{"宇恒一号AIWord简介/宇恒一号AIWord简介.mov"}, "video-aiword.mov", "宇恒一号AIWord简介"},
|
||||
{[]string{"宇恒一号语音办公实例/宇恒一号语音办公实例-封面.jpg"}, "video-voice-office-cover.jpg", "宇恒一号语音办公实例"},
|
||||
{[]string{"宇恒一号语音办公实例/宇恒一号语音办公实例.mov"}, "video-voice-office.mov", "宇恒一号语音办公实例"},
|
||||
{[]string{"宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票-封面.jpg"}, "video-invoice-ai-cover.jpg", "宇恒一号,AI 全自动办发票"},
|
||||
{[]string{"宇恒一号,AI 全自动办发票/宇恒一号,AI 全自动办发票.mov"}, "video-invoice-ai.mov", "宇恒一号,AI 全自动办发票"},
|
||||
}
|
||||
|
||||
func resolveSourceFile(videoPublish string, rule importRule) (absPath, relChosen string, ok bool) {
|
||||
for _, rel := range rule.SrcRels {
|
||||
p := filepath.Join(videoPublish, filepath.FromSlash(rel))
|
||||
if st, err := os.Stat(p); err == nil && !st.IsDir() {
|
||||
return p, rel, true
|
||||
}
|
||||
}
|
||||
if rule.FallbackScanDir == "" {
|
||||
return "", "", false
|
||||
}
|
||||
ext := strings.ToLower(filepath.Ext(rule.Dst))
|
||||
if ext != ".mov" && ext != ".jpg" && ext != ".jpeg" {
|
||||
return "", "", false
|
||||
}
|
||||
dir := filepath.Join(videoPublish, filepath.FromSlash(rule.FallbackScanDir))
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return "", "", false
|
||||
}
|
||||
var matches []string
|
||||
for _, e := range entries {
|
||||
if e.IsDir() {
|
||||
continue
|
||||
}
|
||||
ne := strings.ToLower(filepath.Ext(e.Name()))
|
||||
if ext == ".mov" && ne == ".mov" {
|
||||
matches = append(matches, e.Name())
|
||||
}
|
||||
if (ext == ".jpg" || ext == ".jpeg") && (ne == ".jpg" || ne == ".jpeg") {
|
||||
matches = append(matches, e.Name())
|
||||
}
|
||||
}
|
||||
if len(matches) != 1 {
|
||||
return "", "", false
|
||||
}
|
||||
rel := filepath.ToSlash(filepath.Join(rule.FallbackScanDir, matches[0]))
|
||||
p := filepath.Join(videoPublish, filepath.FromSlash(rel))
|
||||
return p, rel, true
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -144,9 +200,9 @@ func main() {
|
||||
|
||||
ok, skip, fail := 0, 0, 0
|
||||
for _, m := range mappings {
|
||||
from := filepath.Join(videoPublish, filepath.FromSlash(m.SrcRel))
|
||||
if _, err := os.Stat(from); err != nil {
|
||||
log.Printf("SKIP 源文件不存在: %s", from)
|
||||
from, srcRelUsed, found := resolveSourceFile(videoPublish, m)
|
||||
if !found {
|
||||
log.Printf("SKIP 源文件不存在(已试备选路径): dst=%s dir=%s", m.Dst, m.FallbackScanDir)
|
||||
skip++
|
||||
continue
|
||||
}
|
||||
@@ -168,7 +224,7 @@ func main() {
|
||||
}
|
||||
|
||||
if err := copyFile(from, destPath); err != nil {
|
||||
log.Printf("FAIL 复制 %s: %v", m.SrcRel, err)
|
||||
log.Printf("FAIL 复制 %s: %v", srcRelUsed, err)
|
||||
fail++
|
||||
continue
|
||||
}
|
||||
@@ -193,7 +249,7 @@ func main() {
|
||||
"downloadable": false,
|
||||
"created_at": time.Now().Format(time.RFC3339),
|
||||
"import_source": "video_publish_legacy",
|
||||
"source_relpath": m.SrcRel,
|
||||
"source_relpath": srcRelUsed,
|
||||
"promotion_alias": filepath.ToSlash(filepath.Join("promotion", "social", m.Dst)),
|
||||
}
|
||||
if _, err := coll.InsertOne(ctx, doc); err != nil {
|
||||
@@ -201,7 +257,7 @@ func main() {
|
||||
fail++
|
||||
continue
|
||||
}
|
||||
log.Printf("OK %s -> %s", m.SrcRel, relPath)
|
||||
log.Printf("OK %s -> %s", srcRelUsed, relPath)
|
||||
ok++
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user