package services
|
|
import (
|
"fmt"
|
"os"
|
"os/exec"
|
"path/filepath"
|
"runtime"
|
"time"
|
"voicesnap/internal/history"
|
)
|
|
// HistoryService provides recognition history to the frontend.
|
type HistoryService struct {
|
store *history.Store
|
}
|
|
// HistoryStatus summarizes full-history state for paginated views.
|
type HistoryStatus struct {
|
RetentionDays int `json:"retentionDays"`
|
StoragePath string `json:"storagePath"`
|
StorageSizeBytes int64 `json:"storageSizeBytes"`
|
StorageExists bool `json:"storageExists"`
|
StorageSizeAvailable bool `json:"storageSizeAvailable"`
|
TotalCount int `json:"totalCount"`
|
ExportedCount int `json:"exportedCount"`
|
UnexportedTodayCount int `json:"unexportedTodayCount"`
|
UnexportedLast7DaysCount int `json:"unexportedLast7DaysCount"`
|
UnexportedAllCount int `json:"unexportedAllCount"`
|
}
|
|
func NewHistoryService(store *history.Store) *HistoryService {
|
return &HistoryService{store: store}
|
}
|
|
// GetAll returns all history entries (newest first).
|
func (s *HistoryService) GetAll() []history.Entry {
|
return s.store.GetAll()
|
}
|
|
// GetPage returns one page of history entries (newest first).
|
func (s *HistoryService) GetPage(page int, pageSize int) history.PageResult {
|
return s.store.GetPage(page, pageSize)
|
}
|
|
// GetStatus returns full-history metadata used by the paginated UI.
|
func (s *HistoryService) GetStatus() HistoryStatus {
|
path := s.store.Path()
|
counts := s.store.Counts(time.Now(), time.Local)
|
status := HistoryStatus{
|
RetentionDays: s.store.GetRetentionDays(),
|
StoragePath: path,
|
TotalCount: counts.TotalCount,
|
ExportedCount: counts.ExportedCount,
|
UnexportedTodayCount: counts.UnexportedTodayCount,
|
UnexportedLast7DaysCount: counts.UnexportedLast7DaysCount,
|
UnexportedAllCount: counts.UnexportedAllCount,
|
}
|
|
if info, err := os.Stat(path); err == nil {
|
status.StorageExists = true
|
status.StorageSizeAvailable = true
|
status.StorageSizeBytes = info.Size()
|
} else if os.IsPermission(err) {
|
status.StorageExists = true
|
}
|
return status
|
}
|
|
// Add adds a new recognition result to history.
|
func (s *HistoryService) Add(text string) {
|
s.store.Add(text)
|
}
|
|
// Delete removes a single entry by timestamp.
|
func (s *HistoryService) Delete(timestamp int64) {
|
s.store.Delete(timestamp)
|
}
|
|
// ClearAll removes all history entries.
|
func (s *HistoryService) ClearAll() {
|
s.store.ClearAll()
|
}
|
|
// ClearExported removes all history entries that have already been exported.
|
func (s *HistoryService) ClearExported() (history.ClearExportedResult, error) {
|
return s.store.ClearExported()
|
}
|
|
// GetRetentionDays returns the current retention period in days.
|
func (s *HistoryService) GetRetentionDays() int {
|
return s.store.GetRetentionDays()
|
}
|
|
// SetRetentionDays sets how long to keep history (0 = forever).
|
func (s *HistoryService) SetRetentionDays(days int) error {
|
return s.store.SetRetentionDays(days)
|
}
|
|
// GetStoragePath returns the full history.json path.
|
func (s *HistoryService) GetStoragePath() string {
|
return s.store.Path()
|
}
|
|
// OpenStorageFolder opens the folder containing history.json.
|
func (s *HistoryService) OpenStorageFolder() error {
|
dir := filepath.Dir(s.store.Path())
|
info, err := os.Stat(dir)
|
if err != nil {
|
return fmt.Errorf("history storage folder unavailable: %w", err)
|
}
|
if !info.IsDir() {
|
return fmt.Errorf("history storage path is not a folder: %s", dir)
|
}
|
|
switch runtime.GOOS {
|
case "darwin":
|
return exec.Command("open", dir).Start()
|
case "windows":
|
return exec.Command("rundll32", "url.dll,FileProtocolHandler", dir).Start()
|
default:
|
return exec.Command("xdg-open", dir).Start()
|
}
|
}
|