Files
Vocard/function.py
2024-02-11 19:52:14 +08:00

182 lines
6.1 KiB
Python

import discord, json, os
from discord.ext import commands
from datetime import datetime
from time import strptime
from io import BytesIO
from typing import Optional, Union, Any
from addons import Settings, TOKENS
from motor.motor_asyncio import (
AsyncIOMotorClient,
AsyncIOMotorCollection,
)
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
if not os.path.exists(os.path.join(ROOT_DIR, "settings.json")):
raise Exception("Settings file not set!")
#--------------- Cache Var ---------------
tokens: TOKENS = TOKENS()
settings: Settings
MONGO_DB: AsyncIOMotorClient
SETTINGS_DB: AsyncIOMotorCollection
PLAYLISTS_DB: AsyncIOMotorCollection
ERROR_LOGS: dict[int, dict[int, str]] = {} #Stores error that not a Voicelink Exception
LANGS: dict[str, dict[str, str]] = {} #Stores all the languages in ./langs
SETTINGS_BUFFER: dict[int, dict[str, Any]] = {} #Cache guild language
LOCAL_LANGS: dict[str, dict[str, str]] = {} #Stores all the localization languages in ./local_langs
PLAYLIST_NAME: dict[str, list[str]] = {} #Cache the user's playlist name
#-------------- Vocard Functions --------------
def open_json(path: str) -> dict:
try:
with open(os.path.join(ROOT_DIR, path), encoding="utf8") as json_file:
return json.load(json_file)
except:
return {}
def update_json(path: str, new_data: dict) -> None:
data = open_json(path)
if not data:
return
data.update(new_data)
with open(os.path.join(ROOT_DIR, path), "w") as json_file:
json.dump(data, json_file, indent=4)
def get_lang(guild_id:int, key:str) -> str:
lang = SETTINGS_BUFFER.get(guild_id).get("lang", "EN")
if lang in LANGS and not LANGS[lang]:
LANGS[lang] = open_json(os.path.join("langs", f"{lang}.json"))
return LANGS.get(lang, {}).get(key, "Language pack not found!")
def langs_setup() -> None:
for language in os.listdir(os.path.join(ROOT_DIR, "langs")):
if language.endswith('.json'):
LANGS[language[:-5]] = {}
for language in os.listdir(os.path.join(ROOT_DIR, "local_langs")):
if language.endswith('.json'):
LOCAL_LANGS[language[:-5]] = open_json(os.path.join("local_langs", language))
return
def time(millis:int) -> str:
seconds=(millis/1000)%60
minutes=(millis/(1000*60))%60
hours=(millis/(1000*60*60))%24
if hours > 1:
return "%02d:%02d:%02d" % (hours, minutes, seconds)
else:
return "%02d:%02d" % (minutes, seconds)
def formatTime(number:str) -> Optional[int]:
try:
try:
num = strptime(number, '%M:%S')
except ValueError:
try:
num = strptime(number, '%S')
except ValueError:
num = strptime(number, '%H:%M:%S')
except:
return None
return (int(num.tm_hour) * 3600 + int(num.tm_min) * 60 + int(num.tm_sec)) * 1000
def emoji_source(emoji:str) -> str:
return settings.emoji_source_raw.get(emoji.lower(), "🔗")
def gen_report() -> Optional[discord.File]:
if ERROR_LOGS:
errorText = ""
for guild_id, error in ERROR_LOGS.items():
errorText += f"Guild ID: {guild_id}\n" + "-" * 30 + "\n"
for index, (key, value) in enumerate(error.items() , start=1):
errorText += f"Error No: {index}, Time: {datetime.fromtimestamp(key)}\n" + value + "-" * 30 + "\n\n"
buffer = BytesIO(errorText.encode('utf-8'))
file = discord.File(buffer, filename='report.txt')
buffer.close()
return file
return None
def cooldown_check(ctx: commands.Context) -> Optional[commands.Cooldown]:
if ctx.author.id in settings.bot_access_user:
return None
cooldown = settings.cooldowns_settings.get(f"{ctx.command.parent.qualified_name} {ctx.command.name}" if ctx.command.parent else ctx.command.name)
if not cooldown:
return None
return commands.Cooldown(cooldown[0], cooldown[1])
def get_aliases(name: str) -> list:
return settings.aliases_settings.get(name, [])
def check_roles() -> tuple[str, int, int]:
return 'Normal', 5, 500
async def get_settings(guild_id:int) -> dict[str, Any]:
settings = SETTINGS_BUFFER.get(guild_id, None)
if not settings:
settings = await SETTINGS_DB.find_one({"_id": guild_id})
if not settings:
await SETTINGS_DB.insert_one({"_id": guild_id})
settings = SETTINGS_BUFFER[guild_id] = settings or {}
return settings
async def update_settings(guild_id: int, data: dict[str, dict[str, Any]]) -> bool:
settings = await get_settings(guild_id)
for mode, action in data.items():
for key, value in action.items():
cursors = key.split(".")
nested_data = settings
for c in cursors[:-1]:
nested_data = nested_data.setdefault(c, {})
if mode == "$set":
try:
nested_data[cursors[-1]] = value
except TypeError:
nested_data[int(cursors[-1])] = value
elif mode == "$unset":
nested_data.pop(cursors[-1], None)
else:
return False
result = await SETTINGS_DB.update_one({"_id": guild_id}, data)
return result.modified_count > 0
async def create_account(ctx: Union[commands.Context, discord.Interaction]) -> None:
async def get_settings(guild_id:int) -> dict[str, Any]:
async def get_playlist(user_id:int, dType:str=None, dId:str=None) -> bool:
user = await PLAYLISTS_DB.find_one({"_id":user_id}, {"_id": 0})
if not user:
return None
if dType:
if dId and dType == "playlist":
return user[dType][dId] if dId in user[dType] else None
return user[dType]
return user
async def update_playlist(user_id:int, data:dict, *, mode:str="set", update_cache: bool=False) -> None:
if update_cache:
PLAYLIST_NAME.pop(str(user_id), None)
result = await PLAYLISTS_DB.update_one({"_id":user_id}, {f"${mode}": data})
return result.modified_count > 0
async def update_inbox(user_id:int, data:dict) -> bool:
result = await PLAYLISTS_DB.update_one({"_id":user_id}, {"$push":{'inbox':data}})
return result.modified_count > 0