I wanna make generate buttons for each format and then download the video with the chosen format ...
How can I do it?
steps:
1 - ask for the link
2- get the link and show all the available streams (make buttons for them)
3-download the video with the specified resolution (here we need a callback query handler)
Step 1
def ask_for_link(update,context):
bot.send_message(chat_id=update.effective_chat.id ,text="Please Paste the video link here ... ")
return STREAMS
Step 2
def streams (update , context) :
try:
link=str(update.message.text)
Video_Url = YouTube(link)
Video= Video_Url.streams
chooseRes = []
for i in Video :
chooseRes.append([str(i).split()[2][str(i).split()[2].index("=")+2:len(str(i).split()[2])-1] , str(i).split()[3][str(i).split()[3].index("=")+2:len(str(i).split()[3])-1]])
print(chooseRes)
# list of resolution menu's buttons
res_menu_buttons_list = []
# a loop which create a button for each of resolutions
for each in chooseRes:
res_menu_buttons_list.append(InlineKeyboardButton(f"{each[0]} ❤️ {each[1]}", callback_data = each[1] ))
# print(res_menu_buttons_list)
#it'll show the buttons on the screen
replyMarkup=InlineKeyboardMarkup(build_res_menu(res_menu_buttons_list, n_cols=2 ))
#button's explanaions
update.message.reply_text("Choose an Option from the menu below ... ",reply_markup=replyMarkup)
return CLICK_FORMAT
except Exception as e:
print(e)
bot.send_message(chat_id=update.effective_chat.id , text = "Oooops !!! Something Went Wrong ... \n\n ( Make sure that you wrote the link correctly )")
quit(update,context)
# make columns based on how we declared
def build_res_menu(buttons,n_cols,header_buttons=None,footer_buttons=None):
res_menu_buttons = [buttons[i:i + n_cols] for i in range(0 , len(buttons), n_cols)]
if header_buttons:
res_menu_buttons.insert(0, header_buttons)
if footer_buttons:
res_menu_buttons.append(footer_buttons)
return res_menu_buttons
till now everything went good and smooth... Bot asks for the link, Gets the link, and generates a button for each format ...
now we need a CallBackQueryHandler for downloading the video with the chosen format ...
I did so but it doesn't work properly ... I need to use the link
variable in my function but I have no idea HOW ... I tried to return it from the streams
function but I couldn't cause I need to return the function too I use (ConverstationHandler)
anyway, it's the thing that I have till now ...
Step 3
def click_format(update,context):
query = update.callback_query
"""
My problem is exactly HERE
as You see I tried to Use Downloader. link but it doesn't work ...
I receive this error : AttributeError: 'function' object has no attribute 'link'
"""
Video = YouTube(Downloader.link).streams.filter(res=query.data).first().download()
format_vid=re.sub(Video.mime_type[:Video.mime_type.index("/")+1],"",Video.mime_type)
bot.send_message(chat_id=update.effective_chat.id , text = f"{Video.title} has Downloaded successfully ... ")
bot.send_video(chat_id=update.effective_chat.id ,video=open(f"{Video.title}.{format_vid}" , 'rb'), supports_streaming=True)
try:
os.remove(f"{Video.title}.{format_vid}")
print("removed")
except:
print("Can't remove")
quit(update,context)
It's My ConverstationHandler :
DOWNLOADER , CLICK_FORMAT = 0 ,1
YouTube_Downloader_converstation_handler=ConversationHandler(
entry_points=[CommandHandler("YouTubeDownloader", ask_for_link)] ,
states={
STREAMS :[MessageHandler(Filters.text , callback=streams )],
CLICK_FORMAT : [CallbackQueryHandler(click_format)]
},
fallbacks=[CommandHandler("quit" , quit)])
dispatcher.add_handler(YouTube_Downloader_converstation_handler)
Can anyone help me with the third step? I want to download the video in the chosen Format .... How can I use the link
variable in My click_format
function ????
IISC your problem is that you want to access the variable link
defined in streams
in the conversation state CLICK_FORMAT
/ in the callback click_format
.
As the update
variable in the click_format
contains information about the button click and not about the previously sent message, you'll have to store the link
in a variable that click_format
can access. You could naively use a global variable for that, but that has multiple downsides. Most notable, this will not work well when multiple users try to user your bot at the same time.
However, PTB comes with a bulit-in mechanism just for that: context.user_data
is a dictionary where you can store information associated to that user. So you could store the link as e.g. context.user_data['link'] = link
and the access it in click_format
as link = context.user_data['link']
.
Please see the wiki page for an explanation of user_data
with example and also see conversationbot.py example, where this feature is used in conjunction with a ConversationHandler
.