PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/main.py

https://gitlab.com/seanbehan/duckduckgo-bot
Python | 180 lines | 137 code | 14 blank | 29 comment | 1 complexity | b6e4ff5a62ec69f9a761b1755ed079bf MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Simple Bot to reply to Telegram messages
  5. # This program is dedicated to the public domain under the CC0 license.
  6. """
  7. This Bot uses the Updater class to handle the bot.
  8. First, a few handler functions are defined. Then, those functions are passed to
  9. the Dispatcher and registered at their respective places.
  10. Then, the bot is started and runs until we press Ctrl-C on the command line.
  11. Usage:
  12. Basic inline bot example. Applies different text transformations.
  13. Press Ctrl-C on the command line or send a signal to the process to stop the
  14. bot.
  15. """
  16. import configparser
  17. import logging
  18. from os import environ
  19. from urllib.parse import quote_plus
  20. from uuid import uuid4
  21. import requests
  22. from telegram import InlineQueryResultArticle, InputTextMessageContent
  23. from telegram.ext import CommandHandler, InlineQueryHandler, Updater
  24. # Enable logging
  25. logging.basicConfig(
  26. format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
  27. level=logging.INFO)
  28. LOGGER = logging.getLogger(__name__)
  29. logging.getLogger('telegram.vendor.ptb_urllib3').setLevel(logging.WARNING)
  30. # Define a few command handlers. These usually take the two arguments bot and
  31. # update. Error handlers also receive the raised TelegramError object in error.
  32. def start(bot, update):
  33. """When the bot is issued the command /start"""
  34. bot.sendMessage(
  35. update.message.chat_id,
  36. text='''Hello, I am an Inline bot, \
  37. please use me by mentioning my username in a chat along with your query''')
  38. def lmddgtfy_url(query):
  39. """Adds your query to the end of the search string and returns a URL"""
  40. base = "https://lmddgtfy.net/?q="
  41. end = quote_plus(query)
  42. url = base + end
  43. return url
  44. def shorten_url(long_url):
  45. """Puts your URL through the PTPB API to shorten it"""
  46. response = requests.post(
  47. 'https://ptpb.pw/u', data={
  48. 'c': long_url,
  49. 'sunset': 3600
  50. })
  51. url = response.headers.get('Location')
  52. return url
  53. def convert_to_url(query):
  54. """Adds your query to the end of the search string and returns a URL"""
  55. # feel free to fork and change the base url
  56. base = "https://duckduckgo.com/?q="
  57. end = quote_plus(query)
  58. url = base + end
  59. return url
  60. def inlinequery(bot, update):
  61. """Defines the inline query and adds specific functions to it"""
  62. query = update.inline_query.query
  63. results = list()
  64. results.append(
  65. InlineQueryResultArticle(
  66. id=uuid4(),
  67. title='DuckDuckGo: ' + query,
  68. thumb_url=
  69. 'https://duckduckgo.com/assets/icons/meta/DDG-iOS-icon_60x60.png',
  70. url=convert_to_url(query),
  71. input_message_content=InputTextMessageContent(
  72. convert_to_url(query))))
  73. results.append(
  74. InlineQueryResultArticle(
  75. id=uuid4(),
  76. title='Shortened: ' + query,
  77. thumb_url=
  78. 'https://avatars1.githubusercontent.com/u/12021773?v=3&s=200',
  79. url=shorten_url(convert_to_url(query)),
  80. input_message_content=InputTextMessageContent(
  81. shorten_url(convert_to_url(query)))))
  82. results.append(
  83. InlineQueryResultArticle(
  84. id=uuid4(),
  85. title='LMDDGTFY: ' + query,
  86. thumb_url=
  87. 'https://duckduckgo.com/assets/icons/meta/DDG-iOS-icon_60x60.png',
  88. url=lmddgtfy_url(query),
  89. input_message_content=InputTextMessageContent(
  90. lmddgtfy_url(query))))
  91. bot.answer_inline_query(update.inline_query.id, results=results)
  92. def ERROR(bot, update, error):
  93. """Logs all errors"""
  94. LOGGER.warning('Update "%s" caused error "%s"' % (update, error))
  95. def change_token():
  96. """Change API token with prompt on screen"""
  97. config = {}
  98. config['config'] = {'token': input('API Key: ')}
  99. if input('Save? [Y/n]') not in ['n', 'N']:
  100. with open('config.mine.ini', 'w') as configfile:
  101. configfile.write(config)
  102. print('API Key Saved to config.mine.ini')
  103. return config['config']['token']
  104. def main():
  105. """Main function to start the bot"""
  106. try:
  107. token_ = environ['TELEGRAM_API_KEY']
  108. # tries to read the api key inside an environment var if it exists
  109. except KeyError:
  110. config = configparser.ConfigParser()
  111. config.read('config.mine.ini')
  112. try:
  113. token_ = config['config']['token']
  114. except KeyError:
  115. config.read('config.ini')
  116. try:
  117. token_ = config['config']['token']
  118. except KeyError:
  119. pass
  120. # if there's a keyerror the file probably doesn't exist
  121. # we fall back to config.ini (the template file)
  122. if token_ in ['', 'enter your token here']:
  123. token_ = change_token()
  124. # if both token files are empty we prompt the user to enter
  125. # their api key and optionally save it
  126. # Create the Updater and pass it your bot's token.
  127. updater = Updater(token_)
  128. # Get the dispatcher to register handlers
  129. dispatcher = updater.dispatcher
  130. # on different commands - answer in Telegram
  131. dispatcher.add_handler(CommandHandler("start", start))
  132. dispatcher.add_handler(CommandHandler("help", start))
  133. # on noncommand i.e message - echo the message on Telegram
  134. dispatcher.add_handler(InlineQueryHandler(inlinequery))
  135. # log all errors
  136. dispatcher.add_error_handler(ERROR)
  137. # Start the Bot
  138. updater.start_polling()
  139. # Block until the user presses Ctrl-C or the process receives SIGINT,
  140. # SIGTERM or SIGABRT. This should be used most of the time, since
  141. # start_polling() is non-blocking and will stop the bot gracefully.
  142. updater.idle()
  143. if __name__ == '__main__':
  144. main()