电报机器人的多行输入,用于将链接发送到 jdownloader

问题描述 投票:0回答:1

我创建了一个电报机器人,它以

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()
python telegram-bot python-telegram-bot themoviedb-api jdownloader
1个回答
0
投票

要修改您的机器人以处理多个链接+名称对,您需要更新 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 结束对话,因为我们正在一次处理所有行,而不是等待以获得更多用户输入。

请注意,这是一个简化的示例,可能无法满足您的所有需求,特别是当电影选择逻辑对您的用例很重要时。如果是这种情况,您可能需要更复杂的方法,也许为每个输入行维护一个单独的状态,或者提示用户为每个输入行做出选择。

© www.soinside.com 2019 - 2024. All rights reserved.