Fixed bug where the bedreNetflix commands would delete the old response instead of editing it
393 lines
17 KiB
Python
393 lines
17 KiB
Python
import requests, imdb, discord, json, math, time, asyncio
|
||
|
||
class BedreNetflix():
|
||
def __init__(self,bot):
|
||
self.bot = bot
|
||
ip = ["localhost", "192.168.0.40"][self.bot.options.testing]
|
||
|
||
self.radarrURL = "http://"+ip+":7878/api/v3/"
|
||
self.sonarrURL = "http://"+ip+":8989/api/"
|
||
self.qbittorrentURL = "http://"+ip+":1340/api/v2/"
|
||
self.moviePath = "/media/plex/Server/movies/"
|
||
self.showPath = "/media/plex/Server/Shows/"
|
||
|
||
#Returns a list of no more than 5 options when user requests a movie
|
||
async def requestMovie(self, ctx, movieName):
|
||
await ctx.defer()
|
||
|
||
self.bot.log("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)
|
||
|
||
self.bot.log("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, message, imdbId):
|
||
if imdbId == None:
|
||
self.bot.log("Did not find what the user was searching for")
|
||
await message.edit(embed = None, content = "Try searching for the IMDB id")
|
||
else:
|
||
self.bot.log("Trying to add movie "+str(imdbId))
|
||
apiKey = self.bot.credentials.radarrKey
|
||
response = requests.get(self.radarrURL+"movie/lookup/imdb?imdbId=tt"+imdbId+"&apiKey="+apiKey)
|
||
lookupData = response.json()
|
||
postData = {"qualityProfileId": 1,
|
||
"rootFolderPath" : self.moviePath,
|
||
"monitored" : True,
|
||
"addOptions": {"searchForMovie": True}}
|
||
for key in ["tmdbId","title","titleSlug","images","year"]:
|
||
postData.update({key : lookupData[key]})
|
||
|
||
r = requests.post(url= self.radarrURL+"movie?apikey="+apiKey,json = postData)
|
||
|
||
if r.status_code == 201:
|
||
await message.edit(embed = None, content = postData["title"]+" successfully added to Bedre Netflix")
|
||
self.bot.log("Added "+postData["title"]+" to Bedre Netflix")
|
||
elif r.status_code == 400:
|
||
text = f"{postData['title']} is either already on Bedre Netflix, downloading, or not available"
|
||
await message.edit(embed = None, content = text)
|
||
else:
|
||
await message.edit(embed = None, content = "Something went wrong")
|
||
self.bot.log(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):
|
||
await ctx.defer()
|
||
|
||
self.bot.log("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"])
|
||
|
||
self.bot.log("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, message, imdbName):
|
||
if imdbName == None:
|
||
self.bot.log("Did not find what the user was searching for")
|
||
await message.edit(embed = None, content = "Try searching for the IMDB id")
|
||
else:
|
||
self.bot.log("Trying to add show "+str(imdbName))
|
||
apiKey = self.bot.credentials.sonarrKey
|
||
response = requests.get(self.sonarrURL+"series/lookup?term="+imdbName.replace(" ","%20")+"&apiKey="+apiKey)
|
||
lookupData = response.json()[0]
|
||
postData = {"ProfileId" : 1,
|
||
"rootFolderPath" : self.showPath,
|
||
"monitored" : True,
|
||
"addOptions" : {"searchForMissingEpisodes" : True}}
|
||
for key in ["tvdbId","title","titleSlug","images","seasons"]:
|
||
postData.update({key : lookupData[key]})
|
||
|
||
r = requests.post(url= self.sonarrURL+"series?apikey="+apiKey,json = postData)
|
||
|
||
if r.status_code == 201:
|
||
await message.edit(embed = None, content = postData["title"]+" successfully added to Bedre Netflix")
|
||
self.bot.log("Added a "+postData["title"]+" to Bedre Netflix")
|
||
elif r.status_code == 400:
|
||
text = f"{postData['title']} is either already on Bedre Netflix, downloading, or not available"
|
||
await message.edit(embed = None, content = text)
|
||
else:
|
||
await message.edit(embed = None, content = "Something went wrong")
|
||
self.bot.log(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, showDM, showMovies, showShows, episodes):
|
||
self.bot.log("Generating torrent list")
|
||
titleWidth = 100
|
||
message = []
|
||
allDownloaded = True
|
||
|
||
if showDM:
|
||
message.append("")
|
||
DMSectionTitle = "*Torrent Downloads*"
|
||
DMSectionTitleLine = "-"*((titleWidth-len(DMSectionTitle))//2)
|
||
message.append(DMSectionTitleLine+DMSectionTitle+DMSectionTitleLine)
|
||
response = requests.get(self.qbittorrentURL+"torrents/info")
|
||
torrentList = response.json()
|
||
|
||
if len(torrentList) > 0:
|
||
for torrent in torrentList:
|
||
torrentName = torrent["name"]
|
||
if len(torrentName) > 30:
|
||
if torrentName[26] == " ":
|
||
torrentName = torrentName[:26]+"...."
|
||
else:
|
||
torrentName = torrentName[:27]+"..."
|
||
while len(torrentName) < 30:
|
||
torrentName += " "
|
||
|
||
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 torrent["state"] == "stalledDL":
|
||
torrentInfo += " (Stalled)"
|
||
|
||
if not (downloadedRatio == 1 and torrent["last_activity"] < time.time()-7200):
|
||
message.append(torrentInfo)
|
||
|
||
if downloadedRatio < 1 and torrent["state"] != "stalledDL":
|
||
allDownloaded = False
|
||
else:
|
||
message.append("No torrents currently downloading")
|
||
|
||
if showMovies:
|
||
message.append("")
|
||
movieSectionTitle = "*Missing movies not downloading*"
|
||
movieSectionTitleLine = "-"*((titleWidth-len(movieSectionTitle))//2)
|
||
message.append(movieSectionTitleLine+movieSectionTitle+movieSectionTitleLine)
|
||
movieList = requests.get(self.radarrURL+"movie?apiKey="+self.bot.credentials.radarrKey).json()
|
||
movieQueue = requests.get(self.radarrURL+"queue?apiKey="+self.bot.credentials.radarrKey).json()
|
||
movieQueueIDs = []
|
||
|
||
for queueItem in movieQueue["records"]:
|
||
movieQueueIDs.append(queueItem["movieId"])
|
||
|
||
for movie in movieList:
|
||
if not movie["hasFile"]:
|
||
if movie["id"] not in movieQueueIDs:
|
||
movieName = movie["title"]
|
||
if len(movieName) > 40:
|
||
if movieName[36] == " ":
|
||
movieName = movieName[:36]+"...."
|
||
else:
|
||
movieName = movieName[:37]+"..."
|
||
|
||
while len(movieName) < 41:
|
||
movieName += " "
|
||
|
||
if movie["monitored"]:
|
||
movieInfo = movieName+"Could not find a torrent"
|
||
else:
|
||
movieInfo = movieName+"No torrent exists. Likely because the movie is not yet released on DVD"
|
||
|
||
message.append(movieInfo)
|
||
|
||
if showShows:
|
||
message.append("")
|
||
showSectionTitle = "*Missing shows not downloading*"
|
||
showSectionTitleLine = "-"*((titleWidth-len(showSectionTitle))//2)
|
||
message.append(showSectionTitleLine+showSectionTitle+showSectionTitleLine)
|
||
|
||
showList = requests.get(self.sonarrURL+"series?apiKey="+self.bot.credentials.sonarrKey).json()
|
||
|
||
for show in showList:
|
||
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:
|
||
missingEpisodes = sum(i["statistics"]["totalEpisodeCount"] - i["statistics"]["episodeCount"] for i in seasons)
|
||
message.append(show["title"] + f" ({missingEpisodes} episodes)")
|
||
|
||
message.append("-"*titleWidth)
|
||
|
||
messageText = "```"+"\n".join(message[1:])+"```"
|
||
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, content):
|
||
async def SendLongMessage(ctx,messageText):
|
||
if len(messageText) <= 1994:
|
||
await ctx.send("```"+messageText+"```")
|
||
else:
|
||
cutOffIndex = messageText[:1994].rfind("\n")
|
||
await ctx.send("```"+messageText[:cutOffIndex]+"```")
|
||
await SendLongMessage(ctx,messageText[cutOffIndex+1:])
|
||
|
||
await ctx.defer()
|
||
|
||
# showDM, showMovies, showShows, episodes
|
||
params = [False, False, False, False]
|
||
showDMArgs = ["d", "dm", "downloading", "downloadmanager"]
|
||
showMoviesArgs = ["m", "movies"]
|
||
showShowsArgs = ["s", "shows", "series"]
|
||
episodesArgs = ["e", "episodes"]
|
||
argList = [showDMArgs, showMoviesArgs, showShowsArgs, episodesArgs]
|
||
inputArgs = []
|
||
validArguments = True
|
||
|
||
while content != "" and validArguments:
|
||
if content[0] == " ":
|
||
content = content[1:]
|
||
elif content[0] == "-":
|
||
if content[1] == "-":
|
||
argStart = 2
|
||
if " " in content:
|
||
argStop = content.find(" ")
|
||
else:
|
||
argStop = None
|
||
else:
|
||
argStart = 1
|
||
argStop = 2
|
||
|
||
inputArgs.append(content[argStart:argStop])
|
||
if argStop is None:
|
||
content = ""
|
||
else:
|
||
content = content[argStop:]
|
||
else:
|
||
validArguments = False
|
||
|
||
if validArguments:
|
||
for x, argAliases in enumerate(argList):
|
||
argInInput = [i in inputArgs for i in argAliases]
|
||
if any(argInInput):
|
||
inputArgs.remove(argAliases[argInInput.index(True)])
|
||
params[x] = True
|
||
|
||
if len(inputArgs) != 0 or (params[2] == False and params[3] == True):
|
||
validArguments = False
|
||
|
||
showAnything = any(i for i in params)
|
||
if validArguments and showAnything:
|
||
messageText, allDownloaded = await self.genDownloadList(*params)
|
||
if messageText.startswith("```"):
|
||
|
||
if len(messageText) <= 2000:
|
||
if not allDownloaded:
|
||
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(*params)
|
||
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(*params)
|
||
|
||
if messageText.startswith("```"):
|
||
if allDownloaded:
|
||
self.bot.log("All torrents are downloaded")
|
||
else:
|
||
messageText = messageText[:-3]+"\nThis message will not update anymore\n```"
|
||
self.bot.log("The message updated 20 times")
|
||
|
||
await oldMessage.edit(content = messageText)
|
||
|
||
else:
|
||
await ctx.send(messageText)
|
||
else:
|
||
messageText = messageText[3:-3]
|
||
await SendLongMessage(ctx,messageText)
|
||
else:
|
||
await ctx.send(messageText)
|
||
else:
|
||
await ctx.send("Invalid or repeated parameters. Use '/help downloading' to see valid parameters.")
|
||
|