33import requests
44import random
55
6+ from sqlalchemy import Table , Column , PrimaryKeyConstraint , String
7+
68from cloudbot import hook
7- from cloudbot .util import timeformat
9+ from cloudbot .util import timeformat , web , botvars
810
911api_url = "http://ws.audioscrobbler.com/2.0/?format=json"
1012
13+ table = Table (
14+ "lastfm" ,
15+ botvars .metadata ,
16+ Column ('nick' , String ),
17+ Column ('acc' , String ),
18+ PrimaryKeyConstraint ('nick' )
19+ )
20+
21+
22+ @hook .on_start ()
23+ def load_cache (db ):
24+ """
25+ :type db: sqlalchemy.orm.Session
26+ """
27+ global last_cache
28+ last_cache = []
29+ for row in db .execute (table .select ()):
30+ nick = row ["nick" ]
31+ account = row ["acc" ]
32+ last_cache .append ((nick , account ))
33+
34+
35+ def get_account (nick ):
36+ """looks in last_cache for the lastfm account name"""
37+ last_account = [row [1 ] for row in last_cache if nick .lower () == row [0 ]]
38+ if not last_account :
39+ return
40+ else :
41+ last_account = last_account [0 ]
42+ return last_account
1143
12- @hook .command ("lastfm" , "last" , "lfm" , "l" , autohelp = False )
44+
45+ @hook .command ("lastfm" , "last" , "np" , "l" , autohelp = False )
1346def lastfm (text , nick , db , bot , notice ):
1447 """[user] [dontsave] - displays the now playing (or last played) track of LastFM user [user]"""
1548 api_key = bot .config .get ("api_keys" , {}).get ("lastfm" )
@@ -23,17 +56,14 @@ def lastfm(text, nick, db, bot, notice):
2356 else :
2457 user = text
2558
26- db .execute ("create table if not exists lastfm(nick primary key, acc)" )
27-
2859 if not user :
29- user = db .execute ("select acc from lastfm where nick=lower(:nick)" ,
30- {'nick' : nick }).fetchone ()
60+ user = get_account (nick )
3161 if not user :
3262 notice (lastfm .__doc__ )
3363 return
34- user = user [0 ]
3564
36- params = {'method' : 'user.getrecenttracks' , 'api_key' : api_key , 'user' : user , 'limit' : 1 }
65+ params = {'method' : 'user.getrecenttracks' ,
66+ 'api_key' : api_key , 'user' : user , 'limit' : 1 }
3767 request = requests .get (api_url , params = params )
3868
3969 if request .status_code != requests .codes .ok :
@@ -71,12 +101,15 @@ def lastfm(text, nick, db, bot, notice):
71101 title = track ["name" ]
72102 album = track ["album" ]["#text" ]
73103 artist = track ["artist" ]["#text" ]
104+ url = web .try_shorten (track ["url" ])
74105
75106 out = '{} {} "{}"' .format (user , status , title )
76107 if artist :
77108 out += " by \x02 {}\x0f " .format (artist )
78109 if album :
79110 out += " from the album \x02 {}\x0f " .format (album )
111+ if url :
112+ out += " {}" .format (url )
80113
81114 # append ending based on what type it was
82115 out += ending
@@ -85,18 +118,31 @@ def lastfm(text, nick, db, bot, notice):
85118 db .execute ("insert or replace into lastfm(nick, acc) values (:nick, :account)" ,
86119 {'nick' : nick .lower (), 'account' : user })
87120 db .commit ()
88-
121+ load_cache ( db )
89122 return out
90123
91124
92- @hook .command ("lastfmcompare" , "compare" )
93- def lastfmcompare (text , bot ):
94- """<user1> <user2> - compare the music compatibility of two LastFM users """
125+ @hook .command ("lastfmcompare" , "compare" , "lc" )
126+ def lastfmcompare (text , nick , bot , db ):
127+ """[user] ([user] optional) - displays the now playing (or last played) track of LastFM user [user] """
95128 api_key = bot .config .get ("api_keys" , {}).get ("lastfm" )
96129 if not api_key :
97130 return "No last.fm API key set."
131+ if not text :
132+ return ("please specify a lastfm username to compare" )
133+ try :
134+ user1 , user2 = text .split ()
135+ except :
136+ user2 = text
137+ user1 = nick
98138
99- user1 , user2 = text .split ()
139+ user2_check = get_account (user2 )
140+ if user2_check :
141+ user2 = user2_check
142+
143+ user1_check = get_account (user1 )
144+ if user1_check :
145+ user1 = user1_check
100146
101147 params = {
102148 'method' : 'tasteometer.compare' ,
@@ -112,8 +158,13 @@ def lastfmcompare(text, bot):
112158 return "Failed to fetch info ({})" .format (request .status_code )
113159
114160 data = request .json ()
161+ if 'error' in data :
162+ return "Error: {}." .format (data ["message" ])
115163
116- score = int (float (data ["comparison" ]["result" ]["score" ]) * 100 )
164+ score = float (data ["comparison" ]["result" ]["score" ])
165+ score = float ("{:.3f}" .format (score * 100 ))
166+ if score == 0 :
167+ return "{} and {} have no common listening history." .format (user2 , user1 )
117168 level = "Super" if score > 95 else "Very High" if score > 80 else "High" if score > 60 else \
118169 "Medium" if score > 40 else "Low" if score > 10 else "Very Low"
119170
@@ -122,7 +173,85 @@ def lastfmcompare(text, bot):
122173 type (data ["comparison" ]["result" ]["artists" ]["artist" ]) == list else \
123174 [data ["comparison" ]["result" ]["artists" ]["artist" ]["name" ]] if "artist" \
124175 in data ["comparison" ]["result" ]["artists" ] else ""
125- artist_string = "\x02 In Common:\x02 " + ", " .join (artists ) if artists else ""
176+ artist_string = "\x02 In Common:\x02 " + \
177+ ", " .join (artists ) if artists else ""
178+
179+ return "Musical compatibility between \x02 {}\x02 and \x02 {}\x02 : {} (\x02 {}%\x02 ) {}" .format (user1 , user2 , level ,
180+ score , artist_string )
181+
182+
183+ @hook .command ("ltop" , "ltt" , autohelp = False )
184+ def toptrack (text , nick , db , bot , notice ):
185+ """Grabs a list of the top tracks for a last.fm username"""
186+ api_key = bot .config .get ("api_keys" , {}).get ("lastfm" )
187+ if not api_key :
188+ return "error: no api key set"
189+
190+ if text :
191+ username = get_account (text )
192+ if not username :
193+ username = text
194+ else :
195+ username = get_account (nick )
196+ if not username :
197+ return ("No last.fm username specified and no last.fm username is set in the database." )
198+
199+ params = {
200+ 'api_key' : api_key ,
201+ 'method' : 'user.gettoptracks' ,
202+ 'user' : username ,
203+ 'limit' : 5
204+ }
205+ request = requests .get (api_url , params = params )
126206
127- return "Musical compatibility between \x02 {}\x02 and \x02 {}\x02 : {} (\x02 {}%\x02 )" .format (user1 , user2 , level ,
128- score ), artist_string
207+ if request .status_code != requests .codes .ok :
208+ return "Failed to fetch info ({})" .format (request .status_code )
209+
210+ data = request .json ()
211+ if 'error' in data :
212+ return "Error: {}." .format (data ["message" ])
213+ out = "{}'s favorite songs: " .format (username )
214+ for r in range (5 ):
215+ track_name = data ["toptracks" ]["track" ][r ]["name" ]
216+ artist_name = data ["toptracks" ]["track" ][r ]["artist" ]["name" ]
217+ play_count = data ["toptracks" ]["track" ][r ]["playcount" ]
218+ out = out + "{} by {} listened to {} times. " .format (track_name , artist_name , play_count )
219+ return out
220+
221+
222+ @hook .command ("lta" , "topartist" , autohelp = False )
223+ def topartists (text , nick , db , bot , notice ):
224+ """Grabs a list of the top artists for a last.fm username. You can set your lastfm username with .l username"""
225+ api_key = bot .config .get ("api_keys" , {}).get ("lastfm" )
226+ if not api_key :
227+ return "error: no api key set"
228+
229+ if text :
230+ username = get_account (text )
231+ if not username :
232+ username = text
233+ else :
234+ username = get_account (nick )
235+ if not username :
236+ return ("No last.fm username specified and no last.fm username is set in the database." )
237+ params = {
238+ 'api_key' : api_key ,
239+ 'method' : 'user.gettopartists' ,
240+ 'user' : username ,
241+ 'limit' : 5
242+ }
243+ request = requests .get (api_url , params = params )
244+
245+ if request .status_code != requests .codes .ok :
246+ return "Failed to fetch info ({})" .format (request .status_code )
247+
248+ data = request .json ()
249+ if 'error' in data :
250+ return "Error: {}." .format (data ["message" ])
251+
252+ out = "{}'s favorite artists: " .format (username )
253+ for r in range (5 ):
254+ artist_name = data ["topartists" ]["artist" ][r ]["name" ]
255+ play_count = data ["topartists" ]["artist" ][r ]["playcount" ]
256+ out = out + "{} listened to {} times. " .format (artist_name , play_count )
257+ return out
0 commit comments