{"id":37063869,"url":"https://github.com/joseph-gerald/jklm-py-client","last_synced_at":"2026-01-14T07:19:19.793Z","repository":{"id":223867735,"uuid":"761658398","full_name":"joseph-gerald/jklm-py-client","owner":"joseph-gerald","description":"JKLM.fun client built for Python 3","archived":false,"fork":false,"pushed_at":"2025-02-21T20:01:56.000Z","size":363,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-27T02:59:10.602Z","etag":null,"topics":["3rd-party-api","automation","jklm","jklm-client","python","websockets"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/jklm/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joseph-gerald.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-22T08:44:09.000Z","updated_at":"2025-12-17T12:26:12.000Z","dependencies_parsed_at":"2024-02-22T14:04:25.756Z","dependency_job_id":"12968161-22a1-4425-a8ad-eb427d0ece54","html_url":"https://github.com/joseph-gerald/jklm-py-client","commit_stats":null,"previous_names":["joseph-gerald/jklm-py-client"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/joseph-gerald/jklm-py-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseph-gerald%2Fjklm-py-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseph-gerald%2Fjklm-py-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseph-gerald%2Fjklm-py-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseph-gerald%2Fjklm-py-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joseph-gerald","download_url":"https://codeload.github.com/joseph-gerald/jklm-py-client/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joseph-gerald%2Fjklm-py-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28412847,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T05:26:33.345Z","status":"ssl_error","status_checked_at":"2026-01-14T05:21:57.251Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3rd-party-api","automation","jklm","jklm-client","python","websockets"],"created_at":"2026-01-14T07:19:19.183Z","updated_at":"2026-01-14T07:19:19.786Z","avatar_url":"https://github.com/joseph-gerald.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"![image](https://github.com/user-attachments/assets/321a2c60-9a57-4b7a-b89b-166795fa7711)\n\n# jklm-py-client\nFlexible JKLM.fun client built for Python 3\n\n## ✨ Features\n- Versatile implementation allowing you to build anything\n- Integrated JKLM client functions (chat, join, etc)\n- Proxy support allows safe and anonymous connection\n- Simple to use api\n\n# Installation\nInstall via pip\n```sh\npip install -U jklm\n```\n# Documentation\n1. [Make A Room](#make-a-room)\n2. [Simple Usage](#simple-usage)\n3. [Proxy Usage](#proxy-usage)\n4. [Set A Profile Picture](#set-a-profile-picture)\n5. [Connections (Twitch, Discord)](#connections-twitch-discord)\n6. [Chat Client](#chat-client)\n7. [PopSauce](#pop-sauce)\n    - [Challenge Hasher](#challenge-hasher)\n    - [Auto-Answer](#auto-answer)\n8. [Bomb Party](#bomb-party)\n    - Someone make a PR\n\n## PopSauce Answers\n\u003e [!NOTE]  \n\u003e As of **18/02/25** only **9775/9806** *(~99.7%)* of **PopSauce** are indexed due to the nature of scraping them `x log(x)` \n\n### [popsauce.zip](answers/popsauce.zip)\n\u003e heavy zipped folder of *all the questions, answers and data (image, etc)\n\n### [popsauce_pairs.txt](answers/popsauce_pairs.txt)\n\u003e light weight txt file of all the `challenge_hash:answer` pairings\n\n### [extract_pairs.py](answers/extract_pairs.py)\n\u003e simple script to extract pairs from the unzipped popsauce folder to popsauce_pairs.txt\n\n## Make A Room\nHere is an example of how to create a room\n```python\nfrom jklm import JKLM\n\njklm = JKLM(\"BOT\")\n\nres = jklm.start_room(\"selector\", True, \"test\")\nprint(res) # {'url': 'https://falcon.jklm.fun', 'room_code': 'RNGG'}\n```\n\n## Simple Usage\nHere is a simple example of how to connect to a room and join a round *(gamemode agnostic)*\n```python\nfrom jklm import JKLM\n\ndef main(room_id):\n    username = \"EXAMPLE_BOT\"\n\n    # Initialize JKLM session\n    session = JKLM(username)\n\n    try:\n        # Attempt to connect to specified room\n        session.connect(room_id)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        # Handle connection failures gracefully\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    # Join active game round after successful connection\n    session.join_round()\n\nif __name__ == '__main__':\n    # Launch bot and join room \"ABUM\"\n    main(\"ABUM\")\n```\n\n## Proxy Usage\nHere is an example of how to connect to a room using a proxy\n```python\nfrom jklm import JKLM\n\ndef main(room_id):\n    username = \"EXAMPLE_BOT\"\n\n    proxy = {\n        \"host\": \"...\",\n        \"port\": 8080,\n        \"type\": \"http\", # http, https, socks4, socks5\n        \"auth\": (\"username\", \"password\")\n    }\n\n    # Initialize JKLM session\n    session = JKLM(username, proxy=proxy)\n\n    try:\n        # Attempt to connect to specified room\n        session.connect(room_id)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        # Handle connection failures gracefully\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    # Join active game round after successful connection\n    session.join_round()\n\nif __name__ == '__main__':\n    # Launch bot and join room \"ABUM\"\n    main(\"ABUM\")\n```\n\n## Set A Profile Picture\nHere is an example of how to set a profile picture\n```python\nfrom jklm import JKLM\nimport time\n\nimport psutil\nimport os\n\n\ndef main(room_id):\n    image = open(\"logo.png\", \"rb\").read() # Try to keep image 128x128\n\n    username = \"BOT_\" + str(time.time())[-5:]\n    session = JKLM(username, pfp=image)\n\n    try:\n        session.connect(room_id)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    input(\"\")\n    current_system_pid = os.getpid()\n\n    ThisSystem = psutil.Process(current_system_pid)\n    ThisSystem.terminate()\n\n\nif __name__ == '__main__':\n    main(\"KMPW\")\n```\n\n## Connections (Twitch, Discord)\nHere is an example of how to connect to a room using a twitch or discord account\n```python\nfrom jklm import JKLM\nimport time\n\nimport psutil\nimport os\n\n\ndef main(room_id):\n    image = open(\"logo.png\", \"rb\").read() # Try to keep image 128x128\n\n    username = \"BOT_\" + str(time.time())[-5:]\n    session = JKLM(username, pfp=image, connection={\n        \"service\": \"twitch\", # twitch, discord\n        \"username\": \"jklm_bot\", # Isn't validated\n        \"token\": \"YOUR_TOKEN\", # Validated\n        \"expiration\": 0 # Isn't validated\n    })\n\n    try:\n        session.connect(room_id)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    input(\"\")\n    current_system_pid = os.getpid()\n\n    ThisSystem = psutil.Process(current_system_pid)\n    ThisSystem.terminate()\n\n\nif __name__ == '__main__':\n    main(\"KMPW\")\n```\n\n## Chat Client\nHere is an example of how to connect to a room and chat back and forth with other users\n```python\nfrom jklm import JKLM\nimport time\n\nimport psutil\nimport os\n\ndef main(room_id):\n    \n    username = \"BOT_\" + str(time.time())[-5:]\n    session = JKLM(username)\n\n    def chat_handler(code, raw_data):\n        event = raw_data[0]\n        data = raw_data[1]\n\n        # 0 CODE = Kicked from room (event = TYPE [\"KICKED\" | \"BAN\"], data = INFO)\n\n        if (code == 0):\n            print(\"[X] Kicked from room:\", data)\n            return\n\n        match event:\n            case \"chat\":\n                message = raw_data[2]\n\n                print(f\"[CHAT] {data['nickname']}: {message}\")\n                pass\n            case \"chatterAdded\":\n                print(f\"[+] {data} joined the room\")\n            case \"chatterRemoved\":\n                print(f\"[-] {data} left the room\")\n            case \"setPlayerCount\":\n                print(f\"[!] {data} players in the room\")\n            case _:\n                print(f\"[UNHANDLED CHAT EVENT] {event}:\", data)\n\n    try:\n        session.connect(room_id, chat_handler=chat_handler)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    try:\n        while True:\n            message = input(\"\")\n\n            if message == \"\":\n                raise KeyboardInterrupt\n\n            session.send_chat_message(message)\n\n            time.sleep(1)\n\n            if session.reconnect_attempts \u003e 5:\n                print(\"Reconnect attempts exceeded\")\n                current_system_pid = os.getpid()\n\n                ThisSystem = psutil.Process(current_system_pid)\n                ThisSystem.terminate()\n                break\n    except KeyboardInterrupt:\n        current_system_pid = os.getpid()\n\n        ThisSystem = psutil.Process(current_system_pid)\n        ThisSystem.terminate()\n\nif __name__ == '__main__':\n    main(\"ABUM\")\n```\n\n# Pop Sauce\n\n## Challenge Hasher\nHere is an example of how to hash a challenge\n```python\nfrom jklm import JKLM\nimport time\n\nimport hashlib\n\nimport psutil\nimport os\n\nexpecting_image = False\nchallenge = {\n    \"end_time\": 0,\n    \"image\": None,\n    \"prompt\": None,\n    \"text\": None,\n    \"hash\": None\n}\n\ndef sha1(input):\n    if isinstance(input, str):\n        input = input.encode()\n    return hashlib.sha1(input).hexdigest()\n\ndef main(room_id):\n    global expecting_image, challenge\n    \n    username = \"BOT_\" + str(time.time())[-5:]\n    session = JKLM(username)\n\n    def game_handler(code, raw_data):\n        global expecting_image, challenge\n        event = raw_data[0]\n        data = raw_data[1]\n\n        # -1 CODE = Image data\n        # 0 CODE = Kicked from room (event = TYPE [\"KICKED\" | \"BAN\"], data = INFO)\n\n        if (code == 0):\n            print(\"[X] Kicked from room:\", data)\n            return\n\n        if (code == -1):\n            asset_type = challenge[\"image\"][\"type\"]\n            extension = \"\"\n\n            match asset_type:\n                case \"image/svg+xml\":\n                    extension = \"svg\"\n                case \"image/png\":\n                    extension = \"png\"\n                case \"image/jpeg\":\n                    extension = \"jpeg\"\n\n            challenge[\"hash\"] = sha1(challenge[\"prompt\"].encode() + raw_data)\n            challenge[\"image\"][\"extension\"] = extension\n\n            print(\"[?] Challenge Hash:\", challenge[\"hash\"])\n            print(\"[?] Image has been saved to image.\" + extension)\n\n            with open(\"image.\" + extension, \"wb\") as f:\n                f.write(raw_data)\n\n            return\n\n        match event:\n            case \"startChallenge\":\n                print(\"\\n[!] New Challenge Started\")\n\n                challenge[\"end_time\"] = data[\"endTime\"]\n                challenge[\"image\"] = data[\"image\"]\n                challenge[\"prompt\"] = data[\"prompt\"]\n                challenge[\"text\"] = data[\"text\"]\n\n                if challenge[\"image\"]:\n                    expecting_image = True\n                    print(\"[?] Image Challenge\", challenge[\"prompt\"])\n                else:\n                    expecting_image = False\n                    challenge[\"hash\"] = sha1(challenge[\"prompt\"] + challenge[\"text\"])\n\n                    print(\"[?] Text Challenge:\", challenge[\"prompt\"])\n                    print(\"[?] Challenge Hash:\", challenge[\"hash\"])\n                    print(\"[?]\", challenge[\"text\"])\n\n\n            case \"endChallenge\":\n                print(\"\\n[!] Challenge Ended\")\n                print(\"[X] Correct Answer:\", data[\"source\"])\n                \n            case \"setPlayerState\":\n                event, peer_id, data = raw_data\n                    \n                guess = data[\"guess\"]\n                found_answer = data[\"hasFoundSource\"]\n                points = data[\"points\"]\n                elapsed_time = data[\"elapsedTime\"]\n\n                player = list(filter(lambda x: x[\"profile\"][\"peerId\"] == peer_id, session.game[\"players\"]))[0]\n\n                if found_answer:\n                    print(f\"[!] {player['profile']['nickname']} with {points} points guessed it in {elapsed_time} seconds\")\n                else:\n                    print(f\"[!] {player['profile']['nickname']} with {points} points guessed {guess}\")\n\n            case \"updatePlayer\":\n                event, peer_id, data, online = raw_data\n\n                player = list(filter(lambda x: x[\"profile\"][\"peerId\"] == peer_id, session.game[\"players\"]))[0]\n\n                if online:\n                    print(f\"[+] {player['profile']['nickname']} reconnected to the game\")\n                else:\n                    print(f\"[-] {player['profile']['nickname']} disconnected from the game\")\n\n            case \"addPlayer\":\n                print(f\"[+] {data['profile']['nickname']} joined the game\")\n\n            case _:\n                print(f\"[UNHANDLED GAME EVENT] {event}:\", raw_data)\n\n    try:\n        session.connect(room_id, game_handler=game_handler)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    session.join_round()\n\n    # Checks if a challenge is already started\n\n    if (\"challenge\" in session.game[\"milestone\"]):\n        print(\"\\n[!] Challenge already started\")\n        \n        current_challenge = session.game[\"milestone\"][\"challenge\"]\n        \n        # If the challenge has ended but the next one hasn't started yet endTime will be null\n        challenge[\"end_time\"] = current_challenge[\"endTime\"] if \"endTime\" in current_challenge else 0\n        challenge[\"image\"] = current_challenge[\"image\"]\n        challenge[\"prompt\"] = current_challenge[\"prompt\"]\n        challenge[\"text\"] = current_challenge[\"text\"]\n\n        if challenge[\"image\"]:\n            expecting_image = True\n            print(\"[?] Image Challenge\", challenge[\"prompt\"])\n        else:\n            expecting_image = False\n\n            challenge[\"hash\"] = sha1(challenge[\"prompt\"] + challenge[\"text\"])\n\n            print(\"[?] Text Challenge:\", challenge[\"prompt\"])\n            print(\"[?]\", challenge[\"text\"])\n            print(\"[?] Challenge Hash:\", challenge[\"hash\"])\n\n    input(\"\")\n    current_system_pid = os.getpid()\n\n    ThisSystem = psutil.Process(current_system_pid)\n    ThisSystem.terminate()\n\nif __name__ == '__main__':\n    main(\"ABUM\")\n```\n\n## Auto-Answer\nHere is an example of how to auto-answer and send the answer to the chat\n```python\nfrom jklm import JKLM\nimport requests\nimport time\n\nimport hashlib\n\nimport psutil\nimport os\n\nexpecting_image = False\nchallenge = {\n    \"end_time\": 0,\n    \"image\": None,\n    \"prompt\": None,\n    \"text\": None,\n    \"hash\": None\n}\n\nres = requests.get(\"https://cdn.jsdelivr.net/gh/joseph-gerald/jklm-py-client@main/answers/popsauce_pairs.txt\")\nanswers = {x.split(\":\", 1)[0]: x.split(\":\", 1)[1].strip() for x in res.text.split(\"\\n\") if x}\n\ndef sha1(input):\n    if isinstance(input, str):\n        input = input.encode()\n    return hashlib.sha1(input).hexdigest()\n\ndef main(room_id):\n    global expecting_image, challenge\n    \n    username = \"BOT_\" + str(time.time())[-5:]\n    session = JKLM(username)\n\n    def game_handler(code, raw_data):\n        global expecting_image, challenge\n        event = raw_data[0]\n        data = raw_data[1]\n\n        # -1 CODE = Image data\n        # 0 CODE = Kicked from room (event = TYPE [\"KICKED\" | \"BAN\"], data = INFO)\n\n        if (code == 0):\n            print(\"[X] Kicked from room:\", data)\n            return\n\n        if (code == -1):\n            asset_type = challenge[\"image\"][\"type\"]\n            extension = \"\"\n\n            match asset_type:\n                case \"image/svg+xml\":\n                    extension = \"svg\"\n                case \"image/png\":\n                    extension = \"png\"\n                case \"image/jpeg\":\n                    extension = \"jpeg\"\n\n            challenge[\"hash\"] = sha1(challenge[\"prompt\"].encode() + raw_data)\n            challenge[\"image\"][\"extension\"] = extension\n\n            print(\"[?] Challenge Hash:\", challenge[\"hash\"])\n            \n            answer = answers.get(challenge[\"hash\"])\n\n            if answer:\n                print(\"[!] Answer is indexed:\", answer)\n                session.submit_guess(answer)\n                session.send_chat_message(answer)\n            else:\n                print(\"[!] Answer was not indexed\")\n\n            return\n\n        match event:\n            case \"startChallenge\":\n                print(\"\\n[!] New Challenge Started\")\n\n                challenge[\"end_time\"] = data[\"endTime\"]\n                challenge[\"image\"] = data[\"image\"]\n                challenge[\"prompt\"] = data[\"prompt\"]\n                challenge[\"text\"] = data[\"text\"]\n\n                if challenge[\"image\"]:\n                    expecting_image = True\n                    print(\"[?] Image Challenge\", challenge[\"prompt\"])\n                else:\n                    expecting_image = False\n                    challenge[\"hash\"] = sha1(challenge[\"prompt\"] + challenge[\"text\"])\n\n                    print(\"[?] Text Challenge:\", challenge[\"prompt\"])\n                    print(\"[?] Challenge Hash:\", challenge[\"hash\"])\n                    print(\"[?]\", challenge[\"text\"])\n\n                    answer = answers.get(challenge[\"hash\"])\n                    if answer:\n                        print(\"[!] Answer is indexed:\", answer)\n                        session.submit_guess(answer)\n                        session.send_chat_message(answer)\n                    else:\n                        print(\"[!] Answer was not indexed\")\n\n\n            case \"endChallenge\":\n                print(\"\\n[!] Challenge Ended\")\n                print(\"[X] Correct Answer:\", data[\"source\"])\n                \n            case \"setPlayerState\":\n                event, peer_id, data = raw_data\n                    \n                guess = data[\"guess\"]\n                found_answer = data[\"hasFoundSource\"]\n                points = data[\"points\"]\n                elapsed_time = data[\"elapsedTime\"]\n\n                print(f\"[!] {peer_id} {data}\")\n                \n                if peer_id == session.peer_id:\n                    return\n\n                player = list(filter(lambda x: x[\"profile\"][\"peerId\"] == peer_id, session.game[\"players\"]))[0]\n\n                if found_answer:\n                    print(f\"[!] {player['profile']['nickname']} with {points} points guessed it in {elapsed_time} seconds\")\n                else:\n                    print(f\"[!] {player['profile']['nickname']} with {points} points guessed {guess}\")\n\n            case \"updatePlayer\":\n                event, peer_id, data, online = raw_data\n\n                player = list(filter(lambda x: x[\"profile\"][\"peerId\"] == peer_id, session.game[\"players\"]))[0]\n\n                if online:\n                    print(f\"[+] {player['profile']['nickname']} reconnected to the game\")\n                else:\n                    print(f\"[-] {player['profile']['nickname']} disconnected from the game\")\n\n            case \"addPlayer\":\n                print(f\"[+] {data['profile']['nickname']} joined the game\")\n\n            case _:\n                print(f\"[UNHANDLED GAME EVENT] {event}:\", raw_data)\n\n    try:\n        session.connect(room_id, game_handler=game_handler)\n        print(\"[.] Successfully joined\", room_id)\n    except Exception as e:\n        print(\"[X] Failed to join room:\", e)\n        return\n\n    session.join_round()\n\n    # Checks if a challenge is already started\n\n    if (\"challenge\" in session.game[\"milestone\"]):\n        print(\"\\n[!] Challenge already started\")\n        \n        current_challenge = session.game[\"milestone\"][\"challenge\"]\n        \n        # If the challenge has ended but the next one hasn't started yet endTime will be null\n        challenge[\"end_time\"] = current_challenge[\"endTime\"] if \"endTime\" in current_challenge else 0\n        challenge[\"image\"] = current_challenge[\"image\"]\n        challenge[\"prompt\"] = current_challenge[\"prompt\"]\n        challenge[\"text\"] = current_challenge[\"text\"]\n\n        if challenge[\"image\"]:\n            expecting_image = True\n            print(\"[?] Image Challenge\", challenge[\"prompt\"])\n        else:\n            expecting_image = False\n\n            challenge[\"hash\"] = sha1(challenge[\"prompt\"] + challenge[\"text\"])\n\n            print(\"[?] Text Challenge:\", challenge[\"prompt\"])\n            print(\"[?]\", challenge[\"text\"])\n            print(\"[?] Challenge Hash:\", challenge[\"hash\"])\n\n    input(\"\")\n    current_system_pid = os.getpid()\n\n    ThisSystem = psutil.Process(current_system_pid)\n    ThisSystem.terminate()\n\nif __name__ == '__main__':\n    main(\"ABUM\")\n```\n\n# Bomb Party\nsoon™️\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoseph-gerald%2Fjklm-py-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoseph-gerald%2Fjklm-py-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoseph-gerald%2Fjklm-py-client/lists"}