bugfixes
This commit is contained in:
parent
fbac1c6327
commit
19faed7a40
@ -368,7 +368,7 @@ func appendFileAndRemove(dstPath, srcPath string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if sfi == nil || sfi.IsDir() || sfi.Size() <= 0 {
|
if sfi == nil || sfi.IsDir() || sfi.Size() <= 0 {
|
||||||
_ = os.Remove(srcPath)
|
_ = removeWithRetry(srcPath)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,19 +376,55 @@ func appendFileAndRemove(dstPath, srcPath string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
dst, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
|
dst, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
_ = src.Close()
|
||||||
}
|
|
||||||
defer dst.Close()
|
|
||||||
|
|
||||||
if _, err := io.Copy(dst, src); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.Remove(srcPath)
|
_, copyErr := io.Copy(dst, src)
|
||||||
|
|
||||||
|
closeSrcErr := src.Close()
|
||||||
|
closeDstErr := dst.Close()
|
||||||
|
|
||||||
|
if copyErr != nil {
|
||||||
|
return copyErr
|
||||||
|
}
|
||||||
|
if closeSrcErr != nil {
|
||||||
|
return closeSrcErr
|
||||||
|
}
|
||||||
|
if closeDstErr != nil {
|
||||||
|
return closeDstErr
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := removeWithRetry(srcPath); err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupHLSRetryChunks(outFile string) {
|
||||||
|
dir := filepath.Dir(outFile)
|
||||||
|
ext := filepath.Ext(outFile)
|
||||||
|
base := strings.TrimSuffix(filepath.Base(outFile), ext)
|
||||||
|
|
||||||
|
canonical := canonicalAssetIDFromName(base)
|
||||||
|
if canonical == "" {
|
||||||
|
canonical = base
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern := filepath.Join(dir, fmt.Sprintf(".%s.retry.*%s", canonical, ext))
|
||||||
|
|
||||||
|
matches, err := filepath.Glob(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range matches {
|
||||||
|
_ = removeWithRetry(p)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleM3U8Mode(
|
func handleM3U8Mode(
|
||||||
@ -419,10 +455,26 @@ func handleM3U8Mode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimSpace(outFile) == "" {
|
outFile = strings.TrimSpace(outFile)
|
||||||
|
if outFile == "" {
|
||||||
return errors.New("output file path leer")
|
return errors.New("output file path leer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanupHLSRetryChunks(outFile)
|
||||||
|
defer cleanupHLSRetryChunks(outFile)
|
||||||
|
|
||||||
|
ext := strings.ToLower(filepath.Ext(outFile))
|
||||||
|
if ext != ".ts" && ext != ".mp4" {
|
||||||
|
return fmt.Errorf("nicht unterstützte output-endung: %q", ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wichtig: ffmpeg schreibt in temporäre Retry-Datei.
|
||||||
|
// Danach wird sie an outFile angehängt und gelöscht.
|
||||||
|
retryOut := hlsRetryChunkPath(outFile, 1)
|
||||||
|
defer func() {
|
||||||
|
_ = removeWithRetry(retryOut)
|
||||||
|
}()
|
||||||
|
|
||||||
args := []string{
|
args := []string{
|
||||||
"-y",
|
"-y",
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
@ -452,8 +504,6 @@ func handleM3U8Mode(
|
|||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
ext := strings.ToLower(filepath.Ext(strings.TrimSpace(outFile)))
|
|
||||||
|
|
||||||
if audioURL != "" {
|
if audioURL != "" {
|
||||||
args = appendInputOptions(args)
|
args = appendInputOptions(args)
|
||||||
args = append(args, "-i", videoURL)
|
args = append(args, "-i", videoURL)
|
||||||
@ -484,21 +534,19 @@ func handleM3U8Mode(
|
|||||||
case ".ts":
|
case ".ts":
|
||||||
args = append(args,
|
args = append(args,
|
||||||
"-f", "mpegts",
|
"-f", "mpegts",
|
||||||
outFile,
|
retryOut,
|
||||||
)
|
)
|
||||||
case ".mp4":
|
case ".mp4":
|
||||||
args = append(args,
|
args = append(args,
|
||||||
"-movflags", "+faststart",
|
"-movflags", "+faststart",
|
||||||
outFile,
|
retryOut,
|
||||||
)
|
)
|
||||||
default:
|
|
||||||
return fmt.Errorf("nicht unterstützte output-endung: %q", ext)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := exec.CommandContext(ctx, ffmpegPath, args...)
|
cmd := exec.CommandContext(ctx, ffmpegPath, args...)
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
HideWindow: true,
|
HideWindow: true,
|
||||||
CreationFlags: 0x08000000, // CREATE_NO_WINDOW
|
CreationFlags: 0x08000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
@ -520,16 +568,15 @@ func handleM3U8Mode(
|
|||||||
case <-stopStat:
|
case <-stopStat:
|
||||||
return
|
return
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
fi, err := os.Stat(outFile)
|
mainSize := safeFileSize(outFile)
|
||||||
if err != nil || fi == nil || fi.IsDir() {
|
retrySize := safeFileSize(retryOut)
|
||||||
continue
|
sz := mainSize + retrySize
|
||||||
}
|
|
||||||
|
|
||||||
sz := fi.Size()
|
|
||||||
if sz > 0 && sz != last {
|
if sz > 0 && sz != last {
|
||||||
jobsMu.Lock()
|
jobsMu.Lock()
|
||||||
job.SizeBytes = sz
|
job.SizeBytes = sz
|
||||||
jobsMu.Unlock()
|
jobsMu.Unlock()
|
||||||
|
|
||||||
last = sz
|
last = sz
|
||||||
_ = publishJob(job.ID)
|
_ = publishJob(job.ID)
|
||||||
}
|
}
|
||||||
@ -549,6 +596,10 @@ func handleM3U8Mode(
|
|||||||
return fmt.Errorf("ffmpeg m3u8 failed: %w", err)
|
return fmt.Errorf("ffmpeg m3u8 failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := appendFileAndRemove(outFile, retryOut); err != nil {
|
||||||
|
return fmt.Errorf("retry chunk übernehmen fehlgeschlagen: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if job != nil {
|
if job != nil {
|
||||||
if fi, statErr := os.Stat(outFile); statErr == nil && fi != nil && !fi.IsDir() {
|
if fi, statErr := os.Stat(outFile); statErr == nil && fi != nil && !fi.IsDir() {
|
||||||
jobsMu.Lock()
|
jobsMu.Lock()
|
||||||
|
|||||||
@ -2043,9 +2043,9 @@ export default function TrainingTab(props: {
|
|||||||
|
|
||||||
progressTimer = window.setInterval(() => {
|
progressTimer = window.setInterval(() => {
|
||||||
setAnalysisProgress((value) => {
|
setAnalysisProgress((value) => {
|
||||||
if (value < 35) return value + 4
|
if (value < 35) return Math.min(35, value + 4)
|
||||||
if (value < 65) return value + 2
|
if (value < 65) return Math.min(65, value + 2)
|
||||||
if (value < 88) return value + 1
|
if (value < 95) return Math.min(95, value + 1)
|
||||||
return value
|
return value
|
||||||
})
|
})
|
||||||
}, 350)
|
}, 350)
|
||||||
@ -2117,7 +2117,7 @@ export default function TrainingTab(props: {
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
setAnalysisProgress(0)
|
setAnalysisProgress(0)
|
||||||
setAnalysisStep('')
|
setAnalysisStep('')
|
||||||
}, 150)
|
}, 500)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -2159,6 +2159,8 @@ export default function TrainingTab(props: {
|
|||||||
setTraining(Boolean(job?.running))
|
setTraining(Boolean(job?.running))
|
||||||
|
|
||||||
if (job?.message && !job.running) {
|
if (job?.message && !job.running) {
|
||||||
|
setTrainingProgress(100)
|
||||||
|
setTrainingStep('Training abgeschlossen.')
|
||||||
setMessage((prev) => prev || String(job.message))
|
setMessage((prev) => prev || String(job.message))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2311,9 +2313,12 @@ export default function TrainingTab(props: {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!trainingRunning) {
|
if (!trainingRunning) {
|
||||||
setTrainingProgress(0)
|
const timer = window.setTimeout(() => {
|
||||||
setTrainingStep('')
|
setTrainingProgress(0)
|
||||||
return
|
setTrainingStep('')
|
||||||
|
}, 800)
|
||||||
|
|
||||||
|
return () => window.clearTimeout(timer)
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverProgress = Number(trainingStatus?.training?.progress ?? 0)
|
const serverProgress = Number(trainingStatus?.training?.progress ?? 0)
|
||||||
@ -3208,8 +3213,18 @@ export default function TrainingTab(props: {
|
|||||||
disabled={uiLocked}
|
disabled={uiLocked}
|
||||||
className={[
|
className={[
|
||||||
isActiveBox
|
isActiveBox
|
||||||
? 'pointer-events-auto absolute z-20 flex h-7 w-7 touch-none items-center justify-center rounded-full bg-transparent p-0 opacity-100 disabled:opacity-50 sm:h-5 sm:w-5'
|
? [
|
||||||
: 'pointer-events-none absolute z-20 hidden h-7 w-7 touch-none items-center justify-center rounded-full bg-transparent p-0 opacity-100 disabled:opacity-50 sm:h-5 sm:w-5',
|
'pointer-events-auto absolute z-20 flex h-7 w-7 touch-none items-center justify-center',
|
||||||
|
'appearance-none rounded-none border-0 p-0 opacity-100 shadow-none ring-0',
|
||||||
|
'!bg-transparent hover:!bg-transparent active:!bg-transparent focus:!bg-transparent',
|
||||||
|
'focus:outline-none disabled:opacity-50 sm:h-5 sm:w-5',
|
||||||
|
].join(' ')
|
||||||
|
: [
|
||||||
|
'pointer-events-none absolute z-20 hidden h-7 w-7 touch-none items-center justify-center',
|
||||||
|
'appearance-none rounded-none border-0 p-0 opacity-100 shadow-none ring-0',
|
||||||
|
'!bg-transparent hover:!bg-transparent active:!bg-transparent focus:!bg-transparent',
|
||||||
|
'focus:outline-none disabled:opacity-50 sm:h-5 sm:w-5',
|
||||||
|
].join(' '),
|
||||||
handle === 'nw' ? '-left-3.5 -top-3.5 cursor-nwse-resize sm:-left-2.5 sm:-top-2.5' : '',
|
handle === 'nw' ? '-left-3.5 -top-3.5 cursor-nwse-resize sm:-left-2.5 sm:-top-2.5' : '',
|
||||||
handle === 'ne' ? '-right-3.5 -top-3.5 cursor-nesw-resize sm:-right-2.5 sm:-top-2.5' : '',
|
handle === 'ne' ? '-right-3.5 -top-3.5 cursor-nesw-resize sm:-right-2.5 sm:-top-2.5' : '',
|
||||||
handle === 'sw' ? '-bottom-3.5 -left-3.5 cursor-nesw-resize sm:-bottom-2.5 sm:-left-2.5' : '',
|
handle === 'sw' ? '-bottom-3.5 -left-3.5 cursor-nesw-resize sm:-bottom-2.5 sm:-left-2.5' : '',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user