I created a telegram bot that takes input in the form of link name
. The bot takes the name and searches using moviedb api to get the name, year, and id of the movie and then provide a menu to the user with a list of the movies for the user to select. Upon selection, it takes the data and sends the link to jdownloader with the moviename and year as foldername. Right now it takes one link+movie pair as input.
What I wanted was to change this to multiple link+name pairs in each line of the input message like:
link1 name1
link2 name2
link3 name3
and the bot takes each link and name one at a time and processes and sends the links to jdownloader in the same way it currently does. I did try but every time it fails with some error. Any idea how I can go about doing this?
The current code for single line input is:
import os
import requests
import myjdapi
from telegram import Update
from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, ConversationHandler, CallbackContext
TELEGRAM_BOT_TOKEN = 'bot_token'
MYJD_APP_KEY = "key"
MYJD_EMAIL = "email"
MYJD_PASSWORD = "pass"
MYJD_DEVICE_NAME = "name"
MOVIEDB_API_KEY = "api key"
DESTINATION_FOLDER = "destination"
# Define conversation states
GET_MOVIE_NAME, CHOOSE_MOVIE = range(2)
# Create a dictionary to store user data
user_data = {}
def start(update: Update, context: CallbackContext):
user_id = update.message.from_user.id
user_data[user_id] = []
update.message.reply_text('Welcome to the Movie Downloader bot! Send me a link and movie name to search and download.')
return GET_MOVIE_NAME
def get_movie_info(movie_name):
search_url = f'https://api.themoviedb.org/3/search/movie?api_key={MOVIEDB_API_KEY}&query={movie_name}'
response = requests.get(search_url)
if response.status_code == 200:
data = response.json()
results = data.get('results', [])
if results:
return results
return None
def add_movie_to_jdownloader(link, selected_movie):
movie_name = selected_movie['title']
movie_year = selected_movie['release_date'][:4]
movie_id = selected_movie['id']
package_name = f'{movie_name} ({movie_year}) [{movie_id}]'
destination_folder = DESTINATION_FOLDER # Define your destination folder
# Assuming you have already connected to MyJDownloader and have the device
jd = myjdapi.Myjdapi()
jd.set_app_key(MYJD_APP_KEY)
jd.connect(MYJD_EMAIL, MYJD_PASSWORD)
device = jd.get_device(MYJD_DEVICE_NAME)
# Add the link to the Linkgrabber
device.linkgrabber.add_links([{
'autostart': True,
'packageName': package_name,
'links': link,
'destinationFolder': destination_folder,
'overwritePackagizerRules': True
}])
def get_movie_name(update: Update, context: CallbackContext):
user_id = update.message.from_user.id
text = update.message.text # Get the user's message text
parts = text.split(maxsplit=1) # Split the input into two parts (link and movie name)
if len(parts) == 2:
link, movie_name = parts
movie_list = get_movie_info(movie_name)
if movie_list:
user_data[user_id] = (link, movie_list) # Store both the link and movie list
message = 'Multiple movies found. Please select one:\n'
for idx, movie in enumerate(movie_list):
message += f'{idx + 1}. {movie["title"]} ({movie["release_date"][:4]})\n'
message += 'Enter the number of your choice.'
update.message.reply_text(message)
return CHOOSE_MOVIE
else:
context.bot.send_message(chat_id=update.effective_chat.id, text='No movies found with that name. Please try again.')
return GET_MOVIE_NAME
else:
context.bot.send_message(chat_id=update.effective_chat.id, text='Invalid input format. Please use "link moviename."')
return GET_MOVIE_NAME
def choose_movie(update: Update, context: CallbackContext):
user_id = update.message.from_user.id
choice = int(update.message.text)
user_input = user_data.get(user_id)
if user_input and len(user_input) == 2:
link, movie_list = user_input
if 1 <= choice <= len(movie_list):
selected_movie = movie_list[choice - 1]
# Call the JDownloader function to add the movie
add_movie_to_jdownloader(link, selected_movie)
update.message.reply_text('The movie has been added to MyJDownloader.')
update.message.reply_text('Please enter the next link and movie name.')
return GET_MOVIE_NAME # Return to the movie name input state
else:
update.message.reply_text('Invalid choice. Please select a valid movie number.')
return CHOOSE_MOVIE
else:
update.message.reply_text('Something went wrong. Please start over by entering the next link and movie name.')
return GET_MOVIE_NAME
def main():
updater = Updater(TELEGRAM_BOT_TOKEN)
dp = updater.dispatcher # Create a dispatcher instance
# Optional start command handler
dp.add_handler(CommandHandler('start', start))
conv_handler = ConversationHandler(
entry_points=[
CommandHandler('start', start), # Optional /start command
MessageHandler(Filters.text & ~Filters.command, get_movie_name)
],
states={
GET_MOVIE_NAME: [MessageHandler(Filters.text & ~Filters.command, get_movie_name)],
CHOOSE_MOVIE: [MessageHandler(Filters.regex(r'^\d+$'), choose_movie)],
},
fallbacks=[]
)
dp.add_handler(conv_handler)
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
To modify your bot to process multiple link+name pairs, you would need to update the get_movie_name function to handle multiple lines of input, and adapt the rest of the code accordingly. One approach could be to split the input text into lines, and then process each line individually, in a manner similar to what is already done for a single line of input.
Here's a suggestion on how you could do that:
In this code, we've modified the get_movie_name function to split the input text into lines, and then process each line individually. For each line, we've created a new process_line function, which is very similar to your original single-line input processing code. However, instead of asking the user to choose a movie from a list, we're assuming that the first movie returned by the MovieDB API is the correct one, and we're adding it directly to JDownloader. If no movies are found for a given movie name, a message is sent to the user.
This code also utilizes the job_queue from python-telegram-bot to process each input line in a separate "job" which will run immediately. This allows the bot to process multiple input lines in parallel, which might be faster if there are many input lines.
The update.message.reply_text('Processing your request...') call informs the user that the bot is processing their request, and return ConversationHandler.END ends the conversation since we're processing all lines at once, instead of waiting for more user input.
Note that this is a simplified example and may not meet all your needs, especially if the movie selection logic is important to your use case. If that's the case, you may need a more complex approach, perhaps maintaining a separate state for each input line, or prompting the user to make a choice for each input line.