summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-10-24 20:14:45 +0300
committerPaul Buetow <paul@buetow.org>2025-10-24 20:14:45 +0300
commitd52cb9a8c3dedc2a5395f181981805f582d5a772 (patch)
tree917f3f9622e4c459978810b4dd99071332dad85c /internal
parenta78ecb678a204f58b7152d26778cd7af91575ce3 (diff)
increment version after reindexing featurev0.3.0
Diffstat (limited to 'internal')
-rw-r--r--internal/app/messages.go2
-rw-r--r--internal/app/model.go117
-rw-r--r--internal/app/model_durations.go88
-rw-r--r--internal/app/model_keys.go2
-rw-r--r--internal/app/model_test.go2
-rw-r--r--internal/app/style.go1
-rw-r--r--internal/meta/version.go2
7 files changed, 123 insertions, 91 deletions
diff --git a/internal/app/messages.go b/internal/app/messages.go
index 6c571f7..3847750 100644
--- a/internal/app/messages.go
+++ b/internal/app/messages.go
@@ -33,3 +33,5 @@ type tagsSavedMsg struct {
tags []string
err error
}
+
+type reindexVideosMsg struct{}
diff --git a/internal/app/model.go b/internal/app/model.go
index 76ab358..9361e81 100644
--- a/internal/app/model.go
+++ b/internal/app/model.go
@@ -3,6 +3,7 @@ package app
import (
"fmt"
"path/filepath"
+ "runtime"
"strings"
"github.com/charmbracelet/bubbles/table"
@@ -168,6 +169,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m.handleVideosLoaded(typed)
case playVideoMsg:
return m.handlePlayVideo(typed), nil
+ case reindexVideosMsg:
+ return m.handleReindexVideos(typed)
case tagsSavedMsg:
return m.handleTagsSaved(typed)
case tea.WindowSizeMsg:
@@ -193,7 +196,7 @@ func (m model) View() string {
func (m model) renderBody() string {
helpLines := []string{
- "↑/↓ navigate • enter play • s sort • / filter • c crop • t edit tags • q quit",
+ "↑/↓ navigate • enter play • s sort • / filter • c crop • t edit tags • i re-index • q quit",
}
info := statusStyle.Render(m.statusText())
progressLine := m.renderProgressLine()
@@ -327,6 +330,118 @@ func (m model) handlePlayVideo(msg playVideoMsg) model {
return m
}
+func (m model) handleReindexVideos(msg reindexVideosMsg) (tea.Model, tea.Cmd) {
+ m.statusMessage = "Re-indexing videos..."
+ return m, loadVideosCmd(m.root, m.cachePath, m.progress)
+}
+
+func (m model) handleVideosLoaded(msg videosLoadedMsg) (tea.Model, tea.Cmd) {
+ m.loading = false
+ if msg.err != nil {
+ m.err = msg.err
+ m.statusMessage = fmt.Sprintf("error: %v", msg.err)
+ }
+
+ if len(m.videos) == 0 {
+ m.videos = msg.videos
+ } else {
+ existingVideos := make(map[string]int)
+ for i, v := range m.videos {
+ existingVideos[v.Path] = i
+ }
+
+ for _, newVideo := range msg.videos {
+ if i, ok := existingVideos[newVideo.Path]; ok {
+ m.videos[i] = newVideo
+ } else {
+ m.videos = append(m.videos, newVideo)
+ }
+ }
+ }
+
+ m.cache = msg.cache
+ m.pendingDurations = msg.pending
+ m.durationTotal = len(msg.pending)
+ m.durationDone = 0
+ m.applyFiltersAndSort()
+ m.updateStatusAfterLoad(msg)
+ m.durationInFlight = 0
+ if len(msg.pending) == 0 {
+ return m, nil
+ }
+ cmd := m.startDurationWorkers()
+ return m, cmd
+}
+
+func (m *model) updateStatusAfterLoad(msg videosLoadedMsg) {
+ if len(m.filtered) == 0 {
+ m.baseStatus = "No videos found"
+ m.statusMessage = m.baseStatus
+ return
+ }
+ status := ""
+ if len(msg.pending) > 0 {
+ status = fmt.Sprintf("Loaded %d videos, probing durations...", len(m.filtered))
+ if msg.cacheErr != nil {
+ status = fmt.Sprintf("Loaded %d videos (cache warning: %v), probing durations...", len(m.filtered), msg.cacheErr)
+ }
+ } else {
+ status = fmt.Sprintf("Loaded %d videos", len(m.filtered))
+ if msg.cacheErr != nil {
+ status = fmt.Sprintf("Loaded %d videos (cache warning: %v)", len(m.filtered), msg.cacheErr)
+ }
+ }
+ if msg.tagErr != nil {
+ status = fmt.Sprintf("%s (tag warning: %v)", status, msg.tagErr)
+ }
+ m.baseStatus = status
+ m.statusMessage = status
+}
+
+func (m *model) startDurationWorkers() tea.Cmd {
+ if len(m.pendingDurations) == 0 {
+ return nil
+ }
+ workers := runtime.NumCPU()
+ if workers < 1 {
+ workers = 1
+ }
+ if workers > 6 {
+ workers = 6
+ }
+ if workers > len(m.pendingDurations) {
+ workers = len(m.pendingDurations)
+ }
+ cmds := make([]tea.Cmd, 0, workers)
+ for i := 0; i < workers; i++ {
+ cmd := m.dequeueDurationCmd()
+ if cmd != nil {
+ cmds = append(cmds, cmd)
+ }
+ }
+ if len(cmds) == 0 {
+ return nil
+ }
+ return tea.Batch(cmds...)
+}
+
+func (m *model) dequeueDurationCmd() tea.Cmd {
+ if len(m.pendingDurations) == 0 {
+ return nil
+ }
+ path := m.pendingDurations[0]
+ m.pendingDurations = m.pendingDurations[1:]
+ m.durationInFlight++
+ return probeDurationsCmd(path, m.cache)
+}
+
+func (m model) activeCrop() string {
+ if m.cropEnabled && m.cropValue != "" {
+ return m.cropValue
+ }
+ return ""
+}
+
func (m model) handleProgressUpdate(msg progressUpdateMsg) (tea.Model, tea.Cmd) {
if !m.loading {
return m, nil
diff --git a/internal/app/model_durations.go b/internal/app/model_durations.go
index 95fd6c7..d8d767f 100644
--- a/internal/app/model_durations.go
+++ b/internal/app/model_durations.go
@@ -3,7 +3,6 @@ package app
import (
"fmt"
"path/filepath"
- "runtime"
"time"
tea "github.com/charmbracelet/bubbletea"
@@ -95,92 +94,5 @@ func (m *model) resetDurationState() {
m.durationInFlight = 0
}
-func (m *model) dequeueDurationCmd() tea.Cmd {
- if len(m.pendingDurations) == 0 {
- return nil
- }
- path := m.pendingDurations[0]
- m.pendingDurations = m.pendingDurations[1:]
- m.durationInFlight++
- return probeDurationsCmd(path, m.cache)
-}
-func (m *model) startDurationWorkers() tea.Cmd {
- if len(m.pendingDurations) == 0 {
- return nil
- }
- workers := runtime.NumCPU()
- if workers < 1 {
- workers = 1
- }
- if workers > 6 {
- workers = 6
- }
- if workers > len(m.pendingDurations) {
- workers = len(m.pendingDurations)
- }
- cmds := make([]tea.Cmd, 0, workers)
- for i := 0; i < workers; i++ {
- cmd := m.dequeueDurationCmd()
- if cmd != nil {
- cmds = append(cmds, cmd)
- }
- }
- if len(cmds) == 0 {
- return nil
- }
- return tea.Batch(cmds...)
-}
-
-func (m model) activeCrop() string {
- if m.cropEnabled && m.cropValue != "" {
- return m.cropValue
- }
- return ""
-}
-
-func (m model) handleVideosLoaded(msg videosLoadedMsg) (tea.Model, tea.Cmd) {
- m.loading = false
- if msg.err != nil {
- m.err = msg.err
- m.statusMessage = fmt.Sprintf("error: %v", msg.err)
- }
- m.videos = msg.videos
- m.cache = msg.cache
- m.pendingDurations = msg.pending
- m.durationTotal = len(msg.pending)
- m.durationDone = 0
- m.applyFiltersAndSort()
- m.updateStatusAfterLoad(msg)
- m.durationInFlight = 0
- if len(msg.pending) == 0 {
- return m, nil
- }
- cmd := m.startDurationWorkers()
- return m, cmd
-}
-func (m *model) updateStatusAfterLoad(msg videosLoadedMsg) {
- if len(m.filtered) == 0 {
- m.baseStatus = "No videos found"
- m.statusMessage = m.baseStatus
- return
- }
- status := ""
- if len(msg.pending) > 0 {
- status = fmt.Sprintf("Loaded %d videos, probing durations...", len(m.filtered))
- if msg.cacheErr != nil {
- status = fmt.Sprintf("Loaded %d videos (cache warning: %v), probing durations...", len(m.filtered), msg.cacheErr)
- }
- } else {
- status = fmt.Sprintf("Loaded %d videos", len(m.filtered))
- if msg.cacheErr != nil {
- status = fmt.Sprintf("Loaded %d videos (cache warning: %v)", len(m.filtered), msg.cacheErr)
- }
- }
- if msg.tagErr != nil {
- status = fmt.Sprintf("%s (tag warning: %v)", status, msg.tagErr)
- }
- m.baseStatus = status
- m.statusMessage = status
-}
diff --git a/internal/app/model_keys.go b/internal/app/model_keys.go
index ee15d5d..0e786d4 100644
--- a/internal/app/model_keys.go
+++ b/internal/app/model_keys.go
@@ -94,6 +94,8 @@ func (m model) handleTableKey(msg tea.KeyMsg) (tea.Model, tea.Cmd) {
return m.showHelpBar()
case "r":
return m.resetFilterState()
+ case "i":
+ return m, func() tea.Msg { return reindexVideosMsg{} }
default:
return m.updateTable(msg)
}
diff --git a/internal/app/model_test.go b/internal/app/model_test.go
index 6d1053b..4cb9bcf 100644
--- a/internal/app/model_test.go
+++ b/internal/app/model_test.go
@@ -583,7 +583,7 @@ func TestToggleHelpKeys(t *testing.T) {
loaded := videosLoadedMsg{videos: []video{vid}, cache: newDurationCache(filepath.Join(root, "cache.json"))}
modelAny, _ := m.handleVideosLoaded(loaded)
m = modelAny.(model)
- helpLine := "↑/↓ navigate • enter play • s sort • / filter • c crop • t edit tags • q quit"
+ helpLine := "↑/↓ navigate • enter play • s sort • / filter • c crop • t edit tags • i re-index • q quit"
if view := m.View(); !strings.Contains(view, helpLine) {
t.Fatalf("expected help line visible: %s", view)
}
diff --git a/internal/app/style.go b/internal/app/style.go
index de26b8a..452eaa6 100644
--- a/internal/app/style.go
+++ b/internal/app/style.go
@@ -10,6 +10,7 @@ var (
".avi": {},
".wmv": {},
".m4v": {},
+ ".webm": {},
}
tableStyle = lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("63")).Padding(0, 1)
headerStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("99")).Bold(true)
diff --git a/internal/meta/version.go b/internal/meta/version.go
index fcd820f..8b3a685 100644
--- a/internal/meta/version.go
+++ b/internal/meta/version.go
@@ -1,3 +1,3 @@
package meta
-const Version = "v0.2.5"
+const Version = "v0.3.0"