Web-based Winamp controller for CarPC � Go backend, mobile-first UI
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

113 lines
2.4KB

  1. // Package killist maintains a persistent list of track titles that should
  2. // be automatically skipped during playback — a direct port of the Delphi
  3. // KillList / KillFile feature.
  4. package killist
  5. import (
  6. "bufio"
  7. "os"
  8. "path/filepath"
  9. "strings"
  10. "sync"
  11. )
  12. // KillList is a thread-safe set of track titles to skip.
  13. type KillList struct {
  14. mu sync.RWMutex
  15. titles map[string]struct{}
  16. filepath string
  17. }
  18. // Load reads the kill list from disk (creates an empty list if the file
  19. // does not exist yet).
  20. func Load(path string) (*KillList, error) {
  21. kl := &KillList{
  22. titles: make(map[string]struct{}),
  23. filepath: path,
  24. }
  25. f, err := os.Open(path)
  26. if os.IsNotExist(err) {
  27. return kl, nil
  28. }
  29. if err != nil {
  30. return nil, err
  31. }
  32. defer f.Close()
  33. sc := bufio.NewScanner(f)
  34. for sc.Scan() {
  35. line := strings.TrimSpace(sc.Text())
  36. if line != "" {
  37. kl.titles[line] = struct{}{}
  38. }
  39. }
  40. return kl, sc.Err()
  41. }
  42. // Contains reports whether the given title is on the kill list.
  43. func (kl *KillList) Contains(title string) bool {
  44. kl.mu.RLock()
  45. defer kl.mu.RUnlock()
  46. _, ok := kl.titles[title]
  47. return ok
  48. }
  49. // Add appends a title and persists the list.
  50. func (kl *KillList) Add(title string) error {
  51. kl.mu.Lock()
  52. defer kl.mu.Unlock()
  53. kl.titles[title] = struct{}{}
  54. return kl.save()
  55. }
  56. // Remove removes a title and persists the list.
  57. func (kl *KillList) Remove(title string) error {
  58. kl.mu.Lock()
  59. defer kl.mu.Unlock()
  60. delete(kl.titles, title)
  61. return kl.save()
  62. }
  63. // List returns all titles currently on the kill list.
  64. func (kl *KillList) List() []string {
  65. kl.mu.RLock()
  66. defer kl.mu.RUnlock()
  67. out := make([]string, 0, len(kl.titles))
  68. for t := range kl.titles {
  69. out = append(out, t)
  70. }
  71. return out
  72. }
  73. // save writes the kill list atomically: it writes to a temp file in the same
  74. // directory, flushes, closes, then renames over the target. This ensures the
  75. // existing file is never truncated on a partial write or flush error.
  76. func (kl *KillList) save() error {
  77. dir := filepath.Dir(kl.filepath)
  78. tmp, err := os.CreateTemp(dir, ".killist-*.tmp")
  79. if err != nil {
  80. return err
  81. }
  82. tmpName := tmp.Name()
  83. w := bufio.NewWriter(tmp)
  84. for t := range kl.titles {
  85. if _, err := w.WriteString(t + "\n"); err != nil {
  86. tmp.Close()
  87. os.Remove(tmpName)
  88. return err
  89. }
  90. }
  91. if err := w.Flush(); err != nil {
  92. tmp.Close()
  93. os.Remove(tmpName)
  94. return err
  95. }
  96. if err := tmp.Close(); err != nil {
  97. os.Remove(tmpName)
  98. return err
  99. }
  100. return os.Rename(tmpName, kl.filepath)
  101. }