我创建了一个电报机器人,它以
link name
的形式接受输入。该机器人获取名称并使用 moviedb api 进行搜索,以获取电影的名称、年份和 ID,然后向用户提供一个菜单,其中包含电影列表供用户选择。选择后,它会获取数据并将链接发送到 jdownloader,其中包含电影名称和年份作为文件夹名称。现在它需要一个链接+电影对作为输入。
我想要的是将其更改为输入消息的每一行中的多个链接+名称对,例如:
link1 name1
link2 name2
link3 name3
机器人会获取每个链接并一次命名一个链接,然后以与当前相同的方式处理链接并将其发送到 jdownloader。我确实尝试过,但每次都会因一些错误而失败。知道我该怎么做吗?
当前单行输入的代码是:
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()
要修改您的机器人以处理多个链接+名称对,您需要更新 get_movie_name 函数以处理多行输入,并相应地调整其余代码。一种方法是将输入文本分割成行,然后单独处理每一行,其方式类似于已经对单行输入所做的处理。
以下是关于如何做到这一点的建议:
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 = 0
def start(update: Update, context: CallbackContext):
update.message.reply_text('Welcome to the Movie Downloader bot! Send me a list of link and movie name pairs 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
jd = myjdapi.Myjdapi()
jd.set_app_key(MYJD_APP_KEY)
jd.connect(MYJD_EMAIL, MYJD_PASSWORD)
device = jd.get_device(MYJD_DEVICE_NAME)
device.linkgrabber.add_links([{
'autostart': True,
'packageName': package_name,
'links': link,
'destinationFolder': destination_folder,
'overwritePackagizerRules': True
}])
def process_line(line, context: CallbackContext):
parts = line.split(maxsplit=1)
if len(parts) == 2:
link, movie_name = parts
movie_list = get_movie_info(movie_name)
if movie_list:
for movie in movie_list:
add_movie_to_jdownloader(link, movie)
else:
context.bot.send_message(chat_id=context.job.context, text=f'No movies found for {movie_name}. Please try again.')
def get_movie_name(update: Update, context: CallbackContext):
text = update.message.text
lines = text.strip().split('\n')
for line in lines:
context.job_queue.run_once(lambda context: process_line(line, context), 0, context=update.effective_chat.id)
update.message.reply_text('Processing your request...')
return ConversationHandler.END
def main():
updater = Updater(TELEGRAM_BOT_TOKEN)
dp = updater.dispatcher
dp.add_handler(CommandHandler('start', start))
conv_handler = ConversationHandler(
entry_points=[CommandHandler('start', start), MessageHandler(Filters.text & ~Filters.command, get_movie_name)],
states={GET_MOVIE_NAME: [MessageHandler(Filters.text & ~Filters.command, get_movie_name)]},
fallbacks=[]
)
dp.add_handler(conv_handler)
updater.start_polling()
updater.idle()
if __name__ == '__main__':
main()
在此代码中,我们修改了 get_movie_name 函数,将输入文本拆分为行,然后单独处理每一行。对于每一行,我们创建了一个新的 process_line 函数,它与原始的单行输入处理代码非常相似。然而,我们不是要求用户从列表中选择电影,而是假设 MovieDB API 返回的第一部电影是正确的,并且我们将其直接添加到 JDownloader。如果没有找到给定电影名称的电影,则会向用户发送一条消息。
此代码还利用 python-telegram-bot 中的 job_queue 在单独的“作业”中处理每个输入行,该作业将立即运行。这允许机器人并行处理多个输入行,如果输入行很多,速度可能会更快。
update.message.reply_text('Processing your request...') 调用通知用户机器人正在处理他们的请求,并返回 ConversationHandler.END 结束对话,因为我们正在一次处理所有行,而不是等待以获得更多用户输入。
请注意,这是一个简化的示例,可能无法满足您的所有需求,特别是当电影选择逻辑对您的用例很重要时。如果是这种情况,您可能需要更复杂的方法,也许为每个输入行维护一个单独的状态,或者提示用户为每个输入行做出选择。