Guest User

Untitled

a guest
Mar 1st, 2016
49
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.61 KB | None | 0 0
  1. # coding=utf-8
  2. """
  3.    The MIT License (MIT)
  4.  
  5.    Copyright (c) 2016 lapoozza
  6.  
  7.    Permission is hereby granted, free of charge, to any person obtaining a copy
  8.    of this software and associated documentation files (the "Software"), to deal
  9.    in the Software without restriction, including without limitation the rights
  10.    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11.    copies of the Software, and to permit persons to whom the Software is
  12.    furnished to do so, subject to the following conditions:
  13.  
  14.    The above copyright notice and this permission notice shall be included in all
  15.    copies or substantial portions of the Software.
  16.  
  17.    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18.    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19.    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20.    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21.    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22.    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23.    SOFTWARE.
  24. """
  25.  
  26. import discord
  27. import socket
  28. import asyncio
  29. import re
  30. import threading
  31. from time import strftime
  32. import yaml
  33.  
  34. # Configuration settings -------->
  35. try:
  36.     with open('config.yaml') as f:
  37.         stream1 = yaml.load(f)
  38. except FileExistsError:
  39.     print('config.yaml not found.')
  40.     quit()
  41.  
  42. # Channel settings -------->
  43. try:
  44.     with open('channels.yaml') as f:
  45.         stream3 = yaml.load(f)
  46. except FileExistsError:
  47.     print('config.yaml not found.')
  48.     quit()
  49.  
  50.  
  51. class Bot(discord.Client):
  52.     """
  53.    The irc client file. This program is a standalone irc client that bridges osu! bancho server and discord app.
  54.  
  55.    Some helpful IRC codes for bancho
  56.        cho.ppy.sh 001: Bancho welcome message
  57.        cho.ppy.sh 322: For available channels
  58.        cho.ppy.sh 353: For list of users
  59.        cho.ppy.sh 375: Blank line
  60.        cho.ppy.sh 372: Bancho Related information
  61.    """
  62.     # Loading configurations from config.yaml---------->
  63.     admin_ids = stream1['DISCORD']['admin_id']
  64.     bancho_dump = int(stream1['CHANNEL']['bancho_dump'])
  65.  
  66.     bancho_usr = stream1['OSU']['Username']
  67.     bancho_pass = stream1['OSU']['Server Password']
  68.  
  69.     msg_chan = '#osu'
  70.     available_chan = []
  71.  
  72.     def __init__(self):
  73.         super().__init__()
  74.  
  75.     async def on_message(self, message):
  76.         """
  77.  
  78.        :param message:
  79.        """
  80.         if message.author == self.user:
  81.             return
  82.  
  83.         # Discord Interactions ------------->
  84.         if message.content.startswith('!id'):
  85.             await self.send_message(message.channel, '{} your id is: {}'
  86.                                     .format(message.author.mention, message.author.id))
  87.  
  88.         if message.content.startswith('!invite'):
  89.             cont = str(message.content[8:])
  90.             await discord.Client.accept_invite(self, invite=cont)
  91.             await self.send_message(message.channel, '{} accepted invite'
  92.                                     .format(message.author.mention))
  93.  
  94.         if message.content.startswith('!help'):
  95.             await self.send_message(message.channel, 'The available commands are:\n'
  96.                                                      '`!bancho` Logs you into the osu!bancho server.\n'
  97.                                                      '`!join #channel` Joins a specified channel.\n'
  98.                                                      '`!leave #channel` Leaves a specified channel.\n'
  99.                                                      '`!setch channel/user` Sets the channel or user for your texts.\n'
  100.                                                      '`!ch` The channel or user your texts are currently going to.\n'
  101.                                                      '`!list` The available list of channels.\n'
  102.                                                      '`!id` Shows your discord id.')
  103.  
  104.         if message.content.startswith("?"):
  105.             """
  106.                This part deals with sending message. The message must be tagged with a
  107.                initial `?` mark to be sent.
  108.  
  109.                For example:
  110.                    `?hello` ->will be sent
  111.  
  112.                    but,
  113.  
  114.                    `hello` ->will NOT be sent
  115.            """
  116.             if message.author.id == self.admin_ids:
  117.                 cont = message.content[1:]
  118.  
  119.                 await self.send_message(message.channel, '→`{} {} / {}`: {}'
  120.                                         .format(strftime('%H:%M'), message.author, self.msg_chan, cont))
  121.                 irc.send(bytearray('PRIVMSG {} :{}\r\n'.format(self.msg_chan, cont), encoding='utf-8'))
  122.  
  123.         # BANCHO INTERFACING-------------------->
  124.         if message.content.startswith('!bancho'):
  125.             """
  126.                Connects to the osu! Bancho server. Make sure that your osu credentials
  127.                are correct.
  128.            """
  129.             global t
  130.             t = threading.Thread(target=bancho, args=[self])
  131.             t.start()
  132.  
  133.         if message.content.startswith('!join'):
  134.             """
  135.                Joins a specified channel.
  136.  
  137.                Usage: !join #channel
  138.            """
  139.             cont = message.content[6:]
  140.             irc.send(bytearray('JOIN {}\r\n'.format(cont), encoding='utf-8'))
  141.             await self.send_message(message.channel, 'Joined: `{}`'.format(cont))
  142.  
  143.         if message.content.startswith('!leave'):
  144.             """
  145.                Leaves a specified channel.
  146.  
  147.                Usage: !leave #channel
  148.            """
  149.             cont = message.content[7:]
  150.             irc.send(bytearray('PART {}\r\n'.format(cont), encoding='utf-8'))
  151.             await self.send_message(message.channel, 'Left: `{}`'.format(cont))
  152.  
  153.         if message.content.startswith('!leave'):
  154.             """
  155.                Leaves a specified channel.
  156.  
  157.                Usage: !leave #channel
  158.            """
  159.             cont = message.content[7:]
  160.             irc.send(bytearray('PART {}\r\n'.format(cont), encoding='utf-8'))
  161.             await self.send_message(message.channel, 'Left: `{}`'.format(cont))
  162.  
  163.         if message.content.startswith('!setch'):
  164.             """
  165.                Sets the channel/user to where your text messages will go.
  166.  
  167.                Usage: !setch #channel
  168.            """
  169.             cont = message.content[7:]
  170.             self.msg_chan = cont
  171.             await self.send_message(message.channel, 'Channel changed to: `{}`'.format(self.msg_chan))
  172.  
  173.         if message.content.startswith('!ch'):
  174.             """
  175.                Shows the channel to where your text messages are configured to be sent. Please note
  176.                that by default it is set to #osu.
  177.  
  178.                Usage: !ch
  179.            """
  180.             await self.send_message(message.channel, 'Current channel: `{}`'.format(self.msg_chan))
  181.  
  182.         if message.content.startswith('!list'):
  183.             """
  184.                Lists all available channels.
  185.  
  186.                Usage: !list
  187.            """
  188.             b = ''
  189.             for a in self.available_chan:
  190.                 b += str(a) + ', '
  191.  
  192.             await self.send_message(message.channel, '```Available channels are: {}```'.format(b))
  193.  
  194.     async def on_ready(self):
  195.         """
  196.        This function is called once lapzirc logs in to discord and its Server list
  197.        is populated.
  198.  
  199.        :return: This function returns a status message when it is ready.
  200.        :rtype: discord.Client.change_status()
  201.        """
  202.         print('Logged in as')
  203.         print(self.user.name)
  204.         print(self.user.id)
  205.         print('------')
  206.         print('SERVERS')
  207.         for server in self.servers:
  208.             print(server)
  209.         # Game Status updating
  210.         now_playing = discord.Game(name='type !bancho to start')
  211.         await self.change_status(game=now_playing, idle=False)
  212.  
  213.  
  214. def bancho(self):
  215.     """
  216.    The main thread for handling bancho
  217.  
  218.    :param self:
  219.    :return:
  220.    """
  221.     network = 'irc.ppy.sh'
  222.     port = 6667
  223.  
  224.     global irc
  225.     # noinspection PyArgumentEqualDefault
  226.     irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  227.     irc.connect((network, port))
  228.     irc.send(bytearray('PASS {}\r\n'.format(self.bancho_pass), encoding='utf-8'))
  229.     irc.send(bytearray('NICK {}\r\n'.format(self.bancho_usr), encoding='utf-8'))
  230.     irc.send(bytearray('USER {} {} {}\r\n'.format(self.bancho_usr, self.bancho_usr, self.bancho_usr), encoding='utf-8'))
  231.     print('CONNECTED to BANCHO')
  232.  
  233.     # Joins the default channel--->
  234.     irc.send(b'JOIN #osu\r\n')
  235.  
  236.     # Populate the channel list-------------------->
  237.     irc.send(bytearray('LIST\r\n', encoding='utf-8'))
  238.  
  239.     chan = discord.Object(id=self.bancho_dump)
  240.     high_chan = discord.Object(id=stream3['highlights'])
  241.     while True:
  242.         data = irc.recv(4096)
  243.         dats = data.decode('utf-8')
  244.         # print(dats)
  245.  
  246.         if data.find(b'PING') != -1:
  247.             irc.send(b'PONG \r\n')
  248.  
  249.         if 'PRIVMSG' in dats:
  250.             """
  251.                This part handles the messages you receive from user and/or in various channels
  252.            """
  253.             a = dats.split('\n')
  254.             for b in a:
  255.                 if 'PRIVMSG' in b:
  256.                     c = b.split(':', maxsplit=2)
  257.                     msg_content = c[2]
  258.  
  259.                     info = c[1].split()
  260.                     msg_chan = info[2]
  261.                     msg_author = info[0].split('!')[0]
  262.  
  263.                     """
  264.                        If the bancho username is present in either the message content or in
  265.                        the message channel, then the user is highlighted in discord.
  266.  
  267.                        This is to make sure that you get to view the messages directed at you
  268.                    """
  269.                     if self.bancho_usr in msg_content:
  270.                         if 'ACTION' in msg_content:
  271.                             msg_content_strip = re.sub('ACTION', '', msg_content, 1)
  272.                             asyncio.run_coroutine_threadsafe(
  273.                                 self.send_message(high_chan, '<@{}>\n→`{}` {}{}'
  274.                                                   .format(self.admin_ids, strftime('%H:%M'),
  275.                                                           msg_author, msg_content_strip)),
  276.                                 loop=self.loop)
  277.                         else:
  278.                             asyncio.run_coroutine_threadsafe(
  279.                                 self.send_message(high_chan, '<@{}>\n→`{} {} / {}`: {}'
  280.                                                   .format(self.admin_ids, strftime('%H:%M'),
  281.                                                           msg_author, msg_chan, msg_content)),
  282.                                 loop=self.loop)
  283.  
  284.                     elif msg_chan == self.bancho_usr:
  285.                         if 'ACTION' in msg_content:
  286.                             msg_content_strip = re.sub('ACTION', '', msg_content, 1)
  287.                             asyncio.run_coroutine_threadsafe(
  288.                                 self.send_message(high_chan, '<@{}>\n→`{}` {}{}'
  289.                                                   .format(self.admin_ids, strftime('%H:%M'),
  290.                                                           msg_author, msg_content_strip)),
  291.                                 loop=self.loop)
  292.                         else:
  293.                             asyncio.run_coroutine_threadsafe(
  294.                                 self.send_message(high_chan, '<@{}>\n→`{} {} / {}`: {}'
  295.                                                   .format(self.admin_ids, strftime('%H:%M'),
  296.                                                           msg_author, msg_chan, msg_content)),
  297.                                 loop=self.loop)
  298.  
  299.                     else:
  300.                         msg_chan_re = msg_chan[1:]
  301.                         if stream3[msg_chan_re] == '':
  302.                             asyncio.run_coroutine_threadsafe(
  303.                                 self.send_message(chan, 'Discord channel for #{} does not exist. '
  304.                                                         'Creating a new channel...'.format(msg_chan_re)),
  305.                                 loop=self.loop)
  306.  
  307.                             serv = discord.Object(id=stream3['server_id'])
  308.  
  309.                             asyncio.run_coroutine_threadsafe(
  310.                                 self.create_channel(server=serv, name=msg_chan_re, type=discord.ChannelType.text),
  311.                                 loop=self.loop)
  312.  
  313.                             # try:
  314.                             #     stream3[msg_chan_re] = str(new_chan)
  315.                             #     with open('channel.yaml', 'w') as f1:
  316.                             #         f1.write(yaml.dump(stream3, default_flow_style=False))
  317.                             # except FileExistsError:
  318.                             #     print('config.yaml not found.')
  319.                             #     quit()
  320.  
  321.                         if 'ACTION' in msg_content:
  322.                             msg_content_strip = re.sub('ACTION', '', msg_content, 1)
  323.                             asyncio.run_coroutine_threadsafe(
  324.                                 self.send_message(chan, '→`{}` {}{}'
  325.                                                   .format(strftime('%H:%M'), msg_author, msg_content_strip)),
  326.                                 loop=self.loop)
  327.                         else:
  328.                             asyncio.run_coroutine_threadsafe(
  329.                                 self.send_message(chan, '→`{} {} / {}`: {}'
  330.                                                   .format(strftime('%H:%M'), msg_author, msg_chan, msg_content)),
  331.                                 loop=self.loop)
  332.  
  333.         try:
  334.             if 'cho.ppy.sh 322' in dats:
  335.                 """
  336.                    This part is for getting info about the currently available channels.
  337.                """
  338.                 a = dats.split('\n')
  339.                 for b in a:
  340.                     if 'cho.ppy.sh 322' in b:
  341.                         c = b.split(':')
  342.                         chan_name_tup = c[1].split()
  343.                         chan_name = chan_name_tup[3]
  344.                         self.available_chan.append(chan_name)
  345.         except IndexError:
  346.             print('List not populated.')
  347.  
  348.  
  349. bot = Bot()
  350.  
  351. try:
  352.     with open('config.yaml') as f:
  353.         stream2 = yaml.load(f)
  354.  
  355.     bot.run(stream2['DISCORD']['email'], stream2['DISCORD']['password'])
  356. except FileExistsError:
  357.     print('config.yaml not found.')
  358.     quit()
  359. except discord.LoginFailure:
  360.     print('Discord credentials are wrong. Correct them and rerun this script.')
  361.     quit()
Add Comment
Please, Sign In to add comment