import logging from tbotconfig import * # Telegram things: #from telegram import InlineKeyboardButton, InlineKeyboardMarkup from telegram import InlineKeyboardMarkup, InlineKeyboardButton, InlineQueryResultArticle, InputTextMessageContent, InlineQueryResult, InlineQueryResultAudio from telegram.ext import Updater, CommandHandler, MessageHandler, Filters, CallbackQueryHandler, ConversationHandler, InlineQueryHandler, ChosenInlineResultHandler, CallbackContext # Other needful stuff from uuid import uuid4 import urllib.request import urllib import re import spotipy import spotipy.oauth2 import json import dpath import requests import time import os from pathlib import Path #Configure how many results to fetch num_results = 5 # Enable logging logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) # Spotify: spotify_credentials = spotipy.oauth2.SpotifyClientCredentials(SPOTIPY_CLIENT_ID, SPOTIPY_CLIENT_SECRET) sp = spotipy.Spotify(client_credentials_manager=spotify_credentials) # # 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. def start(update, context: CallbackContext): """Send a message when the command /start is issued.""" update.message.reply_text('Hello there!\n/help will give a short introduction to this bot.\nIts an inline bot, so you shouldn\'nt really be using it here.\nThis is a bot made by @DailytheNoob, check out the code on daviddaily.dev/david/telegram-music-bot') def help(update, context: CallbackContext): """Send a message when the command /help is issued.""" update.message.reply_markdown(f"Attention! I am an inline bot only!\n\nStart 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.\nIf 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.") def inlinequery(update, context: CallbackContext): query = update.inline_query.query print(query) results = [] spotify_credentials = spotipy.oauth2.SpotifyClientCredentials(SPOTIPY_CLIENT_ID, SPOTIPY_CLIENT_SECRET) sp = spotipy.Spotify(client_credentials_manager=spotify_credentials) if query: sp_info = sp.search(q=query, limit=num_results) for i in range(num_results): try: dpath.util.get(sp_info, f"/tracks/items/[{i}]/name") except: continue else: sp_title = dpath.util.get(sp_info, f"/tracks/items/[{i}]/name") sp_artist = dpath.util.get(sp_info, f"/tracks/items/[{i}]/artists/[0]/name") sp_albname = dpath.util.get(sp_info, f"/tracks/items/[{i}]/album/name") sp_albdate = dpath.util.get(sp_info, f"/tracks/items/[{i}]/album/release_date") sp_art = dpath.util.get(sp_info, f"/tracks/items/[{i}]/album/images/[2]/url") sp_audio = dpath.util.get(sp_info, f"/tracks/items/[{i}]/preview_url") sp_link = dpath.util.get(sp_info, f"/tracks/items/[{i}]/external_urls/spotify") songlink = "https://song.link/{0}".format(sp_link) reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton("Spotify", url = sp_link), InlineKeyboardButton("More", url = songlink)]]) 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),) update.inline_query.answer(results) def error(update, context: CallbackContext): # Log Errors caused by Updates logger.warning(f"\nUpdate {update} caused error {context.error}\n") def main(): # Create the Updater and pass it your bot's token. # Make sure to set use_context=True to use the new context based callbacks # Post version 12 this will no longer be necessary updater = Updater(TBOT_TOKEN, use_context=True) # Get the dispatcher to register handlers bot = updater.dispatcher # on different commands - answer in Telegram bot.add_handler(CommandHandler("start", start)) bot.add_handler(CommandHandler("help", help)) # on noncommand i.e message - echo the message on Telegram bot.add_handler(InlineQueryHandler(inlinequery)) # log all errors bot.add_error_handler(error) # Start the Bot updater.start_polling() # Block until the user presses Ctrl-C or the process receives SIGINT, # SIGTERM or SIGABRT. This should be used most of the time, since # start_polling() is non-blocking and will stop the bot gracefully. updater.idle() if __name__ == '__main__': main()