mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-08 14:26:37 +08:00
bug处理优化
bug处理优化
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package service
|
||||
|
||||
import "strings"
|
||||
|
||||
// Item-level task status. A single BackgroundTask (one organize → scan →
|
||||
// scrape run) is broken down into per-file / per-library TaskItemRecord rows so
|
||||
// the operator can watch exactly which file is being organized, renamed, ingested
|
||||
// or scraped, and retry only the failed ones.
|
||||
const (
|
||||
ItemStatusPending = "pending" // 待进行
|
||||
ItemStatusRunning = "running" // 进行中
|
||||
ItemStatusSucceeded = "succeeded" // 成功
|
||||
ItemStatusFailed = "failed" // 失败
|
||||
)
|
||||
|
||||
// Item kind / phase. 整理与重命名 share the "organize" phase (per file);
|
||||
// scan(入库)与 scrape(刮削)are reported per library.
|
||||
const (
|
||||
ItemKindOrganize = "organize"
|
||||
ItemKindScan = "scan"
|
||||
ItemKindScrape = "scrape"
|
||||
)
|
||||
|
||||
// TaskItemRecord is a single row on the live tasks board. Each record maps to
|
||||
// exactly one file (organize) or one library (ingest / scrape).
|
||||
type TaskItemRecord struct {
|
||||
ID string `json:"id"`
|
||||
Kind string `json:"kind"` // organize / scan / scrape
|
||||
Status string `json:"status"` // pending / running / succeeded / failed
|
||||
Name string `json:"name"` // display name (file base name or library name)
|
||||
Source string `json:"source,omitempty"` // source file path (organize)
|
||||
DestPath string `json:"dest_path,omitempty"`
|
||||
LibraryID string `json:"library_id,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// organizeItemsFromResult converts the final organize result items into
|
||||
// per-file task records. The organize result is only complete after the whole
|
||||
// directory walk finishes, so this is called once at stage boundaries rather
|
||||
// than per file. Each item is keyed by its source path for stable identity.
|
||||
func organizeItemsFromResult(res *OrganizeResult) []TaskItemRecord {
|
||||
if res == nil || len(res.Items) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]TaskItemRecord, 0, len(res.Items))
|
||||
for _, item := range res.Items {
|
||||
rec := TaskItemRecord{
|
||||
ID: "organize:" + item.Source,
|
||||
Kind: ItemKindOrganize,
|
||||
Name: itemBaseName(item.Source, item.Title),
|
||||
Source: item.Source,
|
||||
DestPath: item.Target,
|
||||
}
|
||||
switch item.Action {
|
||||
case "error":
|
||||
rec.Status = ItemStatusFailed
|
||||
rec.Error = strings.TrimSpace(item.Reason)
|
||||
default:
|
||||
// organize / replace / reclassify / cleanup / skip all count as done.
|
||||
rec.Status = ItemStatusSucceeded
|
||||
}
|
||||
out = append(out, rec)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// scanItemsFromResult converts per-library scan summaries into task records.
|
||||
func scanItemsFromResult(res *OrganizeResult) []TaskItemRecord {
|
||||
if res == nil || len(res.Scans) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]TaskItemRecord, 0, len(res.Scans))
|
||||
for _, scan := range res.Scans {
|
||||
rec := TaskItemRecord{
|
||||
ID: "scan:" + scan.LibraryID,
|
||||
Kind: ItemKindScan,
|
||||
Name: scan.Name,
|
||||
LibraryID: scan.LibraryID,
|
||||
Status: ItemStatusSucceeded,
|
||||
}
|
||||
if scan.Error != "" {
|
||||
rec.Status = ItemStatusFailed
|
||||
rec.Error = scan.Error
|
||||
}
|
||||
out = append(out, rec)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// scrapeItemsFromResult converts per-library scrape summaries into task records.
|
||||
func scrapeItemsFromResult(res *OrganizeResult) []TaskItemRecord {
|
||||
if res == nil || len(res.Scrapes) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]TaskItemRecord, 0, len(res.Scrapes))
|
||||
for _, scrape := range res.Scrapes {
|
||||
rec := TaskItemRecord{
|
||||
ID: "scrape:" + scrape.LibraryID,
|
||||
Kind: ItemKindScrape,
|
||||
Name: scrape.Name,
|
||||
LibraryID: scrape.LibraryID,
|
||||
Status: ItemStatusSucceeded,
|
||||
}
|
||||
if scrape.Error != "" {
|
||||
rec.Status = ItemStatusFailed
|
||||
rec.Error = scrape.Error
|
||||
out = append(out, rec)
|
||||
continue
|
||||
}
|
||||
if scrape.Skipped {
|
||||
rec.Status = ItemStatusSucceeded
|
||||
}
|
||||
out = append(out, rec)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// combineOrganizeItems merges organize + scan + scrape item rows into one flat
|
||||
// list ordered by phase, deduping by ID (scan/scrape share the library ID and
|
||||
// there is at most one of each per run).
|
||||
func combineOrganizeItems(res *OrganizeResult) []TaskItemRecord {
|
||||
items := organizeItemsFromResult(res)
|
||||
items = append(items, scanItemsFromResult(res)...)
|
||||
items = append(items, scrapeItemsFromResult(res)...)
|
||||
return items
|
||||
}
|
||||
|
||||
func itemBaseName(source, title string) string {
|
||||
if strings.TrimSpace(title) != "" && !strings.Contains(title, ".") {
|
||||
return strings.TrimSpace(title)
|
||||
}
|
||||
if source == "" {
|
||||
return ""
|
||||
}
|
||||
base := source
|
||||
if idx := strings.LastIndexAny(base, "/\\"); idx >= 0 {
|
||||
base = base[idx+1:]
|
||||
}
|
||||
if idx := strings.LastIndex(base, "."); idx > 0 {
|
||||
base = base[:idx]
|
||||
}
|
||||
if base == "" {
|
||||
return source
|
||||
}
|
||||
return base
|
||||
}
|
||||
Reference in New Issue
Block a user