refactor: remove disabled watcher feature

This commit is contained in:
Mathis Maquenne
2026-03-01 21:56:54 +01:00
parent acf468eddd
commit 650d578b80
9 changed files with 0 additions and 404 deletions
-16
View File
@@ -1,16 +0,0 @@
package cmd
import (
"github.com/spf13/cobra"
)
// NOTE: The watch command is disabled due to database concurrency issues.
// To re-enable, uncomment RootCmd.AddCommand(watchCmd) in init().
var watchCmd = &cobra.Command{
Use: "watch",
Short: "Watch playlists and auto-download new tracks",
}
func init() {
// RootCmd.AddCommand(watchCmd)
}
-49
View File
@@ -1,49 +0,0 @@
package cmd
import (
"fmt"
"strings"
"time"
"github.com/mathismqn/godeez/internal/store"
"github.com/spf13/cobra"
)
var watchAddCmd = &cobra.Command{
Use: "add <playlist_id>",
Short: "Add a playlist to the watch list",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id := args[0]
ok, err := store.IsWatched(id)
if err != nil {
return err
}
if ok {
fmt.Printf("Playlist %s is already being watched\n", id)
return nil
}
playlist := &store.WatchedPlaylist{
ID: id,
Quality: strings.ToLower(opts.Quality),
BPM: opts.BPM,
Timeout: opts.Timeout,
}
if err := playlist.Save(); err != nil {
return fmt.Errorf("failed to add playlist %s to watch list: %w", id, err)
}
fmt.Printf("Playlist %s added to watch list\n", id)
return nil
},
}
func init() {
watchCmd.AddCommand(watchAddCmd)
watchAddCmd.Flags().StringVarP(&opts.Quality, "quality", "q", "mp3_320", "download quality [mp3_128, mp3_320, flac]")
watchAddCmd.Flags().DurationVarP(&opts.Timeout, "timeout", "t", 2*time.Minute, "timeout for each download (e.g. 10s, 1m, 2m30s)")
watchAddCmd.Flags().BoolVar(&opts.BPM, "bpm", false, "fetch BPM/key and add to file tags")
}
-41
View File
@@ -1,41 +0,0 @@
package cmd
import (
"fmt"
"os"
"text/tabwriter"
"github.com/mathismqn/godeez/internal/store"
"github.com/spf13/cobra"
)
var watchListCmd = &cobra.Command{
Use: "list",
Short: "List watched playlists",
RunE: func(cmd *cobra.Command, args []string) error {
playlists, err := store.ListWatchedPlaylists()
if err != nil {
return fmt.Errorf("failed to list watched playlists: %w", err)
}
if len(playlists) == 0 {
fmt.Println("No watched playlists.")
return nil
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "ID\tQuality\tFetch BPM\tTimeout")
fmt.Fprintln(w, "---\t-------\t----------\t-------")
for _, playlist := range playlists {
fmt.Fprintf(w, "%s\t%s\t%t\t%s\n", playlist.ID, playlist.Quality, playlist.BPM, playlist.Timeout)
}
w.Flush()
return nil
},
}
func init() {
watchCmd.AddCommand(watchListCmd)
}
-35
View File
@@ -1,35 +0,0 @@
package cmd
import (
"fmt"
"github.com/mathismqn/godeez/internal/store"
"github.com/spf13/cobra"
)
var watchRemoveCmd = &cobra.Command{
Use: "remove <playlist_id>",
Short: "Remove a playlist from the watch list",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
id := args[0]
ok, err := store.IsWatched(id)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("playlist %s is not being watched", id)
}
if err := store.RemoveWatchedPlaylist(id); err != nil {
return fmt.Errorf("failed to remove playlist %s from watch list: %w", id, err)
}
fmt.Printf("Playlist %s removed from watch list\n", id)
return nil
},
}
func init() {
watchCmd.AddCommand(watchRemoveCmd)
}
-30
View File
@@ -1,30 +0,0 @@
package cmd
import (
"context"
"github.com/mathismqn/godeez/internal/config"
"github.com/mathismqn/godeez/internal/watcher"
"github.com/spf13/cobra"
)
var watchRunCmd = &cobra.Command{
Use: "run",
Short: "Start the background playlist watcher",
Hidden: true,
PreRun: func(cmd *cobra.Command, args []string) {
appConfig, err := config.New("")
if err != nil {
return
}
cmd.SetContext(context.WithValue(cmd.Context(), appConfigKey, appConfig))
},
Run: func(cmd *cobra.Command, args []string) {
appConfig, _ := cmd.Context().Value(appConfigKey).(*config.Config)
watcher.New(appConfig).Run(cmd.Context(), opts)
},
}
func init() {
watchCmd.AddCommand(watchRunCmd)
}
-84
View File
@@ -1,84 +0,0 @@
package store
import (
"encoding/json"
"fmt"
"time"
bolt "go.etcd.io/bbolt"
)
type WatchedPlaylist struct {
ID string `json:"id"`
Quality string `json:"quality"`
BPM bool `json:"bpm"`
Timeout time.Duration `json:"timeout"`
}
var watchedBucket = []byte("watched")
func ListWatchedPlaylists() ([]*WatchedPlaylist, error) {
var playlists []*WatchedPlaylist
if err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(watchedBucket)
if b == nil {
return nil
}
return b.ForEach(func(k, v []byte) error {
var p WatchedPlaylist
if err := json.Unmarshal(v, &p); err != nil {
return err
}
playlists = append(playlists, &p)
return nil
})
}); err != nil {
return nil, err
}
return playlists, nil
}
func (p *WatchedPlaylist) Save() error {
return db.Update(func(tx *bolt.Tx) error {
b, err := tx.CreateBucketIfNotExists(watchedBucket)
if err != nil {
return err
}
data, err := json.Marshal(p)
if err != nil {
return err
}
return b.Put([]byte(p.ID), data)
})
}
func RemoveWatchedPlaylist(playlistID string) error {
return db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket(watchedBucket)
if b == nil {
return fmt.Errorf("bucket not found")
}
return b.Delete([]byte(playlistID))
})
}
func IsWatched(playlistID string) (bool, error) {
var found bool
err := db.View(func(tx *bolt.Tx) error {
b := tx.Bucket(watchedBucket)
if b == nil {
return nil
}
found = b.Get([]byte(playlistID)) != nil
return nil
})
return found, err
}
-38
View File
@@ -1,38 +0,0 @@
package watcher
import (
"os"
"path/filepath"
"runtime"
"strings"
)
// EnsureAutostart installs the watcher as a system autostart service.
// Currently disabled: installAutostart is not called due to DB concurrency issues.
func EnsureAutostart(homeDir string) error {
if isAutostartInstalled(homeDir) || isTemporaryExecutable() {
return nil
}
// return installAutostart(homeDir)
return nil
}
func isAutostartInstalled(homeDir string) bool {
if runtime.GOOS != "darwin" {
return false
}
path := filepath.Join(homeDir, "Library", "LaunchAgents", "com.godeez.watch.plist")
_, err := os.Stat(path)
return err == nil
}
func isTemporaryExecutable() bool {
exe, err := os.Executable()
if err != nil {
return true
}
return strings.Contains(exe, "go-build")
}
-48
View File
@@ -1,48 +0,0 @@
//go:build darwin
package watcher
import (
"fmt"
"os"
"os/exec"
"path/filepath"
)
func installAutostart(homeDir string) error {
exe, err := os.Executable()
if err != nil {
return err
}
exe, err = filepath.EvalSymlinks(exe)
if err != nil {
return err
}
plist := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.godeez.watch</string>
<key>ProgramArguments</key>
<array>
<string>%s</string>
<string>watch</string>
<string>run</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>`, exe)
path := filepath.Join(homeDir, "Library", "LaunchAgents", "com.godeez.watch.plist")
if err := os.WriteFile(path, []byte(plist), 0644); err != nil {
return err
}
return exec.Command("launchctl", "load", path).Run()
}
-63
View File
@@ -1,63 +0,0 @@
package watcher
import (
"context"
"errors"
"log"
"os"
"path/filepath"
"time"
"github.com/mathismqn/godeez/internal/config"
"github.com/mathismqn/godeez/internal/downloader"
"github.com/mathismqn/godeez/internal/logger"
"github.com/mathismqn/godeez/internal/store"
)
type Watcher struct {
appConfig *config.Config
logger *logger.Logger
}
func New(appConfig *config.Config) *Watcher {
logFile := filepath.Join(appConfig.HomeDir, ".godeez", "watcher.log")
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Fatalf("Failed to open log file: %v\n", err)
}
l := logger.New(log.New(file, "", log.LstdFlags))
return &Watcher{
appConfig: appConfig,
logger: l,
}
}
func (w *Watcher) Run(ctx context.Context, opts downloader.Options) {
w.logger.Infof("Starting watcher...")
for {
playlists, err := store.ListWatchedPlaylists()
if err != nil {
w.logger.Errorf("Failed to list watched playlists: %v", err)
}
for _, playlist := range playlists {
dl := downloader.New(w.appConfig, "playlist")
dl.Logger = w.logger
if err := dl.Run(ctx, opts, playlist.ID); err != nil {
if errors.Is(err, context.Canceled) {
return
}
w.logger.Errorf("Playlist %s: %v", playlist.ID, err)
}
}
select {
case <-ctx.Done():
return
case <-time.After(15 * time.Minute):
}
}
}