breadq 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- breadq-0.1.0/PKG-INFO +35 -0
- breadq-0.1.0/README.md +16 -0
- breadq-0.1.0/breadq/__init__.py +3 -0
- breadq-0.1.0/breadq/actions.py +49 -0
- breadq-0.1.0/breadq/client.py +115 -0
- breadq-0.1.0/breadq/qbreader_client.py +77 -0
- breadq-0.1.0/breadq.egg-info/PKG-INFO +35 -0
- breadq-0.1.0/breadq.egg-info/SOURCES.txt +12 -0
- breadq-0.1.0/breadq.egg-info/dependency_links.txt +1 -0
- breadq-0.1.0/breadq.egg-info/requires.txt +1 -0
- breadq-0.1.0/breadq.egg-info/top_level.txt +1 -0
- breadq-0.1.0/pyproject.toml +3 -0
- breadq-0.1.0/setup.cfg +4 -0
- breadq-0.1.0/setup.py +21 -0
breadq-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: breadq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multiplayer client for QBReader
|
|
5
|
+
Home-page: https://github.com/packjackisback/breadq
|
|
6
|
+
Author: Jack
|
|
7
|
+
Author-email: packjackisback@gmail.com
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: websockets>=11.0
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: home-page
|
|
16
|
+
Dynamic: requires-dist
|
|
17
|
+
Dynamic: requires-python
|
|
18
|
+
Dynamic: summary
|
|
19
|
+
|
|
20
|
+
# breadq
|
|
21
|
+
|
|
22
|
+
A QBReader multiplayer library.
|
|
23
|
+
|
|
24
|
+
This is meant for making clients, bots are very easy to make and boring.
|
|
25
|
+
(Coming soon (tm) a tui qbreader client)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Please don't use this to cheat, it really just looks bad on you.
|
|
29
|
+
|
|
30
|
+
TODO:
|
|
31
|
+
|
|
32
|
+
Adding the rest of the outgoing events
|
|
33
|
+
Adding state
|
|
34
|
+
Adding ratelimiting
|
|
35
|
+
Documentation
|
breadq-0.1.0/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# breadq
|
|
2
|
+
|
|
3
|
+
A QBReader multiplayer library.
|
|
4
|
+
|
|
5
|
+
This is meant for making clients, bots are very easy to make and boring.
|
|
6
|
+
(Coming soon (tm) a tui qbreader client)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Please don't use this to cheat, it really just looks bad on you.
|
|
10
|
+
|
|
11
|
+
TODO:
|
|
12
|
+
|
|
13
|
+
Adding the rest of the outgoing events
|
|
14
|
+
Adding state
|
|
15
|
+
Adding ratelimiting
|
|
16
|
+
Documentation
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
def register(client):
|
|
4
|
+
|
|
5
|
+
async def pause(paused_time=0):
|
|
6
|
+
await client.emit("pause", pausedTime=paused_time)
|
|
7
|
+
|
|
8
|
+
async def buzz():
|
|
9
|
+
await client.emit("buzz")
|
|
10
|
+
await give_answer_live_update()
|
|
11
|
+
|
|
12
|
+
async def ban(userId, username):
|
|
13
|
+
await client.emit("ban", targetId=userId, targetUsername=username)
|
|
14
|
+
|
|
15
|
+
async def chat_live_update(message=""):
|
|
16
|
+
await client.emit("chat-live-update", message=message)
|
|
17
|
+
|
|
18
|
+
async def chat(message=""):
|
|
19
|
+
await chat-live-update("")
|
|
20
|
+
await client.emit("chat", message=message)
|
|
21
|
+
|
|
22
|
+
async def clear_stats():
|
|
23
|
+
await client.emit("clear-stats")
|
|
24
|
+
|
|
25
|
+
async def give_answer_live_update(message=""):
|
|
26
|
+
await client.emit("give-answer-live-update", givenAnswer=message)
|
|
27
|
+
|
|
28
|
+
async def give_answer(message=""):
|
|
29
|
+
await give_answer_live_update()
|
|
30
|
+
await client.emit("give-answer", givenAnswer=message)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
client.pause = pause
|
|
35
|
+
client.buzz = buzz
|
|
36
|
+
client.ban = ban
|
|
37
|
+
client.chat_live_update = chat_live_update
|
|
38
|
+
client.chat = chat
|
|
39
|
+
client.clear_stats = clear_stats
|
|
40
|
+
client.give_answer_live_update = give_answer_live_update
|
|
41
|
+
client.give_answer = give_answer
|
|
42
|
+
|
|
43
|
+
async def do(action_name, **kwargs):
|
|
44
|
+
action = getattr(client, action_name, None)
|
|
45
|
+
if not action:
|
|
46
|
+
raise ValueError(f"Unknown action: {action_name}")
|
|
47
|
+
await action(**kwargs)
|
|
48
|
+
|
|
49
|
+
client.do = do
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import uuid
|
|
4
|
+
import websockets
|
|
5
|
+
|
|
6
|
+
from . import actions
|
|
7
|
+
|
|
8
|
+
# gotta enable that logging
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
class QBReaderClient:
|
|
12
|
+
def __init__(self, room, username, user_id=None, debug_mode=False):
|
|
13
|
+
if debug_mode:
|
|
14
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
15
|
+
logging.getLogger("websockets").setLevel(logging.DEBUG)
|
|
16
|
+
print("Debug Mode ON")
|
|
17
|
+
print("Loading ", username)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
self.room = room
|
|
22
|
+
self.username = username
|
|
23
|
+
self.user_id = user_id or str(uuid.uuid4())
|
|
24
|
+
|
|
25
|
+
self.ws = None
|
|
26
|
+
self.handlers = {}
|
|
27
|
+
self.send_queue = asyncio.Queue()
|
|
28
|
+
self.running = False
|
|
29
|
+
self.debug_mode = debug_mode
|
|
30
|
+
|
|
31
|
+
actions.register(self)
|
|
32
|
+
if debug_mode:
|
|
33
|
+
print(username, " Loaded: ", hasattr(self, "buzz"))
|
|
34
|
+
|
|
35
|
+
def on(self, message_type, handler):
|
|
36
|
+
self.handlers[message_type] = handler
|
|
37
|
+
|
|
38
|
+
async def emit(self, event_type: str, **data):
|
|
39
|
+
payload = {"type": event_type, **data}
|
|
40
|
+
await self.send(payload)
|
|
41
|
+
|
|
42
|
+
async def send(self, payload: dict):
|
|
43
|
+
if self.debug_mode:
|
|
44
|
+
print(f"[{self.user_id}] SEND -> {payload}")
|
|
45
|
+
await self.send_queue.put(payload)
|
|
46
|
+
|
|
47
|
+
async def start(self):
|
|
48
|
+
url = (
|
|
49
|
+
f"wss://www.qbreader.org/play/mp/test"
|
|
50
|
+
f"?roomName={self.room}"
|
|
51
|
+
f"&userId={self.user_id}"
|
|
52
|
+
f"&username={self.username}"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
async with websockets.connect(
|
|
58
|
+
url,
|
|
59
|
+
origin="https://www.qbreader.org",
|
|
60
|
+
ping_interval=None
|
|
61
|
+
) as ws:
|
|
62
|
+
self.ws = ws
|
|
63
|
+
self.running = True
|
|
64
|
+
|
|
65
|
+
await asyncio.gather(
|
|
66
|
+
self._receiver_loop(),
|
|
67
|
+
self._sender_loop(),
|
|
68
|
+
self._heartbeat_loop(),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
except websockets.exceptions.ConnectionClosed as e:
|
|
72
|
+
print(
|
|
73
|
+
f"[{self.user_id}] CLOSED "
|
|
74
|
+
f"code={e.code} reason={e.reason}"
|
|
75
|
+
)
|
|
76
|
+
raise
|
|
77
|
+
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"[{self.user_id}] START ERROR -> {e}")
|
|
80
|
+
raise
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def _receiver_loop(self):
|
|
85
|
+
try:
|
|
86
|
+
async for message in self.ws:
|
|
87
|
+
if self.debug_mode:
|
|
88
|
+
print(f"[{self.user_id}] RECV RAW -> {message}")
|
|
89
|
+
|
|
90
|
+
try:
|
|
91
|
+
data = json.loads(message)
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(f"[{self.user_id}] JSON ERROR -> {e}")
|
|
94
|
+
continue
|
|
95
|
+
|
|
96
|
+
msg_type = data.get("type")
|
|
97
|
+
handler = self.handlers.get(msg_type)
|
|
98
|
+
|
|
99
|
+
if handler:
|
|
100
|
+
await handler(data)
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print(f"[{self.user_id}] RECEIVER ERROR -> {e}")
|
|
104
|
+
raise
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
async def _sender_loop(self):
|
|
108
|
+
while self.running:
|
|
109
|
+
payload = await self.send_queue.get()
|
|
110
|
+
await self.ws.send(json.dumps(payload))
|
|
111
|
+
|
|
112
|
+
async def _heartbeat_loop(self):
|
|
113
|
+
while self.running:
|
|
114
|
+
await asyncio.sleep(20)
|
|
115
|
+
await self.emit("ping")
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
import uuid
|
|
4
|
+
import websockets
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class QBReaderClient:
|
|
8
|
+
def __init__(self, room, username, user_id=None):
|
|
9
|
+
self.room = room
|
|
10
|
+
self.username = username
|
|
11
|
+
self.user_id = user_id or str(uuid.uuid4())
|
|
12
|
+
|
|
13
|
+
self.ws = None
|
|
14
|
+
self.handlers = {}
|
|
15
|
+
self.send_queue = asyncio.Queue()
|
|
16
|
+
self.running = False
|
|
17
|
+
|
|
18
|
+
def on(self, message_type, handler):
|
|
19
|
+
"""
|
|
20
|
+
Register a handler for a message type.
|
|
21
|
+
"""
|
|
22
|
+
self.handlers[message_type] = handler
|
|
23
|
+
|
|
24
|
+
async def send(self, payload: dict):
|
|
25
|
+
"""
|
|
26
|
+
Queue a message to be sent.
|
|
27
|
+
"""
|
|
28
|
+
await self.send_queue.put(payload)
|
|
29
|
+
|
|
30
|
+
async def pause(self):
|
|
31
|
+
await self.send({"type": "pause", "pausedTime": 0})
|
|
32
|
+
|
|
33
|
+
async def start(self):
|
|
34
|
+
url = (
|
|
35
|
+
f"wss://www.qbreader.org/play/mp/test"
|
|
36
|
+
f"?roomName={self.room}"
|
|
37
|
+
f"&userId={self.user_id}"
|
|
38
|
+
f"&username={self.username}"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
async with websockets.connect(
|
|
42
|
+
url,
|
|
43
|
+
origin="https://www.qbreader.org",
|
|
44
|
+
ping_interval=None
|
|
45
|
+
) as ws:
|
|
46
|
+
|
|
47
|
+
self.ws = ws
|
|
48
|
+
self.running = True
|
|
49
|
+
|
|
50
|
+
await asyncio.gather(
|
|
51
|
+
self._receiver_loop(),
|
|
52
|
+
self._sender_loop(),
|
|
53
|
+
self._heartbeat_loop(),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
async def _receiver_loop(self):
|
|
57
|
+
async for message in self.ws:
|
|
58
|
+
try:
|
|
59
|
+
data = json.loads(message)
|
|
60
|
+
except Exception:
|
|
61
|
+
continue
|
|
62
|
+
|
|
63
|
+
msg_type = data.get("type")
|
|
64
|
+
handler = self.handlers.get(msg_type)
|
|
65
|
+
|
|
66
|
+
if handler:
|
|
67
|
+
await handler(data)
|
|
68
|
+
|
|
69
|
+
async def _sender_loop(self):
|
|
70
|
+
while self.running:
|
|
71
|
+
payload = await self.send_queue.get()
|
|
72
|
+
await self.ws.send(json.dumps(payload))
|
|
73
|
+
|
|
74
|
+
async def _heartbeat_loop(self):
|
|
75
|
+
while self.running:
|
|
76
|
+
await asyncio.sleep(1)
|
|
77
|
+
await self.send({"type": "ping"})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: breadq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Multiplayer client for QBReader
|
|
5
|
+
Home-page: https://github.com/packjackisback/breadq
|
|
6
|
+
Author: Jack
|
|
7
|
+
Author-email: packjackisback@gmail.com
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: websockets>=11.0
|
|
11
|
+
Dynamic: author
|
|
12
|
+
Dynamic: author-email
|
|
13
|
+
Dynamic: description
|
|
14
|
+
Dynamic: description-content-type
|
|
15
|
+
Dynamic: home-page
|
|
16
|
+
Dynamic: requires-dist
|
|
17
|
+
Dynamic: requires-python
|
|
18
|
+
Dynamic: summary
|
|
19
|
+
|
|
20
|
+
# breadq
|
|
21
|
+
|
|
22
|
+
A QBReader multiplayer library.
|
|
23
|
+
|
|
24
|
+
This is meant for making clients, bots are very easy to make and boring.
|
|
25
|
+
(Coming soon (tm) a tui qbreader client)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Please don't use this to cheat, it really just looks bad on you.
|
|
29
|
+
|
|
30
|
+
TODO:
|
|
31
|
+
|
|
32
|
+
Adding the rest of the outgoing events
|
|
33
|
+
Adding state
|
|
34
|
+
Adding ratelimiting
|
|
35
|
+
Documentation
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.py
|
|
4
|
+
breadq/__init__.py
|
|
5
|
+
breadq/actions.py
|
|
6
|
+
breadq/client.py
|
|
7
|
+
breadq/qbreader_client.py
|
|
8
|
+
breadq.egg-info/PKG-INFO
|
|
9
|
+
breadq.egg-info/SOURCES.txt
|
|
10
|
+
breadq.egg-info/dependency_links.txt
|
|
11
|
+
breadq.egg-info/requires.txt
|
|
12
|
+
breadq.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
websockets>=11.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
breadq
|
breadq-0.1.0/setup.cfg
ADDED
breadq-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="breadq",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
author="Jack",
|
|
10
|
+
author_email="packjackisback@gmail.com",
|
|
11
|
+
description="Multiplayer client for QBReader",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/packjackisback/breadq",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
install_requires=[
|
|
17
|
+
"websockets>=11.0",
|
|
18
|
+
],
|
|
19
|
+
python_requires=">=3.9",
|
|
20
|
+
)
|
|
21
|
+
|