hooks.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #!/var/www/html/webhooks/.venv/bin/python
  2. # File name: Hooks.py
  3. # Date created: 09/16/2022
  4. # Date last modified: 10/15/2022
  5. # Python Version: 3.9.2
  6. # Copyright © 2022 DeadTOm
  7. # Description: Webhooks for Owncast to send notifications to Discord, Mastodon and Twitter, and to interact with
  8. # my Minecraft server
  9. # TODO: Make routes for various chat and video links
  10. try:
  11. from config import *
  12. from auth import *
  13. from flask import Flask, jsonify, current_app, request
  14. import requests
  15. import logging
  16. import time
  17. from twython import Twython, TwythonError
  18. import socket
  19. from mcstatus import JavaServer
  20. except Exception as import_error: # Log any errors loading modules, and try to keep running
  21. fail_log = open(log_location, 'a')
  22. fail_log.write(f'------{import_error}------\n')
  23. fail_log.close()
  24. logging.basicConfig(filename='/var/www/html/webhooks.log', level=logging.INFO)
  25. #logging.basicConfig(filename='/var/www/html/webhooks.log', level=logging.DEBUG)
  26. #logging.basicConfig(level=logging.DEBUG)
  27. testing = 0 # Are we testing? 1 for testing. 0 for live.
  28. twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
  29. app = Flask(__name__)
  30. def get_now(): # This creates and returns a time stamp
  31. now = str(time.strftime("%Y/%m/%d %H:%M:%S"))
  32. return now
  33. logging.info(f'\n\n\n\n{get_now()} - Webhook called.\n')
  34. def mc_chat(mc_msg): # Send chat message to Minecraft chat
  35. logging.info(f'{get_now()} - Checking Minecraft server for players.')
  36. mc_server = JavaServer.lookup('mc.deadtom.me:25565')
  37. query = mc_server.query() # Query Minecraft server for players
  38. cur_players = query.players.names
  39. if '_DeadTOm_' in cur_players: # If I'm on the server, send message
  40. logging.info(f'{get_now()} - DeadTOm is on the server, sending message.')
  41. logging.info(f'{get_now()} - Connecting...')
  42. sock_host = 'mc.deadtom.me'
  43. sock_port = 6791
  44. mySocket = socket.socket()
  45. mySocket.connect((sock_host, sock_port))
  46. time.sleep(1)
  47. logging.info(f'{get_now()} - Connected. Sending {mc_msg}...')
  48. mySocket.send(mc_msg.encode())
  49. logging.info(f'{get_now()} - sent.')
  50. mySocket.close()
  51. else: # If I'm not on the server, don't send the message
  52. logging.info(f'{get_now()} - DeadTOm is not on the server, so not sending message.')
  53. def set_hashtags(title): # Sets up hash tags to be appended to social media
  54. logging.info(f'{get_now()} - Examining stream title \"{title}\" to apply hashtags.')
  55. check_title = title.lower()
  56. default_tags = '#Owncast '
  57. tags = ''
  58. # tag_dict located in config.py
  59. for tag in tag_dict.keys(): # Iterate through each dict entry, and check for hashtag triggers
  60. if tag in check_title:
  61. print(f'Found {tag}, adding {tag_dict[tag]} to hashtags.')
  62. tags = f'{tags}{tag_dict[tag]} '
  63. tags = f'{tags}#Owncast #NSFW' # Adding NSFW tag, just for good measure
  64. logging.info(f'{get_now()} - Adding {tags} to title.')
  65. return tags
  66. def social_post(msg, discmsg): # Post to Mastodon
  67. # Send to Mastodon
  68. logging.info(f'{get_now()} - Posting to Mastodon.')
  69. response = requests.post(m_api_url,
  70. params={'status': msg},
  71. headers={'Authorization': m_api_key,
  72. 'visibility': 'public',
  73. 'Accept': 'application/json'})
  74. json_response = response.json()
  75. for line in json_response:
  76. logging.debug(f'{get_now()} - API returned: {line}: {json_response[line]}')
  77. # Send to Twitter
  78. twitter.update_status(status=msg) # Tweet the message
  79. logging.info(f'{get_now()} - Posted to Twitter.')
  80. # Send to Discord
  81. # for all params, see https://discordapp.com/developers/docs/resources/webhook#execute-webhook
  82. data = {
  83. 'content': discmsg
  84. }
  85. talkback = requests.post(discordwebhookurl, json=data)
  86. if 200 <= talkback.status_code < 300:
  87. logging.info(f'{get_now()} - Discord message sent {talkback.status_code}')
  88. else:
  89. logging.info(
  90. f'{get_now()} - Discord message not sent with {talkback.status_code}, response:\n{talkback.json()}')
  91. @app.route('/stream_started/', methods=["POST"])
  92. def start():
  93. logging.info(f'{get_now()} - stream_started request')
  94. raw_data = request.get_json(force=True) # Get the raw data
  95. event_data = raw_data['eventData']
  96. stream_title = event_data['streamTitle']
  97. hashtags = set_hashtags(stream_title.lower())
  98. msg = f'I\'m streaming on Owncast, at https://owncast.deadtom.me. {stream_title} {hashtags}'
  99. logging.debug(f'{get_now()} - Constructed Mastodon/Twitter message: {msg}')
  100. discmsg = f'DeadTOm is streaming on Owncast, at https://owncast.deadtom.me. {stream_title}'
  101. if testing != 1: # If we're testing, don't actually send out notification
  102. social_post(msg, discmsg)
  103. else:
  104. logging.info(f'-----------------------\n\n'
  105. f'{get_now()} - Currently running in test mode. We are streaming, but no notifications are being sent to social media.'
  106. f'\n\n---------------------------------')
  107. return jsonify({"Data": raw_data,})
  108. @app.route('/stream_stopped/', methods=["POST"])
  109. def stop():
  110. logging.info(f'{get_now()} - stream_stopped request')
  111. raw_data = request.get_json(force=True) # Get the raw data
  112. event_data = raw_data['eventData']
  113. stream_title = event_data['streamTitle']
  114. hashtags = set_hashtags(stream_title.lower()) # Make title lower case, for comparison with list of tags
  115. msg = f'All done streaming, for now. Maybe catch me next time on Owncast, at https://owncast.deadtom.me.\n\n{hashtags}'
  116. discmsg = f'DeadTOm is done streaming.'
  117. if testing != 1: # If we're testing, don't actually send out notification
  118. social_post(msg, discmsg)
  119. return jsonify({"Data": raw_data,})
  120. @app.route('/user_joined/', methods=["POST"])
  121. def joined():
  122. logging.info(f'{get_now()} - user_joined request')
  123. raw_data = request.get_json(force=True) # Get the raw data
  124. event_data = raw_data['eventData']
  125. chatter_name = event_data['user']['displayName']
  126. ownchat_msg = f'{chatter_name} joined the chat.'
  127. logging.info(f'{get_now()} - {ownchat_msg}')
  128. mc_chat(ownchat_msg)
  129. logging.info(f'{get_now()} - Sent to Minecraft server.')
  130. return jsonify({"Data": raw_data,})
  131. @app.route('/name_changed/', methods=["POST"])
  132. def changed():
  133. logging.info(f'{get_now()} - name_changed request')
  134. raw_data = request.get_json(force=True) # Get the raw data
  135. event_data = raw_data['eventData']
  136. chatter_old_name = event_data['user']['previousNames']
  137. chatter_new_name = event_data['user']['displayName']
  138. last_name = len(chatter_old_name) - 1 # Get last name in previousNames list
  139. chatter_old_name = event_data['user']['previousNames'][last_name]
  140. ownchat_msg = f'{chatter_old_name} changed their name to {chatter_new_name}'
  141. logging.debug(f'{get_now()} - {type}\n{raw_data}')
  142. logging.info(f'{get_now()} - {ownchat_msg}')
  143. mc_chat(ownchat_msg)
  144. logging.info(f'{get_now()} - Sent to Minecraft server.')
  145. return jsonify({"Data": raw_data,})
  146. @app.route('/message_sent/', methods=["POST"])
  147. def sent():
  148. logging.info(f'{get_now()} - message_sent request')
  149. raw_data = request.get_json(force=True) # Get the raw data
  150. event_data = raw_data['eventData']
  151. chatter_name = event_data['user']['displayName']
  152. chat_msg = event_data['rawBody']
  153. ownchat_msg = f'{chatter_name} on Owncast says: {chat_msg}'
  154. logging.info(f'{get_now()} - Chat message: \"{ownchat_msg}\".')
  155. mc_chat(ownchat_msg)
  156. logging.info(f'{get_now()} - Sent to Minecraft server.')
  157. return jsonify({"Data": raw_data,})
  158. if __name__ == '__main__':
  159. try:
  160. app.run()
  161. except Exception as main_error:
  162. logging.info(f'{get_now()} - {main_error}')