diff --git a/app/bot/cogs/app.py b/app/bot/cogs/app.py new file mode 100644 index 0000000..ba2ae79 --- /dev/null +++ b/app/bot/cogs/app.py @@ -0,0 +1,220 @@ +import logging +import discord +from discord.ext import commands +import asyncio +from plexapi.myplex import MyPlexAccount +from discord import Webhook, AsyncWebhookAdapter +from app.bot.helper.confighelper import roles, PLEXUSER, PLEXPASS, PLEX_SERVER_NAME, Plex_LIBS +logging.basicConfig(filename="app/config/invitarr.log", filemode='a', level=logging.ERROR) +import app.bot.helper.db as db +import app.bot.helper.plexhelper as plexhelper +import texttable +import os + +try: + account = MyPlexAccount(PLEXUSER, PLEXPASS) + plex = account.resource(PLEX_SERVER_NAME).connect() # returns a PlexServer instance + logging.info('Logged into plex!') +except: + logging.error('Error with plex login. Please check username and password and Plex server name.') + +class app(commands.Cog): + + def __init__(self, bot): + self.bot = bot + + @commands.Cog.listener() + async def on_ready(self): + logging.info('Made by Sleepingpirate https://github.com/Sleepingpirates/') + logging.info(f'Logged in as {self.bot.user} (ID: {self.bot.user.id})') + logging.info('------') + + async def embederror(self, author, message): + embed1 = discord.Embed(title="ERROR",description=message, color=0xf50000) + await author.send(embed=embed1) + + async def embedinfo(self, author, message): + embed1 = discord.Embed(title=message, color=0x00F500) + await author.send(embed=embed1) + + async def getemail(self, after): + email = None + await self.embedinfo(after,'Welcome To '+ PLEX_SERVER_NAME +'. Just reply with your email so we can add you to Plex!') + await self.embedinfo(after,'I will wait 15 minutes for your message, if you do not send it by then I will cancel the command.') + while(email == None): + def check(m): + return m.author == after and not m.guild + try: + email = await self.bot.wait_for('message', timeout=200, check=check) + if(plexhelper.verifyemail(str(email.content))): + return str(email.content) + else: + email = None + message = "Invalid email. Please just type in your email and nothing else." + await self.embederror(after, message) + continue + except asyncio.TimeoutError: + message = "Timed Out. Message Server Admin with your email so They Can Add You Manually." + await self.embederror(after, message) + return None + + async def addtoplex(self, email, channel): + if(plexhelper.verifyemail(email)): + if plexhelper.plexadd(plex,email): + await self.embedinfo(channel, 'There was an error adding this email address. Message Server Admin.') + return True + else: + await self.embederror(channel, 'There was an error adding this email address. Check logs.') + return False + else: + await self.embederror(channel, 'Invalid email.') + return False + + async def removefromplex(self, email, channel): + if(plexhelper.verifyemail(email)): + if plexhelper.plexadd(plex,email): + await self.embedinfo(channel, 'There was an error removing this email address. Message Server Admin.') + return True + else: + await self.embederror(channel, 'There was an error removing this email address. Check logs.') + return False + else: + await self.embederror(channel, 'Invalid email.') + return False + + #Auto add or remove user from plex if role is given or taken. + + @commands.Cog.listener() + async def on_member_update(self, before, after): + roles_in_guild = after.guild.roles + role = None + for role_for_app in roles: + for role_in_guild in roles_in_guild: + if role_in_guild.name == role_for_app: + role = role_in_guild + + if role is not None and (role in after.roles and role not in before.roles): + email = await self.getemail(after) + if email is not None: + await self.embedinfo(after, "Got it we will be adding your email to plex shortly!") + if plexhelper.plexadd(plex,email): + db.save_user(str(after.id), email) + await asyncio.sleep(5) + await self.embedinfo(after, 'You have Been Added To Plex! Login to plex and accept the invite!') + else: + await self.embedinfo(after, 'There was an error adding this email address. Message Server Admin.') + return + + elif role is not None and (role not in after.roles and role in before.roles): + try: + user_id = after.id + email = db.get_useremail(user_id) + plexremove(email) + deleted = db.delete_user(user_id) + if deleted: + logging.info("Removed {} from db".format(email)) + #await secure.send(plexname + ' ' + after.mention + ' was removed from plex') + else: + logging.error("Cannot remove this user from db.") + except: + logging.error("Cannot remove this user from plex.") + return + + + @commands.has_permissions(administrator=True) + @commands.command() + async def plexinvite(self, ctx): + email = str(ctx.content) + await self.addtoplex(email, ctx.channel) + + @commands.has_permissions(administrator=True) + @commands.command() + async def plexremove(self, ctx): + email = str(ctx.content) + await self.removefromplex(email, ctx.channel) + + @commands.has_permissions(administrator=True) + @commands.command() + async def dbadd(self, ctx, email, member: discord.Member): + #await self.addtoplex(email, ctx.channel) + if plexhelper.verifyemail(email): + try: + db.save_user(str(member.id), email) + await self.embedinfo(ctx.channel,'email and user were added to the database.') + except Exception as e: + await self.embedinfo(ctx.channel, 'There was an error adding this email address to database.') + logging.error(e) + else: + await self.embederror(ctx.channel, 'Invalid email.') + + @commands.has_permissions(administrator=True) + @commands.command() + async def dbls(self, ctx): + + embed = discord.Embed(title='Invitarr Database.') + all = db.read_useremail() + table = texttable.Texttable() + table.set_cols_dtype(["t", "t", "t"]) + table.set_cols_align(["c", "c", "c"]) + header = ("#", "Name", "Email") + table.add_row(header) + for index, peoples in enumerate(all): + index = index + 1 + id = int(peoples[1]) + dbuser = self.bot.get_user(id) + dbemail = peoples[2] + try: + username = dbuser.name + except: + username = "User Not Found." + embed.add_field(name=f"**{index}. {username}**", value=dbemail+'\n', inline=False) + table.add_row((index, username, dbemail)) + + total = str(len(all)) + if(len(all)>25): + f = open("db.txt", "w") + f.write(table.draw()) + f.close() + await ctx.channel.send("Database too large! Total: {total}".format(total = total),file=discord.File('db.txt')) + else: + await ctx.channel.send(embed = embed) + + + + @commands.has_permissions(administrator=True) + @commands.command() + async def dbrm(self, ctx, position): + embed = discord.Embed(title='Invitarr Database.') + all = db.read_useremail() + table = texttable.Texttable() + table.set_cols_dtype(["t", "t", "t"]) + table.set_cols_align(["c", "c", "c"]) + header = ("#", "Name", "Email") + table.add_row(header) + for index, peoples in enumerate(all): + index = index + 1 + id = int(peoples[1]) + dbuser = self.bot.get_user(id) + dbemail = peoples[2] + try: + username = dbuser.name + except: + username = "User Not Found." + embed.add_field(name=f"**{index}. {username}**", value=dbemail+'\n', inline=False) + table.add_row((index, username, dbemail)) + + try: + position = int(position) - 1 + id = all[position][1] + email = db.get_useremail(id) + deleted = db.delete_user(id) + if deleted: + logging.info("Removed {} from db".format(email)) + await self.embedinfo(ctx.channel,"Removed {} from db".format(email)) + else: + await self.embederror(ctx.channel,"Cannot remove this user from db.") + except Exception as e: + logging.error(e) + +def setup(bot): + bot.add_cog(app(bot)) \ No newline at end of file diff --git a/app/bot/helper/confighelper.py b/app/bot/helper/confighelper.py new file mode 100644 index 0000000..760925a --- /dev/null +++ b/app/bot/helper/confighelper.py @@ -0,0 +1,61 @@ +import configparser +from os import environ, path +from dotenv import load_dotenv +config = configparser.ConfigParser() + +CONFIG_PATH = 'app/config/config.ini' +BOT_SECTION = 'bot_envs' +CONFIG_KEYS = ['username', 'password', 'discord_bot_token', 'plex_user', 'plex_pass', + 'roles', 'plex_server_name', 'plex_libs', 'owner_id', 'channel_id', + 'auto_remove_user'] + +def get_config(): + """ + Function to return current config + """ + try: + config.read(CONFIG_PATH) + return config + except Exception as e: + print(e) + print('error in reading config') + return None + + +CONFIG_PATH = 'app/config/config.ini' +BOT_SECTION = 'bot_envs' + +# settings +Discord_bot_token = "" +roles = "" +PLEXUSER = "" +PLEXPASS = "" +PLEX_SERVER_NAME = "" +Plex_LIBS = "" +chan = 0 +ownerid = 0 +auto_remove_user = "" + +switch = 0 + +try: + load_dotenv(dotenv_path='bot.env') + + # settings + Discord_bot_token = environ.get('discord_bot_token') + roles = (environ.get('roles')) # Role Id, right click the role and copy id. + PLEXUSER = environ.get('plex_user') # Plex Username + PLEXPASS = environ.get('plex_pass') # plex password + PLEX_SERVER_NAME = environ.get('plex_server_name') # Name of plex server + Plex_LIBS = environ.get('plex_libs') #name of the libraries you want the user to have access to. + chan = int(environ.get('channel_id')) + ownerid = int(environ.get('owner_id')) + auto_remove_user = environ.get('auto_remove_user') if environ.get('auto_remove_user') else False # auto remove user from plex and db if removed from the role + switch = 1 + if switch == 1: + Plex_LIBS = list(Plex_LIBS.split(',')) + roles = list(roles.split(',')) + +except Exception as e: + print(e) + diff --git a/app/helper/db.py b/app/bot/helper/db.py similarity index 97% rename from app/helper/db.py rename to app/bot/helper/db.py index b982f0b..f163d92 100644 --- a/app/helper/db.py +++ b/app/bot/helper/db.py @@ -40,7 +40,7 @@ else: def save_user(username, email): if username and email: - conn.execute("INSERT INTO clients (discord_username, email) VALUES ('"+ username +"', '" + email + "')"); + conn.execute("INSERT INTO clients (discord_username, email) VALUES ('"+ username +"', '" + email + "')") conn.commit() print("User added to db.") else: diff --git a/app/bot/helper/plexhelper.py b/app/bot/helper/plexhelper.py new file mode 100644 index 0000000..790c2fb --- /dev/null +++ b/app/bot/helper/plexhelper.py @@ -0,0 +1,55 @@ +from plexapi.myplex import MyPlexAccount +import re +from app.bot.helper.confighelper import Plex_LIBS +import logging +logging.basicConfig(filename="app/config/plex.log", filemode='a', level=logging.ERROR) + +def plexadd(plex, plexname): + global Plex_LIBS + try: + if Plex_LIBS[0] == "all": + Plex_LIBS = plex.library.sections() + plex.myPlexAccount().inviteFriend(user=plexname, server=plex, sections=Plex_LIBS, allowSync=False, + allowCameraUpload=False, allowChannels=False, filterMovies=None, + filterTelevision=None, filterMusic=None) + logging.info(plexname +' has been added to plex') + return True + except Exception as e: + logging.error(e) + return False + +def plexremove(plex, plexname): + try: + plex.myPlexAccount().removeFriend(user=plexname) + logging.info(plexname +' has been removed from plex') + return True + except Exception as e: + logging.error(e) + return False + ''' + + plex python api has no tools to remove unaccepted invites... + + logging.info("Trying to remove invite...") + removeinvite = plexremoveinvite(plex, plexname) + if removeinvite: + return True + ''' + +''' +def plexremoveinvite(plex, plexname): + try: + plex.myPlexAccount().removeFriend(user=plexname) + logging.info(plexname +' has been removed from plex') + return True + except Exception as e: + logging.error(e) + return False +''' +def verifyemail(addressToVerify): + regex = '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$' + match = re.match(regex, addressToVerify) + if match == None: + return False + else: + return True \ No newline at end of file diff --git a/app/bot/test.py b/app/bot/test.py new file mode 100644 index 0000000..e69de29 diff --git a/app/cogs/Invitarr.py b/app/cogs/Invitarr.py deleted file mode 100644 index c9ebf74..0000000 --- a/app/cogs/Invitarr.py +++ /dev/null @@ -1,85 +0,0 @@ -import os -from os import environ, path -import logging -import discord -from discord.ext import commands -import asyncio -from plexapi.myplex import MyPlexAccount -from discord import Webhook, AsyncWebhookAdapter -import aiohttp -import texttable -import sys -from app.header.configparser import roleid, PLEXUSER, PLEXPASS, PLEX_SERVER_NAME, Plex_LIBS, chan, ownerid, auto_remove_user - -sys.stdout = sys.stderr - - -if auto_remove_user: - print("auto remove user = True") - import db as db - -account = MyPlexAccount(PLEXUSER, PLEXPASS) -plex = account.resource(PLEX_SERVER_NAME).connect() # returns a PlexServer instance - -class app(commands.Cog): - - def __init__(self, bot): - self.bot = bot - - @commands.Cog.listener() - async def on_ready(self): - print('Made by Sleepingpirate https://github.com/Sleepingpirates/') - print('Logged in as') - print(self.user.name) - print(self.user.id) - print('------') - - @commands.Cog.listener() - async def on_member_update(self, before, after): - secure = client.get_channel(chan) - for role_for_plex in roleid: - role = after.guild.get_role(int(role_for_plex)) - if (role in after.roles and role not in before.roles): - await after.send('Welcome To '+ PLEX_SERVER_NAME +'. Just reply with your email so we can add you to Plex!') - await after.send('I will wait 10 minutes for your message, if you do not send it by then I will cancel the command.') - def check(m): - return m.author == after and not m.guild - try: - email = await client.wait_for('message', timeout=600, check=check) - except asyncio.TimeoutError: - await after.send('Timed Out. Message Server Admin So They Can Add You Manually.') - return - else: - await asyncio.sleep(5) - await after.send('Got it we will be processing your email shortly') - print(email.content) #make it go to a log channel - plexname = str(email.content) - if plexadd(plexname): - if auto_remove_user: - db.save_user(str(after.id), email.content) - await asyncio.sleep(20) - await after.send('You have Been Added To Plex!') - await secure.send(plexname + ' ' + after.mention + ' was added to plex') - else: - await after.send('There was an error adding this email address. Message Server Admin.') - return - - elif(role not in after.roles and role in before.roles): - if auto_remove_user: - try: - user_id = after.id - email = db.get_useremail(user_id) - plexremove(email) - deleted = db.delete_user(user_id) - if deleted: - print("Removed {} from db".format(email)) - await secure.send(plexname + ' ' + after.mention + ' was removed from plex') - else: - print("Cannot remove this user from db.") - except: - print("Cannot remove this user from plex.") - return - - -def setup(bot): - bot.add_cog(app(bot)) \ No newline at end of file diff --git a/app/helper/confighelper.py b/app/helper/confighelper.py deleted file mode 100644 index 9d2f038..0000000 --- a/app/helper/confighelper.py +++ /dev/null @@ -1,77 +0,0 @@ -import configparser -from os import environ, path -from dotenv import load_dotenv -config = configparser.ConfigParser() - -CONFIG_PATH = 'app/config/config.ini' -BOT_SECTION = 'bot_envs' -CONFIG_KEYS = ['username', 'password', 'discord_bot_token', 'plex_user', 'plex_pass', - 'role_id', 'plex_server_name', 'plex_libs', 'owner_id', 'channel_id', - 'auto_remove_user'] - -def get_config(): - """ - Function to return current config - """ - try: - config.read(CONFIG_PATH) - return config - except Exception as e: - print(e) - print('error in reading config') - return None - - -CONFIG_PATH = 'app/config/config.ini' -BOT_SECTION = 'bot_envs' - -# settings -Discord_bot_token = "" -roleid = 0 -PLEXUSER = "" -PLEXPASS = "" -PLEX_SERVER_NAME = "" -Plex_LIBS = "" -chan = 0 -ownerid = 0 -auto_remove_user = "" - -switch = 0 - -try: - if(path.exists(CONFIG_PATH)): #Only for old docker users who already have config mounted at /app/app/config/config.ini - config = configparser.ConfigParser() - config.read(CONFIG_PATH) - Discord_bot_token = config.get(BOT_SECTION, 'discord_bot_token') - roleid = config.get(BOT_SECTION, 'role_id') - PLEXUSER = config.get(BOT_SECTION, 'plex_user') - PLEXPASS = config.get(BOT_SECTION, 'plex_pass') - PLEX_SERVER_NAME = config.get(BOT_SECTION, 'plex_server_name') - Plex_LIBS = config.get(BOT_SECTION, 'plex_libs') - chan = int(config.get(BOT_SECTION, 'channel_id')) - ownerid = int(config.get(BOT_SECTION, 'owner_id')) - auto_remove_user = config.get(BOT_SECTION, 'auto_remove_user') if config.get(BOT_SECTION, 'auto_remove_user') else False - switch = 1 - else: - load_dotenv(dotenv_path='bot.env') - Discord_bot_token = environ.get('discord_bot_token') - roleid = int(environ.get('role_id')) - PLEXUSER = environ.get('PLEXUSER') - PLEXPASS = config.get(BOT_SECTION, 'plex_pass') - PLEX_SERVER_NAME = config.get(BOT_SECTION, 'plex_server_name') - Plex_LIBS = config.get(BOT_SECTION, 'plex_libs') - chan = int(config.get(BOT_SECTION, 'channel_id')) - ownerid = int(config.get(BOT_SECTION, 'owner_id')) - auto_remove_user = config.get(BOT_SECTION, 'auto_remove_user') if config.get(BOT_SECTION, 'auto_remove_user') else False - switch = 1 - - if switch == 1: - if plex_libs.lower() == "all" - continue - else: - Plex_LIBS = list(Plex_LIBS.split(',')) - roleid = list(roleid.split(',')) - -except: - print("Cannot find config/Incomplete config") - diff --git a/app/helper/plexhelper.py b/app/helper/plexhelper.py deleted file mode 100644 index 8162ee7..0000000 --- a/app/helper/plexhelper.py +++ /dev/null @@ -1,34 +0,0 @@ -from plexapi.myplex import MyPlexAccount -import re - -def plexadd(plex, plexname): - try: - plex.myPlexAccount().inviteFriend(user=plexname, server=plex, sections=Plex_LIBS, allowSync=False, - allowCameraUpload=False, allowChannels=False, filterMovies=None, - filterTelevision=None, filterMusic=None) - - except Exception as e: - print(e) - return False - else: - print(plexname +' has been added to plex (☞ຈل͜ຈ)☞') - return True - - -def plexremove(plex, plexname): - try: - plex.myPlexAccount().removeFriend(user=plexname) - except Exception as e: - print(e) - return False - else: - print(plexname +' has been removed from plex (☞ຈل͜ຈ)☞') - return True - -def verifyemail(addressToVerify): - regex = '^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$' - match = re.match(regex, addressToVerify) - if match == None: - return False - else: - return True \ No newline at end of file diff --git a/run.py b/run.py index 59bb516..a6a59bf 100644 --- a/run.py +++ b/run.py @@ -4,7 +4,7 @@ from discord.ext import commands, tasks from discord.utils import get import asyncio import sys -from app.header.configparser import switch, Discord_bot_token +from app.bot.helper.confighelper import switch, Discord_bot_token if switch == 0: print("Missing Config.") @@ -15,7 +15,6 @@ intents.members = True bot = commands.Bot(command_prefix=".", intents = intents) bot.remove_command('help') - @bot.event async def on_ready(): print("bot is online.") @@ -24,22 +23,22 @@ async def on_ready(): @bot.command() @commands.has_permissions(administrator=True) async def load(ctx, name): - bot.load_extension(f'Cogs.{name}') + bot.load_extension(f'app.bot.cogs.{name}') print(f"The {name} cog has been loaded successfully.") @bot.command() @commands.has_permissions(administrator=True) async def unload(ctx, name): - bot.unload_extension(f'Cogs.{name}') + bot.unload_extension(f'app.bot.cogs.{name}') print(f"The {name} cog has been unloaded successfully.") @bot.command() @commands.has_permissions(administrator=True) async def reload(ctx, name): - bot.unload_extension(f'Cogs.{name}') - bot.load_extension(f'Cogs.{name}') + bot.unload_extension(f'app.bot.cogs.{name}') + bot.load_extension(f'app.bot.cogs.{name}') print(f"The {name} cog has been reloaded successfully.") @@ -54,17 +53,17 @@ async def on_message(message): @bot.command() @commands.has_permissions(administrator=True) async def all(ctx): - for filename in os.listdir("Cogs"): + for filename in os.listdir("app/bot/cogs/"): if filename.endswith('.py'): - bot.unload_extension(f'Cogs.{filename[:-3]}') - for filename in os.listdir("Cogs"): + bot.unload_extension(f'app.bot.cogs.{filename[:-3]}') + for filename in os.listdir("app/bot/cogs/"): if filename.endswith('.py'): - bot.load_extension(f'Cogs.{filename[:-3]}') + bot.load_extension(f'app.bot.cogs.{filename[:-3]}') print("All cogs has been reloaded.") -for filename in os.listdir("Cogs"): +for filename in os.listdir("app/bot/cogs/"): if filename.endswith('.py'): - bot.load_extension(f'Cogs.{filename[:-3]}') + bot.load_extension(f'app.bot.cogs.{filename[:-3]}') bot.run(Discord_bot_token) \ No newline at end of file