From a8bfc458ef89b7163f61a114e40129ffd3758f6e Mon Sep 17 00:00:00 2001 From: a Date: Fri, 17 Feb 2023 15:05:06 -0600 Subject: [PATCH 1/2] cache --- src/cache/cache.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/cache/cache.go diff --git a/src/cache/cache.go b/src/cache/cache.go new file mode 100644 index 0000000..3c3dc9d --- /dev/null +++ b/src/cache/cache.go @@ -0,0 +1,85 @@ +package cache + +import ( + "encoding/json" + "os" + "path/filepath" + "time" +) + +type Cache struct { + Root string +} + +type CacheEntry struct { + Expire time.Time `json:"e"` + Value string `json:"v"` +} + +func DefaultCache() *Cache { + return &Cache{ + Root: filepath.Join(os.TempDir(), "gospt.cache"), + } +} + +func (c *Cache) load() (map[string]CacheEntry, error) { + out := map[string]CacheEntry{} + cache, err := os.Open(c.Root) + if err != nil { + return nil, err + } + if err := json.NewDecoder(cache).Decode(&out); err != nil { + return nil, err + } + return out, nil +} + +func (c *Cache) save(map[string]CacheEntry) error { + out := map[string]CacheEntry{} + payload, err := json.Marshal(out) + if err != nil { + return err + } + err = os.WriteFile(c.Root, payload, 0640) + if err != nil { + return err + } + return nil +} + +func (c *Cache) GetOrDo(key string, do func() (string, error), ttl time.Duration) (string, error) { + conf, err := c.load() + if err != nil { + return c.Do(key, do, ttl) + } + val, ok := conf[key] + if !ok { + return c.Do(key, do, ttl) + } + if time.Now().After(val.Expire) { + return c.Do(key, do, ttl) + } + return val.Value, nil +} + +func (c *Cache) Do(key string, do func() (string, error), ttl time.Duration) (string, error) { + if do == nil { + return "", nil + } + res, err := do() + if err != nil { + return "", err + } + return c.Put(key, res, ttl) +} +func (c *Cache) Put(key string, value string, ttl time.Duration) (string, error) { + conf, err := c.load() + if err != nil { + conf = map[string]CacheEntry{} + } + conf[key] = CacheEntry{ + Expire: time.Now().Add(ttl), + Value: value, + } + return value, nil +} From e58674ce171fab0a1b43158a1dd6e1750554b698 Mon Sep 17 00:00:00 2001 From: a Date: Fri, 17 Feb 2023 15:31:19 -0600 Subject: [PATCH 2/2] cache --- go.mod | 5 ++++- go.sum | 16 +++++++++++++++- src/cache/cache.go | 19 ++++++++++++++++--- src/cmd/root.go | 14 ++++++++++++-- src/commands/commands.go | 29 ++++++++++++++++++----------- 5 files changed, 65 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 0a170a0..7ac0f72 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/zmb3/spotify/v2 v2.3.1 golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5 modernc.org/sqlite v1.20.3 + tuxpa.in/a/zlog v1.60.0 ) require ( @@ -25,6 +26,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect @@ -34,11 +36,12 @@ require ( github.com/muesli/termenv v0.13.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/rs/zerolog v1.28.0 // indirect github.com/sahilm/fuzzy v0.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect golang.org/x/mod v0.3.0 // indirect golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 // indirect diff --git a/go.sum b/go.sum index 9255823..4dbc1df 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cristalhq/aconfig v0.17.0/go.mod h1:NXaRp+1e6bkO4dJn+wZ71xyaihMDYPtCSvEhMTm/H3E= github.com/cristalhq/aconfig v0.18.3 h1:Or12LIWIF+2mQpcGWA2PQnNc55+WiHFAqRjYh/pQNtM= @@ -72,6 +74,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -145,6 +148,9 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -168,6 +174,7 @@ github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs= github.com/muesli/termenv v0.13.0 h1:wK20DRpJdDX8b7Ek2QfhvqhRQFZ237RGRO0RQ/Iqdy0= github.com/muesli/termenv v0.13.0/go.mod h1:sP1+uffeLaEYpyOTb8pLCUctGcGLnoFjSn4YJK5e2bc= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -177,6 +184,9 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= +github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI= github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= @@ -311,10 +321,12 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -497,3 +509,5 @@ modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +tuxpa.in/a/zlog v1.60.0 h1:bU4wJk6nwvaFsKIvKKxgGM0uO+Z2kaE8LzgRiQ4NCRw= +tuxpa.in/a/zlog v1.60.0/go.mod h1:1t8SX1a4zLy+p6ylGn6m1ZXnssTPr/2ErdPjjSP+C2k= diff --git a/src/cache/cache.go b/src/cache/cache.go index 3c3dc9d..afd8005 100644 --- a/src/cache/cache.go +++ b/src/cache/cache.go @@ -5,6 +5,8 @@ import ( "os" "path/filepath" "time" + + "tuxpa.in/a/zlog/log" ) type Cache struct { @@ -34,12 +36,12 @@ func (c *Cache) load() (map[string]CacheEntry, error) { return out, nil } -func (c *Cache) save(map[string]CacheEntry) error { - out := map[string]CacheEntry{} - payload, err := json.Marshal(out) +func (c *Cache) save(m map[string]CacheEntry) error { + payload, err := json.Marshal(m) if err != nil { return err } + log.Trace().Str("tosave", string(payload)).Msg("saving cache") err = os.WriteFile(c.Root, payload, 0640) if err != nil { return err @@ -50,6 +52,7 @@ func (c *Cache) save(map[string]CacheEntry) error { func (c *Cache) GetOrDo(key string, do func() (string, error), ttl time.Duration) (string, error) { conf, err := c.load() if err != nil { + log.Trace().Err(err).Msg("cache failed read") return c.Do(key, do, ttl) } val, ok := conf[key] @@ -72,6 +75,7 @@ func (c *Cache) Do(key string, do func() (string, error), ttl time.Duration) (st } return c.Put(key, res, ttl) } + func (c *Cache) Put(key string, value string, ttl time.Duration) (string, error) { conf, err := c.load() if err != nil { @@ -81,5 +85,14 @@ func (c *Cache) Put(key string, value string, ttl time.Duration) (string, error) Expire: time.Now().Add(ttl), Value: value, } + log.Trace().Str("key", key).Str("val", value).Msg("saving new cache key") + err = c.save(conf) + if err != nil { + log.Trace().Err(err).Msg("cache failed save") + } return value, nil } + +func (c *Cache) Clear() error { + return os.Remove(c.Root) +} diff --git a/src/cmd/root.go b/src/cmd/root.go index 24e0e36..ff7b88d 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -11,6 +11,7 @@ import ( "gitea.asdf.cafe/abs3nt/gospt/src/auth" "gitea.asdf.cafe/abs3nt/gospt/src/config" "gitea.asdf.cafe/abs3nt/gospt/src/gctx" + "tuxpa.in/a/zlog" "github.com/cristalhq/aconfig" "github.com/cristalhq/aconfig/aconfigyaml" @@ -24,6 +25,7 @@ var ( client *spotify.Client cfgFile string userLicense string + verbose bool rootCmd = &cobra.Command{ Use: "gospt", @@ -45,13 +47,21 @@ func Execute(defCmd string) { } func init() { + zlog.SetGlobalLevel(zlog.DebugLevel) if len(os.Args) > 1 { if os.Args[1] == "completion" || os.Args[1] == "__complete" { return } } - cobra.OnInitialize(initConfig) - cobra.OnInitialize(initClient) + rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "enable verbose logging") + + cobra.OnInitialize(func() { + if verbose { + zlog.SetGlobalLevel(zlog.TraceLevel) + } + }) + cobra.OnInitialize(initConfig, initClient) + } func initClient() { diff --git a/src/commands/commands.go b/src/commands/commands.go index d287eef..4039307 100644 --- a/src/commands/commands.go +++ b/src/commands/commands.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "gitea.asdf.cafe/abs3nt/gospt/src/cache" "gitea.asdf.cafe/abs3nt/gospt/src/gctx" "github.com/zmb3/spotify/v2" @@ -870,11 +871,26 @@ func LinkContext(ctx *gctx.Context, client *spotify.Client) (string, error) { } func NowPlaying(ctx *gctx.Context, client *spotify.Client) error { - current, err := client.PlayerCurrentlyPlaying(ctx) + song, err := cache.DefaultCache().GetOrDo("now_playing", func() (string, error) { + current, err := client.PlayerCurrentlyPlaying(ctx) + if err != nil { + return "", err + } + str := FormatSong(current) + return str, nil + }, 5*time.Second) if err != nil { return err } - return PrintPlaying(current) + fmt.Println(song) + return nil +} +func FormatSong(current *spotify.CurrentlyPlaying) string { + icon := "▶" + if !current.Playing { + icon = "⏸" + } + return fmt.Sprintf("%s %s - %s", icon, current.Item.Name, current.Item.Artists[0].Name) } func Shuffle(ctx *gctx.Context, client *spotify.Client) error { @@ -935,15 +951,6 @@ func PrintState(state *spotify.PlayerState) error { return nil } -func PrintPlaying(current *spotify.CurrentlyPlaying) error { - icon := "▶" - if !current.Playing { - icon = "⏸" - } - fmt.Println(fmt.Sprintf("%s %s - %s", icon, current.Item.Name, current.Item.Artists[0].Name)) - return nil -} - func PrintDevices(devices []spotify.PlayerDevice) error { out, err := json.MarshalIndent(devices, "", " ") if err != nil {