Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
modlastfm
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
Operations
Operations
Incidents
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
stella-irc
modlastfm
Commits
2c818f8c
Commit
2c818f8c
authored
Nov 13, 2018
by
Mike Jones
🌶
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Linter
parent
f4aa9df3
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
54 additions
and
19 deletions
+54
-19
internal/app/modlastfm/command/artist.go
internal/app/modlastfm/command/artist.go
+8
-2
internal/app/modlastfm/command/init.go
internal/app/modlastfm/command/init.go
+9
-5
internal/app/modlastfm/command/user.go
internal/app/modlastfm/command/user.go
+23
-2
internal/app/modlastfm/gauntlet/run.go
internal/app/modlastfm/gauntlet/run.go
+4
-3
internal/app/modlastfm/store/bolt.go
internal/app/modlastfm/store/bolt.go
+8
-7
internal/app/modlastfm/util/config.go
internal/app/modlastfm/util/config.go
+2
-0
No files found.
internal/app/modlastfm/command/artist.go
View file @
2c818f8c
...
...
@@ -7,6 +7,7 @@ import (
"github.com/n7st/lastfm-go/lastfm"
)
// ArtistInfo gets and formats an artist information string.
func
(
f
*
Fn
)
ArtistInfo
(
artist
string
,
nickname
string
)
string
{
artistInfo
,
err
:=
f
.
getArtistInfo
(
artist
)
...
...
@@ -17,8 +18,8 @@ func (f *Fn) ArtistInfo(artist string, nickname string) string {
return
f
.
fmtArtistInfo
(
artistInfo
)
}
// returns a comma separated list of tags, e.g.:
// death metal, old school death metal, danish, breakbeat, seen live
//
GetArtistTags
returns a comma separated list of tags, e.g.:
// death metal, old school death metal, danish, breakbeat, seen live
.
func
(
f
*
Fn
)
GetArtistTags
(
artist
string
,
nickname
string
)
string
{
var
tags
=
"no tags"
...
...
@@ -31,6 +32,8 @@ func (f *Fn) GetArtistTags(artist string, nickname string) string {
return
tags
}
// getArtistInfo() calls the Last.FM API and marshals the response into a
// lastfm.P.
func
(
f
*
Fn
)
getArtistInfo
(
artist
string
)
(
lastfm
.
ArtistGetInfo
,
error
)
{
return
f
.
LastFM
.
Artist
.
GetInfo
(
lastfm
.
P
{
"artist"
:
artist
,
...
...
@@ -38,6 +41,7 @@ func (f *Fn) getArtistInfo(artist string) (lastfm.ArtistGetInfo, error) {
})
}
// fmtArtistInfo formats artist information data into a pretty string.
func
(
f
*
Fn
)
fmtArtistInfo
(
artist
lastfm
.
ArtistGetInfo
)
string
{
return
fmt
.
Sprintf
(
"%s have %s plays and %s listeners. Similar artists: %s. Tags: %s."
,
artist
.
Name
,
...
...
@@ -48,6 +52,7 @@ func (f *Fn) fmtArtistInfo(artist lastfm.ArtistGetInfo) string {
)
}
// fmtArtistTags formats an artist's tags into a pretty string.
func
fmtArtistTags
(
artist
lastfm
.
ArtistGetInfo
)
string
{
var
(
t
[]
string
...
...
@@ -66,6 +71,7 @@ func fmtArtistTags(artist lastfm.ArtistGetInfo) string {
return
strings
.
Join
(
t
,
", "
)
}
// fmtArtistSimilar formats an artist's similar artists into a pretty string.
func
fmtArtistSimilar
(
artist
lastfm
.
ArtistGetInfo
)
string
{
var
(
s
[]
string
...
...
internal/app/modlastfm/command/init.go
View file @
2c818f8c
...
...
@@ -11,17 +11,21 @@ import (
)
type
(
FnCommand
func
(
message
string
,
username
string
)
string
// FnCommand is a command for registered users only.
FnCommand
func
(
message
string
,
username
string
)
string
// OpenFnCommand is a command which may be used by any user.
OpenFnCommand
func
(
message
string
,
nickname
string
)
string
)
// Fn contains utilities required by commands.
type
Fn
struct
{
Config
*
util
.
Config
Store
*
store
.
BoltStore
LastFM
*
lastfm
.
Api
}
// fmtError
()
should only be used if the result from a "top level" API call is
// fmtError should only be used if the result from a "top level" API call is
// an error (e.g. user.getRecentTracks for "now playing" is useless without the
// first API call).
// sub-API calls (e.g. track.getInfo for "now playing") may still fail with an
...
...
@@ -31,9 +35,9 @@ func fmtError(err error) string {
return
fmt
.
Sprintf
(
"Error: %s"
,
err
.
Error
())
}
//
the parameters here are strings because we're getting them from the XML
//
response.
// returns a string like "10.502%".
//
fmtPlayCountPercentage formats a user's percentage of an item's total plays.
//
The parameters here are strings because we're getting them from the XML
// re
sponse. Re
turns a string like "10.502%".
func
fmtPlaycountPercentage
(
needle
string
,
haystack
string
)
string
{
n
,
err
:=
strconv
.
ParseFloat
(
needle
,
32
)
h
,
err
:=
strconv
.
ParseFloat
(
haystack
,
32
)
...
...
internal/app/modlastfm/command/user.go
View file @
2c818f8c
...
...
@@ -14,6 +14,7 @@ const (
noTopArtistsForPeriodF
=
"%s has no listening data for this period"
)
// SetUser sets a username against a nickname in the database.
func
(
f
*
Fn
)
SetUser
(
message
string
,
nickname
string
)
string
{
var
err
error
...
...
@@ -38,6 +39,7 @@ func (f *Fn) SetUser(message string, nickname string) string {
return
fmt
.
Sprintf
(
"Last.fm username set to %s"
,
args
[
0
])
}
// NowPlaying shows which track the current user is now or last played.
func
(
f
*
Fn
)
NowPlaying
(
message
string
,
username
string
)
string
{
resp
,
err
:=
f
.
LastFM
.
User
.
GetRecentTracks
(
lastfm
.
P
{
"autocorrect"
:
1
,
...
...
@@ -55,6 +57,7 @@ func (f *Fn) NowPlaying(message string, username string) string {
return
fmtError
(
err
)
}
// UserArtistStats gets a formatted string of a given user's artist stats.
func
(
f
*
Fn
)
UserArtistStats
(
message
string
,
username
string
)
string
{
userArtistInfo
,
err
:=
f
.
getUserArtistInfo
(
username
,
message
)
...
...
@@ -65,6 +68,7 @@ func (f *Fn) UserArtistStats(message string, username string) string {
return
f
.
fmtUserArtistStats
(
username
,
userArtistInfo
)
}
// UserAlbumStats gets a formatted string of a given user's stats for an album.
func
(
f
*
Fn
)
UserAlbumStats
(
message
string
,
username
string
)
string
{
artist
,
album
:=
extractTitles
(
message
)
...
...
@@ -81,6 +85,7 @@ func (f *Fn) UserAlbumStats(message string, username string) string {
return
f
.
fmtUserAlbumStats
(
username
,
userAlbumInfo
)
}
// UserTrackStats gets a user's stats for a song.
func
(
f
*
Fn
)
UserTrackStats
(
message
string
,
username
string
)
string
{
artist
,
songTitle
:=
extractTitles
(
message
)
...
...
@@ -97,22 +102,29 @@ func (f *Fn) UserTrackStats(message string, username string) string {
return
f
.
fmtUserTrackStats
(
username
,
userTrackInfo
)
}
// UserTopWeek shows what a user has listened to most in the last week.
func
(
f
*
Fn
)
UserTopWeek
(
message
string
,
username
string
)
string
{
return
f
.
getUserTop
(
username
,
"7day"
)
}
// UserTopMonth shows what a user has listened to most in the last month.
func
(
f
*
Fn
)
UserTopMonth
(
message
string
,
username
string
)
string
{
return
f
.
getUserTop
(
username
,
"1month"
)
}
// UserTopYear shows what a user has listened to most in the last year.
func
(
f
*
Fn
)
UserTopYear
(
message
string
,
username
string
)
string
{
return
f
.
getUserTop
(
username
,
"12month"
)
}
// UserTopAll shows what a user has listened to most since registering to
// Last.fm.
func
(
f
*
Fn
)
UserTopAll
(
message
string
,
username
string
)
string
{
return
f
.
getUserTop
(
username
,
"overall"
)
}
// getUserTop shows what a user has listened to most over a given time period,
// returned as a pretty string.
func
(
f
*
Fn
)
getUserTop
(
username
string
,
period
string
)
string
{
userTop
,
err
:=
f
.
LastFM
.
User
.
GetTopArtists
(
lastfm
.
P
{
"user"
:
username
,
...
...
@@ -130,7 +142,7 @@ func (f *Fn) getUserTop(username string, period string) string {
return
f
.
fmtUserTop
(
username
,
userTop
)
}
// formats a "now playing" string from recent user tracks, e.g.:
// f
mtNowPlaying f
ormats a "now playing" string from recent user tracks, e.g.:
// ne7split is now playing Undergang "Kronisk betændelse i tarmene" (Døden læger
// alle sår) [10x] (death metal, old school death metal, danish, breakbeat, seen
// live)
...
...
@@ -176,6 +188,8 @@ func (f *Fn) fmtNowPlaying(username string, np lastfm.UserGetRecentTracks) strin
)
}
// fmtUserArtistStats returns a pretty string of a user's stats for a given
// artist.
func
(
f
*
Fn
)
fmtUserArtistStats
(
username
string
,
info
lastfm
.
ArtistGetInfo
)
string
{
return
fmt
.
Sprintf
(
"%s have %s total plays, of which %s are %s's (%s)"
,
info
.
Name
,
...
...
@@ -186,6 +200,7 @@ func (f *Fn) fmtUserArtistStats(username string, info lastfm.ArtistGetInfo) stri
)
}
// fmtUserAlbumStats returns a pretty string of a user's stats for a given album.
func
(
f
*
Fn
)
fmtUserAlbumStats
(
username
string
,
album
lastfm
.
AlbumGetInfo
)
string
{
return
fmt
.
Sprintf
(
statLineF
,
album
.
Name
,
...
...
@@ -197,6 +212,7 @@ func (f *Fn) fmtUserAlbumStats(username string, album lastfm.AlbumGetInfo) strin
)
}
// fmtUserTrackStats returns a pretty string of a user's stats for a given track.
func
(
f
*
Fn
)
fmtUserTrackStats
(
username
string
,
track
lastfm
.
TrackGetInfo
)
string
{
return
fmt
.
Sprintf
(
statLineF
,
track
.
Artist
.
Name
,
...
...
@@ -208,6 +224,7 @@ func (f *Fn) fmtUserTrackStats(username string, track lastfm.TrackGetInfo) strin
)
}
// fmtUserTop returns a comma-separated string of a user's top artists.
func
(
f
*
Fn
)
fmtUserTop
(
username
string
,
top
lastfm
.
UserGetTopArtists
)
string
{
var
(
output
[]
string
...
...
@@ -229,6 +246,7 @@ func (f *Fn) fmtUserTop(username string, top lastfm.UserGetTopArtists) string {
return
strings
.
Join
(
output
,
", "
)
}
// getUserTrackInfo gets information about a track for a given user.
func
(
f
*
Fn
)
getUserTrackInfo
(
username
string
,
artist
string
,
track
string
)
(
lastfm
.
TrackGetInfo
,
error
)
{
return
f
.
LastFM
.
Track
.
GetInfo
(
lastfm
.
P
{
"artist"
:
artist
,
...
...
@@ -238,6 +256,7 @@ func (f *Fn) getUserTrackInfo(username string, artist string, track string) (las
})
}
// getUserArtistInfo gets information about an artist for a given user.
func
(
f
*
Fn
)
getUserArtistInfo
(
username
string
,
artist
string
)
(
lastfm
.
ArtistGetInfo
,
error
)
{
return
f
.
LastFM
.
Artist
.
GetInfo
(
lastfm
.
P
{
"artist"
:
artist
,
...
...
@@ -246,6 +265,7 @@ func (f *Fn) getUserArtistInfo(username string, artist string) (lastfm.ArtistGet
})
}
// getUserArtistInfo gets information about an album for a given user.
func
(
f
*
Fn
)
getUserAlbumInfo
(
username
string
,
artist
string
,
album
string
)
(
lastfm
.
AlbumGetInfo
,
error
)
{
return
f
.
LastFM
.
Album
.
GetInfo
(
lastfm
.
P
{
"album"
:
album
,
...
...
@@ -255,7 +275,8 @@ func (f *Fn) getUserAlbumInfo(username string, artist string, album string) (las
})
}
// jesus christ
// extractTitles retrieves an artist and a title from user input using gnarly
// regex.
func
extractTitles
(
message
string
)
(
string
,
string
)
{
r
:=
regexp
.
MustCompile
(
`^(?P<Artist>.+) "(?P<Title>.+)"$`
)
m
:=
r
.
FindStringSubmatch
(
message
)
...
...
internal/app/modlastfm/gauntlet/run.go
View file @
2c818f8c
...
...
@@ -2,9 +2,10 @@ package gauntlet
import
(
"fmt"
"git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/store"
"strings"
"git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/store"
"github.com/n7st/lastfm-go/lastfm"
"git.netsplit.uk/stella-irc/modlastfm/internal/app/modlastfm/command"
...
...
@@ -19,7 +20,7 @@ var (
openCommands
=
make
(
map
[
string
]
command
.
OpenFnCommand
)
)
// sets up fn commands (which contain the configuration, database and an
//
New
sets up fn commands (which contain the configuration, database and an
// instance of shkh/lastfm-go/lastfm)
func
New
(
c
*
util
.
Config
,
store
*
store
.
BoltStore
)
{
var
fn
=
command
.
Fn
{
...
...
@@ -48,7 +49,7 @@ func New(c *util.Config, store *store.BoltStore) {
}
}
// Run
() attempts to run a command with the given user input
// Run
attempts to run a command with the given user input.
func
Run
(
nickname
string
,
message
string
,
db
*
store
.
BoltStore
)
string
{
var
arguments
=
strings
.
Split
(
message
,
" "
)
...
...
internal/app/modlastfm/store/bolt.go
View file @
2c818f8c
...
...
@@ -9,12 +9,13 @@ const (
noUserBucketErr
=
"DB error: no user bucket"
)
// BoltStore contains the database.
type
BoltStore
struct
{
db
*
bolt
.
DB
}
// NewBoltStore
() returns a BoltStore{}
struct with an initialised database
// member
// NewBoltStore
returns a BoltStore
struct with an initialised database
// member
.
func
NewBoltStore
(
db
*
bolt
.
DB
)
(
*
BoltStore
,
error
)
{
st
:=
&
BoltStore
{
db
:
db
}
err
:=
st
.
init
()
...
...
@@ -26,7 +27,7 @@ func NewBoltStore(db *bolt.DB) (*BoltStore, error) {
return
st
,
err
}
// SetAssociatedUser
() sets an associated Last.fm user against an IRC nickname
// SetAssociatedUser
sets an associated Last.fm user against an IRC nickname.
func
(
b
*
BoltStore
)
SetAssociatedUser
(
nickname
string
,
username
string
)
error
{
err
:=
b
.
db
.
Update
(
func
(
tx
*
bolt
.
Tx
)
error
{
userBucket
:=
tx
.
Bucket
([]
byte
(
userBucketKey
))
...
...
@@ -41,7 +42,7 @@ func (b *BoltStore) SetAssociatedUser(nickname string, username string) error {
return
err
}
// GetAssociatedUser
() gets an associated Last.fm username for an IRC nickname
// GetAssociatedUser
gets an associated Last.fm username for an IRC nickname.
func
(
b
*
BoltStore
)
GetAssociatedUser
(
nickname
string
)
(
string
,
error
)
{
var
username
[]
byte
...
...
@@ -60,8 +61,8 @@ func (b *BoltStore) GetAssociatedUser(nickname string) (string, error) {
return
string
(
username
),
err
}
// RemoveAssociatedUser
()
deletes a username set against a nickname (woo, GDPR
// compliance!)
// RemoveAssociatedUser deletes a username set against a nickname (woo, GDPR
// compliance!)
.
func
(
b
*
BoltStore
)
RemoveAssociatedUser
(
nickname
string
)
error
{
return
b
.
db
.
Update
(
func
(
tx
*
bolt
.
Tx
)
error
{
userBucket
:=
tx
.
Bucket
([]
byte
(
userBucketKey
))
...
...
@@ -74,7 +75,7 @@ func (b *BoltStore) RemoveAssociatedUser(nickname string) error {
})
}
// init
() initialises the database with the required buckets
// init
initialises the database with the required buckets.
func
(
b
*
BoltStore
)
init
()
error
{
return
b
.
db
.
Update
(
func
(
tx
*
bolt
.
Tx
)
error
{
_
,
err
:=
tx
.
CreateBucketIfNotExists
([]
byte
(
userBucketKey
))
...
...
internal/app/modlastfm/util/config.go
View file @
2c818f8c
...
...
@@ -13,12 +13,14 @@ const (
defaultDbPath
=
"lastfm.db"
)
// Config contains configuration settings for the program.
type
Config
struct
{
APIKey
string
APISecret
string
DBPath
string
}
// NewConfig creates and validates a Config struct from environment variables.
func
NewConfig
()
*
Config
{
c
:=
&
Config
{
APIKey
:
os
.
Getenv
(
apiKeyKey
),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment