2019-12-13 07:57:48 -06:00
from tbotconfig import *
# Telegram things:
2023-04-05 13:24:47 -05:00
from telegram import InlineQueryResultArticle , InputTextMessageContent , Update
from telegram . constants import ParseMode
from telegram . ext import Application , CommandHandler , ContextTypes , InlineQueryHandler
2019-12-13 07:57:48 -06:00
# Other needful stuff
2023-04-05 13:24:47 -05:00
import asyncio
2021-01-14 14:59:07 -06:00
import html
import json
import logging
import traceback
2019-12-13 07:57:48 -06:00
from uuid import uuid4
import urllib . request
import urllib
import re
import spotipy
import spotipy . oauth2
2021-01-14 14:59:07 -06:00
from dpath import util
2019-12-13 07:57:48 -06:00
import requests
import time
import os
from pathlib import Path
2023-04-05 13:24:47 -05:00
logging . basicConfig (
format = ' %(asctime)s - %(name)s - %(levelname)s - %(message)s ' ,
level = logging . INFO
)
2019-12-13 07:57:48 -06:00
# Actual bot stuffs
#
# Define a few command handlers. These usually take the two arguments bot and update. Error handlers also receive the raised TelegramError object in error.
2023-04-05 13:24:47 -05:00
async def start ( update : Update , context : ContextTypes . DEFAULT_TYPE ) - > None :
2019-12-13 07:57:48 -06:00
""" Send a message when the command /start is issued. """
2023-04-05 13:24:47 -05:00
await context . bot . send_message (
chat_id = update . effective_chat . id ,
text = " ' Hello there! \n /help will give a short introduction to this bot. \n Its an inline bot, so you shouldn \' nt really be using it here. \n This is a bot made by @DailytheNoob, check out the code on daviddaily.dev/david/telegram-music-bot ' "
)
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
async def help ( update : Update , context : ContextTypes . DEFAULT_TYPE ) - > None :
2019-12-13 07:57:48 -06:00
""" Send a message when the command /help is issued. """
2023-04-05 13:24:47 -05:00
await context . bot . update . message . reply_markdown_v2 ( f " Attention! I am an inline bot only! \n \n Start your message with @MusicServiceBot and then the name of the song you want me to search spotify for. Wait for a few seconds and you should get { num_results } results back. \n If spotify provides a preview for the song, when you tap the desired result you ' ll get a 30 second preview for the song, otherwise its just the name of the song. Once you pick the right result you ' ll get a button for Spotify and more links that goes to a link aggregation site that will have links to most other services. " )
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
async def inline_query ( update : Update , context : ContextTypes . DEFAULT_TYPE ) - > None :
""" Handle the inline query. This is run when you type: @botusername <query> """
2019-12-13 07:57:48 -06:00
query = update . inline_query . query
2023-04-05 13:24:47 -05:00
if query == " " :
return
2021-01-14 14:59:07 -06:00
2023-04-05 13:24:47 -05:00
results = [ ]
2023-04-05 13:35:27 -05:00
sp_info = sp_search ( query )
2023-04-05 13:24:47 -05:00
for i in range ( len ( sp_info ) ) :
""" Spotify """
sp_title = util . get ( sp_info , f " /tracks/items/[ { i } ]/name " )
sp_artist = util . get ( sp_info , f " /tracks/items/[ { i } ]/artists/[0]/name " )
sp_albname = util . get ( sp_info , f " /tracks/items/[ { i } ]/album/name " )
sp_albdate = util . get ( sp_info , f " /tracks/items/[ { i } ]/album/release_date " )
sp_art = util . get ( sp_info , f " /tracks/items/[ { i } ]/album/images/[2]/url " )
sp_audio = util . get ( sp_info , f " /tracks/items/[ { i } ]/preview_url " )
sp_link = util . get ( sp_info , f " /tracks/items/[ { i } ]/external_urls/spotify " )
songlink = " https://song.link/ {0} " . format ( sp_link )
2023-04-05 13:35:27 -05:00
reply_markup = InlineKeyboardMarkup ( [ [ InlineKeyboardButton ( " Spotify " , url = sp_link ) , InlineKeyboardButton ( " More " , url = songlink ) ] ] )
2023-04-05 13:24:47 -05:00
description = f " By { sp_artist } on the album { sp_albname } , released { sp_albdate } "
if " None " in str ( sp_audio ) :
message_content = f " Check out \" { sp_title } \" by { sp_artist } on the album \" { sp_albname } \" "
results . append ( InlineQueryResultArticle ( id = i , title = sp_title , description = description , input_message_content = InputTextMessageContent ( message_content ) , thumb_url = sp_art , reply_markup = reply_markup ) , )
else :
message_content = f " Listen to \" { sp_title } \" by { sp_artist } on the album \" { sp_albname } \" "
results . append ( InlineQueryResultAudio ( id = i , audio_url = sp_audio , title = sp_title , performer = sp_artist , audio_duration = 30 , caption = message_content , reply_markup = reply_markup ) , )
2020-04-02 12:36:30 -05:00
2021-01-12 21:50:41 -06:00
update . inline_query . answer ( results )
2019-12-13 07:57:48 -06:00
2021-01-14 14:59:07 -06:00
2023-04-05 13:24:47 -05:00
async def sp_search ( query ) :
return sp . search ( q = query , limit = num_results )
2021-01-14 14:59:07 -06:00
2023-04-05 13:24:47 -05:00
async def error_handler ( update ) - > None :
2021-01-14 14:59:07 -06:00
""" Log the error and send a telegram message to notify the developer. """
# Log the error before we do anything else, so we can see it even if something breaks.
logger . error ( msg = " Exception while handling an update: " , exc_info = context . error )
2023-04-05 13:24:47 -05:00
# This can be your own ID, or one for a developer group/channel.
# You can use the /start command of this bot to see your chat id.
DEVELOPER_CHAT_ID = 175042676
2021-01-14 14:59:07 -06:00
# traceback.format_exception returns the usual python message about an exception, but as a
# list of strings rather than a single string, so we have to join them together.
tb_list = traceback . format_exception ( None , context . error , context . error . __traceback__ )
tb_string = ' ' . join ( tb_list )
# Build the message with some markup and additional information about what happened.
# You might need to add some logic to deal with messages longer than the 4096 character limit.
message = (
f ' An exception was raised while handling an update \n '
f ' <pre>update = { html . escape ( json . dumps ( update . to_dict ( ) , indent = 2 , ensure_ascii = False ) ) } '
' </pre> \n \n '
f ' <pre>context.chat_data = { html . escape ( str ( context . chat_data ) ) } </pre> \n \n '
f ' <pre>context.user_data = { html . escape ( str ( context . user_data ) ) } </pre> \n \n '
f ' <pre> { html . escape ( tb_string ) } </pre> '
)
# Finally, send the message
context . bot . send_message ( chat_id = DEVELOPER_CHAT_ID , text = message , parse_mode = ParseMode . HTML )
2023-04-05 13:24:47 -05:00
def main ( ) - > None :
#Configure how many results to fetch
num_results = 5
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
# Spotify:
spotify_credentials = spotipy . oauth2 . SpotifyClientCredentials ( SPOTIPY_CLIENT_ID , SPOTIPY_CLIENT_SECRET )
sp = spotipy . Spotify ( client_credentials_manager = spotify_credentials )
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
# Create the Application and pass it your bot's token.
application = Application . builder ( ) . token ( BOT_TOKEN ) . build ( )
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
# on different commands - answer in Telegram
application . add_handler ( CommandHandler ( " start " , start ) )
application . add_handler ( CommandHandler ( " help " , help ) )
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
# on non command i.e message - echo the message on Telegram
application . add_handler ( InlineQueryHandler ( inline_query ) )
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
# Run the bot until the user presses Ctrl-C
application . run_polling ( )
2019-12-13 07:57:48 -06:00
2023-04-05 13:24:47 -05:00
if __name__ == " __main__ " :
main ( )