Compare commits

...

2 Commits

Author SHA1 Message Date
f94629e55e Add in-module cancel for running jobs 2025-12-10 15:46:18 -05:00
a8d42b2c8f Add runtime encoder fallback to git_converter 2025-12-10 15:37:03 -05:00
3 changed files with 79 additions and 8 deletions

View File

@ -186,6 +186,19 @@ func (q *Queue) Stats() (pending, running, completed, failed int) {
return
}
// CurrentRunning returns the currently running job, if any.
func (q *Queue) CurrentRunning() *Job {
q.mu.RLock()
defer q.mu.RUnlock()
for _, job := range q.jobs {
if job.Status == JobStatusRunning {
clone := *job
return &clone
}
}
return nil
}
// Pause pauses a running job
func (q *Queue) Pause(id string) error {
q.mu.Lock()

32
main.go
View File

@ -4465,12 +4465,32 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
}
var convertBtn *widget.Button
var cancelBtn *widget.Button
var cancelQueueBtn *widget.Button
cancelBtn = widget.NewButton("Cancel", func() {
state.cancelConvert(cancelBtn, convertBtn, activity, statusLabel)
})
cancelBtn.Importance = widget.DangerImportance
cancelBtn.Disable()
cancelQueueBtn = widget.NewButton("Cancel Active Job", func() {
if state.jobQueue == nil {
dialog.ShowInformation("Cancel", "Queue not initialized.", state.window)
return
}
job := state.jobQueue.CurrentRunning()
if job == nil {
dialog.ShowInformation("Cancel", "No running job to cancel.", state.window)
return
}
if err := state.jobQueue.Cancel(job.ID); err != nil {
dialog.ShowError(fmt.Errorf("failed to cancel job: %w", err), state.window)
return
}
dialog.ShowInformation("Cancelled", fmt.Sprintf("Cancelled job: %s", job.Title), state.window)
})
cancelQueueBtn.Importance = widget.DangerImportance
cancelQueueBtn.Disable()
// Add to Queue button
addQueueBtn := widget.NewButton("Add to Queue", func() {
state.persistConvertConfig()
@ -4594,7 +4614,7 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
leftControls := container.NewHBox(resetBtn, loadCfgBtn, saveCfgBtn, autoCompareCheck)
centerStatus := container.NewHBox(activity, statusLabel)
rightControls := container.NewHBox(cancelBtn, viewLogBtn, addQueueBtn, convertBtn)
rightControls := container.NewHBox(cancelBtn, cancelQueueBtn, viewLogBtn, addQueueBtn, convertBtn)
actionInner := container.NewBorder(nil, nil, leftControls, rightControls, centerStatus)
actionBar := ui.TintedBar(convertColor, actionInner)
@ -4626,6 +4646,11 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
if isBusy {
convertBtn.Disable()
cancelBtn.Enable()
if state.jobQueue != nil && state.jobQueue.CurrentRunning() != nil {
cancelQueueBtn.Enable()
} else {
cancelQueueBtn.Disable()
}
activity.Show()
if !activity.Running() {
activity.Start()
@ -4637,6 +4662,11 @@ func buildConvertView(state *appState, src *videoSource) fyne.CanvasObject {
convertBtn.Disable()
}
cancelBtn.Disable()
if state.jobQueue != nil && state.jobQueue.CurrentRunning() != nil {
cancelQueueBtn.Enable()
} else {
cancelQueueBtn.Disable()
}
activity.Stop()
activity.Hide()
}

View File

@ -7,6 +7,22 @@
OUT="Converted"
mkdir -p "$OUT"
# Choose best available encoder with runtime check
pick_encoder() {
# candidate list in order of preference
local candidates=("$@")
for enc in "${candidates[@]}"; do
# Quick runtime probe: attempt tiny encode and discard output
if ffmpeg -hide_banner -loglevel error \
-f lavfi -i color=size=16x16:rate=1 -frames:v 1 \
-c:v "$enc" -f null - >/dev/null 2>&1; then
echo "$enc"
return 0
fi
done
return 1
}
clear
cat << "EOF"
@ -61,8 +77,8 @@ echo
read -p " Enter 16 → " c
case $c in
1|3) codec="av1_amf" ;;
2|4|5|6) codec="hevc_amf" ;;
1|3) codec_pref=("av1_amf" "libaom-av1") ;;
2|4|5|6) codec_pref=("hevc_amf" "hevc_nvenc" "h264_nvenc" "libx265") ;;
*) echo "Invalid — exiting"; sleep 3; exit ;;
esac
@ -76,6 +92,15 @@ case $c in
*) fps_filter=""; suf="" ;;
esac
# Resolve encoder now, once
codec=$(pick_encoder "${codec_pref[@]}")
if [ -z "$codec" ]; then
echo "No supported encoder found (tried: ${codec_pref[*]})."
echo "Install/enable GPU drivers or fall back to CPU codecs."
echo "Defaulting to libx265."
codec="libx265"
fi
# — Bitrate Selection —
clear
cat << "EOF"
@ -131,14 +156,17 @@ for f in *.mp4 *.mkv *.mov *.avi *.wmv *.ts *.m2ts; do
fi
# FINAL FIXED CONVERSION — 1080p FORCED + 60fps works
ffmpeg -y -i "$f" $bitdepth_filter -vf "scale=${scale}:flags=lanczos${fps_filter}" \
-c:v "$codec" -b:v "$this_bitrate" -c:a aac -b:a 192k -ac 2 "$out"
echo "DONE → $(basename "$out")"
if ffmpeg -y -i "$f" $bitdepth_filter -vf "scale=${scale}:flags=lanczos${fps_filter}" \
-c:v "$codec" -b:v "$this_bitrate" -c:a aac -b:a 192k -ac 2 "$out"; then
echo "DONE → $(basename "$out")"
else
echo "FAILED → $f (encoder: $codec). Check ffmpeg output above."
rm -f "$out"
fi
echo
done
echo "========================================================"
echo "All finished — files in '$OUT'"
echo "========================================================"
read -p "Press Enter to exit"
read -p "Press Enter to exit"