Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions cycler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package main

import (
"fmt"
"log/slog"
"time"

log "github.com/sirupsen/logrus"
"github.com/lmittmann/tint"
lfm "github.com/twangodev/lfm-api"
"github.com/xeyossr/go-discordrpc/client"
)
Expand All @@ -24,7 +25,7 @@ func cycle() {
LargeImage: "lfm_logo",
})
if err != nil {
log.Warnln("Failed to keep activity. Dropping connection to reconnect next cycle.")
slog.Warn("Failed to keep activity. Dropping connection to reconnect next cycle.", tint.Err(err))
logout()
return
}
Expand All @@ -33,46 +34,46 @@ func cycle() {
// Login logout logic
if s.Active { // Login if scrobble detected and if currently logged out
if !loggedIn {
log.Info("New scrobble detected. Logging in.")
slog.Info("New scrobble detected. Logging in.")
login()
}
} else { // No new scrobble
if loggedIn { // Logout if logged in
log.Info("No scrobble detected. Logging out.")
slog.Info("No scrobble detected. Logging out.")
logout()
} else { // Retain logout state
log.Traceln("No new scrobble detected.")
slog.Debug("No new scrobble detected.")
}
return
}
}

if ts != s.DataTimestamp { // Update old timestamp to match current scrobble
ts = s.DataTimestamp
log.WithFields(log.Fields{"scrobbling": s}).Infoln("Updating presence.")
slog.Info("Updating presence.", "scrobbling", s)
} else { // Prevents update of the same scrobble, use timestamp to differentiate
return
}

// First RPC attempt is without songLink
err1 := rpcClient.SetActivity(createActivity(s, false))
if err1 != nil {
log.Info("Failed to set base RPC. Retrying with detailed payload.")
slog.Info("Failed to set base RPC. Retrying with detailed payload.", tint.Err(err1))
} else {
log.Traceln("Successfully set base RPC.")
slog.Debug("Successfully set base RPC.")
}

// Second RPC attempt is with songLink
err2 := rpcClient.SetActivity(createActivity(s, true))
if err2 != nil {
if err1 != nil {
log.Warnln("Both attempts to set RPC failed. Reconnecting next cycle.")
slog.Warn("Both attempts to set RPC failed. Reconnecting next cycle.", "base_err", err1, "detailed_err", err2)
logout()
ts = time.Time{}
} else {
log.Info("Failed to set detailed RPC.")
slog.Info("Failed to set detailed RPC.", tint.Err(err2))
}
} else {
log.Traceln("Successfully set detailed RPC.")
slog.Debug("Successfully set detailed RPC.")
}
}
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ module lfm-cli
go 1.25.0

require (
github.com/lmittmann/tint v1.1.3
github.com/mattn/go-colorable v0.1.14
github.com/sirupsen/logrus v1.9.4
github.com/mattn/go-isatty v0.0.20
github.com/twangodev/lfm-api v1.1.0
github.com/urfave/cli/v2 v2.27.7
github.com/xeyossr/go-discordrpc v1.1.0
golang.org/x/net v0.55.0
)

require (
github.com/bozd4g/go-http-client v1.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.45.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/lmittmann/tint v1.1.3 h1:Hv4EaHWXQr+GTFnOU4VKf8UvAtZgn0VuKT+G0wFlO3I=
github.com/lmittmann/tint v1.1.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
Expand All @@ -14,8 +16,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twangodev/lfm-api v1.1.0 h1:xxg55iZfcYs+1rAHeiCrpSJay0G3ugrp+RFcqO97jc8=
Expand Down
45 changes: 27 additions & 18 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package main

import (
"fmt"
"log/slog"
"os"
"time"

"github.com/lmittmann/tint"
"github.com/mattn/go-colorable"
log "github.com/sirupsen/logrus"
"github.com/mattn/go-isatty"
lfm "github.com/twangodev/lfm-api"
"github.com/urfave/cli/v2"
)
Expand All @@ -28,6 +30,9 @@ var debug bool

var profileUrl string

// logLevel lets main() build the handler before flags are parsed; exec() raises it for --debug.
var logLevel = new(slog.LevelVar)

func exec(ctx *cli.Context) error {

showProfile = !ctx.Bool("hide-profile")
Expand All @@ -37,37 +42,40 @@ func exec(ctx *cli.Context) error {
keepStatus = ctx.Bool("keep-status")
debug = ctx.Bool("debug")
if debug {
log.SetLevel(log.TraceLevel)
logLevel.Set(slog.LevelDebug)
} else {
log.SetLevel(log.InfoLevel)
logLevel.Set(slog.LevelInfo)
}

profileUrl = fmt.Sprintf("%vuser/%v", lfm.LastFmUrl, username)

log.WithFields(log.Fields{
"username": username,
"refresh_interval": refreshInterval,
"show_profile": showProfile,
"show_loved": showLoved,
"show_covers": covers,
"show_elapsed": elapsed,
"keep_status": keepStatus,
"debug_enabled": debug,
}).Infoln("Configuration loaded from arguments")
slog.Info("Configuration loaded from arguments",
"username", username,
"refresh_interval", refreshInterval,
"show_profile", showProfile,
"show_loved", showLoved,
"show_covers", covers,
"show_elapsed", elapsed,
"keep_status", keepStatus,
"debug_enabled", debug,
)

for {
log.Traceln("Cycle begin.")
slog.Debug("Cycle begin.")
cycle()
log.Traceln("Cycle complete.")
slog.Debug("Cycle complete.")
time.Sleep(time.Duration(refreshInterval) * time.Second)
}

}

func main() {

log.SetFormatter(&log.TextFormatter{ForceColors: true})
log.SetOutput(colorable.NewColorableStdout())
slog.SetDefault(slog.New(tint.NewHandler(colorable.NewColorableStderr(), &tint.Options{
Level: logLevel,
TimeFormat: "15:04:05.000",
NoColor: !isatty.IsTerminal(os.Stderr.Fd()),
})))

app := &cli.App{
Name: name,
Expand Down Expand Up @@ -130,7 +138,8 @@ func main() {

err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
slog.Error("fatal error", tint.Err(err))
os.Exit(1)
}

}
18 changes: 9 additions & 9 deletions rpc.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
log "github.com/sirupsen/logrus"
"log/slog"

"github.com/lmittmann/tint"
"github.com/xeyossr/go-discordrpc/client"
)

Expand All @@ -10,29 +12,27 @@ var loggedIn = false
// Logout closes the socket; the next Login redials to recover a dropped connection
var rpcClient = client.NewClient(discordAppId)

func getRPCLogCtx() *log.Entry {
return log.WithFields(log.Fields{
"loggedIn": loggedIn,
})
func getRPCLogCtx() *slog.Logger {
return slog.With("loggedIn", loggedIn)
}

func login() {
if loggedIn {
return
}
if err := rpcClient.Login(); err != nil {
getRPCLogCtx().Warnln("Could not login to Discord.")
getRPCLogCtx().Warn("Could not login to Discord.", tint.Err(err))
logout()
return
}
loggedIn = true
getRPCLogCtx().Debugln("Successfully logged into Discord's RPC Server.")
getRPCLogCtx().Debug("Successfully logged into Discord's RPC Server.")
}

func logout() {
if err := rpcClient.Logout(); err != nil {
getRPCLogCtx().WithError(err).Debugln("Error closing Discord RPC connection.")
getRPCLogCtx().Debug("Error closing Discord RPC connection.", tint.Err(err))
}
loggedIn = false
getRPCLogCtx().Debugln("Successfully logged out of Discord's RPC Server.")
getRPCLogCtx().Debug("Successfully logged out of Discord's RPC Server.")
}
Loading