bugfixes
This commit is contained in:
parent
1775cb5acd
commit
7a5b29c3e4
@ -23,6 +23,19 @@ type cleanupCandidate struct {
|
|||||||
size int64
|
size int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type recordCleanupFile struct {
|
||||||
|
path string
|
||||||
|
name string
|
||||||
|
lowName string
|
||||||
|
size int64
|
||||||
|
modTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type recordCleanupDeleteCandidate struct {
|
||||||
|
file recordCleanupFile
|
||||||
|
reason string
|
||||||
|
}
|
||||||
|
|
||||||
type cleanupResp struct {
|
type cleanupResp struct {
|
||||||
// Small / broken downloads cleanup
|
// Small / broken downloads cleanup
|
||||||
ScannedFiles int `json:"scannedFiles"`
|
ScannedFiles int `json:"scannedFiles"`
|
||||||
@ -435,14 +448,39 @@ func cleanupVideoLooksBroken(ctx context.Context, path string) (bool, string) {
|
|||||||
return false, ""
|
return false, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanupRecordOrphanMinAge = 60 * time.Second
|
const (
|
||||||
|
cleanupRecordOrphanMinAge = 60 * time.Second
|
||||||
|
cleanupRecordStableDelay = 1200 * time.Millisecond
|
||||||
|
)
|
||||||
|
|
||||||
func cleanupRecordFileIsActive(path string) bool {
|
func cleanupRecordPathKey(path string) string {
|
||||||
path = filepath.Clean(strings.TrimSpace(path))
|
path = filepath.Clean(strings.TrimSpace(path))
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.ToLower(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupRecordPathIsActive(path string, activePaths map[string]struct{}) bool {
|
||||||
|
key := cleanupRecordPathKey(path)
|
||||||
|
if key == "" || activePaths == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, ok := activePaths[key]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func snapshotCleanupRecordActivePaths() map[string]struct{} {
|
||||||
|
active := make(map[string]struct{}, 32)
|
||||||
|
|
||||||
|
add := func(path string) {
|
||||||
|
key := cleanupRecordPathKey(path)
|
||||||
|
if key != "" {
|
||||||
|
active[key] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
jobsMu.RLock()
|
jobsMu.RLock()
|
||||||
defer jobsMu.RUnlock()
|
defer jobsMu.RUnlock()
|
||||||
|
|
||||||
@ -452,132 +490,158 @@ func cleanupRecordFileIsActive(path string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
out := filepath.Clean(strings.TrimSpace(j.Output))
|
out := filepath.Clean(strings.TrimSpace(j.Output))
|
||||||
if out != "" && strings.EqualFold(out, path) {
|
add(out)
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, sidecar := range postworkAudioSidecarCandidatesForOutput(out) {
|
for _, sidecar := range postworkAudioSidecarCandidatesForOutput(out) {
|
||||||
if sidecar != "" && strings.EqualFold(filepath.Clean(sidecar), path) {
|
add(sidecar)
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return active
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupAudioSidecarNamesForTS(tsName string) []string {
|
||||||
|
tsName = strings.TrimSpace(filepath.Base(tsName))
|
||||||
|
if tsName == "" || strings.HasPrefix(tsName, ".") || !strings.EqualFold(filepath.Ext(tsName), ".ts") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
base := strings.TrimSuffix(tsName, filepath.Ext(tsName))
|
||||||
|
if strings.TrimSpace(base) == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
names := []string{
|
||||||
|
base + ".audio.m4s",
|
||||||
|
"." + base + ".audio.m4s",
|
||||||
|
}
|
||||||
|
|
||||||
|
if canonical := strings.TrimSpace(canonicalAssetIDFromName(base)); canonical != "" && !strings.EqualFold(canonical, base) {
|
||||||
|
names = append(names,
|
||||||
|
canonical+".audio.m4s",
|
||||||
|
"."+canonical+".audio.m4s",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupHasAudioSidecarForTS(tsName string, filesByLowName map[string]recordCleanupFile) bool {
|
||||||
|
for _, sidecarName := range cleanupAudioSidecarNamesForTS(tsName) {
|
||||||
|
f, ok := filesByLowName[strings.ToLower(sidecarName)]
|
||||||
|
if ok && f.size > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupFileStable(path string) bool {
|
func cleanupWaitForStableRecordCandidates(
|
||||||
path = strings.TrimSpace(path)
|
ctx context.Context,
|
||||||
if path == "" {
|
candidates []recordCleanupDeleteCandidate,
|
||||||
return false
|
activePaths map[string]struct{},
|
||||||
|
resp *cleanupResp,
|
||||||
|
) ([]recordCleanupDeleteCandidate, error) {
|
||||||
|
if len(candidates) == 0 {
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fi1, err := os.Stat(path)
|
now := time.Now()
|
||||||
if err != nil || fi1 == nil || fi1.IsDir() || fi1.Size() <= 0 {
|
pendingStable := make([]recordCleanupDeleteCandidate, 0, len(candidates))
|
||||||
return false
|
ready := make([]recordCleanupDeleteCandidate, 0, len(candidates))
|
||||||
|
|
||||||
|
for _, candidate := range candidates {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if now.Sub(candidate.file.modTime) < cleanupRecordOrphanMinAge {
|
||||||
|
resp.SkippedFiles++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if cleanupRecordPathIsActive(candidate.file.path, activePaths) {
|
||||||
|
resp.SkippedFiles++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if candidate.file.size <= 0 {
|
||||||
|
ready = append(ready, candidate)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pendingStable = append(pendingStable, candidate)
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1200 * time.Millisecond)
|
if len(pendingStable) == 0 {
|
||||||
|
return ready, nil
|
||||||
fi2, err := os.Stat(path)
|
|
||||||
if err != nil || fi2 == nil || fi2.IsDir() || fi2.Size() <= 0 {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fi1.Size() == fi2.Size()
|
timer := time.NewTimer(cleanupRecordStableDelay)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
timer.Stop()
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-timer.C:
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, candidate := range pendingStable {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(candidate.file.path)
|
||||||
|
if err != nil || fi == nil || fi.IsDir() {
|
||||||
|
resp.SkippedFiles++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.Size() != candidate.file.size {
|
||||||
|
resp.SkippedFiles++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate.file.size = fi.Size()
|
||||||
|
candidate.file.modTime = fi.ModTime()
|
||||||
|
ready = append(ready, candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ready, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupTSPathForAudioSidecar(audioPath string) string {
|
func cleanupDeleteRecordOrphanCandidate(candidate recordCleanupDeleteCandidate, resp *cleanupResp) {
|
||||||
audioPath = strings.TrimSpace(audioPath)
|
|
||||||
if audioPath == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
dir := filepath.Dir(audioPath)
|
|
||||||
name := filepath.Base(audioPath)
|
|
||||||
lowName := strings.ToLower(name)
|
|
||||||
|
|
||||||
if !strings.HasSuffix(lowName, ".audio.m4s") {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
base := name[:len(name)-len(".audio.m4s")]
|
|
||||||
base = strings.TrimPrefix(base, ".")
|
|
||||||
|
|
||||||
if strings.TrimSpace(base) == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.Join(dir, base+".ts")
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanupDeleteRecordOrphanFile(ctx context.Context, jobID string, path string, resp *cleanupResp, reason string) {
|
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
file := candidate.file
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
path = strings.TrimSpace(path)
|
if err := removeWithRetry(file.path); err != nil && !os.IsNotExist(err) {
|
||||||
if path == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Stat(path)
|
|
||||||
if err != nil || fi == nil || fi.IsDir() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
size := fi.Size()
|
|
||||||
name := filepath.Base(path)
|
|
||||||
lowName := strings.ToLower(name)
|
|
||||||
|
|
||||||
if time.Since(fi.ModTime()) < cleanupRecordOrphanMinAge {
|
|
||||||
resp.SkippedFiles++
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if cleanupRecordFileIsActive(path) {
|
|
||||||
resp.SkippedFiles++
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0-KB-Dateien sind stabil genug zum Löschen.
|
|
||||||
// Für >0 Bytes weiter die Stabilitätsprüfung behalten.
|
|
||||||
if size > 0 && !cleanupFileStable(path) {
|
|
||||||
resp.SkippedFiles++
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fortschritt (Done/Total/CurrentFile) steuert der Aufrufer
|
|
||||||
// cleanupRecordDirOrphanAVFiles, damit die Progress-Bar sichtbar bleibt.
|
|
||||||
|
|
||||||
if err := removeWithRetry(path); err != nil && !os.IsNotExist(err) {
|
|
||||||
resp.ErrorCount++
|
resp.ErrorCount++
|
||||||
appLogln("⚠️ cleanup record orphan konnte nicht gelöscht werden:", name, reason, err)
|
appLogln("⚠️ cleanup record orphan konnte nicht gelöscht werden:", file.name, candidate.reason, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.DeletedFiles++
|
resp.DeletedFiles++
|
||||||
resp.DeletedRecordOrphans++
|
resp.DeletedRecordOrphans++
|
||||||
resp.DeletedBytes += size
|
resp.DeletedBytes += file.size
|
||||||
resp.DeletedRecordOrphanBytes += size
|
resp.DeletedRecordOrphanBytes += file.size
|
||||||
|
|
||||||
if strings.HasSuffix(lowName, ".muxing.ts") {
|
if strings.HasSuffix(file.lowName, ".muxing.ts") {
|
||||||
resp.DeletedMuxingTemps++
|
resp.DeletedMuxingTemps++
|
||||||
} else if strings.HasSuffix(lowName, ".audio.m4s") {
|
} else if strings.HasSuffix(file.lowName, ".audio.m4s") {
|
||||||
resp.DeletedAudioOrphans++
|
resp.DeletedAudioOrphans++
|
||||||
} else if !strings.HasPrefix(name, ".") && strings.EqualFold(filepath.Ext(name), ".ts") {
|
} else if !strings.HasPrefix(file.name, ".") && strings.EqualFold(filepath.Ext(file.name), ".ts") {
|
||||||
resp.DeletedTSOrphans++
|
resp.DeletedTSOrphans++
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeDurationCacheForPath(path)
|
purgeDurationCacheForPath(file.path)
|
||||||
|
|
||||||
base := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
|
base := strings.TrimSuffix(filepath.Base(file.path), filepath.Ext(file.path))
|
||||||
base = strings.TrimPrefix(base, ".")
|
base = strings.TrimPrefix(base, ".")
|
||||||
base = strings.TrimSuffix(base, ".audio")
|
base = strings.TrimSuffix(base, ".audio")
|
||||||
base = strings.TrimSuffix(base, ".muxing")
|
base = strings.TrimSuffix(base, ".muxing")
|
||||||
@ -586,7 +650,7 @@ func cleanupDeleteRecordOrphanFile(ctx context.Context, jobID string, path strin
|
|||||||
removeGeneratedForID(stripHotPrefix(base))
|
removeGeneratedForID(stripHotPrefix(base))
|
||||||
}
|
}
|
||||||
|
|
||||||
appLogln("🧹 cleanup deleted record orphan:", name, "reason:", reason, "size=", size)
|
appLogln("🧹 cleanup deleted record orphan:", file.name, "reason:", candidate.reason, "size=", file.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanupRecordDirOrphanAVFiles(ctx context.Context, jobID string, recordAbs string, resp *cleanupResp) error {
|
func cleanupRecordDirOrphanAVFiles(ctx context.Context, jobID string, recordAbs string, resp *cleanupResp) error {
|
||||||
@ -600,41 +664,10 @@ func cleanupRecordDirOrphanAVFiles(ctx context.Context, jobID string, recordAbs
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gesamtzahl der zu prüfenden Dateien für einen sichtbaren Fortschritt.
|
files := make([]recordCleanupFile, 0, len(entries))
|
||||||
total := 0
|
filesByLowName := make(map[string]recordCleanupFile, len(entries))
|
||||||
for _, e := range entries {
|
|
||||||
if e == nil || e.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(e.Name()) == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
total++
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCleanupJobState(jobID, func(st *CleanupTaskState) {
|
|
||||||
st.Queued = false
|
|
||||||
st.Running = true
|
|
||||||
if st.StartedAt.IsZero() {
|
|
||||||
st.StartedAt = time.Now()
|
|
||||||
}
|
|
||||||
st.Done = 0
|
|
||||||
st.Total = total
|
|
||||||
st.CurrentFile = ""
|
|
||||||
st.Text = "Räume Record-Reste auf…"
|
|
||||||
st.Error = ""
|
|
||||||
st.FinishedAt = nil
|
|
||||||
})
|
|
||||||
|
|
||||||
processed := 0
|
|
||||||
|
|
||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if e == nil || e.IsDir() {
|
if e == nil || e.IsDir() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -644,54 +677,153 @@ func cleanupRecordDirOrphanAVFiles(ctx context.Context, jobID string, recordAbs
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
processed++
|
info, err := e.Info()
|
||||||
updateCleanupJobState(jobID, func(st *CleanupTaskState) {
|
if err != nil || info == nil || info.IsDir() {
|
||||||
st.Done = processed
|
continue
|
||||||
st.Total = total
|
}
|
||||||
st.CurrentFile = name
|
|
||||||
})
|
|
||||||
|
|
||||||
full := filepath.Join(recordAbs, name)
|
file := recordCleanupFile{
|
||||||
low := strings.ToLower(name)
|
path: filepath.Join(recordAbs, name),
|
||||||
|
name: name,
|
||||||
|
lowName: strings.ToLower(name),
|
||||||
|
size: info.Size(),
|
||||||
|
modTime: info.ModTime(),
|
||||||
|
}
|
||||||
|
|
||||||
|
files = append(files, file)
|
||||||
|
filesByLowName[file.lowName] = file
|
||||||
|
}
|
||||||
|
|
||||||
|
audioSidecarMatchedByLowName := make(map[string]bool, len(files))
|
||||||
|
for _, file := range files {
|
||||||
|
if strings.HasPrefix(file.name, ".") || !strings.EqualFold(filepath.Ext(file.name), ".ts") || file.size <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sidecarName := range cleanupAudioSidecarNamesForTS(file.name) {
|
||||||
|
lowSidecarName := strings.ToLower(sidecarName)
|
||||||
|
if _, ok := filesByLowName[lowSidecarName]; ok {
|
||||||
|
audioSidecarMatchedByLowName[lowSidecarName] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCleanupJobState(jobID, func(st *CleanupTaskState) {
|
||||||
|
st.Queued = false
|
||||||
|
st.Running = true
|
||||||
|
if st.StartedAt.IsZero() {
|
||||||
|
st.StartedAt = time.Now()
|
||||||
|
}
|
||||||
|
st.Done = 0
|
||||||
|
st.Total = len(files)
|
||||||
|
st.CurrentFile = ""
|
||||||
|
st.Text = "Suche Record-Reste…"
|
||||||
|
st.Error = ""
|
||||||
|
st.FinishedAt = nil
|
||||||
|
})
|
||||||
|
|
||||||
|
activePaths := snapshotCleanupRecordActivePaths()
|
||||||
|
candidates := make([]recordCleanupDeleteCandidate, 0, 64)
|
||||||
|
lastProgressAt := time.Time{}
|
||||||
|
|
||||||
|
updateProgress := func(done, total int, currentFile, text string, force bool) {
|
||||||
|
now := time.Now()
|
||||||
|
if !force && now.Sub(lastProgressAt) < 250*time.Millisecond && done%100 != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lastProgressAt = now
|
||||||
|
|
||||||
|
updateCleanupJobState(jobID, func(st *CleanupTaskState) {
|
||||||
|
st.Done = done
|
||||||
|
st.Total = total
|
||||||
|
st.CurrentFile = strings.TrimSpace(currentFile)
|
||||||
|
if strings.TrimSpace(text) != "" {
|
||||||
|
st.Text = text
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, file := range files {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(i+1, len(files), file.name, "Suche Record-Reste…", false)
|
||||||
|
|
||||||
// Fall 0:
|
// Fall 0:
|
||||||
// alte .muxing.ts sind temporäre Remux-/Muxing-Reste.
|
// alte .muxing.ts sind temporäre Remux-/Muxing-Reste.
|
||||||
if strings.HasSuffix(low, ".muxing.ts") {
|
if strings.HasSuffix(file.lowName, ".muxing.ts") {
|
||||||
resp.ScannedFiles++
|
resp.ScannedFiles++
|
||||||
cleanupDeleteRecordOrphanFile(ctx, jobID, full, resp, "stale muxing temp")
|
candidates = append(candidates, recordCleanupDeleteCandidate{
|
||||||
|
file: file,
|
||||||
|
reason: "stale muxing temp",
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall 1:
|
// Fall 1:
|
||||||
// foo.ts existiert, aber kein passendes foo.audio.m4s/.foo.audio.m4s.
|
// foo.ts existiert, aber kein passendes foo.audio.m4s/.foo.audio.m4s.
|
||||||
if !strings.HasPrefix(name, ".") && strings.EqualFold(filepath.Ext(name), ".ts") {
|
if !strings.HasPrefix(file.name, ".") && strings.EqualFold(filepath.Ext(file.name), ".ts") {
|
||||||
resp.ScannedFiles++
|
resp.ScannedFiles++
|
||||||
|
|
||||||
if _, ok := findPostworkAudioSidecarForTS(full); ok {
|
if cleanupHasAudioSidecarForTS(file.name, filesByLowName) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupDeleteRecordOrphanFile(ctx, jobID, full, resp, "missing audio sidecar")
|
candidates = append(candidates, recordCleanupDeleteCandidate{
|
||||||
|
file: file,
|
||||||
|
reason: "missing audio sidecar",
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fall 2:
|
// Fall 2:
|
||||||
// foo.audio.m4s/.foo.audio.m4s existiert, aber foo.ts fehlt.
|
// foo.audio.m4s/.foo.audio.m4s existiert, aber foo.ts fehlt.
|
||||||
if strings.HasSuffix(low, ".audio.m4s") {
|
if strings.HasSuffix(file.lowName, ".audio.m4s") {
|
||||||
resp.ScannedFiles++
|
resp.ScannedFiles++
|
||||||
|
|
||||||
tsPath := cleanupTSPathForAudioSidecar(full)
|
if audioSidecarMatchedByLowName[file.lowName] {
|
||||||
if strings.TrimSpace(tsPath) != "" {
|
continue
|
||||||
if fi, err := os.Stat(tsPath); err == nil && fi != nil && !fi.IsDir() && fi.Size() > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupDeleteRecordOrphanFile(ctx, jobID, full, resp, "missing ts file")
|
candidates = append(candidates, recordCleanupDeleteCandidate{
|
||||||
|
file: file,
|
||||||
|
reason: "missing ts file",
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateProgress(len(files), len(files), "", "Prüfe stabile Record-Reste…", true)
|
||||||
|
|
||||||
|
stableCandidates, err := cleanupWaitForStableRecordCandidates(ctx, candidates, activePaths, resp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(0, len(stableCandidates), "", "Lösche Record-Reste…", true)
|
||||||
|
activePaths = snapshotCleanupRecordActivePaths()
|
||||||
|
|
||||||
|
for i, candidate := range stableCandidates {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(i+1, len(stableCandidates), candidate.file.name, "Lösche Record-Reste…", false)
|
||||||
|
if cleanupRecordPathIsActive(candidate.file.path, activePaths) {
|
||||||
|
resp.SkippedFiles++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanupDeleteRecordOrphanCandidate(candidate, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(len(stableCandidates), len(stableCandidates), "", cleanupProgressText(*resp), true)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user