3 Commits

Author SHA1 Message Date
ed1ea1f7af 2025-10-28 17:34:32 +01:00
f79a27aaca Merge branch 'complete-rework' of git.ingemanngade.net:NikolajDanger/Gwendolyn into complete-rework 2025-10-28 15:45:36 +01:00
18d7f318f6 2025-10-28 15:42:26 +01:00
44 changed files with 7182 additions and 7142 deletions

View File

@@ -1,7 +1,7 @@
from interactions import Extension, slash_command, SlashContext from interactions import Extension, slash_command, SlashContext
from gwendolyn.utils import PARAMS as params from gwendolyn.utils import PARAMS as params
class BetterNeflixExtension(Extension): class BetterNetflixExtension(Extension):
"""Contains the Better Netflix commands.""" """Contains the Better Netflix commands."""
@slash_command(**params["better_netflix"]["movie"]) @slash_command(**params["better_netflix"]["movie"])
async def movie(self, ctx: SlashContext): async def movie(self, ctx: SlashContext):
@@ -10,3 +10,7 @@ class BetterNeflixExtension(Extension):
@slash_command(**params["better_netflix"]["show"]) @slash_command(**params["better_netflix"]["show"])
async def show(self, ctx: SlashContext): async def show(self, ctx: SlashContext):
await self.bot.better_netflix.show(ctx) await self.bot.better_netflix.show(ctx)
@slash_command(**params["better_netflix"]["downloading"])
async def downloading(self, ctx: SlashContext):
await self.bot.better_netflix.downloading(ctx)

23
gwendolyn/ext/games.py Normal file
View File

@@ -0,0 +1,23 @@
import typing
from interactions import Extension, slash_command, SlashContext, User, Client
from gwendolyn.utils import PARAMS as params
if typing.TYPE_CHECKING:
from gwendolyn_client import Gwendolyn
class GamesExtension(Extension):
"""Contains the game commands."""
def dummy(self):
# For type checking:
self.bot: "Gwendolyn"
@slash_command(**params["games"]["money"]["balance"])
async def balance(self, ctx: SlashContext):
await self.bot.money.sendBalance(ctx)
@slash_command(**params["games"]["money"]["give"])
async def give(self, ctx: SlashContext, user: User, amount: int):
await self.bot.money.giveMoney(ctx, user, amount)

View File

@@ -1,6 +1,7 @@
"""A collection of all Gwendolyn functions.""" """A collection of all Gwendolyn functions."""
__all__ = ["Other","BetterNetflix", "Sonarr", "Radarr", "TMDb", "QBittorrent"] __all__ = ["Other","BetterNetflix", "Sonarr", "Radarr", "TMDb", "QBittorrent", "Money"]
from .other import Other from .other import Other
from .better_netflix import Radarr, Sonarr, BetterNetflix, TMDb, QBittorrent from .better_netflix import Radarr, Sonarr, BetterNetflix, TMDb, QBittorrent
from .games import Money, Games

View File

@@ -117,7 +117,7 @@ class BetterNetflix():
if "imdb" in picked_movie['ratings']: if "imdb" in picked_movie['ratings']:
description += f"<:imdb:1301506320603676782> {picked_movie['ratings']['imdb']['value']}" description += f"<:imdb:1301506320603676782> {picked_movie['ratings']['imdb']['value']}"
description += "/10" description += "/10 "
if "rottenTomatoes" in picked_movie['ratings']: if "rottenTomatoes" in picked_movie['ratings']:
rt_value = picked_movie['ratings']['rottenTomatoes']['value'] rt_value = picked_movie['ratings']['rottenTomatoes']['value']
@@ -195,7 +195,7 @@ class BetterNetflix():
return progress_bar return progress_bar
message = [""] message = []
all_downloaded = True all_downloaded = True
dm_section_title = "*Torrent Downloads*" dm_section_title = "*Torrent Downloads*"
@@ -260,222 +260,45 @@ class BetterNetflix():
torrent["last_activity"] < time()-7200): torrent["last_activity"] < time()-7200):
message.append(torrent_info) message.append(torrent_info)
if download_ratio < 1 and torrent["state"] != "stalledDL": return message
all_downloaded = False
return message, all_downloaded async def _generate_download_list(self):
async def _generate_download_list(self, show_dm, show_movies, show_shows,
episodes):
"""Generate a list of all torrents. """Generate a list of all torrents.
*Returns* *Returns*
message_text: str message_text: str
A formatted list of all torrents A formatted list of all torrents
all_downloaded: bool
Whether all torrents are downloaded
""" """
self.bot.log("Generating torrent list") self.bot.log("Generating torrent list")
title_width = 100 title_width = 90
message = [] message = self._draw_torrent_list(title_width)
if show_dm: message_text = "```"+"\n".join(message)+"```"
m, all_downloaded = self._draw_torrent_list(title_width)
message += m
# if show_movies:
# message.append("")
# movies_section_title = "*Missing movies not downloading*"
# movies_section_line = (
# "-"*((title_width-len(movies_section_title))//2)
# )
# message.append(
# movies_section_line+movies_section_title+movies_section_line
# )
# movie_list = requests.get(
# self.radarr_url+"movie?apiKey="+self.credentials["radarr_key"]
# ).json()
# print(
# self.radarr_url+"movie?apiKey="+self.credentials["radarr_key"]
# )
# movie_queue = requests.get(
# self.radarr_url+"queue?apiKey="+self.credentials["radarr_key"]
# ).json()
# movie_queue_ids = []
# for queue_item in movie_queue["records"]:
# movie_queue_ids.append(queue_item["movieId"])
# for movie in movie_list:
# if (not movie["hasFile"] and
# movie["id"] not in movie_queue_ids):
# movie_name = movie["title"]
# if len(movie_name) > 40:
# if movie_name[36] == " ":
# movie_name = movie_name[:36]+"...."
# else:
# movie_name = movie_name[:37]+"..."
# while len(movie_name) < 41:
# movie_name += " "
# if movie["monitored"]:
# movie_info = movie_name+"Could not find a torrent"
# else:
# movie_info = self.long_strings["No torrent"].format(
# movie_name
# )
# message.append(movie_info)
# if show_shows:
# message.append("")
# show_section_title = "*Missing shows not downloading*"
# show_section_line = "-"*((title_width-len(show_section_title))//2)
# message.append(
# show_section_line+show_section_title+show_section_line
# )
# show_list = requests.get(
# self.sonarr_url+"series?apiKey="+self.credentials["sonarr_key"]
# ).json()
# for show in show_list:
# if show["seasons"][0]["seasonNumber"] == 0:
# seasons = show["seasons"][1:]
# else:
# seasons = show["seasons"]
# if any(
# (
# i["statistics"]["episodeCount"] !=
# i["statistics"]["totalEpisodeCount"]
# ) for i in seasons):
# if all(
# i["statistics"]["episodeCount"] == 0 for i in seasons
# ):
# message.append(show["title"] + " (all episodes)")
# else:
# if episodes:
# missing_episodes = sum(
# (i["statistics"]["totalEpisodeCount"] -
# i["statistics"]["episodeCount"])
# for i in seasons)
# message.append(
# f"{show['title']} ({missing_episodes} episodes)"
# )
message.append("-"*title_width)
message_text = "```"+"\n".join(message[1:])+"```"
if message_text == "``````": if message_text == "``````":
message_text = self.long_strings["No torrents downloading"] message_text = self.long_strings["No torrents downloading"]
return message_text, all_downloaded return message_text
# async def downloading(self, ctx, content): async def downloading(self, ctx: SlashContext):
# """Send message with list of all downloading torrents.""" """Send message with list of all downloading torrents."""
# async def send_long_message(ctx,message_text): async def send_long_message(ctx,message_text):
# if len(message_text) <= 1994: if len(message_text) <= 1994:
# await ctx.send("```"+message_text+"```") await ctx.send("```"+message_text+"```")
# else: else:
# cut_off_index = message_text[:1994].rfind("\n") cut_off_index = message_text[:1994].rfind("\n")
# await ctx.send("```"+message_text[:cut_off_index]+"```") await ctx.send("```"+message_text[:cut_off_index]+"```")
# await send_long_message(ctx,message_text[cut_off_index+1:]) await send_long_message(ctx,message_text[cut_off_index+1:])
# await self.bot.defer(ctx) await ctx.defer()
# # showDM, showMovies, showShows, episodes message_text = await self._generate_download_list()
# parameters = [False, False, False, False] if not message_text.startswith("```"):
# show_dm_args = ["d", "dm", "downloading", "downloadmanager"] await ctx.send(message_text)
# show_movies_args = ["m", "movies"]
# show_shows_args = ["s", "shows", "series"]
# show_episode_args = ["e", "episodes"]
# arg_list = [
# show_dm_args, show_movies_args, show_shows_args, show_episode_args
# ]
# input_args = []
# valid_arguments = True
# while content != "" and valid_arguments: elif len(message_text) > 2000:
# if content[0] == " ": message_text = message_text[3:-3]
# content = content[1:] await send_long_message(ctx,message_text)
# elif content[0] == "-":
# if content[1] == "-":
# arg_start = 2
# if " " in content:
# arg_stop = content.find(" ")
# else:
# arg_stop = None
# else:
# arg_start = 1
# arg_stop = 2
# input_args.append(content[arg_start:arg_stop]) else:
# if arg_stop is None: await ctx.send(message_text)
# content = ""
# else:
# content = content[arg_stop:]
# else:
# valid_arguments = False
# if valid_arguments:
# for arg_index, arg_aliases in enumerate(arg_list):
# arg_in_input = [i in input_args for i in arg_aliases]
# if any(arg_in_input):
# input_args.remove(arg_aliases[arg_in_input.index(True)])
# parameters[arg_index] = True
# if len(input_args) != 0 or (not parameters[2] and parameters[3]):
# valid_arguments = False
# show_anything = any(i for i in parameters)
# if not (valid_arguments and show_anything):
# await ctx.send(self.long_strings["Invalid parameters"])
# else:
# message_text, all_downloaded = await self.__generate_download_list(
# *parameters
# )
# if not message_text.startswith("```"):
# await ctx.send(message_text)
# elif len(message_text) > 2000:
# message_text = message_text[3:-3]
# await send_long_message(ctx,message_text)
# elif all_downloaded:
# await ctx.send(message_text)
# else:
# updates_left = 60
# message_text = self.long_strings["Update"].format(
# message_text[:-3], ceil(updates_left/6)
# )
# old_message = await ctx.send(message_text)
# while ((not all_downloaded) and updates_left > 0):
# await asyncio.sleep(10)
# updates_left -= 1
# message_text, all_downloaded = await (
# self.__generate_download_list(*parameters)
# )
# message_text = self.long_strings["Update"].format(
# message_text[:-3],
# ceil(updates_left/6)
# )
# await old_message.edit(content = message_text)
# message_text, all_downloaded = await (
# self.__generate_download_list(*parameters)
# )
# if message_text.startswith("```"):
# if all_downloaded:
# self.bot.log("All torrents are downloaded")
# else:
# message_text = self.long_strings["No updates"].format(
# message_text[:-3]
# )
# self.bot.log("The message updated 20 times")
# await old_message.edit(content = message_text)

View File

@@ -0,0 +1,11 @@
"""Game functions for Gwendolyn."""
__all__ = ["Money", "Games"]
from .money import Money
class Games():
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
self.database = bot.database

View File

@@ -0,0 +1,140 @@
"""
Contains the code that deals with money.
*Classes*
---------
Money
Deals with money.
"""
import typing
import interactions # Used for typehints
if typing.TYPE_CHECKING:
from gwendolyn_client import Gwendolyn
class Money():
"""
Deals with money.
*Methods*
---------
checkBalance(user: str)
sendBalance(ctx: interactions.SlashContext)
addMoney(user: str, amount: int)
giveMoney(ctx: interactions.SlashContext, user: discord.User,
amount: int)
*Attributes*
------------
bot: Gwendolyn
The instance of Gwendolyn
database: pymongo.Client
The mongo database
"""
def __init__(self, bot: "Gwendolyn"):
"""Initialize the class."""
self.bot = bot
self.database = bot.database
def checkBalance(self, user: str):
"""
Get the account balance of a user.
*Parameters*
------------
user: str
The user to get the balance of.
*Returns*
---------
balance: int
The balance of the user's account.
"""
self.bot.log("checking "+user+"'s account balance")
user_data = self.database["users"].find_one({"_id": user})
if user_data is not None:
return user_data["money"]
else:
return 0
async def sendBalance(self, ctx: interactions.SlashContext):
"""
Get your own account balance.
*Parameters*
------------
ctx: interactions.SlashContext
The context of the command.
"""
await ctx.defer()
response = self.checkBalance("#"+str(ctx.author.id))
user_name = ctx.author.display_name
if response == 1:
new_message = f"{user_name} has 1 GwendoBuck"
else:
new_message = f"{user_name} has {response} GwendoBucks"
await ctx.send(new_message)
# Adds money to the account of a user
def addMoney(self, user: interactions.User, amount: int):
"""
Add money to a user account.
*Parameters*
------------
user: User
The user to give money.
amount: int
The amount to add to the user's account.
"""
self.bot.log(f"adding {amount} to {user}'s account")
user_id = f"#{user.id}"
user_data = self.database["users"].find_one({"_id": user_id})
if user_data is not None:
updater = {"$inc": {"money": amount}}
self.database["users"].update_one({"_id": user_id}, updater)
else:
new_user = {
"_id": user_id,
"user name": user.display_name,
"money": amount
}
self.database["users"].insert_one(new_user)
# Transfers money from one user to another
async def giveMoney(self, ctx: interactions.SlashContext,
user: interactions.User, amount: int):
"""
Give someone else money from your account.
*Parameters*
------------
ctx: interactions.SlashContext
The context of the command.
user: interactions.User
The user to give money.
amount: int
The amount to transfer.
"""
await ctx.defer()
username = user.display_name
userid = f"#{ctx.author.id}"
user_data = self.database["users"].find_one({"_id": userid})
if amount <= 0:
self.bot.log("They tried to steal")
await ctx.send("Yeah, no. You can't do that")
elif user_data is None or user_data["money"] < amount:
self.bot.log("They didn't have enough GwendoBucks")
await ctx.send("You don't have that many GwendoBuck")
else:
self.addMoney(ctx.author, -1 * amount)
self.addMoney(user, amount)
await ctx.send(f"Transferred {amount} GwendoBucks to {username}")

View File

@@ -7,7 +7,7 @@ from .name_generator import NameGenerator
from .roll import DieRoller from .roll import DieRoller
def gen_help_text(commands: list[SlashCommand]): def gen_help_text(commands: list[SlashCommand]):
return '\n'.join([f"`/{i.name}`\t{i.description}" for i in commands]) return '\n'.join(sorted([f"`/{i.name}`\t{i.description}" for i in commands]))
class Other(): class Other():
def __init__(self, bot): def __init__(self, bot):

View File

@@ -6,7 +6,7 @@ from pymongo import MongoClient # Used for database management
from gwendolyn.utils import log from gwendolyn.utils import log
from gwendolyn.exceptions import NoToken, CannotConnectToService from gwendolyn.exceptions import NoToken, CannotConnectToService
from gwendolyn.funcs import Other, BetterNetflix, Sonarr, Radarr, TMDb, QBittorrent from gwendolyn.funcs import Other, BetterNetflix, Sonarr, Radarr, TMDb, QBittorrent, Money, Games
class Gwendolyn(Client): class Gwendolyn(Client):
def __init__(self): def __init__(self):
@@ -26,6 +26,9 @@ class Gwendolyn(Client):
"""Add all the client, option and credentials objects.""" """Add all the client, option and credentials objects."""
load_dotenv() load_dotenv()
self.testing = getenv("GWENDOLYN_TESTING", "False").lower() in ('true', '1', 't') self.testing = getenv("GWENDOLYN_TESTING", "False").lower() in ('true', '1', 't')
if self.testing:
self.log("Testing mode", level=25)
self.enable_nework_services = getenv("NETWORK_SERVICES", "False").lower() in ('true', '1', 't') self.enable_nework_services = getenv("NETWORK_SERVICES", "False").lower() in ('true', '1', 't')
self.bot_token = getenv("DISCORD_TOKEN") self.bot_token = getenv("DISCORD_TOKEN")
@@ -50,19 +53,24 @@ class Gwendolyn(Client):
if self.testing: if self.testing:
self.log("Testing mode") self.log("Testing mode")
self.database = database_client["Gwendolyn-Test"] self.database = database_client["Gwendolyn-Test"]
self.load_extension("interactions.ext.jurigged")
else: else:
self.database = database_client["Gwendolyn"] self.database = database_client["Gwendolyn"]
def _add_functions(self): def _add_functions(self):
self.other = Other(self) self.other = Other(self)
self.money = Money(self)
if self.enable_nework_services: if self.enable_nework_services:
self.better_netflix = BetterNetflix( self.better_netflix = BetterNetflix(
self, self,
radarr=Radarr(getenv("RADARR_IP"),getenv("RADARR_PORT"),getenv("RADARR_API_KEY")), radarr=Radarr(getenv("RADARR_IP"),getenv("RADARR_PORT"),getenv("RADARR_API_KEY")),
sonarr=Sonarr(getenv("SONARR_IP"),getenv("SONARR_PORT"),getenv("SONARR_API_KEY")), sonarr=Sonarr(getenv("SONARR_IP"),getenv("SONARR_PORT"),getenv("SONARR_API_KEY")),
tmdb=TMDb(getenv("TMDB_API_ACCESS_TOKEN")), tmdb=TMDb(getenv("TMDB_API_ACCESS_TOKEN")),
qbittorrent=QBittorrent(getenv("QBITTORRENT_IP"),getenv("QBITTORRENT_PORT"),getenv("QBITTORRENT_USERNAME"),getenv("QBITTORRENT_PASSWORD")) qbittorrent=QBittorrent(
getenv("QBITTORRENT_IP"),
getenv("QBITTORRENT_PORT"),
getenv("QBITTORRENT_USERNAME"),
getenv("QBITTORRENT_PASSWORD")
)
) )
def _add_extensions(self): def _add_extensions(self):

View File

@@ -34,7 +34,7 @@
}, },
"ping" : { "ping" : {
"name" : "ping", "name" : "ping",
"description" : "Get the Gwendolyn's latency to the server" "description" : "Get Gwendolyn's latency to the server"
}, },
"roll" : { "roll" : {
"name": "roll", "name": "roll",
@@ -65,6 +65,36 @@
"show": { "show": {
"name": "show", "name": "show",
"description": "Get a random show from Better Netflix" "description": "Get a random show from Better Netflix"
},
"downloading": {
"name": "downloading",
"description": "Get a list of everything being downloaded"
}
},
"games": {
"money": {
"balance" : {
"name" : "balance",
"description" : "See your balance of GwendoBucks"
},
"give" : {
"name" : "give",
"description" : "Give GwendoBucks to another user",
"options" : [
{
"name" : "user",
"description" : "The user you're sending GwendoBucks to",
"type" : 6,
"required" : "true"
},
{
"name" : "amount",
"description" : "The number of GwendoBucks you're sending",
"type" : 4,
"required" : "true"
}
]
}
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB