import requests, imdb, discord, json, math, time, asyncio, os, concurrent.futures from funcs import logThis radarrURL = "http://localhost:7878/api/v3/" sonarrURL = "http://localhost:8989/api/" qbittorrentURL = "http://localhost:1340/api/v2/" moviePath = "/media/plex/Server/movies/" showPath = "/media/plex/Server/Shows/" def getSize(startPath,pathLength): logThis("Getting the size of "+startPath) totalSize = 0 for dirpath, dirnames, filenames in os.walk(startPath): for f in filenames: fp = os.path.join(dirpath, f) # skip if it is symbolic link if not os.path.islink(fp): print(fp[:60],end="\r") totalSize += os.path.getsize(fp) return totalSize async def formatSize(size): if size >= 1024**4: return ("%.1f" % (size/(1024**4))) + "TB" elif size >= 1024**3: return ("%.1f" % (size/(1024**3))) + "GB" elif size >= 1024**2: return ("%.1f" % (size/(1024**2))) + "MB" elif size >= 1024: return ("%.1f" % (size/(1024))) + "KB" else: return str(size)+"b" class BedreNetflix(): def __init__(self,bot): self.bot = bot #Returns a list of no more than 5 options when user requests a movie async def requestMovie(self, ctx, movieName): logThis("Searching for "+movieName) movieList = imdb.IMDb().search_movie(movieName) movies = [] for movie in movieList: if movie["kind"] == "movie": movies.append(movie) if len(movies) > 5: movies = movies[:5] if len(movies) == 1: messageTitle = "**Is it this movie?**" else: messageTitle = "**Is it any of these movies?**" messageText = "" imdbIds = [] for x, movie in enumerate(movies): try: messageText += "\n"+str(x+1)+") "+movie["title"]+" ("+str(movie["year"])+")" except: try: messageText += "\n"+str(x+1)+") "+movie["title"] except: messageText += "Error" imdbIds.append(movie.movieID) logThis("Returning a list of "+str(len(movies))+" possible movies: "+str(imdbIds)) em = discord.Embed(title=messageTitle,description=messageText,colour=0x00FF00) message = await ctx.send(embed=em) messageData = {"messageID":message.id,"imdbIds":imdbIds} with open("resources/bedreNetflix/oldMessage"+str(ctx.channel.id),"w") as f: json.dump(messageData,f) if len(movies) == 1: await message.add_reaction("✔️") else: for x in range(len(movies)): await message.add_reaction(["1️⃣","2️⃣","3️⃣","4️⃣","5️⃣"][x]) await message.add_reaction("❌") #Adds the requested movie to Bedre Netflix async def addMovie(self,channel,imdbId): if imdbId == None: logThis("Did not find what the user was searching for") await channel.send("Try searching for the IMDB id") else: logThis("Trying to add movie "+str(imdbId)) apiKey = self.bot.credentials.radarrKey response = requests.get(radarrURL+"movie/lookup/imdb?imdbId=tt"+imdbId+"&apiKey="+apiKey) lookupData = response.json() postData = {"qualityProfileId": 1, "rootFolderPath" : moviePath, "monitored" : True, "addOptions": {"searchForMovie": True}} for key in ["tmdbId","title","titleSlug","images","year"]: postData.update({key : lookupData[key]}) r = requests.post(url= radarrURL+"movie?apikey="+apiKey,json = postData) if r.status_code == 201: await channel.send("Movie successfully added to Bedre Netflix") logThis("Added a movie to Bedre Netflix") elif r.status_code == 400: await channel.send("The movie is already on Bedre Netflix") else: await channel.send("Something went wrong") logThis(str(r.status_code)+" "+r.reason) #Returns a list of no more than 5 options when user requests a show async def requestShow(self, ctx, showName): logThis("Searching for "+showName) movies = imdb.IMDb().search_movie(showName) #Replace with tvdb shows = [] for movie in movies: if movie["kind"] in ["tv series","tv miniseries"]: shows.append(movie) if len(shows) > 5: shows = shows[:5] if len(shows) == 1: messageTitle = "**Is it this show?**" else: messageTitle = "**Is it any of these shows?**" messageText = "" imdbNames = [] for x, show in enumerate(shows): try: messageText += "\n"+str(x+1)+") "+show["title"]+" ("+str(show["year"])+")" except: try: messageText += "\n"+str(x+1)+") "+show["title"] except: messageText += "Error" imdbNames.append(show["title"]) logThis("Returning a list of "+str(len(shows))+" possible shows: "+str(imdbNames)) em = discord.Embed(title=messageTitle,description=messageText,colour=0x00FF00) message = await ctx.send(embed=em) messageData = {"messageID":message.id,"imdbNames":imdbNames} with open("resources/bedreNetflix/oldMessage"+str(ctx.channel.id),"w") as f: json.dump(messageData,f) if len(shows) == 1: await message.add_reaction("✔️") else: for x in range(len(shows)): await message.add_reaction(["1️⃣","2️⃣","3️⃣","4️⃣","5️⃣"][x]) await message.add_reaction("❌") #Adds the requested show to Bedre Netflix async def addShow(self,channel,imdbName): if imdbName == None: logThis("Did not find what the user was searching for") await channel.send("Try searching for the IMDB id") else: logThis("Trying to add show "+str(imdbName)) apiKey = self.bot.credentials.sonarrKey response = requests.get(sonarrURL+"series/lookup?term="+imdbName.replace(" ","%20")+"&apiKey="+apiKey) lookupData = response.json()[0] postData = {"ProfileId" : 1, "rootFolderPath" : showPath, "monitored" : True, "addOptions" : {"searchForMissingEpisodes" : True}} for key in ["tvdbId","title","titleSlug","images","seasons"]: postData.update({key : lookupData[key]}) r = requests.post(url= sonarrURL+"series?apikey="+apiKey,json = postData) if r.status_code == 201: await channel.send("Show successfully added to Bedre Netflix") logThis("Added a show to Bedre Netflix") elif r.status_code == 400: await channel.send("The show is already on Bedre Netflix") else: await channel.send("Something went wrong") logThis(str(r.status_code)+" "+r.reason) #Generates a list of all torrents and returns formatted list and whether all torrents are downloaded async def genDownloadList(self): logThis("Generating torrent list") response = requests.get(qbittorrentURL+"torrents/info") torrentList = response.json() message = [] allDownloaded = True for torrent in torrentList: torrentName = torrent["name"] if len(torrentName) > 30: if torrentName[26] == " ": torrentName = torrentName[:26]+"...." else: torrentName = torrentName[:27]+"..." if torrent["size"] == 0: downloadedRatio = 0 elif torrent["amount_left"] == 0: downloadedRatio = 1 else: downloadedRatio = min(torrent["downloaded"]/torrent["size"],1) progressBar = "|"+("█"*math.floor(downloadedRatio*20)) while len(progressBar) < 21: progressBar += " " progressBar += "| "+str(math.floor(downloadedRatio*100))+"%" while len(progressBar) < 27: progressBar += " " etaInSeconds = torrent["eta"] if etaInSeconds >= 8640000: eta = "∞" else: eta = "" if etaInSeconds >= 86400: eta += str(math.floor(etaInSeconds/86400))+"d " if etaInSeconds >= 3600: eta += str(math.floor((etaInSeconds%86400)/3600))+"h " if etaInSeconds >= 60: eta += str(math.floor((etaInSeconds%3600)/60))+"m " eta += str(etaInSeconds%60)+"s" torrentInfo = torrentName+" "+progressBar+" (Eta: "+eta+")" if not (downloadedRatio == 1 and torrent["last_activity"] < time.time()-7200): message.append(torrentInfo) if downloadedRatio < 1: allDownloaded = False messageText = "```"+"\n".join(message)+"```" if messageText == "``````": messageText = "There are no torrents downloading right. If the torrent you're looking for was added more than 24 hours ago, it might already be on Bedre Netflix." return messageText, allDownloaded async def downloading(self,ctx): messageText, allDownloaded = await self.genDownloadList() if messageText.startswith("```"): updatesLeft = 60 messageText = messageText[:-3]+"\nThis message will update every 10 seconds for "+str(math.ceil(updatesLeft/6))+" more minutes\n```" oldMessage = await ctx.send(messageText) while ((not allDownloaded) and updatesLeft > 0): await asyncio.sleep(10) updatesLeft -= 1 messageText, allDownloaded = await self.genDownloadList() messageText = messageText[:-3]+"\nThis message will update every 10 seconds for "+str(math.ceil(updatesLeft/6))+" more minutes\n```" await oldMessage.edit(content = messageText) messageText, allDownloaded = await self.genDownloadList() if allDownloaded: messageText = messageText[:-3]+"\nThis message will not update because all torrents are downloaded.\n```" logThis("All torrents are downloaded") else: messageText = messageText[:-3]+"\nThis message will not update anymore\n```" logThis("The message updated 20 times") await oldMessage.edit(content = messageText) else: await ctx.send(messageText) async def directorySizes(self,ctx): logThis("Calculating directory size") message = await ctx.send("```Calculating directory size. This might take a while.```") startPath = ".." pathLength = len(startPath) directories = [] for f in os.listdir(startPath): fp = os.path.join(startPath, f) if os.path.isfile(fp): size = os.path.getsize(fp) else: with concurrent.futures.ThreadPoolExecutor() as executor: future = executor.submit(getSize,fp,pathLength) size = future.result() directories.append((str(f),size)) directories.sort(key=lambda tup: tup[1]) directories.reverse() returnText = "```Calculating directory size. This might take a while.\n" total = 0 for directory, size in directories: total += size sizeText = await formatSize(size) returnText += "\n"+directory+": "+sizeText returnText += "\nTotal: "+await formatSize(total)+"```" await message.edit(content=returnText) directories.sort(key=lambda tup: tup[1]) directories.reverse() returnText = "```" total = 0 for directory, size in directories: total += size sizeText = await formatSize(size) returnText += "\n"+directory+": "+sizeText returnText += "\nTotal: "+await formatSize(total)+"```" logThis("Returning final result of dirsize") await message.edit(content=returnText)