Compare commits
13 commits
0664529c70
...
c3bba4bb20
| Author | SHA1 | Date | |
|---|---|---|---|
| c3bba4bb20 | |||
| 3a18e9d543 | |||
| 06f358c7a5 | |||
| 7b214d87c9 | |||
| 1aa5a9b36c | |||
| f45d91d0c0 | |||
| 55d2409a80 | |||
| ec25b73c4f | |||
| b32a704e12 | |||
| c9c8bff683 | |||
| a889b78efb | |||
| 6b7e38cd0f | |||
| 0d7271eee4 |
7 changed files with 207 additions and 105 deletions
|
|
@ -6,13 +6,14 @@ dead simple last.fm bot
|
||||||
|
|
||||||
[click here to invite!!](https://nerimity.com/bot/1693424011649925120?perms=2)
|
[click here to invite!!](https://nerimity.com/bot/1693424011649925120?perms=2)
|
||||||
|
|
||||||
(i cannot promise stable uptime)
|
**note:** i am not planning on implementing leaderbords (`.fmwk`) due to the strain it would put on my server.
|
||||||
|
|
||||||
**TODO:**
|
**TODO:**
|
||||||
- add database username checker to utils.py
|
- ~~add database username checker to utils.py~~ ✅ (added to bot.py)
|
||||||
- ~~add collage generation~~ ✅
|
- ~~add collage generation~~ ✅
|
||||||
- fix attachment generation and upload
|
- fix attachment generation and upload
|
||||||
- ~~**temporary fix**: upload and link to catbox urls~~ __the asynchronous catbox library does not accept byte arrays__
|
- ~~**temporary fix**: upload and link to catbox urls~~ __the asynchronous catbox library does not accept byte arrays__
|
||||||
- ~~**temporary fix**: construct the attachment object from scratch and upload manually(?)~~ __its still broken__
|
- ~~**temporary fix**: construct the attachment object from scratch and upload manually(?)~~ __its still broken__
|
||||||
- ~~**temporary fix:** use 0x0.st~~ ✅
|
- ~~**temporary fix:** use 0x0.st~~ ✅
|
||||||
- **permanent fix**: fork and update nerimity library
|
- **permanent fix**: fork and update nerimity library
|
||||||
|
- add list generation
|
||||||
|
|
|
||||||
24
bot.py
24
bot.py
|
|
@ -10,6 +10,8 @@ from pyzxz.pyzxz.pyzxz import ZeroXZero # :sob:
|
||||||
from lastfmcollagegenerator.collage_generator import CollageGenerator
|
from lastfmcollagegenerator.collage_generator import CollageGenerator
|
||||||
# from catbox_async_uploader.catbox_async_uploader.core import CatboxAsyncUploader
|
# from catbox_async_uploader.catbox_async_uploader.core import CatboxAsyncUploader
|
||||||
|
|
||||||
|
import utils as u
|
||||||
|
|
||||||
class Bot(nerimity.Client):
|
class Bot(nerimity.Client):
|
||||||
"""Extended client class for extra functionality."""
|
"""Extended client class for extra functionality."""
|
||||||
def __init__(self, lastfm_api_key: str, lastfm_api_secret: str,
|
def __init__(self, lastfm_api_key: str, lastfm_api_secret: str,
|
||||||
|
|
@ -90,3 +92,25 @@ class Bot(nerimity.Client):
|
||||||
) as cursor:
|
) as cursor:
|
||||||
row = await cursor.fetchone()
|
row = await cursor.fetchone()
|
||||||
return row[0] if row else None
|
return row[0] if row else None
|
||||||
|
|
||||||
|
async def find_lastfm_username(self, ctx: nerimity.Context, username: str = None):
|
||||||
|
if not username:
|
||||||
|
try: username = await self.get_lastfm(ctx.author.id)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
await ctx.send(u.error_msg(f"Unknown database error:\n{e}"))
|
||||||
|
|
||||||
|
if not username:
|
||||||
|
await ctx.send(u.error_msg("Please provide a Last.fm username (or set yours with `/setfm`)."))
|
||||||
|
|
||||||
|
elif u.is_mention(username):
|
||||||
|
mentioned = self.get_user(username[3:-1])
|
||||||
|
try: username = await self.get_lastfm(mentioned.id)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
await ctx.send(u.error_msg(f"Unknown database error:\n{e}"))
|
||||||
|
|
||||||
|
if not username:
|
||||||
|
await ctx.send(u.error_msg(f"[@:{mentioned.id}] doesn't seem to have an account set. Do so with `/setfm`."))
|
||||||
|
|
||||||
|
return username
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import nerimity
|
|
||||||
|
|
||||||
import bot
|
|
||||||
|
|
||||||
def setup(bot: bot.Bot):
|
|
||||||
@bot.command(name="topartists", aliases=["ta","topartist"])
|
|
||||||
@bot.slash_command(name="topartists")
|
|
||||||
def topartists(ctx: nerimity.Context, timeframe)
|
|
||||||
|
|
@ -8,7 +8,8 @@ import utils as u
|
||||||
# from catbox_async_uploader.catbox_async_uploader.enums import LitterboxDuration
|
# from catbox_async_uploader.catbox_async_uploader.enums import LitterboxDuration
|
||||||
# from pyzxz import ZeroXZero
|
# from pyzxz import ZeroXZero
|
||||||
|
|
||||||
async def send_collage(bot: bot.Bot, ctx: nerimity.Context, entity: str, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
def setup(bot: bot.Bot):
|
||||||
|
async def send_collage(ctx: nerimity.Context, entity: str, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
||||||
temp_msg = None
|
temp_msg = None
|
||||||
|
|
||||||
if 'x' not in size:
|
if 'x' not in size:
|
||||||
|
|
@ -20,31 +21,12 @@ async def send_collage(bot: bot.Bot, ctx: nerimity.Context, entity: str, size: s
|
||||||
await ctx.send(u.error_msg("Maximum size allowed is 5x5."))
|
await ctx.send(u.error_msg("Maximum size allowed is 5x5."))
|
||||||
return
|
return
|
||||||
|
|
||||||
except ValueError:
|
except Exception:
|
||||||
await ctx.send(u.error_msg(f"Please provide a valid size.\nie `/chart{entity} 5x5`"))
|
await ctx.send(u.error_msg(f"Please provide a valid size.\nie `/chart{entity} 5x5`"))
|
||||||
|
|
||||||
if not username:
|
|
||||||
try: username = await bot.get_lastfm(ctx.author.id)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
await ctx.send(u.error_msg(f"Unknown database error:\n{e}"))
|
|
||||||
|
|
||||||
if not username:
|
|
||||||
await ctx.send(u.error_msg("Please provide a Last.fm username (or set yours with `/setfm`)."))
|
|
||||||
print("returned")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if username.startswith("[@:"):
|
username = await bot.find_lastfm_username(ctx, username)
|
||||||
mentioned = bot.get_user(username[3:-1])
|
if not username: return
|
||||||
try: username = await bot.get_lastfm(mentioned.id)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
await ctx.send(u.error_msg(f"Unknown database error:\n{e}"))
|
|
||||||
|
|
||||||
if not username:
|
|
||||||
await ctx.send(u.error_msg(f"[@:{mentioned.id}] doesn't seem to have an account set. Do so with `/setfm`."))
|
|
||||||
print("returned")
|
|
||||||
return
|
|
||||||
|
|
||||||
match timeframe:
|
match timeframe:
|
||||||
case "a" | "all" | "alltime" | "o": timeframe = "overall"
|
case "a" | "all" | "alltime" | "o": timeframe = "overall"
|
||||||
|
|
@ -96,12 +78,10 @@ async def send_collage(bot: bot.Bot, ctx: nerimity.Context, entity: str, size: s
|
||||||
finally:
|
finally:
|
||||||
if temp_msg: temp_msg.delete()
|
if temp_msg: temp_msg.delete()
|
||||||
|
|
||||||
def setup(bot: bot.Bot):
|
|
||||||
@bot.command(name="chart", aliases=["c", "chartalbum", "albumchart", "collage"])
|
@bot.command(name="chart", aliases=["c", "chartalbum", "albumchart", "collage"])
|
||||||
@bot.slash_command(name="chartalbum", description="Generate an album collage.")
|
@bot.slash_command(name="chartalbum", description="Generate an album collage.")
|
||||||
async def chartalbum(ctx: nerimity.Context, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
async def chartalbum(ctx: nerimity.Context, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
||||||
await send_collage(
|
await send_collage(
|
||||||
bot = bot,
|
|
||||||
ctx = ctx,
|
ctx = ctx,
|
||||||
entity = "album",
|
entity = "album",
|
||||||
size = size,
|
size = size,
|
||||||
|
|
@ -113,7 +93,6 @@ def setup(bot: bot.Bot):
|
||||||
@bot.slash_command(name="chartartist", description="Generate an artist collage.")
|
@bot.slash_command(name="chartartist", description="Generate an artist collage.")
|
||||||
async def chartartist(ctx: nerimity.Context, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
async def chartartist(ctx: nerimity.Context, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
||||||
await send_collage(
|
await send_collage(
|
||||||
bot = bot,
|
|
||||||
ctx = ctx,
|
ctx = ctx,
|
||||||
entity = "artist",
|
entity = "artist",
|
||||||
size = size,
|
size = size,
|
||||||
|
|
@ -125,7 +104,6 @@ def setup(bot: bot.Bot):
|
||||||
@bot.slash_command(name="charttrack", description="Generate a track/song collage.")
|
@bot.slash_command(name="charttrack", description="Generate a track/song collage.")
|
||||||
async def charttrack(ctx: nerimity.Context, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
async def charttrack(ctx: nerimity.Context, size: str = "3x3", timeframe: str = "7day", username: str = None):
|
||||||
await send_collage(
|
await send_collage(
|
||||||
bot = bot,
|
|
||||||
ctx = ctx,
|
ctx = ctx,
|
||||||
entity = "track",
|
entity = "track",
|
||||||
size = size,
|
size = size,
|
||||||
|
|
|
||||||
|
|
@ -8,26 +8,8 @@ def setup(bot: bot.Bot):
|
||||||
@bot.command(name="fm", aliases=["np"])
|
@bot.command(name="fm", aliases=["np"])
|
||||||
@bot.slash_command(name="fm", description="Shows what you're currently playing")
|
@bot.slash_command(name="fm", description="Shows what you're currently playing")
|
||||||
async def fm(ctx: nerimity.Context, username: str = None):
|
async def fm(ctx: nerimity.Context, username: str = None):
|
||||||
if not username:
|
username = await bot.find_lastfm_username(ctx, username)
|
||||||
try: username = await bot.get_lastfm(ctx.author.id)
|
if not username: return
|
||||||
except Exception as e:
|
|
||||||
await ctx.send(u.error_msg(f"Unknown database error:\n{e}"))
|
|
||||||
|
|
||||||
if not username:
|
|
||||||
await ctx.send(u.error_msg("Please provide a Last.fm username (or set yours with `/setfm`)"))
|
|
||||||
return
|
|
||||||
|
|
||||||
if username.startswith("[@:"):
|
|
||||||
mentioned = bot.get_user(username[3:-1])
|
|
||||||
try: username = await bot.get_lastfm(mentioned.id)
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
await ctx.send(u.error_msg(f"Unknown database error:\n{e}"))
|
|
||||||
|
|
||||||
if not username:
|
|
||||||
await ctx.send(u.error_msg(f"[@:{mentioned.id}] doesn't seem to have an account set. Do so with `/setfm`."))
|
|
||||||
print("returned")
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user = bot.lastfm.get_user(username)
|
user = bot.lastfm.get_user(username)
|
||||||
|
|
|
||||||
120
commands/top.py
Normal file
120
commands/top.py
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
import nerimity
|
||||||
|
import pylast
|
||||||
|
|
||||||
|
import bot
|
||||||
|
import utils as u
|
||||||
|
|
||||||
|
def setup(bot: bot.Bot):
|
||||||
|
async def send_top(ctx: nerimity.Context, entity: str, timeframe: str, username: str, countstr: str):
|
||||||
|
try: count = int(countstr)
|
||||||
|
except ValueError:
|
||||||
|
await ctx.send(u.error_msg("Please input a valid number for `count`."))
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
await ctx.send(u.error_msg(f"Unknown error:\n`{e}`"))
|
||||||
|
return
|
||||||
|
|
||||||
|
if count > 10 or count < 1:
|
||||||
|
await ctx.send(u.error_msg("Please enter a count number between 1 and 10."))
|
||||||
|
return
|
||||||
|
|
||||||
|
requested = True if username else False
|
||||||
|
|
||||||
|
username = await bot.find_lastfm_username(ctx, username)
|
||||||
|
if not username: return
|
||||||
|
|
||||||
|
match timeframe:
|
||||||
|
case "a" | "all" | "alltime" | "o":
|
||||||
|
timeframe = "overall"
|
||||||
|
period = timeframe
|
||||||
|
|
||||||
|
case "y" | "year" | "yearly":
|
||||||
|
timeframe = "12month"
|
||||||
|
period = "in the past year"
|
||||||
|
|
||||||
|
case "m" | "month" | "monthly":
|
||||||
|
timeframe = "1month"
|
||||||
|
period = "in the past month"
|
||||||
|
|
||||||
|
case "w" | "week" | "weekly":
|
||||||
|
timeframe = "7day"
|
||||||
|
period = "in the past week"
|
||||||
|
|
||||||
|
case "d" | "day" | "daily":
|
||||||
|
timeframe = "1day"
|
||||||
|
period = "in the past day"
|
||||||
|
|
||||||
|
case _:
|
||||||
|
timeframe = "7day"
|
||||||
|
period = "in the past week (default)"
|
||||||
|
|
||||||
|
try:
|
||||||
|
user = bot.lastfm.get_user(username)
|
||||||
|
msg_content = ""
|
||||||
|
|
||||||
|
match entity:
|
||||||
|
case "artist":
|
||||||
|
top_list = user.get_top_artists(period=timeframe, limit=count)
|
||||||
|
for index, i in enumerate(top_list):
|
||||||
|
msg_content += f"\n{index+1}. [{i.item.get_name(properly_capitalized=True)}]({i.item.get_url()}) | {i.weight} plays"
|
||||||
|
|
||||||
|
case "album":
|
||||||
|
top_list = user.get_top_albums(period=timeframe, limit=count)
|
||||||
|
for index, i in enumerate(top_list):
|
||||||
|
msg_content += f"\n{index+1}. [{i.item.get_title(properly_capitalized=True)}]({i.item.get_url()}) by [{i.item.get_artist().get_name(properly_capitalized=True)}]({i.item.get_artist().get_url()}) | {i.weight} plays"
|
||||||
|
|
||||||
|
case "track":
|
||||||
|
top_list = user.get_top_tracks(period=timeframe, limit=count)
|
||||||
|
for index, i in enumerate(top_list):
|
||||||
|
msg_content += f"\n{index+1}. [{i.item.get_title(properly_capitalized=True)}]({i.item.get_url()}) by [{i.item.get_artist().get_name(properly_capitalized=True)}]({i.item.get_artist().get_url()}) | {i.weight} plays"
|
||||||
|
|
||||||
|
msg_head = f"Top {len(top_list)} {entity}s {period} for [{username}]({user.get_url()}):\n"
|
||||||
|
|
||||||
|
msg = msg_head + msg_content
|
||||||
|
if requested is True:
|
||||||
|
msg += f"\n### Requested by [@:{ctx.author.id}]"
|
||||||
|
|
||||||
|
await ctx.send(msg)
|
||||||
|
|
||||||
|
except pylast.WSError as e:
|
||||||
|
print(e)
|
||||||
|
await ctx.send(u.error_msg(f"Last.fm error:\n`{e}`"))
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
await ctx.send(u.error_msg(f"Unknown error:\n`{e}`"))
|
||||||
|
return
|
||||||
|
|
||||||
|
@bot.command(name="topartists", aliases=["ta","topartist"])
|
||||||
|
@bot.slash_command(name="topartists", description="Generate a list of your most played artists.")
|
||||||
|
async def topartists(ctx: nerimity.Context, timeframe: str = "7day", username: str = None, countstr: str = "10"):
|
||||||
|
await send_top(
|
||||||
|
ctx = ctx,
|
||||||
|
entity = "artist",
|
||||||
|
timeframe = timeframe,
|
||||||
|
username = username,
|
||||||
|
countstr = countstr
|
||||||
|
)
|
||||||
|
|
||||||
|
@bot.command(name="topalbums", aliases=["t","top","topalbum"])
|
||||||
|
@bot.slash_command(name="topalbums", description="Generate a list of your most played albums.")
|
||||||
|
async def topalbums(ctx: nerimity.Context, timeframe: str = "7day", username: str = None, countstr: str = "10"):
|
||||||
|
await send_top(
|
||||||
|
ctx = ctx,
|
||||||
|
entity = "album",
|
||||||
|
timeframe = timeframe,
|
||||||
|
username = username,
|
||||||
|
countstr = countstr
|
||||||
|
)
|
||||||
|
|
||||||
|
@bot.command(name="toptracks", aliases=["tt","toptrack"])
|
||||||
|
@bot.slash_command(name="toptracks", description="Generate a list of your most played songs.")
|
||||||
|
async def toptracks(ctx: nerimity.Context, timeframe: str = "7day", username: str = None, countstr: str = "10"):
|
||||||
|
await send_top(
|
||||||
|
ctx = ctx,
|
||||||
|
entity = "track",
|
||||||
|
timeframe = timeframe,
|
||||||
|
username = username,
|
||||||
|
countstr = countstr
|
||||||
|
)
|
||||||
5
utils.py
5
utils.py
|
|
@ -37,3 +37,8 @@ def error_msg(message: str) -> str:
|
||||||
|
|
||||||
def good_msg(message: str) -> str:
|
def good_msg(message: str) -> str:
|
||||||
return f"[#52ff54][Success] [#reset]{message}"
|
return f"[#52ff54][Success] [#reset]{message}"
|
||||||
|
|
||||||
|
def is_mention(mention: str) -> bool:
|
||||||
|
if not mention: return None
|
||||||
|
|
||||||
|
return True if mention.startswith("[@:") else False
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue