Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from websocket import create_connection, WebSocket
- import requests
- import json
- import threading
- import time
- import socket
- # manage our connection to the discord gateway
- class Gateway:
- def __init__(self, token):
- self.api_token = token
- self.alive = True
- def run(self):
- # get discord gateway socketurl
- r = json.loads(requests.get("https://discordapp.com/api/gateway?v=6").text)
- gateway_ws_url = r["url"] + "?v=6&encoding=json" # voice ws url
- print(gateway_ws_url)
- # connect to gateway socket
- self.gws = create_connection(gateway_ws_url)
- # identify with the gateway
- self.gws.send(json.dumps({
- "op": 2,
- "d": {
- "token": self.api_token,
- "properties": {
- "$os": "linux",
- "$browser": "disco",
- "$device": "disco"
- },
- "compress": False,
- "large_threshold": 250,
- "presence": {
- "afk": False
- }
- }
- }))
- # now read from the socket and respond accordingly
- while True:
- # consume ready
- self.consume()
- def heartbeat(self):
- i = 0
- while i < self.interval / 1000 and self.alive:
- i += 1
- time.sleep(1)
- # send heartbeat
- self.gws.send(json.dumps({
- "op": 1,
- "d": self.s
- }))
- # recvs one value from the gateway socket, and processes it accordingly
- def consume(self):
- # get recv data and opcode
- opcode, raw_recv = self.gws.recv_data()
- print(opcode, raw_recv)
- # if we recv a blank string, that means the server disconnected us
- if not raw_recv or raw_recv.strip() == "" or opcode > 1:
- exit("disconnected")
- # parse recv data
- recv = json.loads(raw_recv)
- # identify the sent operation and handle it
- if recv["op"] == 10: # HELLO
- # start a new thread handling heartbeat pulses (ping)
- self.interval = recv["d"]["heartbeat_interval"]
- self.s = recv["s"]
- self.heartbeat_thread = threading.Thread(
- target=self.heartbeat, args=()
- )
- self.heartbeat_thread.start()
- elif recv["op"] == 11: # Heartbeat ACK
- # start the next hearbeat thread
- self.heartbeat_thread = threading.Thread(
- target=self.heartbeat, args=()
- )
- self.heartbeat_thread.start()
- elif recv["op"] == 0: # DISPATCH
- if recv["t"] == "READY": # READY
- # possibly store information
- self.on_ready(self, recv)
- elif recv["t"] == "GUILD_CREATE": # GUILD_CREATE
- # possibly store information
- pass
- elif recv["t"] == "VOICE_STATE_UPDATE": # VOICE_STATE_UPDATE
- self.session_id = recv["d"]["session_id"]
- self.user_id = recv["d"]["user_id"]
- elif recv["t"] == "VOICE_SERVER_UPDATE": # VOICE_SERVER_UPDATE
- self.on_voice_server_update(self, recv)
- # manage our connection to the voice server
- class VoiceChat:
- def __init__(self, token, guild_id, channel_id):
- self.guild_id = guild_id
- self.channel_id = channel_id
- gateway = Gateway(token)
- gateway.on_ready = self.on_ready
- gateway.on_voice_server_update = self.on_voice_server_update
- #gateway.run(); return None
- try:
- gateway.run()
- except Exception as e:
- print(e)
- gateway.alive = False
- def on_ready(self, gateway, recv):
- # inform the gateway of our intent to establish voice connectivity...
- gateway.gws.send(json.dumps({
- "op": 4,
- "d": {
- "guild_id": self.guild_id,
- "channel_id": self.channel_id,
- "self_mute": False,
- "self_deaf": False
- }
- }))
- def on_voice_server_update(self, gateway, recv):
- # Now we can make the actual voice websocket connection.
- self.endpoint = recv["d"]["endpoint"]
- # remove the port
- self.endpoint = endpoint[:endpoint.find(":")]
- self.vws = create_connection(
- "wss://" + self.endpoint + "?v=3"
- )
- self.alive = True
- # identify with the voice server
- self.vws.send(json.dumps({
- "op": 0,
- "d": {
- "server_id": self.guild_id, #namecontinuity
- "user_id": gateway.user_id,
- "session_id": gateway.session_id, # just going to assume this is here
- "token": recv["d"]["token"]
- }
- }))
- # start handling the voice socket in a background thread
- self.consume_thread = threading.Thread(
- target=self.consume_forever, args=()
- )
- self.consume_thread.start()
- def consume_forever(self):
- while True:
- self.consume()
- # handles one packet from the voice chat websocket
- def consume(self):
- # get recv data and opcode
- opcode, raw_recv = self.vws.recv_data()
- print(opcode, raw_recv)
- # if we recv a blank string, that means the server disconnected us
- if not raw_recv or raw_recv.strip() == "" or opcode > 1:
- exit("disconnected")
- # parse recv data
- recv = json.loads(raw_recv)
- if "op" not in recv and "heartbeat_interval" in recv: # HELLO
- # start a new thread handling heartbeat pulses (ping)
- self.interval = recv["heartbeat_interval"] * 0.75
- self.heartbeat_thread = threading.Thread(
- target=self.heartbeat, args=()
- )
- self.heartbeat_thread.start()
- elif recv["op"] == 2: # READY
- self.on_ready(recv)
- def heartbeat(self):
- i = 0
- while i < self.interval / 1000 and self.alive:
- i += 1
- time.sleep(1)
- # send heartbeat
- self.gws.send(json.dumps({
- "op": 3,
- "d": i * 314195 # because I don't really understand nonces
- }))
- def on_ready(self, recv):
- # create a udp socket to the server
- socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # send an IP Lookup packet
- packet = bytearray(70)
- struct.pack_into(">I", packet, 0, recv["d"]["ssrc"])
- socket.sendto(packet, (self.endpoint, recv["d"]["ssrc"]))
- recv = socket.recv(70)
- # get the port and host from the udp socket
- # send host and port to websocket in exchange for private key
- if __name__ == "__main__":
- v = VoiceChat(
- "authtoken",
- "guildid",
- "channelid"
- )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement