Python client for the party game JKLM.fun
Project description
jklm-py-client
Flexible JKLM.fun client built for Python 3
✨ Features
- Versatile implementation allowing you to build anything
- Integrated JKLM client functions (chat, join, etc)
- Proxy support allows safe and anonymous connection
- Simple to use api
Installation
Install via pip
pip install -U jklm
Documentation
- Make A Room
- Simple Usage
- Proxy Usage
- Set A Profile Picture
- Connections (Twitch, Discord)
- Chat Client
- PopSauce
- Bomb Party
- Someone make a PR
PopSauce Answers
[!NOTE]
As of 18/02/25 only 9775/9806 (~99.7%) of PopSauce are indexed due to the nature of scraping themx log(x)
popsauce.zip
heavy zipped folder of *all the questions, answers and data (image, etc)
popsauce_pairs.txt
light weight txt file of all the
challenge_hash:answerpairings
extract_pairs.py
simple script to extract pairs from the unzipped popsauce folder to popsauce_pairs.txt
Make A Room
Here is an example of how to create a room
from jklm import JKLM
jklm = JKLM("BOT")
res = jklm.start_room("selector", True, "test")
print(res) # {'url': 'https://falcon.jklm.fun', 'room_code': 'RNGG'}
Simple Usage
Here is a simple example of how to connect to a room and join a round (gamemode agnostic)
from jklm import JKLM
def main(room_id):
username = "EXAMPLE_BOT"
# Initialize JKLM session
session = JKLM(username)
try:
# Attempt to connect to specified room
session.connect(room_id)
print("[.] Successfully joined", room_id)
except Exception as e:
# Handle connection failures gracefully
print("[X] Failed to join room:", e)
return
# Join active game round after successful connection
session.join_round()
if __name__ == '__main__':
# Launch bot and join room "ABUM"
main("ABUM")
Proxy Usage
Here is an example of how to connect to a room using a proxy
from jklm import JKLM
def main(room_id):
username = "EXAMPLE_BOT"
proxy = {
"host": "...",
"port": 8080,
"type": "http", # http, https, socks4, socks5
"auth": ("username", "password")
}
# Initialize JKLM session
session = JKLM(username, proxy=proxy)
try:
# Attempt to connect to specified room
session.connect(room_id)
print("[.] Successfully joined", room_id)
except Exception as e:
# Handle connection failures gracefully
print("[X] Failed to join room:", e)
return
# Join active game round after successful connection
session.join_round()
if __name__ == '__main__':
# Launch bot and join room "ABUM"
main("ABUM")
Set A Profile Picture
Here is an example of how to set a profile picture
from jklm import JKLM
import time
import psutil
import os
def main(room_id):
image = open("logo.png", "rb").read() # Try to keep image 128x128
username = "BOT_" + str(time.time())[-5:]
session = JKLM(username, pfp=image)
try:
session.connect(room_id)
print("[.] Successfully joined", room_id)
except Exception as e:
print("[X] Failed to join room:", e)
return
input("")
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
if __name__ == '__main__':
main("KMPW")
Connections (Twitch, Discord)
Here is an example of how to connect to a room using a twitch or discord account
from jklm import JKLM
import time
import psutil
import os
def main(room_id):
image = open("logo.png", "rb").read() # Try to keep image 128x128
username = "BOT_" + str(time.time())[-5:]
session = JKLM(username, pfp=image, connection={
"service": "twitch", # twitch, discord
"username": "jklm_bot", # Isn't validated
"token": "YOUR_TOKEN", # Validated
"expiration": 0 # Isn't validated
})
try:
session.connect(room_id)
print("[.] Successfully joined", room_id)
except Exception as e:
print("[X] Failed to join room:", e)
return
input("")
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
if __name__ == '__main__':
main("KMPW")
Chat Client
Here is an example of how to connect to a room and chat back and forth with other users
from jklm import JKLM
import time
import psutil
import os
def main(room_id):
username = "BOT_" + str(time.time())[-5:]
session = JKLM(username)
def chat_handler(code, raw_data):
event = raw_data[0]
data = raw_data[1]
# 0 CODE = Kicked from room (event = TYPE ["KICKED" | "BAN"], data = INFO)
if (code == 0):
print("[X] Kicked from room:", data)
return
match event:
case "chat":
message = raw_data[2]
print(f"[CHAT] {data['nickname']}: {message}")
pass
case "chatterAdded":
print(f"[+] {data} joined the room")
case "chatterRemoved":
print(f"[-] {data} left the room")
case "setPlayerCount":
print(f"[!] {data} players in the room")
case _:
print(f"[UNHANDLED CHAT EVENT] {event}:", data)
try:
session.connect(room_id, chat_handler=chat_handler)
print("[.] Successfully joined", room_id)
except Exception as e:
print("[X] Failed to join room:", e)
return
try:
while True:
message = input("")
if message == "":
raise KeyboardInterrupt
session.send_chat_message(message)
time.sleep(1)
if session.reconnect_attempts > 5:
print("Reconnect attempts exceeded")
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
break
except KeyboardInterrupt:
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
if __name__ == '__main__':
main("ABUM")
Pop Sauce
Challenge Hasher
Here is an example of how to hash a challenge
from jklm import JKLM
import time
import hashlib
import psutil
import os
expecting_image = False
challenge = {
"end_time": 0,
"image": None,
"prompt": None,
"text": None,
"hash": None
}
def sha1(input):
if isinstance(input, str):
input = input.encode()
return hashlib.sha1(input).hexdigest()
def main(room_id):
global expecting_image, challenge
username = "BOT_" + str(time.time())[-5:]
session = JKLM(username)
def game_handler(code, raw_data):
global expecting_image, challenge
event = raw_data[0]
data = raw_data[1]
# -1 CODE = Image data
# 0 CODE = Kicked from room (event = TYPE ["KICKED" | "BAN"], data = INFO)
if (code == 0):
print("[X] Kicked from room:", data)
return
if (code == -1):
asset_type = challenge["image"]["type"]
extension = ""
match asset_type:
case "image/svg+xml":
extension = "svg"
case "image/png":
extension = "png"
case "image/jpeg":
extension = "jpeg"
challenge["hash"] = sha1(challenge["prompt"].encode() + raw_data)
challenge["image"]["extension"] = extension
print("[?] Challenge Hash:", challenge["hash"])
print("[?] Image has been saved to image." + extension)
with open("image." + extension, "wb") as f:
f.write(raw_data)
return
match event:
case "startChallenge":
print("\n[!] New Challenge Started")
challenge["end_time"] = data["endTime"]
challenge["image"] = data["image"]
challenge["prompt"] = data["prompt"]
challenge["text"] = data["text"]
if challenge["image"]:
expecting_image = True
print("[?] Image Challenge", challenge["prompt"])
else:
expecting_image = False
challenge["hash"] = sha1(challenge["prompt"] + challenge["text"])
print("[?] Text Challenge:", challenge["prompt"])
print("[?] Challenge Hash:", challenge["hash"])
print("[?]", challenge["text"])
case "endChallenge":
print("\n[!] Challenge Ended")
print("[X] Correct Answer:", data["source"])
case "setPlayerState":
event, peer_id, data = raw_data
guess = data["guess"]
found_answer = data["hasFoundSource"]
points = data["points"]
elapsed_time = data["elapsedTime"]
player = list(filter(lambda x: x["profile"]["peerId"] == peer_id, session.game["players"]))[0]
if found_answer:
print(f"[!] {player['profile']['nickname']} with {points} points guessed it in {elapsed_time} seconds")
else:
print(f"[!] {player['profile']['nickname']} with {points} points guessed {guess}")
case "updatePlayer":
event, peer_id, data, online = raw_data
player = list(filter(lambda x: x["profile"]["peerId"] == peer_id, session.game["players"]))[0]
if online:
print(f"[+] {player['profile']['nickname']} reconnected to the game")
else:
print(f"[-] {player['profile']['nickname']} disconnected from the game")
case "addPlayer":
print(f"[+] {data['profile']['nickname']} joined the game")
case _:
print(f"[UNHANDLED GAME EVENT] {event}:", raw_data)
try:
session.connect(room_id, game_handler=game_handler)
print("[.] Successfully joined", room_id)
except Exception as e:
print("[X] Failed to join room:", e)
return
session.join_round()
# Checks if a challenge is already started
if ("challenge" in session.game["milestone"]):
print("\n[!] Challenge already started")
current_challenge = session.game["milestone"]["challenge"]
# If the challenge has ended but the next one hasn't started yet endTime will be null
challenge["end_time"] = current_challenge["endTime"] if "endTime" in current_challenge else 0
challenge["image"] = current_challenge["image"]
challenge["prompt"] = current_challenge["prompt"]
challenge["text"] = current_challenge["text"]
if challenge["image"]:
expecting_image = True
print("[?] Image Challenge", challenge["prompt"])
else:
expecting_image = False
challenge["hash"] = sha1(challenge["prompt"] + challenge["text"])
print("[?] Text Challenge:", challenge["prompt"])
print("[?]", challenge["text"])
print("[?] Challenge Hash:", challenge["hash"])
input("")
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
if __name__ == '__main__':
main("ABUM")
Auto-Answer
Here is an example of how to auto-answer and send the answer to the chat
from jklm import JKLM
import requests
import time
import hashlib
import psutil
import os
expecting_image = False
challenge = {
"end_time": 0,
"image": None,
"prompt": None,
"text": None,
"hash": None
}
res = requests.get("https://cdn.jsdelivr.net/gh/joseph-gerald/jklm-py-client@main/answers/popsauce_pairs.txt")
answers = {x.split(":", 1)[0]: x.split(":", 1)[1].strip() for x in res.text.split("\n") if x}
def sha1(input):
if isinstance(input, str):
input = input.encode()
return hashlib.sha1(input).hexdigest()
def main(room_id):
global expecting_image, challenge
username = "BOT_" + str(time.time())[-5:]
session = JKLM(username)
def game_handler(code, raw_data):
global expecting_image, challenge
event = raw_data[0]
data = raw_data[1]
# -1 CODE = Image data
# 0 CODE = Kicked from room (event = TYPE ["KICKED" | "BAN"], data = INFO)
if (code == 0):
print("[X] Kicked from room:", data)
return
if (code == -1):
asset_type = challenge["image"]["type"]
extension = ""
match asset_type:
case "image/svg+xml":
extension = "svg"
case "image/png":
extension = "png"
case "image/jpeg":
extension = "jpeg"
challenge["hash"] = sha1(challenge["prompt"].encode() + raw_data)
challenge["image"]["extension"] = extension
print("[?] Challenge Hash:", challenge["hash"])
answer = answers.get(challenge["hash"])
if answer:
print("[!] Answer is indexed:", answer)
session.submit_guess(answer)
session.send_chat_message(answer)
else:
print("[!] Answer was not indexed")
return
match event:
case "startChallenge":
print("\n[!] New Challenge Started")
challenge["end_time"] = data["endTime"]
challenge["image"] = data["image"]
challenge["prompt"] = data["prompt"]
challenge["text"] = data["text"]
if challenge["image"]:
expecting_image = True
print("[?] Image Challenge", challenge["prompt"])
else:
expecting_image = False
challenge["hash"] = sha1(challenge["prompt"] + challenge["text"])
print("[?] Text Challenge:", challenge["prompt"])
print("[?] Challenge Hash:", challenge["hash"])
print("[?]", challenge["text"])
answer = answers.get(challenge["hash"])
if answer:
print("[!] Answer is indexed:", answer)
session.submit_guess(answer)
session.send_chat_message(answer)
else:
print("[!] Answer was not indexed")
case "endChallenge":
print("\n[!] Challenge Ended")
print("[X] Correct Answer:", data["source"])
case "setPlayerState":
event, peer_id, data = raw_data
guess = data["guess"]
found_answer = data["hasFoundSource"]
points = data["points"]
elapsed_time = data["elapsedTime"]
print(f"[!] {peer_id} {data}")
if peer_id == session.peer_id:
return
player = list(filter(lambda x: x["profile"]["peerId"] == peer_id, session.game["players"]))[0]
if found_answer:
print(f"[!] {player['profile']['nickname']} with {points} points guessed it in {elapsed_time} seconds")
else:
print(f"[!] {player['profile']['nickname']} with {points} points guessed {guess}")
case "updatePlayer":
event, peer_id, data, online = raw_data
player = list(filter(lambda x: x["profile"]["peerId"] == peer_id, session.game["players"]))[0]
if online:
print(f"[+] {player['profile']['nickname']} reconnected to the game")
else:
print(f"[-] {player['profile']['nickname']} disconnected from the game")
case "addPlayer":
print(f"[+] {data['profile']['nickname']} joined the game")
case _:
print(f"[UNHANDLED GAME EVENT] {event}:", raw_data)
try:
session.connect(room_id, game_handler=game_handler)
print("[.] Successfully joined", room_id)
except Exception as e:
print("[X] Failed to join room:", e)
return
session.join_round()
# Checks if a challenge is already started
if ("challenge" in session.game["milestone"]):
print("\n[!] Challenge already started")
current_challenge = session.game["milestone"]["challenge"]
# If the challenge has ended but the next one hasn't started yet endTime will be null
challenge["end_time"] = current_challenge["endTime"] if "endTime" in current_challenge else 0
challenge["image"] = current_challenge["image"]
challenge["prompt"] = current_challenge["prompt"]
challenge["text"] = current_challenge["text"]
if challenge["image"]:
expecting_image = True
print("[?] Image Challenge", challenge["prompt"])
else:
expecting_image = False
challenge["hash"] = sha1(challenge["prompt"] + challenge["text"])
print("[?] Text Challenge:", challenge["prompt"])
print("[?]", challenge["text"])
print("[?] Challenge Hash:", challenge["hash"])
input("")
current_system_pid = os.getpid()
ThisSystem = psutil.Process(current_system_pid)
ThisSystem.terminate()
if __name__ == '__main__':
main("ABUM")
Bomb Party
soon™️
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jklm-1.0.3.tar.gz.
File metadata
- Download URL: jklm-1.0.3.tar.gz
- Upload date:
- Size: 49.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.9.21
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b2165af7918d57b087e096f1a71be35fb80a51a68466642b0971135357b1e3c
|
|
| MD5 |
a6d2377091baeb00eb145cb7537c13e7
|
|
| BLAKE2b-256 |
884a3ab35b8bed545bcfacae70daaa83094ce6191a52d2b7bb454f4f4272e1a5
|
File details
Details for the file jklm-1.0.3-py3-none-any.whl.
File metadata
- Download URL: jklm-1.0.3-py3-none-any.whl
- Upload date:
- Size: 34.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.9.21
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58ab4a6d8c4bc479b1f408ec0156e9b060cba88c208cf987b563ae72b55f6553
|
|
| MD5 |
292adfdbeebc7acbaf31961f05bd1647
|
|
| BLAKE2b-256 |
a7955cad967584ee8ae09eb3e561a8e20b79b076e3181be033c654712b43d340
|