├── .gitignore ├── Kitty ├── __init__.py ├── scripts │ ├── __init__.py │ ├── check.py │ ├── sprint.py │ └── colors.py ├── Info │ ├── scripts │ │ ├── __init__.py │ │ ├── sprint.py │ │ └── colors.py │ ├── extra.py │ ├── contributors.py │ ├── main.py │ └── legal.py ├── readme.md ├── htu.py ├── Flood │ ├── main.py │ └── flood.js └── client.py ├── docs ├── public │ ├── favicon.png │ ├── pfp1-200h.png │ ├── pfp2-200h.png │ ├── pfp3-200h.png │ ├── pfp4-200h.png │ ├── pfp5-200h.png │ ├── gray-vector.svg │ └── white-vector.svg ├── readme.md ├── style.css ├── index.css └── index.html ├── public └── readme.md ├── SECURITY.md ├── LITE ├── Readme.md └── lite.py ├── extra.md ├── .github ├── FAQ │ └── readme.md └── ISSUE_TEMPLATE │ └── bug_report.md ├── README.md ├── LICENSE ├── src ├── main.py └── client.py └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ -------------------------------------------------------------------------------- /Kitty/__init__.py: -------------------------------------------------------------------------------- 1 | # Hello, World! 2 | -------------------------------------------------------------------------------- /Kitty/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | # Hola 2 | -------------------------------------------------------------------------------- /Kitty/Info/scripts/__init__.py: -------------------------------------------------------------------------------- 1 | # Hello, world! 2 | -------------------------------------------------------------------------------- /docs/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPScript/Kitty-Tools/HEAD/docs/public/favicon.png -------------------------------------------------------------------------------- /docs/public/pfp1-200h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPScript/Kitty-Tools/HEAD/docs/public/pfp1-200h.png -------------------------------------------------------------------------------- /docs/public/pfp2-200h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPScript/Kitty-Tools/HEAD/docs/public/pfp2-200h.png -------------------------------------------------------------------------------- /docs/public/pfp3-200h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPScript/Kitty-Tools/HEAD/docs/public/pfp3-200h.png -------------------------------------------------------------------------------- /docs/public/pfp4-200h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPScript/Kitty-Tools/HEAD/docs/public/pfp4-200h.png -------------------------------------------------------------------------------- /docs/public/pfp5-200h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CPScript/Kitty-Tools/HEAD/docs/public/pfp5-200h.png -------------------------------------------------------------------------------- /Kitty/readme.md: -------------------------------------------------------------------------------- 1 | This directory is were all of the magic happens... this is were all of the main scripts for the CTI are 2 | -------------------------------------------------------------------------------- /Kitty/scripts/check.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os import system 3 | 4 | def try_install(str): 5 | os.system("pip install colorama") #required 6 | os.system("pip install pystyle") #required 7 | -------------------------------------------------------------------------------- /docs/public/gray-vector.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/public/white-vector.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## Welcome to `Kitty-Tool's` website dir | BETA 4 | 5 |
6 | 7 | * Created By - Kira 8 | * Version 1.5 9 | * Being updated soon 10 | 11 |

12 | © 2024 Kitty-Tools All rights reserved. 13 |

14 | -------------------------------------------------------------------------------- /Kitty/Info/extra.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import sys 4 | from scripts.sprint import sprint 5 | from scripts.colors import ran,y,r,g,c 6 | import time 7 | sprint(f"{y}Your a poopie head <3") 8 | time.sleep(5) 9 | 10 | from subprocess import call 11 | call(["python", "main.py"]) 12 | -------------------------------------------------------------------------------- /Kitty/scripts/sprint.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys, time 3 | from scripts import colors 4 | 5 | c = colors 6 | 7 | 8 | def sprint(str): 9 | for i in str + c.c + "\n": 10 | sys.stdout.write(i) 11 | sys.stdout.flush() 12 | 13 | time.sleep(3 / 90) 14 | 15 | 16 | def command(str): 17 | os.system(str) 18 | -------------------------------------------------------------------------------- /Kitty/Info/scripts/sprint.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys, time 3 | from scripts import colors 4 | 5 | c = colors 6 | 7 | 8 | def sprint(str): 9 | for i in str + c.c + "\n": 10 | sys.stdout.write(i) 11 | sys.stdout.flush() 12 | 13 | time.sleep(3 / 90) 14 | 15 | 16 | def command(str): 17 | os.system(str) 18 | -------------------------------------------------------------------------------- /public/readme.md: -------------------------------------------------------------------------------- 1 | # Progress images 2 | ![Screenshot at 2025-03-31 23-04-07](https://github.com/user-attachments/assets/e74ca239-3a9e-46db-a0dc-da8d3c0d1da2) 3 | ![image](https://github.com/user-attachments/assets/ff001853-3cee-4e11-895a-0c192b279b81) 4 | ![image](https://github.com/user-attachments/assets/9c9c6098-3690-4447-9c0e-228cd63fce21) 5 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | Only the most **Up to Date** version of this repo will get vulnerability checks! 3 | 4 | ## Supported Versions 5 | 6 | | Version | Supported | 7 | | ------- | ------------------ | 8 | | main(most recent) | :white_check_mark: | 9 | 10 | 11 | ## Reporting a Vulnerability 12 | 13 | When you find Vulnerability please make an issue and use the bug issue template, fill out the template and name the title of your issue "vuln by {your username}" 14 | -------------------------------------------------------------------------------- /Kitty/Info/contributors.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import sys 4 | from scripts.sprint import sprint 5 | from scripts.colors import ran,y,r,g,c 6 | import time 7 | print("Cool contributers") 8 | sprint(f"""{y}Thank you 9 | {r}@Ccode-lang {y}for helping out! 10 | {r}@xTobyPlayZ {y}for Flooder! 11 | {r}@cheepling {y}for finding bugs! 12 | {r}@Zacky2613 {y}for helping and fixing issus! 13 | {r}@KiraKenjiro {y}for reviewing and making changes! {r}<3 {y} 14 | """) 15 | time.sleep(5) 16 | 17 | from subprocess import call 18 | call(["python", "main.py"]) 19 | -------------------------------------------------------------------------------- /LITE/Readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # `Kitty-Tools LITE v1.10` 4 | 5 |
6 | 7 | # How to use 8 | 9 | * INSTALL TERMUX ON YOUR ANDROID PHONE 10 | * Install python: `pkg install python` 11 | * Install git: `pkg install git` 12 | * clone the repo: `git clone https://github.com/CPScript/Kitty-Tools` 13 | * Go to `LITE`'s dir: `cd Kitty-Tools/LITE` 14 | * Run script: `python lite.py` 15 | 16 | --- 17 | 18 | > This version of `Kitty-Tools` is ment to be ran on Android! 19 | 20 | --- 21 | 22 |

23 | © 2025 Kitty Tools LITE. All rights reserved. 24 | | BETA v1.10 25 |

26 | -------------------------------------------------------------------------------- /Kitty/scripts/colors.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | try: 4 | from colorama import Style, Fore 5 | 6 | except ModuleNotFoundError: 7 | os.system("pip install colorama") 8 | import random 9 | 10 | all_col = [ 11 | Style.BRIGHT + Fore.RED, Style.BRIGHT + Fore.CYAN, 12 | Style.BRIGHT + Fore.LIGHTCYAN_EX, Style.BRIGHT + Fore.LIGHTBLUE_EX, 13 | Style.BRIGHT + Fore.LIGHTCYAN_EX, Style.BRIGHT + Fore.LIGHTMAGENTA_EX, 14 | Style.BRIGHT + Fore.LIGHTYELLOW_EX 15 | ] 16 | 17 | ran = random.choice(all_col) 18 | 19 | lg = Style.BRIGHT + Fore.LIGHTGREEN_EX 20 | g = Style.BRIGHT + Fore.GREEN 21 | lc = Style.BRIGHT + Fore.LIGHTCYAN_EX 22 | c = Style.BRIGHT + Fore.CYAN 23 | ly = Style.BRIGHT + Fore.LIGHTYELLOW_EX 24 | y = Style.BRIGHT + Fore.YELLOW 25 | r = Style.BRIGHT + Fore.RED 26 | lr = Style.BRIGHT + Fore.LIGHTRED_EX 27 | -------------------------------------------------------------------------------- /Kitty/Info/scripts/colors.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | try: 4 | from colorama import Style, Fore 5 | 6 | except ModuleNotFoundError: 7 | os.system("pip install colorama") 8 | import random 9 | 10 | all_col = [ 11 | Style.BRIGHT + Fore.RED, Style.BRIGHT + Fore.CYAN, 12 | Style.BRIGHT + Fore.LIGHTCYAN_EX, Style.BRIGHT + Fore.LIGHTBLUE_EX, 13 | Style.BRIGHT + Fore.LIGHTCYAN_EX, Style.BRIGHT + Fore.LIGHTMAGENTA_EX, 14 | Style.BRIGHT + Fore.LIGHTYELLOW_EX 15 | ] 16 | 17 | ran = random.choice(all_col) 18 | 19 | lg = Style.BRIGHT + Fore.LIGHTGREEN_EX 20 | g = Style.BRIGHT + Fore.GREEN 21 | lc = Style.BRIGHT + Fore.LIGHTCYAN_EX 22 | c = Style.BRIGHT + Fore.CYAN 23 | ly = Style.BRIGHT + Fore.LIGHTYELLOW_EX 24 | y = Style.BRIGHT + Fore.YELLOW 25 | r = Style.BRIGHT + Fore.RED 26 | lr = Style.BRIGHT + Fore.LIGHTRED_EX 27 | -------------------------------------------------------------------------------- /extra.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## Website 4 | * {infomation here} 5 | 6 | ## LITE 7 | * This is a version of Kitty-Tools that is ment to run on slower systems as it doesn't have as many graphical effects so it should be faster, it also doesn't have as many non requires modules so it shouldn't run into any error! 8 | 9 | ## Definitions 10 | * apt: Advanced Package Tool (High level package installer) 11 | * pkg: Package 12 | * install git: Installs a github Repo via a terminal 13 | * cd: Change directory (Used to go to a file via terminal) 14 | * cmd: Command (You can type "CMD" in the windows start bar to open its command prompt!) 15 | * repo: repository (If your reading this than your looking at a repository's readme.md) 16 | * dir: directory (File location) 17 | 18 | 19 | ## Versions 20 | * You can past versions here: 21 | 22 | ![Screenshot 2024-01-05 8 21 22 AM](https://github.com/CPScript/Kitty-Tools/assets/83523587/ea8f7306-ee2e-4ca7-8dfb-767df8bfa8cc) 23 | 24 |
25 | -------------------------------------------------------------------------------- /.github/FAQ/readme.md: -------------------------------------------------------------------------------- 1 | ## Table of Contents 2 | - [Network responses](#network) 3 | - [Bot issues](#bot) 4 | - [Contributing & Issues](#contributing) 5 | 6 | ## Network 7 | 8 | There are some error codes you might get in return when attempting to use the answer hack. Here are a few of those listed to go ahead and help before you make an issue! 9 | 10 | * **HTTP Error : 403 - Forbidden** ~ The quiz you are attempting to acces using the quiz ID is most likely private. Try again and see if you get the same responce. 11 | * **HTTP Error :400 - Bad Request** ~ You will see this when you type the quiz ID incorrectly. Try re-typing it. 12 | * **HTTP Error :404 - Not found** ~ The quiz you are attempting to get answer from does not exist. 13 | 14 | ## Bot 15 | 16 | There are some isses with the current bot implementation. 17 | 18 | * **NPM: Not found** ~ You will need to install NPM properly. This project will automate the full process. 19 | 20 | * **The bot only supports 4 answer quizes.** It wont be able to do TOF, polls, typing questions, etc. ~ Im working on makiing a new bot that will support more quiz formats. the current bot was not made by me but edited. 21 | 22 | 23 | ## **Contributing** 24 | * Contributing to this project helps me out a lot. **All pull requests and issues are looked over by yours truely** 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: A bug was found within the Kitty-Tools repository 4 | title: "" 5 | labels: bug 6 | --- 7 | 8 | >[!WARNING] 9 | > **BEFORE YOU MAKE THIS ISSUE**; 10 | > * Make sure that there isn't an answer to your issue in [FAQ](https://github.com/CPScript/Kitty-Tools/blob/main/.github/FAQ/readme.md). 11 | > * Make sure that the issue hasnt be brought up in [past issues](https://github.com/CPScript/Kitty-Tools/issues?q=is%3Aissue%20state%3Aclosed). 12 | > * Fully fill out this template as much as you possibly can. 13 | > * **BLANK ISSUES WILL BE CLOSED!** 14 | > 15 | > **If you make an issue without this template or checking the FAQ then your issue will be ignored/closed.** 16 | 17 | --- 18 | 19 | ## **1.** Describe the bug 20 | * A clear and concise description of what the bug is. 21 | 22 | 23 | ## **2.** To Reproduce 24 | * Steps to reproduce the behavior: 25 | - Please tell us what you ran in the terminal to get such error 26 | 27 | ## **3.** Screenshots 28 | * If applicable, add screenshots to help explain your problem. 29 | 30 | ## **4.** Desktop (please complete the following information): 31 | - OS: [e.g. iOS] 32 | - Browser [e.g. chrome, safari] 33 | - Version [e.g. 22] 34 | 35 | ## **5.** Smartphone (please complete the following information): 36 | - Device: [e.g. iPhone6] 37 | - OS: [e.g. iOS8.1] 38 | - Browser [e.g. stock browser, safari] 39 | - Version [e.g. 22] 40 | 41 | ## **6.** Additional context 42 | Add any other context about the problem here. 43 | -------------------------------------------------------------------------------- /Kitty/Info/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import sys 4 | from scripts.sprint import sprint 5 | from scripts.colors import ran, y, r, g, c 6 | import time 7 | from subprocess import call 8 | 9 | 10 | def clear(): 11 | system = platform.system().lower() 12 | 13 | if system == 'windows': 14 | _ = os.system('cls') 15 | elif system == 'linux' or system == 'darwin': 16 | _ = os.system('clear') 17 | elif system == 'android': 18 | _ = subprocess.run(['termux-exec', 'sh', '-c', 'clear'], check=False) 19 | else: 20 | print(f"Unsupported platform, please use Kitty-Tools LITE '{system}'") 21 | print( 22 | f"For more info go to https://github.com/CPScript/Kitty-Tools/more/moreinfo.md" 23 | ) 24 | 25 | 26 | clear() 27 | 28 | print("[Extra-InfoChart v2.7") 29 | print("[====================") 30 | print("[1] GO BACK ") 31 | print("[2] More info ") 32 | print("[3] Contributors ") 33 | print("[4] Legal (COC & TOS)") 34 | print("[====================") 35 | choice = input("[U] >> ") 36 | 37 | if choice == "1": 38 | print(" ") 39 | print("Loading...") 40 | time.sleep(1) 41 | print("\n" * 64) 42 | call(["python", "main.py"]) 43 | 44 | if choice == "2": 45 | print(" ") 46 | print("Loading...") 47 | time.sleep(1) 48 | print("\n" * 64) 49 | call(["python", "Kitty/Info/extra.py"]) 50 | 51 | if choice == "3": 52 | print(" ") 53 | print("Loading...") 54 | time.sleep(1) 55 | print("\n" * 64) 56 | call(["python", "Kitty/Info/contributors.py"]) 57 | 58 | if choice == "4": 59 | print(" ") 60 | print("Loading...") 61 | time.sleep(1) 62 | print("\n" * 64) 63 | call(["python", "Kitty/Info/legal.py"]) 64 | -------------------------------------------------------------------------------- /Kitty/htu.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import sys 4 | from scripts.sprint import sprint 5 | from scripts.colors import ran,y,r,g,c 6 | print("\n" * 32) 7 | print(""" 8 | $$\ $$\ $$\ 9 | $$ | $$ | $$ | 10 | $$ | $$ | $$$$$$\ $$\ $$\ $$\ $$$$$$\ $$$$$$\ $$\ $$\ $$$$$$$\ $$$$$$\ 11 | $$$$$$$$ |$$ __$$\ $$ | $$ | $$ | \_$$ _| $$ __$$\ $$ | $$ |$$ _____|$$ __$$\ 12 | $$ __$$ |$$ / $$ |$$ | $$ | $$ | $$ | $$ / $$ | $$ | $$ |\$$$$$$\ $$$$$$$$ | 13 | $$ | $$ |$$ | $$ |$$ | $$ | $$ | $$ |$$\ $$ | $$ | $$ | $$ | \____$$\ $$ ____| 14 | $$ | $$ |\$$$$$$ |\$$$$$\$$$$ | \$$$$ |\$$$$$$ | \$$$$$$ |$$$$$$$ |\$$$$$$$\ 15 | \__| \__| \______/ \_____\____/ \____/ \______/ \______/ \_______/ \_______| 16 | ================================================================================================ 17 | Selection '1' : You are looking at it! 18 | Selection '2' : This opens a catigory with more information such as; Contributers, the repo's licence, and more! 19 | Selection '3' : This runs a script that will flood the game lobbie with bots, its currently not working and I havn't fixed it yet~ 20 | Selection '4' : This runs a script that gives you the answers to a kahoot game. 21 | """) 22 | sprint(f"{r} PS! if the quiz was assigned to you instead of hosted, it should be there so it should work :) ") 23 | 24 | import sys 25 | def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+ 26 | count = len(it) 27 | def show(j): 28 | x = int(size*j/count) 29 | print("{}[{}{}] {}/{}".format(prefix, "#"*x, "."*(size-x), j, count), 30 | end='\r', file=out, flush=True) 31 | show(0) 32 | for i, item in enumerate(it): 33 | yield item 34 | show(i+1) 35 | print("\n", flush=True, file=out) 36 | 37 | import time 38 | for i in progressbar(range(500), "Loading: ", 35): 39 | time.sleep(0.1) 40 | print("\n" * 64) 41 | from subprocess import call 42 | call(["python", "Kahoot/kahoot.py"]) 43 | -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --dl-color-gray-700: #999999; 3 | --dl-color-gray-900: #c3c5c9ff; 4 | --dl-size-size-unit: 1rem; 5 | --dl-color-gray-black: #000000; 6 | --dl-color-gray-white: #FFFFFF; 7 | --dl-color-pimary-300: #0284c7ff; 8 | --dl-color-pimary-500: #4aa4e3ff; 9 | --dl-color-pimary-700: #c3e5faff; 10 | --dl-color-pimary-800: #e3e8efff; 11 | --dl-color-pimary-900: #f2f5f9ff; 12 | --dl-space-space-unit: 1rem; 13 | --dl-size-size-halfunit: 0.5rem; 14 | --dl-color-secondary-100: #111729ff; 15 | --dl-color-secondary-300: #1e293bff; 16 | --dl-color-secondary-400: #334155ff; 17 | --dl-color-secondary-500: #677b8eff; 18 | --dl-color-secondary-700: #94a3b8ff; 19 | --dl-radius-radius-round: 50%; 20 | --dl-size-size-doubleunit: 2rem; 21 | --dl-size-size-tripleunit: 3rem; 22 | --dl-space-space-halfunit: 0.5rem; 23 | --dl-radius-radius-radius4: 4px; 24 | --dl-space-space-fiveunits: 5rem; 25 | --dl-radius-radius-radius25: 0.25rem; 26 | --dl-radius-radius-radius50: 0.5rem; 27 | --dl-radius-radius-radius75: 0.75rem; 28 | --dl-space-space-doubleunit: 2rem; 29 | --dl-space-space-tripleunit: 3rem; 30 | --dl-space-space-twoandhalf: 2.5rem; 31 | --dl-space-space-unitandhalf: 1.5rem; 32 | --dl-space-space-triplequarter: 0.75rem; 33 | } 34 | .teleport-show { 35 | display: flex !important; 36 | transform: none !important; 37 | } 38 | .list { 39 | width: 100%; 40 | margin: 1em 0px 1em 0px; 41 | display: block; 42 | padding: 0px 0px 0px 1.5rem; 43 | list-style-type: none; 44 | list-style-position: outside; 45 | } 46 | .list-item { 47 | display: list-item; 48 | } 49 | .button { 50 | color: var(--dl-color-gray-900); 51 | display: inline-block; 52 | padding: 0.5rem 1rem; 53 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 54 | border-color: var(--dl-color-gray-900); 55 | border-width: 1px; 56 | border-radius: 4px; 57 | background-color: var(--dl-color-gray-white); 58 | } 59 | .textarea { 60 | color: var(--dl-color-gray-900); 61 | cursor: auto; 62 | padding: 0.5rem; 63 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 64 | border-color: var(--dl-color-gray-900); 65 | border-width: 1px; 66 | border-radius: 4px; 67 | background-color: var(--dl-color-gray-white); 68 | } 69 | .input { 70 | color: var(--dl-color-gray-900); 71 | cursor: auto; 72 | padding: 0.5rem 1rem; 73 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 74 | border-color: var(--dl-color-gray-900); 75 | border-width: 1px; 76 | border-radius: 4px; 77 | background-color: var(--dl-color-gray-white); 78 | } 79 | .Healine { 80 | font-size: 1.875rem; 81 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 82 | font-weight: 700; 83 | text-transform: none; 84 | text-decoration: none; 85 | } 86 | .TextXL { 87 | font-size: 1.25rem; 88 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 89 | font-weight: 400; 90 | text-transform: none; 91 | text-decoration: none; 92 | } 93 | .TextSM { 94 | font-size: 0.87rem; 95 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 96 | font-weight: 400; 97 | line-height: 1.25; 98 | text-decoration: none; 99 | } 100 | .TextXS { 101 | font-size: 0.75rem; 102 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 103 | font-weight: 500; 104 | text-transform: none; 105 | text-decoration: none; 106 | } 107 | .Content { 108 | font-size: 1.12rem; 109 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 110 | font-weight: 300; 111 | line-height: 1.75; 112 | text-transform: none; 113 | text-decoration: none; 114 | } 115 | .TextMD { 116 | font-size: 1rem; 117 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 118 | font-weight: 400; 119 | line-height: 1.25; 120 | text-decoration: none; 121 | } 122 | .Text2XL { 123 | font-size: 2.25rem; 124 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 125 | font-weight: 700; 126 | line-height: 1.25; 127 | text-transform: none; 128 | text-decoration: none; 129 | } 130 | .Text3XL { 131 | font-size: 3rem; 132 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 133 | font-weight: 500; 134 | text-transform: none; 135 | text-decoration: none; 136 | } 137 | .TextLG { 138 | font-size: 1.125rem; 139 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans","Droid Sans", "Helvetica Neue", sans-serif; 140 | font-weight: 400; 141 | text-transform: none; 142 | text-decoration: none; 143 | } 144 | -------------------------------------------------------------------------------- /LITE/lite.py: -------------------------------------------------------------------------------- 1 | # This version is purly just a one file script with no extra fetures, the simpleist it can be! 2 | 3 | import json 4 | import urllib.request 5 | import os 6 | from os import system 7 | import platform 8 | 9 | print(f"'{system}'") # OS Alert 10 | 11 | print(""" 12 | - Kitty-Tools LITE v1.10 - 13 | ======= For Termux ========= 14 | 15 | Please enter your quiz ID 16 | / 17 | >.< 18 | ---------------------------- 19 | """) 20 | api = 'https://play.kahoot.it/rest/kahoots/' 21 | usrinput = input(f" Enter ID >> ") 22 | link = api + usrinput 23 | finished = False 24 | 25 | answers = {} 26 | images = {} 27 | questions = {} 28 | 29 | try: 30 | with urllib.request.urlopen(link) as url: 31 | print("") 32 | data = json.load(url) 33 | quizlength = len(data['questions']) 34 | 35 | def is_a_question(dat): 36 | try: 37 | eval(dat) 38 | return True 39 | except KeyError: 40 | return False 41 | 42 | question = 0 43 | for x in range(quizlength): 44 | if is_a_question("data['questions'][question]['choices']"): 45 | try: 46 | if data['questions'][question]['type'] == "quiz": 47 | if data['questions'][question]['choices'][0]['correct']: 48 | answers[f"Question {question + 1}"] = 'Red' 49 | elif data['questions'][question]['choices'][1]['correct']: 50 | answers[f"Question {question + 1}"] = 'Blue' 51 | elif data['questions'][question]['choices'][2]['correct']: 52 | answers[f"Question {question + 1}"] = 'Yellow' 53 | elif data['questions'][question]['choices'][3]['correct']: 54 | answers[f"Question {question + 1}"] = 'Green' 55 | elif data['questions'][question]['type'] == "jumble": 56 | length = len(data['questions'][question]['choices']) 57 | for y in range(length): 58 | if answers.get(f"Question {question + 1}") is None: 59 | answers[f"Question {question + 1}"] = "" 60 | answers[f"Question {question + 1}"] += str(data['questions'][question]['choices'][y]['answer']).upper() 61 | 62 | elif data['questions'][question]['type'] == "survey": 63 | answers[f"Question {question + 1}"] = "Could not find any answers" 64 | 65 | elif data['questions'][question]['type'] == "content": 66 | answers[f"Question {question + 1}"] = "Could not find any answers" 67 | 68 | elif data['questions'][question]['type'] == "multiple_select_quiz": 69 | multiselect = [] 70 | for z in range(len(data['questions'][question]['choices'])): 71 | if data['questions'][question]['choices'][0]['correct']: 72 | multiselect.append("Blue") 73 | 74 | if data['questions'][question]['choices'][1]['correct']: 75 | multiselect.append("Red") 76 | 77 | if data['questions'][question]['choices'][2]['correct']: 78 | multiselect.append("Yellow") 79 | 80 | if data['questions'][question]['choices'][3]['correct']: 81 | multiselect.append("Green") 82 | 83 | answers[f"Question {question + 1}"] = list(dict.fromkeys(multiselect)) 84 | else: 85 | answers[f"Question {question + 1}"] = 'Could not find any answers' 86 | 87 | questions[f"Question {question + 1}"] = data["questions"][question]["question"] 88 | 89 | if is_a_question('data["questions"][question]["image"]'): 90 | images[f"Question {question + 1}"] = data["questions"][question]["image"] 91 | else: 92 | images[f"Question {question + 1}"] = None 93 | 94 | question += 1 95 | if question + 1 == quizlength: 96 | finished = True 97 | except Exception as err: 98 | print(err) 99 | else: 100 | answers[f"Question {question + 1}"] = 'Could not find any answers' 101 | images[f"Question {question + 1}"] = 'Could not find any images' 102 | questions[f"Question {question + 1}"] = 'Could not find the question' 103 | 104 | question += 1 105 | 106 | except Exception as err: 107 | os.system('clear') 108 | print("Womp Womp! ") 109 | print("There was an error! Mabey you typed the 'Quiz ID' incorrectly!\n") 110 | print(err) 111 | 112 | 113 | def print_answers(): 114 | for key, value in answers.items(): 115 | if type(value) == list: 116 | print(key, ':', f"{', '.join(value)}\n") 117 | else: 118 | print(key, ':', f"{value}\n") 119 | 120 | 121 | print_answers() 122 | 123 | if finished: 124 | # try: 125 | dir_path = os.path.dirname(os.path.realpath(__file__)) 126 | data_path = os.path.join(dir_path, "quizzes", f"{usrinput}.json") 127 | 128 | if not os.path.exists(os.path.join(dir_path, "quizzes")): 129 | os.mkdir(os.path.join(dir_path, "quizzes"), 0o666) 130 | 131 | if not os.path.exists(data_path): 132 | with open(data_path, "x") as f: 133 | startconfig = {"answers": {}, "questions": {}, "images": {}} 134 | json.dump(startconfig, f, indent=4) 135 | 136 | with open(data_path, "r") as f: 137 | config = json.load(f) 138 | 139 | for i, v in answers.items(): 140 | if "Woops! Could not find any answers" in v: 141 | config["answers"][i] = None 142 | else: 143 | config["answers"][i] = v 144 | 145 | for i, v in questions.items(): 146 | if "Woops! Could not find the question" in v: 147 | config["questions"][i] = None 148 | else: 149 | config["questions"][i] = str(v).replace("T or F: ", '').replace("", '').replace("T or F: ", '').replace('', '') 150 | 151 | for i, v in images.items(): 152 | if "Woops! Could not find any images" in v: 153 | config["images"][i] = None 154 | else: 155 | config["images"][i] = v 156 | 157 | with open(data_path, "w+") as f: 158 | json.dump(config, f, indent=4) 159 | 160 | # except Exception as err: 161 | # print(f"{err}\n") 162 | 163 | input("Enter to exit...") 164 | -------------------------------------------------------------------------------- /Kitty/Info/legal.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os import system 3 | import platform 4 | 5 | 6 | def clear(): 7 | system = platform.system().lower() 8 | 9 | if system == 'windows': 10 | _ = os.system('cls') 11 | elif system == 'linux' or system == 'darwin': 12 | _ = os.system('clear') 13 | elif system == 'android': 14 | _ = subprocess.run(['termux-exec', 'sh', '-c', 'clear'], check=False) 15 | else: 16 | print(f"Unsupported platform, please use Kitty-Tools LITE '{system}'") 17 | print( 18 | f"For more info go to https://github.com/CPScript/Kitty-Tools/more/moreinfo.md" 19 | ) 20 | 21 | 22 | # Call the clear function 23 | print("Loading") 24 | clear() 25 | 26 | print(""" 27 | This Repo is not yours, most of the code here was made by me and i'dd like it if you didn't claim that you made it. 28 | ------------------------------------------------------- 29 | > If you would like to bypass such you can do this: 30 | 1. Create large changes to the script making it differant than my script. 31 | ------------------------------------------------------- 32 | 33 | I dont want to but I will DMCA your repo if you try to steal my work and say it is your own! 34 | """) 35 | 36 | print("CODE OF CONDUCT:") 37 | print(""" 38 | > Contributor Covenant Code of Conduct 39 | 40 | > Our Pledge 41 | 42 | We as members, contributors, and leaders pledge to make participation in our 43 | community a harassment-free experience for everyone, regardless of age, body 44 | size, visible or invisible disability, ethnicity, sex characteristics, gender 45 | identity and expression, level of experience, education, socio-economic status, 46 | nationality, personal appearance, race, religion, or sexual identity 47 | and orientation. 48 | 49 | We pledge to act and interact in ways that contribute to an open, welcoming, 50 | diverse, inclusive, and healthy community. 51 | 52 | > Our Standards 53 | 54 | Examples of behavior that contributes to a positive environment for our 55 | community include: 56 | 57 | * Demonstrating empathy and kindness toward other people 58 | * Being respectful of differing opinions, viewpoints, and experiences 59 | * Giving and gracefully accepting constructive feedback 60 | * Accepting responsibility and apologizing to those affected by our mistakes, 61 | and learning from the experience 62 | * Focusing on what is best not just for us as individuals, but for the 63 | overall community 64 | 65 | Examples of unacceptable behavior include: 66 | 67 | * The use of sexualized language or imagery, and sexual attention or 68 | advances of any kind 69 | * Trolling, insulting or derogatory comments, and personal or political attacks 70 | * Public or private harassment 71 | * Publishing others' private information, such as a physical or email 72 | address, without their explicit permission 73 | * Other conduct which could reasonably be considered inappropriate in a 74 | professional setting 75 | 76 | > Enforcement Responsibilities 77 | 78 | Community leaders are responsible for clarifying and enforcing our standards of 79 | acceptable behavior and will take appropriate and fair corrective action in 80 | response to any behavior that they deem inappropriate, threatening, offensive, 81 | or harmful. 82 | 83 | Community leaders have the right and responsibility to remove, edit, or reject 84 | comments, commits, code, wiki edits, issues, and other contributions that are 85 | not aligned to this Code of Conduct, and will communicate reasons for moderation 86 | decisions when appropriate. 87 | 88 | > Scope 89 | 90 | This Code of Conduct applies within all community spaces, and also applies when 91 | an individual is officially representing the community in public spaces. 92 | Examples of representing our community include using an official e-mail address, 93 | posting via an official social media account, or acting as an appointed 94 | representative at an online or offline event. 95 | 96 | > Enforcement 97 | 98 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 99 | reported to the community leaders responsible for enforcement at 100 | . 101 | All complaints will be reviewed and investigated promptly and fairly. 102 | 103 | All community leaders are obligated to respect the privacy and security of the 104 | reporter of any incident. 105 | 106 | > Enforcement Guidelines 107 | 108 | Community leaders will follow these Community Impact Guidelines in determining 109 | the consequences for any action they deem in violation of this Code of Conduct: 110 | 111 | > 1. Correction 112 | 113 | *Community Impact*: Use of inappropriate language or other behavior deemed 114 | unprofessional or unwelcome in the community. 115 | 116 | *Consequence*: A private, written warning from community leaders, providing 117 | clarity around the nature of the violation and an explanation of why the 118 | behavior was inappropriate. A public apology may be requested. 119 | 120 | > 2. Warning 121 | 122 | *Community Impact*: A violation through a single incident or series 123 | of actions. 124 | 125 | *Consequence*: A warning with consequences for continued behavior. No 126 | interaction with the people involved, including unsolicited interaction with 127 | those enforcing the Code of Conduct, for a specified period of time. This 128 | includes avoiding interactions in community spaces as well as external channels 129 | like social media. Violating these terms may lead to a temporary or 130 | permanent ban. 131 | 132 | > 3. Temporary Ban 133 | 134 | *Community Impact*: A serious violation of community standards, including 135 | sustained inappropriate behavior. 136 | 137 | *Consequence*: A temporary ban from any sort of interaction or public 138 | communication with the community for a specified period of time. No public or 139 | private interaction with the people involved, including unsolicited interaction 140 | with those enforcing the Code of Conduct, is allowed during this period. 141 | Violating these terms may lead to a permanent ban. 142 | 143 | > 4. Permanent Ban 144 | 145 | *Community Impact*: Demonstrating a pattern of violation of community 146 | standards, including sustained inappropriate behavior, harassment of an 147 | individual, or aggression toward or disparagement of classes of individuals. 148 | 149 | *Consequence*: A permanent ban from any sort of public interaction within 150 | the community. 151 | 152 | > Attribution 153 | 154 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 155 | version 2.0, available at 156 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 157 | 158 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 159 | enforcement ladder](https://github.com/mozilla/diversity). 160 | 161 | [homepage]: https://www.contributor-covenant.org 162 | 163 | For answers to common questions about this code of conduct, see the FAQ at 164 | https://www.contributor-covenant.org/faq. Translations are available at 165 | https://www.contributor-covenant.org/translations. 166 | 167 | """) 168 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kitty-Tools - v36.2 2 | > Please go check out my other repositories. there might be something you like <3 3 | 4 |
5 | 6 | [![Version](https://img.shields.io/badge/Version-36.2-orange.svg)](https://github.com/CPScript/Kitty-Tools) 7 | [![License](https://img.shields.io/badge/License-CC0_1.0-blue.svg)](https://github.com/CPScript/Kitty-Tools/blob/main/LICENSE) 8 | [![Platform](https://img.shields.io/badge/Platform-Windows_|_Linux_|_Web_|_Android_|_IOS_|_MACos_|_Mobile-orange.svg)](https://github.com/CPScript/Kitty-Tools) 9 | 10 |
11 | 12 | ## Overview 13 | 14 | Kitty-Tools is a comprehensive suite of utilities designed for enhancing and analyzing Kahoot quiz interactions. The toolkit provides powerful features for educators, students, and quiz enthusiasts, enabling advanced quiz analysis, answer retrieval, and automated participation capabilities. 15 | 16 |
17 | 18 | ![Header Image](https://github.com/user-attachments/assets/329567e9-2de0-4cf8-92be-86b525365514) 19 | 20 |
21 | 22 | ## ✨ Key Features 23 | 24 | - **Answer Retrieval System** - Obtain answers for any Kahoot quiz using Quiz ID or Game PIN 25 | - **Multi-bot Participation** - Create multiple automated quiz participants with configurable behaviors **NOTE; YOU CAN NOT USE THIS OPTION IN GITHUB CODESPACE** 26 | - **Cross-Platform Support** - Works on Windows, macOS, Linux, and Android (via Termux) 27 | - **Modern GUI Interface** - Sleek, intuitive graphical user interface with dark theme 28 | - **Export Functionality** - Save quiz answers in text format for future reference 29 | - **Enhanced CLI Mode** - Full functionality available via command line for low-resource environments 30 | 31 |
32 | 33 |
34 | 35 | ## 🚀 Installation Guide 36 | 37 | ### Prerequisites 38 | 39 | - Python 3.6+ 40 | - Git 41 | - Node.js (for Flooder functionality) 42 | 43 | ### Installation by Platform 44 | 45 |
46 | Windows 47 | 48 | 1. Install Python from [python.org/downloads](https://www.python.org/downloads/) (ensure "Add to PATH" is checked) 49 | 2. Install Git from [git-scm.com/download/win](https://git-scm.com/download/win) 50 | 3. Open Command Prompt and run: 51 | ``` 52 | git clone https://github.com/CPScript/Kitty-Tools 53 | cd Kitty-Tools 54 | python main.py 55 | ``` 56 |
57 | 58 |
59 | Linux/macOS 60 | 61 | 1. Install required packages: 62 | ```bash 63 | # Ubuntu/Debian 64 | sudo apt install python3 python3-pip git 65 | 66 | # Fedora 67 | sudo dnf install python3 python3-pip git 68 | 69 | # macOS (with Homebrew) 70 | brew install python git 71 | ``` 72 | 73 | 2. Clone and run: 74 | ```bash 75 | git clone https://github.com/CPScript/Kitty-Tools 76 | cd Kitty-Tools 77 | python3 main.py 78 | ``` 79 |
80 | 81 |
82 | Mobile 83 | 84 | 1. Install Termux by *F-Droid* **And** IOS using [iSH](https://ish.app/) 85 | 2. Install requirements: 86 | ```bash 87 | pkg install python git 88 | git clone https://github.com/CPScript/Kitty-Tools 89 | cd Kitty-Tools/LITE 90 | python lite.py 91 | ``` 92 |
93 | 94 |
95 | GitHub Codespace / Replit 96 | 97 | #### Codespace 98 | 1. Create a new Codespace based on the repository 99 | 2. In the terminal, run: 100 | ```bash 101 | python main.py 102 | ``` 103 | 104 | #### Replit 105 | 1. Use this replit link 106 | ```bash 107 | https://replit.com/@Kitty-Tools/Kitty-Tools 108 | ``` 109 |
110 | 111 | ## 📊 Usage Guide 112 | 113 | ### 1. Answer Viewer 114 | 115 | The Answer Viewer module allows you to retrieve answers for Kahoot quizzes: 116 | 117 | 1. Start the application with `python main.py` 118 | 2. Select "Answer Hack" from the main menu 119 | 3. Enter the Kahoot Quiz ID (not the Game PIN) 120 | image 121 | 122 | 5. View answers displayed in an organized format 123 | 6. Optionally export answers to a text file 124 | 125 | ### 2. Kahoot Flooder 126 | 127 | The Flooder creates multiple bot participants in a Kahoot game: 128 | 129 | 1. Start the application with `python main.py` (**Won't work in codespace**) 130 | 2. Select "Kahoot Flooder" from the main menu 131 | 3. Configure bot settings: 132 | - Game PIN 133 | - Number of bots 134 | - Name generation options 135 | - Bot behavior settings 136 | 4. Start the flooder and optionally control bot responses 137 | 138 | ### 3. Graphical Interface 139 | 140 | For a more user-friendly experience: 141 | 142 | 1. Start the application with `python main.py` 143 | 2. Select "GUI" from the main menu 144 | 3. Use the intuitive tabbed interface to access all features 145 | 146 | ## 🔧 Advanced Configuration 147 | 148 | Kitty-Tools supports various advanced configurations and custom settings: 149 | 150 | - **Name Generation** - Generate random names or use custom prefixes 151 | - **Anti-Detection Mode** - Implement techniques to avoid bot detection 152 | - **Export Format Control** - Customize how answers are exported 153 | - **Bot Behavior Patterns** - Configure response timing and answer selection 154 | 155 | ## ❓ Troubleshooting 156 | 157 | **Common Issues:** 158 | 159 | - **Module Not Found** - Run `pip install ` for any missing dependencies 160 | - **Node.js Not Found** - Install Node.js for Flooder functionality 161 | - **Game PIN Connection Fails** - Verify the PIN and ensure the Kahoot game is active 162 | - **Performance Issues** - Use LITE version on low-resource systems 163 | 164 | ## 📜 Legal Disclaimer 165 | 166 | Kitty-Tools is provided for **educational purposes only**. This software is designed to demonstrate educational platform vulnerabilities and to be used in controlled, ethical environments. 167 | 168 | The developers do not endorse or encourage any use of this software that violates terms of service of educational platforms or disrupts educational activities. Use at your own risk and responsibility. 169 | 170 | ## 🤝 Contributors 171 | 172 | A special thanks to all contributors who have helped make Kitty-Tools better: 173 | 174 | - **@CPScript** - Lead Developer & Project Maintainer 175 | - **@Ccode-lang** - Core Development & API Integration 176 | - **@xTobyPlayZ** - Flooder Module Development 177 | - **@cheepling** - Quality Assurance & Bug Reporting 178 | - **@Zacky2613** - Technical Support & Issue Resolution 179 | - **@KiraKenjiro** - Code Review & Optimization 180 | 181 | ## 📱 Mobile Support 182 | 183 | For mobile devices, we provide Kitty-Tools LITE - a streamlined version designed specifically for Android via Termux: 184 | 185 | ```bash 186 | cd Kitty-Tools/LITE 187 | python lite.py 188 | ``` 189 | 190 | The LITE version offers core functionality with reduced resource requirements. 191 | 192 | ## 🌟 Star the Project 193 | 194 | If you find Kitty-Tools useful, please consider giving it a star on GitHub to help others discover it! 195 | 196 | --- 197 | 198 |

199 | © 2025 Kitty-Tools | All rights reserved 200 |

201 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /src/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import platform 5 | import subprocess 6 | import time 7 | 8 | class Colors: 9 | RED = "\033[91m" 10 | GREEN = "\033[92m" 11 | YELLOW = "\033[93m" 12 | BLUE = "\033[94m" 13 | CYAN = "\033[96m" 14 | RESET = "\033[0m" 15 | 16 | @staticmethod 17 | def print(text, color): 18 | print(f"{color}{text}{Colors.RESET}") 19 | 20 | def clear_screen(): 21 | if platform.system().lower() == "windows": 22 | os.system('cls') 23 | else: 24 | os.system('clear') 25 | 26 | def run_command_safe(command, cwd=None, timeout=30): 27 | is_windows = platform.system().lower() == "windows" 28 | 29 | try: 30 | result = subprocess.run( 31 | command, 32 | cwd=cwd, 33 | shell=is_windows, 34 | capture_output=True, 35 | text=True, 36 | timeout=timeout 37 | ) 38 | return result.returncode == 0, result.stdout, result.stderr 39 | except subprocess.TimeoutExpired: 40 | return False, "", "Command timed out" 41 | except Exception as e: 42 | return False, "", str(e) 43 | 44 | def install_essential_packages(): 45 | Colors.print("Installing essential packages for flood.js...", Colors.CYAN) 46 | 47 | script_dir = os.path.dirname(os.path.abspath(__file__)) 48 | project_root = os.path.dirname(script_dir) 49 | 50 | essential_packages = [ 51 | "readline-sync", 52 | "request", 53 | "random-name", 54 | "an-array-of-english-words", 55 | "console-title", 56 | "beepbeep" 57 | ] 58 | 59 | kahoot_packages = [ 60 | "kahoot.js-latest", 61 | "kahoot.js-api", 62 | "node-kahoot" 63 | ] 64 | 65 | installed_count = 0 66 | 67 | for package in essential_packages: 68 | Colors.print(f"Installing {package}...", Colors.YELLOW) 69 | success, stdout, stderr = run_command_safe( 70 | ["npm", "install", package, "--no-fund", "--no-audit"], 71 | cwd=project_root 72 | ) 73 | 74 | if success: 75 | Colors.print(f"Successfully installed {package}", Colors.GREEN) 76 | installed_count += 1 77 | else: 78 | Colors.print(f"Failed to install {package}", Colors.RED) 79 | 80 | kahoot_installed = False 81 | for package in kahoot_packages: 82 | if kahoot_installed: 83 | break 84 | 85 | Colors.print(f"Trying {package}...", Colors.YELLOW) 86 | success, stdout, stderr = run_command_safe( 87 | ["npm", "install", package, "--no-fund", "--no-audit"], 88 | cwd=project_root 89 | ) 90 | 91 | if success: 92 | Colors.print(f"Successfully installed {package}", Colors.GREEN) 93 | installed_count += 1 94 | kahoot_installed = True 95 | else: 96 | Colors.print(f"Failed to install {package}", Colors.RED) 97 | 98 | return installed_count > 0 99 | 100 | def try_run_flood_js(): 101 | script_dir = os.path.dirname(os.path.abspath(__file__)) 102 | project_root = os.path.dirname(script_dir) 103 | flood_js_path = os.path.join(project_root, "Kitty", "Flood", "flood.js") 104 | 105 | if not os.path.exists(flood_js_path): 106 | Colors.print(f"ERROR: flood.js not found at {flood_js_path}", Colors.RED) 107 | return False 108 | 109 | Colors.print(f"Found flood.js at: {flood_js_path}", Colors.GREEN) 110 | Colors.print("Starting Kahoot Flooder...", Colors.CYAN) 111 | print("=" * 50) 112 | 113 | try: 114 | is_windows = platform.system().lower() == "windows" 115 | 116 | process = subprocess.Popen( 117 | ["node", flood_js_path], 118 | cwd=os.path.dirname(flood_js_path), 119 | stdout=subprocess.PIPE, 120 | stderr=subprocess.STDOUT, 121 | text=True, 122 | bufsize=1, 123 | universal_newlines=True, 124 | shell=is_windows 125 | ) 126 | 127 | while True: 128 | output = process.stdout.readline() 129 | if output == '' and process.poll() is not None: 130 | break 131 | if output: 132 | print(output.strip()) 133 | 134 | rc = process.poll() 135 | return rc == 0 136 | 137 | except FileNotFoundError: 138 | Colors.print("ERROR: Node.js not found!", Colors.RED) 139 | Colors.print("Please install Node.js from https://nodejs.org/", Colors.YELLOW) 140 | return False 141 | except KeyboardInterrupt: 142 | Colors.print("\\nFlooder stopped by user", Colors.YELLOW) 143 | return True 144 | except Exception as e: 145 | Colors.print(f"ERROR: {e}", Colors.RED) 146 | return False 147 | 148 | def main(): 149 | clear_screen() 150 | 151 | Colors.print("Kitty-Tools Flooder Launcher", Colors.CYAN) 152 | print("=" * 40) 153 | Colors.print("This script will run the Kahoot flooder from Kitty/Flood/flood.js", Colors.BLUE) 154 | print("=" * 40) 155 | 156 | node_available, _, _ = run_command_safe(["node", "--version"]) 157 | if not node_available: 158 | Colors.print("ERROR: Node.js is not installed or not in PATH", Colors.RED) 159 | Colors.print("Please install Node.js from https://nodejs.org/", Colors.YELLOW) 160 | input("Press Enter to exit...") 161 | return 162 | 163 | npm_available, _, _ = run_command_safe(["npm", "--version"]) 164 | if not npm_available: 165 | Colors.print("ERROR: npm is not available", Colors.RED) 166 | input("Press Enter to exit...") 167 | return 168 | 169 | Colors.print("Node.js and npm are available", Colors.GREEN) 170 | print() 171 | 172 | Colors.print("Attempting to run flood.js...", Colors.CYAN) 173 | 174 | script_dir = os.path.dirname(os.path.abspath(__file__)) 175 | project_root = os.path.dirname(script_dir) 176 | 177 | test_modules = [ 178 | "readline-sync", 179 | "kahoot.js-latest", 180 | "an-array-of-english-words", 181 | "request", 182 | "random-name", 183 | "console-title", 184 | "beepbeep" 185 | ] 186 | 187 | missing_modules = [] 188 | for module in test_modules: 189 | test_success, _, _ = run_command_safe( 190 | ["node", "-e", f"require('{module}'); console.log('{module} OK');"], 191 | cwd=project_root, 192 | timeout=5 193 | ) 194 | if not test_success: 195 | missing_modules.append(module) 196 | 197 | if not missing_modules: 198 | Colors.print("All required modules are available!", Colors.GREEN) 199 | print() 200 | if try_run_flood_js(): 201 | Colors.print("Flooder completed successfully!", Colors.GREEN) 202 | else: 203 | Colors.print("Flooder encountered an error", Colors.YELLOW) 204 | else: 205 | Colors.print(f"Missing modules: {', '.join(missing_modules)}", Colors.YELLOW) 206 | Colors.print("Installing required packages...", Colors.CYAN) 207 | print() 208 | 209 | if install_essential_packages(): 210 | Colors.print("Package installation completed!", Colors.GREEN) 211 | print() 212 | Colors.print("Trying to run flood.js again...", Colors.CYAN) 213 | print() 214 | 215 | if try_run_flood_js(): 216 | Colors.print("Flooder completed successfully!", Colors.GREEN) 217 | else: 218 | Colors.print("Flooder still failed to run", Colors.RED) 219 | print() 220 | Colors.print("Manual troubleshooting:", Colors.YELLOW) 221 | print("1. Try running: npm install kahoot.js-latest") 222 | print("2. Try running: npm install readline-sync") 223 | print("3. Try running: node Kitty/Flood/flood.js") 224 | else: 225 | Colors.print("Failed to install required packages", Colors.RED) 226 | Colors.print("Please try manually installing with:", Colors.YELLOW) 227 | print(" npm install kahoot.js-latest") 228 | print(" npm install readline-sync") 229 | 230 | print() 231 | input("Press Enter to exit...") 232 | 233 | if __name__ == "__main__": 234 | try: 235 | main() 236 | except KeyboardInterrupt: 237 | Colors.print("\\nExiting...", Colors.YELLOW) 238 | except Exception as e: 239 | Colors.print(f"Unexpected error: {e}", Colors.RED) 240 | input("Press Enter to exit...") 241 | -------------------------------------------------------------------------------- /Kitty/Flood/main.py: -------------------------------------------------------------------------------- 1 | # THE CONTENT IN THIS FILE AND ITS SIMPLICITY IS UGLY AND MAKES MY MIND HURT 2 | 3 | import time 4 | import os 5 | import platform 6 | import subprocess 7 | import json 8 | from os import system 9 | from subprocess import call 10 | 11 | def clear(): 12 | system = platform.system().lower() 13 | 14 | if system == 'windows': 15 | _ = os.system('cls') 16 | elif system == 'linux' or system == 'darwin': 17 | _ = os.system('clear') 18 | elif system == 'android': 19 | _ = subprocess.run(['termux-exec', 'sh', '-c', 'clear'], check=False) 20 | print("Please use LITE!") 21 | exit() 22 | else: 23 | print(f"Unsupported platform, please use Kitty-Tools LITE '{system}'") 24 | print(f"For more info go to https://github.com/CPScript/Kitty-Tools/extra.md") 25 | 26 | def check_node_installed(): 27 | """Check if Node.js is installed""" 28 | try: 29 | result = subprocess.run(['node', '--version'], capture_output=True, text=True, check=True) 30 | return True, result.stdout.strip() 31 | except (subprocess.CalledProcessError, FileNotFoundError): 32 | return False, None 33 | 34 | def check_npm_installed(): 35 | """Check if npm is installed""" 36 | try: 37 | result = subprocess.run(['npm', '--version'], capture_output=True, text=True, check=True) 38 | return True, result.stdout.strip() 39 | except (subprocess.CalledProcessError, FileNotFoundError): 40 | return False, None 41 | 42 | def install_nodejs_guide(): 43 | """Show Node.js installation guide""" 44 | system_name = platform.system().lower() 45 | 46 | print("\nNode.js is required but not found on your system.") 47 | print("Please install Node.js using the following instructions:") 48 | print() 49 | 50 | if system_name == "windows": 51 | print("Windows Installation:") 52 | print("1. Go to https://nodejs.org/") 53 | print("2. Download the Windows Installer (.msi)") 54 | print("3. Run the installer and follow the installation wizard") 55 | print("4. Make sure to check 'Add to PATH' during installation") 56 | print("5. Restart your computer after installation") 57 | print() 58 | print("Alternative - Using Chocolatey:") 59 | print("choco install nodejs") 60 | 61 | elif system_name == "darwin": # macOS 62 | print("macOS Installation:") 63 | print("Option 1 - Using Homebrew (recommended):") 64 | print(" brew install node") 65 | print() 66 | print("Option 2 - Official installer:") 67 | print(" 1. Go to https://nodejs.org/") 68 | print(" 2. Download the macOS Installer (.pkg)") 69 | print(" 3. Run the installer") 70 | 71 | elif system_name == "linux": 72 | print("Linux Installation:") 73 | print("Ubuntu/Debian:") 74 | print(" sudo apt update && sudo apt install nodejs npm") 75 | print() 76 | print("Fedora:") 77 | print(" sudo dnf install nodejs npm") 78 | print() 79 | print("Arch Linux:") 80 | print(" sudo pacman -S nodejs npm") 81 | print() 82 | print("CentOS/RHEL:") 83 | print(" sudo yum install nodejs npm") 84 | 85 | else: 86 | print("For other platforms, please visit: https://nodejs.org/") 87 | 88 | print() 89 | print("After installation, restart your terminal and run this script again.") 90 | 91 | def create_package_json(): 92 | """Create package.json file for dependencies""" 93 | script_dir = os.path.dirname(os.path.abspath(__file__)) 94 | package_json_path = os.path.join(script_dir, 'package.json') 95 | 96 | package_data = { 97 | "name": "kitty-tools-kahoot-flooder", 98 | "version": "1.4.0", 99 | "description": "Kahoot game flooding utility", 100 | "main": "flood.js", 101 | "dependencies": { 102 | "readline-sync": "1.4.10", 103 | "kahoot.js-updated": "3.1.2", 104 | "an-array-of-english-words": "2.0.0", 105 | "request": "2.88.2", 106 | "random-name": "0.1.2", 107 | "console-title": "1.1.0", 108 | "beepbeep": "1.3.0" 109 | }, 110 | "engines": { 111 | "node": ">=12.0.0" 112 | } 113 | } 114 | 115 | try: 116 | with open(package_json_path, 'w') as f: 117 | json.dump(package_data, f, indent=2) 118 | print("Created package.json file") 119 | return True 120 | except Exception as e: 121 | print(f"Failed to create package.json: {e}") 122 | return False 123 | 124 | def install_node_packages(): 125 | """Install required Node.js packages""" 126 | script_dir = os.path.dirname(os.path.abspath(__file__)) 127 | 128 | print("Installing Node.js dependencies...") 129 | 130 | # Create package.json first 131 | if not create_package_json(): 132 | return False 133 | 134 | # Clean install to fix corrupted packages 135 | print("Cleaning previous installations...") 136 | node_modules_path = os.path.join(script_dir, 'node_modules') 137 | package_lock_path = os.path.join(script_dir, 'package-lock.json') 138 | 139 | # Remove node_modules and package-lock.json if they exist 140 | try: 141 | if os.path.exists(node_modules_path): 142 | import shutil 143 | shutil.rmtree(node_modules_path) 144 | print("Removed old node_modules directory") 145 | 146 | if os.path.exists(package_lock_path): 147 | os.remove(package_lock_path) 148 | print("Removed old package-lock.json") 149 | except Exception as e: 150 | print(f"Warning: Could not clean old files: {e}") 151 | 152 | try: 153 | # Clear npm cache 154 | print("Clearing npm cache...") 155 | subprocess.run( 156 | ['npm', 'cache', 'clean', '--force'], 157 | cwd=script_dir, 158 | capture_output=True, 159 | text=True, 160 | check=False 161 | ) 162 | 163 | # Try installing from package.json 164 | print("Installing packages from package.json...") 165 | result = subprocess.run( 166 | ['npm', 'install', '--no-fund', '--no-audit', '--force'], 167 | cwd=script_dir, 168 | capture_output=True, 169 | text=True, 170 | check=True 171 | ) 172 | 173 | if result.returncode == 0: 174 | print("Successfully installed all Node.js packages") 175 | return True 176 | else: 177 | print(f"npm install failed: {result.stderr}") 178 | return False 179 | 180 | except subprocess.CalledProcessError as e: 181 | print(f"Package installation failed, trying individual installation...") 182 | 183 | # Try installing packages individually with specific versions 184 | packages_with_versions = [ 185 | "readline-sync@1.4.10", 186 | "kahoot.js-updated@3.1.2", 187 | "an-array-of-english-words@2.0.0", 188 | "request@2.88.2", 189 | "random-name@0.1.2", 190 | "console-title@1.1.0", 191 | "beepbeep@1.3.0" 192 | ] 193 | 194 | success_count = 0 195 | for package in packages_with_versions: 196 | try: 197 | print(f"Installing {package}...") 198 | subprocess.run( 199 | ['npm', 'install', package, '--no-fund', '--no-audit', '--force'], 200 | cwd=script_dir, 201 | capture_output=True, 202 | text=True, 203 | check=True 204 | ) 205 | print(f"Successfully installed {package}") 206 | success_count += 1 207 | except subprocess.CalledProcessError: 208 | print(f"Failed to install {package}") 209 | 210 | # Special handling for kahoot.js-updated 211 | if "kahoot.js-updated" in package: 212 | print("Trying alternative Kahoot package...") 213 | try: 214 | subprocess.run( 215 | ['npm', 'install', 'kahoot.js@3.0.4', '--no-fund', '--no-audit', '--force'], 216 | cwd=script_dir, 217 | capture_output=True, 218 | text=True, 219 | check=True 220 | ) 221 | print("Successfully installed alternative kahoot.js package") 222 | success_count += 1 223 | except subprocess.CalledProcessError: 224 | print("Failed to install alternative Kahoot package") 225 | 226 | if success_count >= 6: # Allow one failure 227 | print("Most packages installed successfully") 228 | return True 229 | else: 230 | print("Too many packages failed to install") 231 | return False 232 | except Exception as e: 233 | print(f"Unexpected error during package installation: {e}") 234 | return False 235 | 236 | def verify_installation(): 237 | """Verify that Node.js modules are installed correctly""" 238 | script_dir = os.path.dirname(os.path.abspath(__file__)) 239 | 240 | test_script = ''' 241 | const modules = [ 242 | 'readline-sync', 243 | 'an-array-of-english-words', 244 | 'request', 245 | 'random-name', 246 | 'console-title', 247 | 'beepbeep' 248 | ]; 249 | 250 | // Special handling for Kahoot module with fallback 251 | const kahootModules = ['kahoot.js-updated', 'kahoot.js']; 252 | 253 | let success = 0; 254 | let failed = 0; 255 | 256 | // Test regular modules 257 | for (const moduleName of modules) { 258 | try { 259 | require(moduleName); 260 | console.log(`SUCCESS: ${moduleName}`); 261 | success++; 262 | } catch (error) { 263 | console.log(`FAILED: ${moduleName} - ${error.message}`); 264 | failed++; 265 | } 266 | } 267 | 268 | // Test Kahoot module with fallback 269 | let kahootSuccess = false; 270 | for (const kahootModule of kahootModules) { 271 | try { 272 | require(kahootModule); 273 | console.log(`SUCCESS: ${kahootModule}`); 274 | kahootSuccess = true; 275 | success++; 276 | break; 277 | } catch (error) { 278 | console.log(`FAILED: ${kahootModule} - ${error.message}`); 279 | } 280 | } 281 | 282 | if (!kahootSuccess) { 283 | console.log('FAILED: No working Kahoot module found'); 284 | failed++; 285 | } 286 | 287 | console.log(`SUMMARY: ${success} success, ${failed} failed`); 288 | process.exit(failed > 0 ? 1 : 0); 289 | ''' 290 | 291 | test_file = os.path.join(script_dir, 'test_modules.js') 292 | 293 | try: 294 | with open(test_file, 'w') as f: 295 | f.write(test_script) 296 | 297 | result = subprocess.run(['node', test_file], capture_output=True, text=True, cwd=script_dir) 298 | 299 | # Parse output 300 | for line in result.stdout.split('\n'): 301 | if line.startswith('SUCCESS:'): 302 | print(f"✓ Module verified: {line.split(': ')[1]}") 303 | elif line.startswith('FAILED:'): 304 | print(f"✗ Module failed: {line.split(': ')[1]}") 305 | elif line.startswith('SUMMARY:'): 306 | print(line) 307 | 308 | # Clean up test file 309 | os.remove(test_file) 310 | 311 | return result.returncode == 0 312 | 313 | except Exception as e: 314 | print(f"Verification failed: {e}") 315 | return False 316 | 317 | def run_flood_script(): 318 | """Run the flood.js script""" 319 | script_dir = os.path.dirname(os.path.abspath(__file__)) 320 | flood_js_path = os.path.join(script_dir, 'flood.js') 321 | 322 | if not os.path.exists(flood_js_path): 323 | print(f"Error: flood.js not found at {flood_js_path}") 324 | return False 325 | 326 | try: 327 | print("Starting Kahoot flooder...") 328 | subprocess.run(['node', flood_js_path], cwd=script_dir, check=False) 329 | return True 330 | except KeyboardInterrupt: 331 | print("\nFlooder stopped by user") 332 | return True 333 | except Exception as e: 334 | print(f"Error running flooder: {e}") 335 | return False 336 | 337 | clear() # call check 338 | 339 | print("Start???") 340 | print("yes | no") 341 | choice = input("").lower() 342 | 343 | if choice == "yes": 344 | time.sleep(1) 345 | clear() 346 | 347 | # Check if Node.js is installed 348 | node_installed, node_version = check_node_installed() 349 | npm_installed, npm_version = check_npm_installed() 350 | 351 | if not node_installed: 352 | print("Node.js is not installed!") 353 | install_nodejs_guide() 354 | input("\nPress Enter to return to main menu...") 355 | clear() 356 | call(["python", "../../main.py"]) 357 | exit() 358 | 359 | if not npm_installed: 360 | print("npm is not installed!") 361 | print("npm is usually installed with Node.js. Please reinstall Node.js.") 362 | input("\nPress Enter to return to main menu...") 363 | clear() 364 | call(["python", "../../main.py"]) 365 | exit() 366 | 367 | print(f"Node.js found: {node_version}") 368 | print(f"npm found: {npm_version}") 369 | 370 | # Check if node exists 371 | print("Checking if Node.js is accessible...") 372 | try: 373 | import node # does node exist 374 | except ModuleNotFoundError: 375 | print("Attempting to install node Python package...") 376 | time.sleep(2) 377 | os.system("pip install node") # installation 378 | clear() 379 | 380 | # Install Node.js packages 381 | if not install_node_packages(): 382 | print("Failed to install required Node.js packages!") 383 | print("\nTroubleshooting:") 384 | print("1. Check your internet connection") 385 | print("2. Try running as administrator/sudo") 386 | print("3. Clear npm cache: npm cache clean --force") 387 | input("\nPress Enter to return to main menu...") 388 | clear() 389 | call(["python", "../../main.py"]) 390 | exit() 391 | 392 | # Verify installation 393 | if not verify_installation(): 394 | print("Warning: Some modules failed verification") 395 | print("The flooder might still work, but some features may be limited") 396 | 397 | proceed = input("Continue anyway? (y/n): ").lower() 398 | if proceed != 'y': 399 | clear() 400 | call(["python", "../../main.py"]) 401 | exit() 402 | 403 | clear() 404 | print("Executing!") 405 | time.sleep(2) 406 | clear() 407 | 408 | # Run the flooder 409 | if not run_flood_script(): 410 | print("Flooder execution failed!") 411 | input("\nPress Enter to return to main menu...") 412 | 413 | clear() 414 | call(["python", "../../main.py"]) 415 | 416 | if choice == "no": 417 | print("\nRe-Running main menu file!") 418 | time.sleep(3) 419 | clear() 420 | call(["python", "../../main.py"]) 421 | -------------------------------------------------------------------------------- /Kitty/Flood/flood.js: -------------------------------------------------------------------------------- 1 | readline = require('readline-sync'); 2 | const Kahoot = require("kahoot.js-latest"); 3 | var words = require('an-array-of-english-words') 4 | const request = require('request'); 5 | var random = require('random-name') 6 | var setTitle = require('console-title'); 7 | setTitle('flood.js'); 8 | var beep = require('beepbeep') 9 | 10 | function getRandomInt(min, max) { 11 | min = Math.ceil(min); 12 | max = Math.floor(max); 13 | return Math.floor(Math.random() * (max - min + 1)) + min; 14 | } 15 | 16 | function getName() { 17 | ran = getRandomInt(1, 5) 18 | if (ran == 5) { 19 | request('https://apis.kahoot.it/namerator', function(error, response, body) { 20 | if (error) { console.log(error); } 21 | return JSON.parse(body).name 22 | }); 23 | } 24 | if (ran == 4) { 25 | return words[getRandomInt(1, words.length)] 26 | } 27 | if (ran == 3) { 28 | return (random.first()) 29 | } 30 | if (ran == 2) { 31 | return (random.first() + random.middle() + random.last()) 32 | } 33 | if (ran == 1) { 34 | return (random.first() + random.last()) 35 | } 36 | } 37 | 38 | function shuffle(array) { 39 | var currentIndex = array.length, temporaryValue, randomIndex; 40 | 41 | while (0 !== currentIndex) { 42 | 43 | randomIndex = Math.floor(Math.random() * currentIndex); 44 | currentIndex -= 1; 45 | 46 | temporaryValue = array[currentIndex]; 47 | array[currentIndex] = array[randomIndex]; 48 | array[randomIndex] = temporaryValue; 49 | } 50 | 51 | return array; 52 | } 53 | 54 | function getAnswerDelay() { 55 | const baseDelay = 7500; // Delay for promot - question time (DO NOT EDIT) 56 | const userDelay = answerdelay || 1500; 57 | const randomVariation = getRandomInt(-200, 500); 58 | 59 | const totalDelay = baseDelay + userDelay + randomVariation; 60 | return Math.max(1000, totalDelay); 61 | } 62 | function getAnswerCount(question) { 63 | try { 64 | if (question.type !== "quiz" && question.type !== "survey") { 65 | return 0; 66 | } 67 | 68 | if (question.numberOfAnswers && typeof question.numberOfAnswers === 'number') { 69 | return Math.max(1, Math.min(question.numberOfAnswers, 4)); 70 | } 71 | 72 | if (question.quizQuestionAnswers && Array.isArray(question.quizQuestionAnswers) && 73 | typeof question.questionIndex === 'number' && 74 | question.questionIndex >= 0 && 75 | question.questionIndex < question.quizQuestionAnswers.length && 76 | question.quizQuestionAnswers[question.questionIndex] != null) { 77 | return Math.max(1, Math.min(question.quizQuestionAnswers[question.questionIndex], 4)); 78 | } 79 | 80 | if (question.choices && Array.isArray(question.choices)) { 81 | return Math.max(1, Math.min(question.choices.length, 4)); 82 | } 83 | 84 | if (question.answers && Array.isArray(question.answers)) { 85 | return Math.max(1, Math.min(question.answers.length, 4)); 86 | } 87 | 88 | return 4; 89 | } catch (error) { 90 | console.log("Error getting answer count for " + question.type + ", using default of 4:", error.message); 91 | return 4; 92 | } 93 | } 94 | 95 | process.setMaxListeners(Number.POSITIVE_INFINITY) 96 | 97 | function ads() { 98 | console.clear() 99 | console.log("==================================================") 100 | console.log("Made by ZaWarudo1") 101 | console.log("Enhancements by; CPScript") 102 | console.log("==================================================") 103 | console.log("My own version will be made soon with;\n") 104 | console.log("> Better answer handling") 105 | console.log("> Better error handling") 106 | console.log("> Better UI") 107 | console.log("==================================================\n") 108 | } 109 | ads() 110 | 111 | antibotmode = readline.question('Use the new antibot mode? (y/n)> '); 112 | if (antibotmode == "y") { 113 | console.log("NOTE: 2-factor brute forcing does not work with antibot.") 114 | } 115 | 116 | pin = readline.question('Enter Game PIN --> '); 117 | bots = readline.question('Enter number of bots --> '); 118 | 119 | answerdelay = readline.question('Answer delay in milliseconds (1-1000, recommended 500-2000) --> '); 120 | if (answerdelay == "" || isNaN(answerdelay) || answerdelay < 1 || answerdelay > 10000) { 121 | answerdelay = 1500; 122 | console.log("Using default answer delay: 1500ms"); 123 | } else { 124 | answerdelay = parseInt(answerdelay); 125 | console.log("Answer delay set to: " + answerdelay + "ms"); 126 | } 127 | 128 | if (antibotmode == "y") { 129 | ranname = true 130 | er = "n" 131 | } else { 132 | ranname = readline.question('Use random name? (y/n) --> '); 133 | 134 | if (ranname == "y") { 135 | ranname = true 136 | } else { 137 | ranname = false 138 | botname = readline.question('Enter name --> '); 139 | botprefix = "" 140 | } 141 | er = readline.question('Use name bypass? (y/n) --> '); 142 | } 143 | 144 | usercontrolled = readline.question('Control the bots manually? (y/n) --> '); 145 | 146 | if (usercontrolled == "y") { 147 | usercontrolled = true 148 | beepis = readline.question('Beep when the bots need controlling? (y/n) --> '); 149 | } else { 150 | usercontrolled = false 151 | beepis = "n" 152 | } 153 | 154 | console.clear() 155 | 156 | repeattimes = 0 157 | 158 | function sendjoin(name, id) { 159 | if (ranname) { 160 | join(getName(), id) 161 | } else { 162 | join(name, id) 163 | } 164 | } 165 | 166 | function spam() { 167 | 168 | if (repeattimes == bots) { 169 | console.log("All join requests have finished.") 170 | } else { 171 | repeattimes++ 172 | 173 | if (ranname) { rt = getRandomInt(90, 200) } else { rt = 15 } 174 | 175 | setTimeout(() => { 176 | spam() 177 | }, rt); 178 | setTimeout(() => { 179 | 180 | if (ranname) { 181 | sendjoin("This will become a random name!", bots - repeattimes - 1) 182 | } else { 183 | sendjoin(botname + (bots - repeattimes - 1), (bots - repeattimes - 1)) 184 | } 185 | }, rt); 186 | } 187 | } 188 | 189 | process.setMaxListeners(Number.POSITIVE_INFINITY) 190 | 191 | Arandomint = 0 192 | todo = false 193 | function join(name, idee) { 194 | while (name == undefined) { 195 | name = getName() 196 | } 197 | const client = new Kahoot(); 198 | client.setMaxListeners(Number.POSITIVE_INFINITY) 199 | if (er == "y") { 200 | client.join(pin, name.replace(/a/g, 'ᗩ').replace(/b/g, 'ᗷ').replace(/c/g, 'ᑕ').replace(/d/g, 'ᗪ').replace(/e/g, 'E').replace(/f/g, 'ᖴ').replace(/g/g, 'G').replace(/h/g, 'ᕼ').replace(/i/g, 'I').replace(/j/g, 'ᒍ').replace(/k/g, 'K').replace(/l/g, 'ᒪ').replace(/m/g, 'ᗰ').replace(/n/g, 'ᑎ').replace(/o/g, 'O').replace(/p/g, 'ᑭ').replace(/q/g, 'ᑫ').replace(/r/g, 'ᖇ').replace(/s/g, 'ᔕ').replace(/t/g, 'T').replace(/u/g, 'ᑌ').replace(/v/g, 'ᐯ').replace(/w/g, 'ᗯ').replace(/x/g, '᙭').replace(/y/g, 'Y').replace(/z/g, 'ᘔ').replace(/A/g, 'ᗩ').replace(/B/g, 'ᗷ').replace(/C/g, 'ᑕ').replace(/D/g, 'ᗪ').replace(/E/g, 'E').replace(/F/g, 'ᖴ').replace(/G/g, 'G').replace(/H/g, 'ᕼ').replace(/I/g, 'I').replace(/J/g, 'ᒍ').replace(/K/g, 'K').replace(/L/g, 'ᒪ').replace(/M/g, 'ᗰ').replace(/N/g, 'ᑎ').replace(/O/g, 'O').replace(/P/g, 'ᑭ').replace(/Q/g, 'ᑫ').replace(/R/g, 'ᖇ').replace(/S/g, 'ᔕ').replace(/T/g, 'T').replace(/U/g, 'ᑌ').replace(/V/g, 'ᐯ').replace(/W/g, 'ᗯ').replace(/X/g, '᙭').replace(/Y/g, 'Y').replace(/Z/g, 'ᘔ'), [random.first(), random.last()]).catch(err => { 201 | if (err.description == "Duplicate name" & ranname) { 202 | sendjoin(name, idee) 203 | } else { 204 | console.log("Client " + idee + " failed to join with the error '" + err.description + "'") 205 | client.leave() 206 | } 207 | }); 208 | } else { 209 | client.join(pin, name, [random.first(), random.last()]).catch(err => { 210 | if (err.description == "Duplicate name" & ranname) { 211 | sendjoin(name, idee) 212 | } else { 213 | console.log("Client " + idee + " failed to join with the error '" + err.description + "'") 214 | client.leave() 215 | } 216 | }); 217 | } 218 | var list = [0, 1, 2, 3] 219 | todo = false 220 | client.on("Joined", info => { 221 | if (info.twoFactorAuth) { 222 | setInterval(() => { 223 | if (!todo == false) { 224 | client.answerTwoFactorAuth(todo) 225 | } 226 | shuffle(list) 227 | client.answerTwoFactorAuth(list) 228 | }, 1000); 229 | } 230 | }); 231 | client.on("TwoFactorCorrect", function() { 232 | console.log(name + " Got 2-factor correct!") 233 | todo = list 234 | }) 235 | 236 | client.on("QuestionReady", question => { 237 | try { 238 | if (idee == 1 & beepis == "y") { 239 | beep() 240 | } 241 | 242 | if (question.type !== "quiz" && question.type !== "survey" && question.type !== "word_cloud" && question.type !== "open_ended" && question.type !== "jumble") { 243 | console.log(name + " skipped question type: " + question.type + " (not supported)") 244 | return; 245 | } 246 | 247 | everyoneanswerthis = false 248 | 249 | if (question.type == "word_cloud") { 250 | if (usercontrolled) { 251 | if (idee == 1) { 252 | everyoneanswerthis = true 253 | answer = readline.question('type your answer> '); 254 | everyoneanswerthis = answer 255 | Arandomint = answer 256 | setTimeout(() => { client.answer(answer) }, getAnswerDelay()); 257 | 258 | } else { 259 | var waittill = setInterval(() => { 260 | if (!everyoneanswerthis == false || !everyoneanswerthis == true) { 261 | clearInterval(waittill); 262 | setTimeout(() => { 263 | client.answer(Arandomint) 264 | }, getAnswerDelay()); 265 | } 266 | }, 100); 267 | } 268 | } else { 269 | console.log(name + " answered with 'kahootflood.weebly.com'") 270 | setTimeout(() => { client.answer("kahootflood.weebly.com") }, getAnswerDelay()); 271 | } 272 | } 273 | 274 | if (question.type == "jumble") { 275 | console.log("User controlling is not currently available for jumbles. The bot " + name + " responded with a random answer.") 276 | const answerCount = getAnswerCount(question); 277 | if (answerCount > 0) { 278 | setTimeout(() => { client.answer(getRandomInt(0, answerCount - 1)) }, getAnswerDelay()); 279 | } else { 280 | console.log(name + " skipped jumble question (no answer count available)") 281 | } 282 | } 283 | 284 | if (question.type == "quiz") { 285 | const answerCount = getAnswerCount(question); 286 | 287 | if (answerCount == 0) { 288 | console.log(name + " skipped quiz question (no answer count available)") 289 | return; 290 | } 291 | 292 | if (usercontrolled) { 293 | if (answerCount == 2) { 294 | if (idee == 1) { 295 | everyoneanswerthis = true 296 | answer = readline.question('t for triangle, d for diamond> '); 297 | answer = answer.replace('t', 1).replace('d', 2) 298 | everyoneanswerthis = answer 299 | Arandomint = answer 300 | setTimeout(() => { client.answer(answer - 1) }, getAnswerDelay()); 301 | 302 | } else { 303 | var waittill = setInterval(() => { 304 | if (!everyoneanswerthis == false || !everyoneanswerthis == true) { 305 | clearInterval(waittill); 306 | setTimeout(() => { 307 | client.answer(Arandomint - 1) 308 | }, getAnswerDelay()); 309 | } 310 | }, 100); 311 | } 312 | } 313 | 314 | if (answerCount == 3) { 315 | if (idee == 1) { 316 | everyoneanswerthis = true 317 | answer = readline.question('t for triangle, d for diamond, c for circle> '); 318 | answer = answer.replace('t', 1).replace('d', 2).replace('c', 3) 319 | everyoneanswerthis = answer 320 | Arandomint = answer 321 | setTimeout(() => { client.answer(answer - 1) }, getAnswerDelay()); 322 | 323 | } else { 324 | var waittill = setInterval(() => { 325 | if (!everyoneanswerthis == false || !everyoneanswerthis == true) { 326 | clearInterval(waittill); 327 | setTimeout(() => { 328 | client.answer(Arandomint - 1) 329 | }, getAnswerDelay()); 330 | } 331 | }, 100); 332 | } 333 | } 334 | 335 | if (answerCount == 4) { 336 | if (idee == 1) { 337 | everyoneanswerthis = true 338 | answer = readline.question('t for triangle, d for diamond, c for circle or s for square > '); 339 | answer = answer.replace('t', 1).replace('d', 2).replace('c', 3).replace('s', 4) 340 | everyoneanswerthis = answer 341 | Arandomint = answer 342 | setTimeout(() => { client.answer(answer - 1) }, getAnswerDelay()); 343 | 344 | } else { 345 | var waittill = setInterval(() => { 346 | if (!everyoneanswerthis == false || !everyoneanswerthis == true) { 347 | clearInterval(waittill); 348 | setTimeout(() => { 349 | client.answer(Arandomint - 1) 350 | }, getAnswerDelay()); 351 | } 352 | }, 100); 353 | } 354 | } 355 | } else { 356 | setTimeout(() => { 357 | try { 358 | toanswer = getRandomInt(0, answerCount - 1) 359 | console.log(name + " answered with option " + (toanswer + 1) + " after " + getAnswerDelay() + "ms delay") 360 | client.answer(toanswer) 361 | } catch (error) { 362 | console.log(name + " had an error answering: " + error.message) 363 | } 364 | }, getAnswerDelay()); 365 | } 366 | } 367 | 368 | if (question.type == "survey") { 369 | const answerCount = getAnswerCount(question); 370 | 371 | if (answerCount == 0) { 372 | console.log(name + " skipped survey question (no answer count available)") 373 | return; 374 | } 375 | 376 | if (usercontrolled) { 377 | if (idee == 1) { 378 | everyoneanswerthis = true 379 | answer = readline.question('t for triangle, d for diamond, c for circle or s for square > '); 380 | answer = answer.replace('t', 1).replace('d', 2).replace('c', 3).replace('s', 4) 381 | everyoneanswerthis = answer 382 | Arandomint = answer 383 | setTimeout(() => { client.answer(answer - 1) }, getAnswerDelay()); 384 | 385 | } else { 386 | var waittill = setInterval(() => { 387 | if (!everyoneanswerthis == false || !everyoneanswerthis == true) { 388 | clearInterval(waittill); 389 | setTimeout(() => { 390 | client.answer(Arandomint - 1) 391 | }, getAnswerDelay()); 392 | } 393 | }, 100); 394 | } 395 | } else { 396 | setTimeout(() => { 397 | try { 398 | toanswer = getRandomInt(0, answerCount - 1) 399 | console.log(name + " answered survey with option " + (toanswer + 1) + " after " + getAnswerDelay() + "ms delay") 400 | client.answer(toanswer) 401 | } catch (error) { 402 | console.log(name + " had an error answering: " + error.message) 403 | } 404 | }, getAnswerDelay()); 405 | } 406 | } 407 | 408 | if (question.type == "open_ended") { 409 | if (usercontrolled) { 410 | if (idee == 1) { 411 | everyoneanswerthis = true 412 | answer = readline.question('type your answer> '); 413 | everyoneanswerthis = answer 414 | Arandomint = answer 415 | setTimeout(() => { client.answer(answer) }, getAnswerDelay()); 416 | 417 | } else { 418 | var waittill = setInterval(() => { 419 | if (!everyoneanswerthis == false || !everyoneanswerthis == true) { 420 | clearInterval(waittill); 421 | setTimeout(() => { 422 | client.answer(Arandomint) 423 | }, getAnswerDelay()); 424 | } 425 | }, 100); 426 | } 427 | } else { 428 | console.log(name + " answered with 'kahootflood.weebly.com'") 429 | setTimeout(() => { client.answer("kahootflood.weebly.com") }, getAnswerDelay()); 430 | } 431 | } 432 | 433 | } catch (error) { 434 | console.log(name + " had an error handling question: " + error.message) 435 | } 436 | }); 437 | 438 | client.on("Disconnect", reason => { 439 | if (!reason == "Quiz Locked") { 440 | sendjoin(name, idee) 441 | } 442 | }) 443 | 444 | client.on("QuestionEnd", data => { 445 | if (data.isCorrect) { 446 | console.log(name + " Got it correct!") 447 | } else { 448 | console.log(name + " Got it wrong.") 449 | } 450 | }) 451 | client.on("QuizEnd", data => { 452 | console.log("The quiz has ended and " + name + " got rank " + data.rank) 453 | }) 454 | process.on("SIGINT", function() { 455 | process.exit() 456 | }); 457 | } 458 | 459 | console.clear() 460 | console.log("Joining bots") 461 | spam() 462 | -------------------------------------------------------------------------------- /Kitty/client.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from os import system 4 | import platform 5 | import json 6 | import re 7 | import ssl 8 | import random 9 | import threading 10 | from urllib.request import urlopen, Request 11 | from urllib.error import HTTPError, URLError 12 | from urllib.parse import urlparse, parse_qs 13 | from http.client import InvalidURL 14 | 15 | print("Attempting to check if imports are installed; colorama, pystyle.") 16 | time.sleep(1) 17 | 18 | def clear(): 19 | system = platform.system().lower() 20 | 21 | if system == 'windows': 22 | _ = os.system('cls') 23 | elif system == 'linux' or system == 'darwin': 24 | _ = os.system('clear') 25 | elif system == 'android': 26 | _ = os.system('clear') 27 | print("How are you here, leave!") 28 | print("Please use the 'LITE' version so this kahoot client will run smoothly!") 29 | exit() 30 | clear() # Call clear func 31 | 32 | try: 33 | import colorama 34 | import pystyle 35 | except ModuleNotFoundError: 36 | print("Result: You dont have a certain import(s) installed, installing them now") 37 | time.sleep(1) 38 | os.system("pip install colorama") 39 | os.system("pip install pystyle") 40 | clear() 41 | 42 | from urllib.request import urlopen 43 | from urllib.error import HTTPError 44 | from urllib.parse import urlparse, parse_qs 45 | from json import load 46 | from http.client import InvalidURL 47 | import json, random, string, re, ctypes, threading 48 | from colorama import Fore, Style 49 | from pystyle import Write, System, Colors, Colorate, Anime 50 | from datetime import datetime 51 | 52 | # Colors :D 53 | red = Fore.RED 54 | yellow = Fore.YELLOW 55 | green = Fore.GREEN 56 | blue = Fore.BLUE 57 | orange = Fore.RED + Fore.YELLOW 58 | pretty = Fore.LIGHTMAGENTA_EX + Fore.LIGHTCYAN_EX 59 | magenta = Fore.MAGENTA 60 | lightblue = Fore.LIGHTBLUE_EX 61 | cyan = Fore.CYAN 62 | gray = Fore.LIGHTBLACK_EX + Fore.WHITE 63 | reset = Fore.RESET 64 | pink = Fore.LIGHTGREEN_EX + Fore.LIGHTMAGENTA_EX 65 | dark_green = Fore.GREEN + Style.BRIGHT 66 | 67 | output_lock = threading.Lock() 68 | colorama.init() 69 | 70 | class SSLContextManager: 71 | """Handle SSL certificate issues across platforms""" 72 | 73 | @staticmethod 74 | def create_ssl_context(): 75 | """Create SSL context with fallback for certificate issues""" 76 | try: 77 | # Try to create default context first 78 | context = ssl.create_default_context() 79 | 80 | # For macOS, try to use certifi if available 81 | if platform.system() == 'Darwin': 82 | try: 83 | import certifi 84 | context = ssl.create_default_context(cafile=certifi.where()) 85 | except ImportError: 86 | # certifi not available, use default 87 | pass 88 | 89 | return context 90 | except Exception: 91 | # If all else fails, create unverified context 92 | print("Warning: Using unverified SSL context due to certificate issues") 93 | return ssl._create_unverified_context() 94 | 95 | class RateLimiter: 96 | """Rate limiter to avoid getting blocked""" 97 | 98 | def __init__(self, min_delay=1.0, max_delay=3.0): 99 | self.min_delay = min_delay 100 | self.max_delay = max_delay 101 | self.last_request = None 102 | 103 | def wait(self): 104 | """Wait appropriate time between requests""" 105 | if self.last_request: 106 | elapsed = time.time() - self.last_request 107 | delay = random.uniform(self.min_delay, self.max_delay) 108 | 109 | if elapsed < delay: 110 | sleep_time = delay - elapsed 111 | time.sleep(sleep_time) 112 | 113 | self.last_request = time.time() 114 | 115 | # Enhanced Kahoot API 116 | api = "https://play.kahoot.it/rest/kahoots/" 117 | 118 | class Kahoot: 119 | def __init__(self, uuid): 120 | self.uuid = uuid 121 | self.rate_limiter = RateLimiter() 122 | self.ssl_context = SSLContextManager.create_ssl_context() 123 | 124 | try: 125 | if not re.fullmatch(r"^[A-Za-z0-9-]*$", uuid): 126 | self.data = False 127 | else: 128 | self.data = self._fetch_quiz_data(uuid) 129 | except HTTPError or InvalidURL: 130 | self.data = False 131 | 132 | def _get_headers(self): 133 | """Generate realistic browser headers""" 134 | user_agents = [ 135 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 136 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 137 | 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' 138 | ] 139 | 140 | return { 141 | 'User-Agent': random.choice(user_agents), 142 | 'Accept': 'application/json, text/plain, */*', 143 | 'Accept-Language': 'en-US,en;q=0.9', 144 | 'Accept-Encoding': 'gzip, deflate, br', 145 | 'DNT': '1', 146 | 'Connection': 'keep-alive', 147 | 'Cache-Control': 'no-cache', 148 | 'Pragma': 'no-cache' 149 | } 150 | 151 | def _fetch_quiz_data(self, uuid): 152 | """Fetch quiz data with enhanced error handling""" 153 | max_retries = 3 154 | 155 | for attempt in range(max_retries): 156 | try: 157 | # Apply rate limiting 158 | self.rate_limiter.wait() 159 | 160 | url = f"https://play.kahoot.it/rest/kahoots/{uuid}" 161 | headers = self._get_headers() 162 | request = Request(url, headers=headers) 163 | 164 | with urlopen(request, timeout=15, context=self.ssl_context) as response: 165 | return load(response) 166 | 167 | except HTTPError as e: 168 | if e.code == 403: 169 | print(f"Attempt {attempt + 1}: Access forbidden (403)") 170 | if attempt < max_retries - 1: 171 | wait_time = (attempt + 1) * 5 172 | print(f"Waiting {wait_time} seconds before retry...") 173 | time.sleep(wait_time) 174 | continue 175 | else: 176 | print("Error: Access forbidden. This could be due to rate limiting or geographic restrictions.") 177 | return False 178 | 179 | elif e.code == 404: 180 | print("Error: Quiz not found. Please verify the Quiz ID is correct.") 181 | return False 182 | 183 | elif e.code == 429: # Too Many Requests 184 | if attempt < max_retries - 1: 185 | wait_time = (attempt + 1) * 10 186 | print(f"Rate limited. Waiting {wait_time} seconds...") 187 | time.sleep(wait_time) 188 | continue 189 | else: 190 | print("Error: Rate limited by server. Please wait a few minutes and try again.") 191 | return False 192 | 193 | else: 194 | print(f"HTTP Error {e.code}: {e.reason}") 195 | return False 196 | 197 | except URLError as e: 198 | print(f"Connection error: {e.reason}") 199 | return False 200 | 201 | except ssl.SSLError as e: 202 | print(f"SSL Error on attempt {attempt + 1}: {e}") 203 | if attempt < max_retries - 1: 204 | # Try with unverified context on next attempt 205 | self.ssl_context = ssl._create_unverified_context() 206 | print("Retrying with unverified SSL context...") 207 | continue 208 | else: 209 | print(f"SSL connection failed: {e}") 210 | return False 211 | 212 | except json.JSONDecodeError: 213 | print("Error: Failed to parse the response from Kahoot servers.") 214 | return False 215 | 216 | except Exception as e: 217 | if attempt < max_retries - 1: 218 | print(f"Attempt {attempt + 1} failed: {e}") 219 | time.sleep(2) 220 | continue 221 | else: 222 | print(f"Unexpected error: {str(e)}") 223 | return False 224 | 225 | return False 226 | 227 | def get_quiz_details(self): 228 | return { 229 | "uuid": self.data["uuid"], 230 | "creator_username": self.data["creator_username"], 231 | "title": self.data["title"], 232 | "description": self.data["description"], 233 | "cover": self.data["cover"]} 234 | 235 | def get_questions(self): 236 | return self.data["questions"] 237 | 238 | def get_question_names(self): 239 | questions = [] 240 | for i in range(self.get_quiz_length()): 241 | if self.get_question_details(i)["type"] == "content": 242 | questions.append(self.get_question_details(i)["title"]) 243 | else: 244 | questions.append(self.get_question_details(i)["question"]) 245 | return questions 246 | 247 | def get_quiz_length(self): 248 | return len(self.data["questions"]) 249 | 250 | def get_question_details(self, question): 251 | if self.data["questions"][question]["type"] == "content": 252 | data = { 253 | "type": "content", 254 | "title": self.data["questions"][question]["title"], 255 | "description": self.data["questions"][question]["description"] 256 | } 257 | else: 258 | data = { 259 | "type": self.data["questions"][question]["type"], 260 | "question": str(self.data["questions"][question]["question"]).replace('"', '\\"').replace("

", "").replace("

", "").replace("", "").replace("", "").replace("
", "\n").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", ""), 261 | "choices": self.data["questions"][question]["choices"], 262 | "amount_of_answers": len(self.data["questions"][question]["choices"]), 263 | "amount_of_correct_answers": 0} 264 | 265 | for i in range(len(self.data["questions"][question]["choices"])): 266 | self.data["questions"][question]["choices"][i]["answer"] = self.data["questions"][question]["choices"][i]["answer"].replace('"', '\\"').replace("

", "").replace("

", "").replace("", "").replace("", "").replace("
", "\n").replace("", "").replace("
", "").replace("
", "").replace("", "").replace("", "").replace("", "").replace("
", "").replace("
", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "") 267 | 268 | for i in range(len(self.data["questions"][question]["choices"])): 269 | if self.data["questions"][question]["choices"][i]["correct"]: 270 | data["amount_of_correct_answers"] += 1 271 | 272 | if "layout" in self.data["questions"][question]: 273 | data["layout"] = self.data["questions"][question]["layout"] 274 | else: 275 | data["layout"] = None 276 | 277 | if "image" in self.data["questions"][question]: 278 | data["image"] = self.data["questions"][question]["image"] 279 | else: 280 | data["image"] = None 281 | 282 | if "pointsMultiplier" in self.data["questions"][question]: 283 | data["pointsMultiplier"] = self.data["questions"][question]["pointsMultiplier"] 284 | else: 285 | data["pointsMultiplier"] = None 286 | 287 | if "time" in self.data["questions"][question]: 288 | data["time"] = self.data["questions"][question]["time"] 289 | else: 290 | data["time"] = None 291 | 292 | return data 293 | 294 | def get_answer(self, question): 295 | answers = [] 296 | if self.get_question_details(question)["type"] == "content": 297 | answers = None 298 | 299 | elif self.get_question_details(question)["type"] == "jumble": 300 | for i in self.get_question_details(question)["choices"]: 301 | answers.append(str(i["answer"]).replace('"', '\\"').replace("

", "").replace("

", "").replace("", "").replace("", "").replace("
", "\n").replace("", "").replace("
", "").replace("
", "").replace("", "").replace("", "").replace("", "").replace("
", "").replace("
", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "")) 302 | 303 | else: 304 | for i in self.get_question_details(question)["choices"]: 305 | if i["correct"]: 306 | answers.append(str(i["answer"]).replace('"', '\\"').replace("

", "").replace("

", "").replace("", "").replace("", "").replace("
", "\n").replace("", "").replace("
", "").replace("
", "").replace("", "").replace("", "").replace("", "").replace("
", "").replace("
", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "")) 307 | if len(answers) == 0: 308 | answers = None 309 | return answers 310 | 311 | def start_kahoot(): 312 | print("NOTICE: This version is under development and sometimes it might bug, please create an issue at 'https://github.com/CPScript/Kitty-tools/issues' and we will try to fix it <3") 313 | Write.Print(f""" 314 | _______________________ 315 | || Enter your quiz ID || 316 | || below! <3 || 317 | |// 318 | (>﹏<) 319 | -------------------------------------- 320 | ---- Kitty-Tools | By <> CPScript ---- 321 | -------------------------------------- 322 | \n""", Colors.orange, interval=0.000) 323 | Write.Print(f"┌─[Enter Kahoot-ID] <> [User-Input]\n", Colors.white, interval=0.000) 324 | Write.Print(f"└─────► ", Colors.white, interval=0.000); quiz_id = input(pretty) 325 | try: 326 | kahoot = Kahoot(quiz_id) 327 | 328 | if not kahoot.data: 329 | print(f"{red}Error: Failed to fetch quiz data. Please check the Quiz ID and try again.{reset}") 330 | input("Press any key to exit...") 331 | return 332 | 333 | print(f"{pretty}{orange}({green}!{orange}) Fetching Answers From: {orange}[{reset}Quiz-ID: {quiz_id}{orange}]\n") 334 | time.sleep(1) 335 | for i in range(kahoot.get_quiz_length()): 336 | if kahoot.get_answer(i) is not None: 337 | if kahoot.get_question_details(i)['type'] == 'open_ended': 338 | with output_lock: 339 | print(f"{pretty}{orange}[{reset}Question{orange}]{green}--{orange}[{reset}{kahoot.get_question_names()[i]}{orange}]{reset}\n{pretty}{orange}[{reset}Answer{orange}]{green}--{orange}[{reset}{', '.join(kahoot.get_answer(i))}{orange}]{reset}\n") 340 | else: 341 | with output_lock: 342 | print(f"{pretty}{orange}[{reset}Question{orange}]{green}--{orange}[{reset}{kahoot.get_question_names()[i]}{orange}]{reset}\n{pretty}{orange}[{reset}Answer{orange}]{green}--{orange}[{reset}{', '.join(kahoot.get_answer(i))}{orange}]{reset}\n") 343 | time.sleep(0.010) 344 | except Exception as err: 345 | os.system('clear') 346 | print("Womp Womp! ") 347 | print("There was an error! Maybe you typed the 'Quiz ID' incorrectly!\n") 348 | print(f"Error details: {err}") 349 | print("\nTroubleshooting tips:") 350 | print("1. Check your internet connection") 351 | print("2. Verify the Quiz ID is correct") 352 | print("3. The quiz might be private or restricted") 353 | print("4. Try again in a few minutes") 354 | Write.Print(f""" 355 | ||========================================================= 356 | ||Thanks for using Kitty-Tools <3 357 | ||Please *STAR* this repo and follow the creator on github! 358 | ||=========================================================\n 359 | """, Colors.red_to_purple, interval=0.000) 360 | 361 | start_kahoot() 362 | 363 | input("Press any key to exit...") 364 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import time 5 | import platform 6 | import subprocess 7 | from pathlib import Path 8 | from datetime import datetime 9 | 10 | # Terminal Control Constants 11 | class TermCtrl: 12 | RESET = "\033[0m" 13 | BOLD = "\033[1m" 14 | DIM = "\033[2m" 15 | ITALIC = "\033[3m" 16 | UNDERLINE = "\033[4m" 17 | 18 | # Foreground Colors 19 | BLACK = "\033[30m" 20 | RED = "\033[31m" 21 | GREEN = "\033[32m" 22 | YELLOW = "\033[33m" 23 | BLUE = "\033[34m" 24 | MAGENTA = "\033[35m" 25 | CYAN = "\033[36m" 26 | WHITE = "\033[37m" 27 | 28 | # Bright Foreground Colors 29 | BRIGHT_BLACK = "\033[90m" 30 | BRIGHT_RED = "\033[91m" 31 | BRIGHT_GREEN = "\033[92m" 32 | BRIGHT_YELLOW = "\033[93m" 33 | BRIGHT_BLUE = "\033[94m" 34 | BRIGHT_MAGENTA = "\033[95m" 35 | BRIGHT_CYAN = "\033[96m" 36 | BRIGHT_WHITE = "\033[97m" 37 | 38 | # Background Colors 39 | BG_BLACK = "\033[40m" 40 | BG_RED = "\033[41m" 41 | BG_GREEN = "\033[42m" 42 | BG_YELLOW = "\033[43m" 43 | BG_BLUE = "\033[44m" 44 | BG_MAGENTA = "\033[45m" 45 | BG_CYAN = "\033[46m" 46 | BG_WHITE = "\033[47m" 47 | 48 | # Clear Screen 49 | CLEAR = "\033[2J\033[H" 50 | 51 | # Cursor Movement 52 | @staticmethod 53 | def pos(x, y): 54 | return f"\033[{y};{x}H" 55 | 56 | class SystemManager: 57 | @staticmethod 58 | def detect_platform(): 59 | system = platform.system().lower() 60 | 61 | if system == 'windows': 62 | return "windows" 63 | elif system == 'linux': 64 | if os.path.exists("/data/data/com.termux"): 65 | return "android" 66 | return "linux" 67 | elif system == 'darwin': 68 | return "macos" 69 | else: 70 | return "unknown" 71 | 72 | @staticmethod 73 | def clear_screen(): 74 | system = SystemManager.detect_platform() 75 | 76 | try: 77 | if system == "windows": 78 | os.system('cls') 79 | elif system in ["linux", "macos", "android"]: 80 | os.system('clear') 81 | else: 82 | print("\033[2J\033[H", end="") 83 | except Exception: 84 | print("\n" * 100) 85 | 86 | @staticmethod 87 | def detect_terminal_size(): 88 | try: 89 | columns, lines = os.get_terminal_size() 90 | return columns, lines 91 | except: 92 | return 80, 24 93 | 94 | @staticmethod 95 | def is_dependency_installed(command): 96 | try: 97 | devnull = open(os.devnull, 'w') 98 | subprocess.check_call([command, "--version"], stdout=devnull, stderr=devnull) 99 | return True 100 | except: 101 | return False 102 | 103 | class DependencyChecker: 104 | """Check and install Python dependencies""" 105 | 106 | @staticmethod 107 | def check_python_version(): 108 | """Check if Python version is compatible""" 109 | if sys.version_info < (3, 6): 110 | print(f"{TermCtrl.BRIGHT_RED}Error: Python 3.6 or higher is required.{TermCtrl.RESET}") 111 | print(f"Current version: {sys.version}") 112 | return False 113 | return True 114 | 115 | @staticmethod 116 | def install_missing_packages(): 117 | """Install missing Python packages""" 118 | packages_to_check = ['colorama', 'pystyle'] 119 | missing_packages = [] 120 | 121 | for package in packages_to_check: 122 | try: 123 | __import__(package) 124 | except ImportError: 125 | missing_packages.append(package) 126 | 127 | if missing_packages: 128 | print(f"{TermCtrl.BRIGHT_YELLOW}Installing missing packages: {', '.join(missing_packages)}{TermCtrl.RESET}") 129 | for package in missing_packages: 130 | try: 131 | subprocess.check_call([sys.executable, '-m', 'pip', 'install', package]) 132 | print(f"{TermCtrl.BRIGHT_GREEN}Successfully installed {package}{TermCtrl.RESET}") 133 | except subprocess.CalledProcessError: 134 | print(f"{TermCtrl.BRIGHT_RED}Failed to install {package}{TermCtrl.RESET}") 135 | 136 | return True 137 | 138 | class MenuManager: 139 | def __init__(self): 140 | self.base_dir = os.path.dirname(os.path.abspath(__file__)) 141 | self.src_dir = os.path.join(self.base_dir, "src") 142 | self.gui_dir = os.path.join(self.base_dir, "src", "client") 143 | self.kitty_dir = os.path.join(self.base_dir, "Kitty") 144 | 145 | # Check if src directory exists 146 | self.is_src_available = os.path.isdir(self.src_dir) 147 | 148 | # Initialize terminal state 149 | self.term_width, self.term_height = SystemManager.detect_terminal_size() 150 | 151 | # Menu state 152 | self.exit_requested = False 153 | self.current_selection = 0 154 | self.menu_items = [ 155 | {"id": "howto", "label": "How to Use", "description": "Interactive guide on using Kitty Tools "}, 156 | {"id": "info", "label": "Information", "description": "Credits, license, and additional information "}, 157 | {"id": "flood", "label": "Kahoot Flooder", "description": "Advanced Kahoot game flooding utility "}, 158 | {"id": "answers", "label": "Answer Hack", "description": "Obtain answers for Kahoot quizzes "}, 159 | {"id": "graphical", "label": "GUI", "description": "A graphical user interface for ease of use "}, 160 | {"id": "exit", "label": "Exit", "description": "Exit the application "} 161 | ] 162 | 163 | def render_header(self): 164 | version_number = "v36.2 Enhanced" 165 | print(f" {TermCtrl.BRIGHT_YELLOW}┌{'─' * (self.term_width - 4)}┐{TermCtrl.RESET}") 166 | print(f" {TermCtrl.BRIGHT_YELLOW}│{TermCtrl.RESET} {TermCtrl.BOLD}{TermCtrl.BRIGHT_WHITE}KITTY TOOLS{TermCtrl.RESET} {TermCtrl.DIM}by CPScript{TermCtrl.RESET}{' ' * (self.term_width - 28)}{TermCtrl.DIM}{TermCtrl.RESET}{TermCtrl.BRIGHT_YELLOW}│{TermCtrl.RESET}") 167 | print(f" {TermCtrl.BRIGHT_YELLOW}│{TermCtrl.RESET} {TermCtrl.DIM}{version_number}{TermCtrl.RESET}{' ' * (self.term_width - 17 - len(version_number))}{TermCtrl.BRIGHT_YELLOW} │{TermCtrl.RESET}") 168 | print(f" {TermCtrl.BRIGHT_YELLOW}└{'─' * (self.term_width - 4)}┘{TermCtrl.RESET}") 169 | print() 170 | 171 | def render_menu(self): 172 | print(f" {TermCtrl.BRIGHT_CYAN}╭{'─' * (self.term_width - 4)}╮{TermCtrl.RESET}") 173 | print(f" {TermCtrl.BRIGHT_CYAN}│{TermCtrl.RESET} {TermCtrl.BOLD}Main Menu{TermCtrl.RESET}{' ' * (self.term_width - 14)}{TermCtrl.BRIGHT_CYAN}│{TermCtrl.RESET}") 174 | print(f" {TermCtrl.BRIGHT_CYAN}├{'─' * (self.term_width - 4)}┤{TermCtrl.RESET}") 175 | 176 | for idx, item in enumerate(self.menu_items): 177 | if idx == self.current_selection: 178 | selector = f"{TermCtrl.BRIGHT_GREEN}▶{TermCtrl.RESET}" 179 | label = f"{TermCtrl.BRIGHT_WHITE}{TermCtrl.BOLD}{item['label']}{TermCtrl.RESET}" 180 | desc = f"{TermCtrl.BRIGHT_WHITE}{item['description']}{TermCtrl.RESET}" 181 | else: 182 | selector = " " 183 | label = f"{TermCtrl.WHITE}{item['label']}{TermCtrl.RESET}" 184 | desc = f"{TermCtrl.DIM}{item['description']}{TermCtrl.RESET}" 185 | 186 | id_text = f"{idx + 1}. " 187 | spacing = " " * (20 - len(item['label'])) 188 | print(f" {TermCtrl.BRIGHT_CYAN}│{TermCtrl.RESET} {selector} {id_text}{label}{spacing}{desc}{' ' * (self.term_width - 50 - len(item['description']))}{TermCtrl.BRIGHT_CYAN}│{TermCtrl.RESET}") 189 | 190 | print(f" {TermCtrl.BRIGHT_CYAN}╰{'─' * (self.term_width - 4)}╯{TermCtrl.RESET}") 191 | print() 192 | print(f" {TermCtrl.DIM}Use number keys to navigate, Enter to select{TermCtrl.RESET}") 193 | 194 | def render_status(self, message=None): 195 | platform_info = SystemManager.detect_platform() 196 | platform_label = f"{platform_info.capitalize()} platform detected" 197 | 198 | if message: 199 | status_text = message 200 | else: 201 | status_text = "Ready" 202 | 203 | print() 204 | print(f" {TermCtrl.BRIGHT_BLACK}Status: {TermCtrl.RESET}{status_text}") 205 | print(f" {TermCtrl.BRIGHT_BLACK}System: {TermCtrl.RESET}{platform_label}") 206 | 207 | # Check if enhanced version is available 208 | if self.is_src_available: 209 | print(f" {TermCtrl.BRIGHT_BLACK}Mode: {TermCtrl.RESET}{TermCtrl.BRIGHT_GREEN}Enhanced Version Available{TermCtrl.RESET}") 210 | else: 211 | print(f" {TermCtrl.BRIGHT_BLACK}Mode: {TermCtrl.RESET}{TermCtrl.YELLOW}Standard Version{TermCtrl.RESET}") 212 | 213 | def get_user_selection(self): 214 | try: 215 | choice = input("\n Make a selection (1-6): ") 216 | if choice.isdigit() and 1 <= int(choice) <= len(self.menu_items): 217 | return int(choice) - 1 218 | return self.current_selection 219 | except KeyboardInterrupt: 220 | return len(self.menu_items) - 1 # Select exit option 221 | except: 222 | return self.current_selection 223 | 224 | def check_dependencies_for_action(self, action_id): 225 | """Check if dependencies are available for the selected action""" 226 | if action_id in ["flood", "answers", "graphical"]: 227 | # Check Python dependencies 228 | try: 229 | import colorama 230 | import pystyle 231 | except ImportError: 232 | print(f"{TermCtrl.BRIGHT_YELLOW}Installing required Python packages...{TermCtrl.RESET}") 233 | DependencyChecker.install_missing_packages() 234 | 235 | # For flooder, check Node.js 236 | if action_id == "flood": 237 | node_available = SystemManager.is_dependency_installed("node") 238 | npm_available = SystemManager.is_dependency_installed("npm") 239 | 240 | if not node_available or not npm_available: 241 | print(f"{TermCtrl.BRIGHT_RED}Node.js is required for the Kahoot Flooder.{TermCtrl.RESET}") 242 | print("The setup script will guide you through installation.") 243 | time.sleep(2) 244 | 245 | return True 246 | 247 | def execute_selected_action(self, selection): 248 | action_id = self.menu_items[selection]["id"] 249 | 250 | # Check dependencies before executing 251 | if not self.check_dependencies_for_action(action_id): 252 | input(f"\n{TermCtrl.BRIGHT_YELLOW}Press Enter to return to the main menu...{TermCtrl.RESET}") 253 | return 254 | 255 | # Prepare to execute selected action 256 | print(f"\n {TermCtrl.BRIGHT_BLUE}Launching {self.menu_items[selection]['label']}...{TermCtrl.RESET}") 257 | time.sleep(1) 258 | SystemManager.clear_screen() 259 | 260 | try: 261 | if action_id == "howto": 262 | self.execute_howto() 263 | elif action_id == "info": 264 | self.execute_info() 265 | elif action_id == "flood": 266 | self.execute_flood() 267 | elif action_id == "answers": 268 | self.execute_answers() 269 | elif action_id == "graphical": 270 | self.execute_graphical() 271 | elif action_id == "exit": 272 | self.exit_requested = True 273 | print(f"{TermCtrl.BRIGHT_GREEN}Thank you for using KITTY TOOLS{TermCtrl.RESET}") 274 | return 275 | 276 | input(f"\n{TermCtrl.BRIGHT_YELLOW}Press Enter to return to the main menu...{TermCtrl.RESET}") 277 | 278 | except KeyboardInterrupt: 279 | print(f"\n{TermCtrl.BRIGHT_YELLOW}Operation cancelled by user{TermCtrl.RESET}") 280 | input(f"\n{TermCtrl.BRIGHT_YELLOW}Press Enter to return to the main menu...{TermCtrl.RESET}") 281 | except Exception as e: 282 | print(f"\n{TermCtrl.BRIGHT_RED}Error executing {action_id}: {str(e)}{TermCtrl.RESET}") 283 | print(f"{TermCtrl.DIM}If this error persists, please report it on GitHub{TermCtrl.RESET}") 284 | input(f"\n{TermCtrl.BRIGHT_YELLOW}Press Enter to return to the main menu...{TermCtrl.RESET}") 285 | 286 | def execute_howto(self): 287 | print(f"{TermCtrl.BOLD}{TermCtrl.BRIGHT_CYAN}How to Use KITTY TOOLS{TermCtrl.RESET}\n") 288 | 289 | if self.is_src_available: 290 | # Enhanced version 291 | print(f"{TermCtrl.BRIGHT_WHITE}KITTY TOOLS is a suite of utilities for Kahoot:{TermCtrl.RESET}\n") 292 | print(f"{TermCtrl.BRIGHT_CYAN}1. Information{TermCtrl.RESET}") 293 | print(f" View credits, license information, and contributors to the project.") 294 | print(f"{TermCtrl.BRIGHT_CYAN}2. Kahoot Flooder{TermCtrl.RESET}") 295 | print(f" Create multiple automated players in Kahoot games with customizable settings.") 296 | print(f" You can control the bots collectively or let them act autonomously.") 297 | print(f" Note: Requires Node.js installation") 298 | print(f"{TermCtrl.BRIGHT_CYAN}3. Answer Hack{TermCtrl.RESET}") 299 | print(f" Retrieve answers for a Kahoot quiz by providing the Quiz ID.") 300 | print(f" Export answers to a file for future reference.") 301 | print(f"{TermCtrl.BRIGHT_CYAN}4. GUI{TermCtrl.RESET}") 302 | print(f" Use the graphical user interface for easier interaction.") 303 | print(f" Requires PyQt5 installation.\n") 304 | print(f"{TermCtrl.BRIGHT_YELLOW}Note: All features require an active internet connection.{TermCtrl.RESET}") 305 | print(f"{TermCtrl.BRIGHT_YELLOW}Troubleshooting: If you encounter SSL errors, the tools will attempt to fix them automatically.{TermCtrl.RESET}") 306 | else: 307 | # Standard version 308 | try: 309 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "htu.py")]) 310 | except Exception as e: 311 | print(f"Error running how-to guide: {e}") 312 | print("Please check the Kitty directory for the htu.py file") 313 | 314 | def execute_info(self): 315 | if self.is_src_available: 316 | # Enhanced version 317 | print(f"{TermCtrl.BOLD}{TermCtrl.BRIGHT_CYAN}KITTY TOOLS Information{TermCtrl.RESET}\n") 318 | print(f"{TermCtrl.BRIGHT_WHITE}KITTY TOOLS v36.2 Enhanced{TermCtrl.RESET}") 319 | print(f"Developed by: {TermCtrl.BRIGHT_YELLOW}CPScript{TermCtrl.RESET}\n") 320 | 321 | print(f"{TermCtrl.UNDERLINE}Contributors:{TermCtrl.RESET}") 322 | print(f"- {TermCtrl.BRIGHT_RED}@Ccode-lang{TermCtrl.RESET} for helping out!") 323 | print(f"- {TermCtrl.BRIGHT_RED}@xTobyPlayZ{TermCtrl.RESET} for Flooder!") 324 | print(f"- {TermCtrl.BRIGHT_RED}@cheepling{TermCtrl.RESET} for finding bugs!") 325 | print(f"- {TermCtrl.BRIGHT_RED}@Zacky2613{TermCtrl.RESET} for helping and fixing issues!") 326 | print(f"- {TermCtrl.BRIGHT_RED}@KiraKenjiro{TermCtrl.RESET} for reviewing and making changes! {TermCtrl.BRIGHT_RED}<3{TermCtrl.RESET}\n") 327 | 328 | print(f"{TermCtrl.UNDERLINE}License:{TermCtrl.RESET}") 329 | print(f"This software is provided for educational purposes only.") 330 | print(f"Use at your own risk. The authors are not responsible for any misuse.") 331 | print(f"Please read the complete license in the repository for more details.\n") 332 | 333 | print(f"{TermCtrl.UNDERLINE}Recent Fixes:{TermCtrl.RESET}") 334 | print(f"- Fixed SSL certificate issues on macOS") 335 | print(f"- Fixed HTTP 403 Forbidden errors with better headers") 336 | print(f"- Fixed Node.js module loading issues") 337 | print(f"- Added automatic dependency installation") 338 | print(f"- Improved error handling and user feedback\n") 339 | 340 | print(f"{TermCtrl.BRIGHT_GREEN}Thank you for using KITTY TOOLS!{TermCtrl.RESET}") 341 | else: 342 | # Standard version 343 | try: 344 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "Info", "main.py")]) 345 | except Exception as e: 346 | print(f"Error running info module: {e}") 347 | print("Please check the Kitty/Info directory") 348 | 349 | def execute_flood(self): 350 | if self.is_src_available: 351 | # Enhanced version 352 | try: 353 | subprocess.run([sys.executable, os.path.join(self.src_dir, "main.py")]) 354 | except Exception as e: 355 | print(f"Error running enhanced flooder: {e}") 356 | print("Falling back to standard version...") 357 | try: 358 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "Flood", "main.py")]) 359 | except Exception as e2: 360 | print(f"Error running standard flooder: {e2}") 361 | else: 362 | # Standard version 363 | try: 364 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "Flood", "main.py")]) 365 | except Exception as e: 366 | print(f"Error running flooder: {e}") 367 | print("Please check the Kitty/Flood directory") 368 | 369 | def execute_answers(self): 370 | if self.is_src_available: 371 | # Enhanced version 372 | try: 373 | subprocess.run([sys.executable, os.path.join(self.src_dir, "client.py")]) 374 | except Exception as e: 375 | print(f"Error running enhanced client: {e}") 376 | print("Falling back to standard version...") 377 | try: 378 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "client.py")]) 379 | except Exception as e2: 380 | print(f"Error running standard client: {e2}") 381 | else: 382 | # Standard version 383 | try: 384 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "client.py")]) 385 | except Exception as e: 386 | print(f"Error running client: {e}") 387 | print("Please check the Kitty directory") 388 | 389 | def execute_graphical(self): 390 | if self.is_src_available: 391 | # Enhanced version - try GUI first, fallback to client 392 | try: 393 | # Check if PyQt5 is available 394 | import PyQt5 395 | subprocess.run([sys.executable, os.path.join(self.gui_dir, "main.py")]) 396 | except ImportError: 397 | print(f"{TermCtrl.BRIGHT_YELLOW}PyQt5 not found. Installing...{TermCtrl.RESET}") 398 | try: 399 | subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'PyQt5']) 400 | print(f"{TermCtrl.BRIGHT_GREEN}PyQt5 installed successfully. Starting GUI...{TermCtrl.RESET}") 401 | subprocess.run([sys.executable, os.path.join(self.gui_dir, "main.py")]) 402 | except subprocess.CalledProcessError: 403 | print(f"{TermCtrl.BRIGHT_RED}Failed to install PyQt5. Using console client instead.{TermCtrl.RESET}") 404 | subprocess.run([sys.executable, os.path.join(self.src_dir, "client.py")]) 405 | except Exception as e: 406 | print(f"Error running GUI: {e}") 407 | print("Falling back to console client...") 408 | subprocess.run([sys.executable, os.path.join(self.src_dir, "client.py")]) 409 | else: 410 | # Standard version - just run the client 411 | try: 412 | subprocess.run([sys.executable, os.path.join(self.kitty_dir, "client.py")]) 413 | except Exception as e: 414 | print(f"Error running client: {e}") 415 | 416 | def run(self): 417 | while not self.exit_requested: 418 | SystemManager.clear_screen() 419 | self.term_width, self.term_height = SystemManager.detect_terminal_size() 420 | 421 | self.render_header() 422 | self.render_menu() 423 | self.render_status() 424 | 425 | selection = self.get_user_selection() 426 | if 0 <= selection < len(self.menu_items): 427 | self.current_selection = selection 428 | self.execute_selected_action(selection) 429 | 430 | def check_system_requirements(): 431 | """Check system requirements and dependencies""" 432 | print(f"{TermCtrl.BRIGHT_CYAN}Checking system requirements...{TermCtrl.RESET}") 433 | 434 | # Check Python version 435 | if not DependencyChecker.check_python_version(): 436 | sys.exit(1) 437 | 438 | # Install missing Python packages 439 | DependencyChecker.install_missing_packages() 440 | 441 | print(f"{TermCtrl.BRIGHT_GREEN}System requirements check completed.{TermCtrl.RESET}") 442 | time.sleep(1) 443 | 444 | def main(): 445 | try: 446 | # Check system requirements first 447 | check_system_requirements() 448 | 449 | # Ensure necessary directories exist 450 | menu_manager = MenuManager() 451 | menu_manager.run() 452 | 453 | except KeyboardInterrupt: 454 | SystemManager.clear_screen() 455 | print(f"{TermCtrl.BRIGHT_GREEN}Thank you for using KITTY TOOLS{TermCtrl.RESET}") 456 | except Exception as e: 457 | print(f"{TermCtrl.BRIGHT_RED}A critical error occurred: {str(e)}{TermCtrl.RESET}") 458 | print(f"{TermCtrl.BRIGHT_YELLOW}Please report this issue on GitHub: https://github.com/CPScript/Kitty-Tools/issues{TermCtrl.RESET}") 459 | 460 | if __name__ == "__main__": 461 | main() 462 | -------------------------------------------------------------------------------- /src/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import time 4 | import sys 5 | import platform 6 | import json 7 | import re 8 | import threading 9 | import random 10 | import ssl 11 | from urllib.request import urlopen, Request 12 | from urllib.error import HTTPError, URLError 13 | from urllib.parse import urlparse, parse_qs 14 | from http.client import InvalidURL 15 | 16 | # Dependency management with graceful fallbacks 17 | DEPENDENCIES = { 18 | "colorama": {"package": "colorama", "components": ["Fore", "Style"]}, 19 | "pystyle": {"package": "pystyle", "components": ["Write", "System", "Colors", "Colorate", "Anime"]} 20 | } 21 | 22 | def check_and_install_dependencies(): 23 | missing_deps = [] 24 | 25 | for dep_name, dep_info in DEPENDENCIES.items(): 26 | try: 27 | module = __import__(dep_info["package"]) 28 | for component in dep_info["components"]: 29 | if not hasattr(module, component): 30 | raise ImportError(f"Component {component} not found in {dep_name}") 31 | except (ImportError, ModuleNotFoundError): 32 | missing_deps.append(dep_info["package"]) 33 | 34 | if missing_deps: 35 | print(f"Installing missing dependencies: {', '.join(missing_deps)}") 36 | for dep in missing_deps: 37 | install_status = os.system(f"pip install {dep}") 38 | if install_status != 0: 39 | print(f"Warning: Failed to install {dep}. Some features may not work correctly.") 40 | 41 | check_and_install_dependencies() 42 | 43 | from colorama import Fore, Style 44 | from pystyle import Write, System, Colors, Colorate, Anime 45 | 46 | class ColorScheme: 47 | RED = Fore.RED 48 | YELLOW = Fore.YELLOW 49 | GREEN = Fore.GREEN 50 | BLUE = Fore.BLUE 51 | ORANGE = Fore.RED + Fore.YELLOW 52 | MAGENTA = Fore.MAGENTA 53 | LIGHTBLUE = Fore.LIGHTBLUE_EX 54 | CYAN = Fore.CYAN 55 | GRAY = Fore.LIGHTBLACK_EX + Fore.WHITE 56 | RESET = Fore.RESET 57 | PINK = Fore.LIGHTGREEN_EX + Fore.LIGHTMAGENTA_EX 58 | DARK_GREEN = Fore.GREEN + Style.BRIGHT 59 | PRETTY = Fore.LIGHTMAGENTA_EX + Fore.LIGHTCYAN_EX 60 | 61 | @classmethod 62 | def random(cls): 63 | colors = [cls.RED, cls.YELLOW, cls.GREEN, cls.BLUE, cls.CYAN, 64 | cls.MAGENTA, cls.LIGHTBLUE] 65 | return random.choice(colors) 66 | 67 | class PlatformManager: 68 | @staticmethod 69 | def detect_platform(): 70 | system = platform.system().lower() 71 | 72 | if system == 'windows': 73 | return "windows" 74 | elif system == 'linux': 75 | # Check if running in Termux on Android 76 | if os.path.exists("/data/data/com.termux"): 77 | return "android" 78 | return "linux" 79 | elif system == 'darwin': 80 | return "macos" 81 | else: 82 | return "unknown" 83 | 84 | @staticmethod 85 | def clear_screen(): 86 | system = PlatformManager.detect_platform() 87 | 88 | try: 89 | if system == "windows": 90 | os.system('cls') 91 | elif system in ["linux", "macos"]: 92 | os.system('clear') 93 | elif system == "android": 94 | os.system('clear') 95 | print("Notice: Running on Android. For optimal performance, consider using Kitty-Tools LITE.") 96 | else: 97 | print("\033[H\033[J", end="") 98 | print(f"Notice: Unsupported platform '{system}'. Some features may not work as expected.") 99 | print("For more info: https://github.com/CPScript/Kitty-Tools/extra.md") 100 | except Exception as e: 101 | # Last resort fallback 102 | print("\n" * 100) 103 | print(f"Screen clearing failed: {e}") 104 | 105 | class SSLContextManager: 106 | """Handle SSL certificate issues across platforms""" 107 | 108 | @staticmethod 109 | def create_ssl_context(): 110 | """Create SSL context with fallback for certificate issues""" 111 | try: 112 | # Try to create default context first 113 | context = ssl.create_default_context() 114 | 115 | # For macOS, try to use certifi if available 116 | if platform.system() == 'Darwin': 117 | try: 118 | import certifi 119 | context = ssl.create_default_context(cafile=certifi.where()) 120 | except ImportError: 121 | # certifi not available, use default 122 | pass 123 | 124 | return context 125 | except Exception: 126 | # If all else fails, create unverified context 127 | print("Warning: Using unverified SSL context due to certificate issues") 128 | return ssl._create_unverified_context() 129 | 130 | class RateLimiter: 131 | """Rate limiter to avoid getting blocked""" 132 | 133 | def __init__(self, min_delay=1.0, max_delay=3.0): 134 | self.min_delay = min_delay 135 | self.max_delay = max_delay 136 | self.last_request = None 137 | 138 | def wait(self): 139 | """Wait appropriate time between requests""" 140 | if self.last_request: 141 | elapsed = time.time() - self.last_request 142 | delay = random.uniform(self.min_delay, self.max_delay) 143 | 144 | if elapsed < delay: 145 | sleep_time = delay - elapsed 146 | time.sleep(sleep_time) 147 | 148 | self.last_request = time.time() 149 | 150 | # Kahoot API interaction 151 | class KahootAPI: 152 | BASE_API_URL = "https://play.kahoot.it/rest/kahoots/" 153 | CHALLENGE_API_URL = "https://kahoot.it/rest/challenges/pin/" 154 | REQUEST_TIMEOUT = 15 # seconds 155 | 156 | def __init__(self): 157 | self.rate_limiter = RateLimiter() 158 | self.ssl_context = SSLContextManager.create_ssl_context() 159 | 160 | def _get_headers(self): 161 | """Generate realistic browser headers""" 162 | user_agents = [ 163 | 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 164 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 165 | 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' 166 | ] 167 | 168 | return { 169 | 'User-Agent': random.choice(user_agents), 170 | 'Accept': 'application/json, text/plain, */*', 171 | 'Accept-Language': 'en-US,en;q=0.9', 172 | 'DNT': '1', 173 | 'Connection': 'keep-alive', 174 | 'Cache-Control': 'no-cache', 175 | 'Pragma': 'no-cache' 176 | } 177 | 178 | def _make_request(self, url, max_retries=3): 179 | """Make request with retry logic and proper error handling""" 180 | for attempt in range(max_retries): 181 | try: 182 | # Apply rate limiting 183 | self.rate_limiter.wait() 184 | 185 | # Create request with headers 186 | headers = self._get_headers() 187 | request = Request(url, headers=headers) 188 | 189 | # Make the request with SSL context 190 | with urlopen(request, timeout=self.REQUEST_TIMEOUT, context=self.ssl_context) as response: 191 | return json.loads(response.read().decode('utf-8')) 192 | 193 | except HTTPError as e: 194 | if e.code == 403: 195 | print(f"Attempt {attempt + 1}: Access forbidden (403)") 196 | if attempt < max_retries - 1: 197 | wait_time = (attempt + 1) * 5 198 | print(f"Waiting {wait_time} seconds before retry...") 199 | time.sleep(wait_time) 200 | continue 201 | else: 202 | return {'error': 'Access forbidden. This could be due to rate limiting, geographic restrictions, or the quiz being private.'} 203 | 204 | elif e.code == 404: 205 | return {'error': 'Quiz not found. The ID may be incorrect.'} 206 | 207 | elif e.code == 429: # Too Many Requests 208 | if attempt < max_retries - 1: 209 | wait_time = (attempt + 1) * 10 210 | print(f"Rate limited. Waiting {wait_time} seconds...") 211 | time.sleep(wait_time) 212 | continue 213 | else: 214 | return {'error': 'Rate limited by server. Please wait a few minutes and try again.'} 215 | 216 | else: 217 | return {'error': f'HTTP Error: {e.code} - {e.reason}'} 218 | 219 | except URLError as e: 220 | return {'error': f'Connection error: {e.reason}. Check your internet connection.'} 221 | 222 | except ssl.SSLError as e: 223 | print(f"SSL Error on attempt {attempt + 1}: {e}") 224 | if attempt < max_retries - 1: 225 | # Try with unverified context on next attempt 226 | self.ssl_context = ssl._create_unverified_context() 227 | print("Retrying with unverified SSL context...") 228 | continue 229 | else: 230 | return {'error': f'SSL connection failed: {e}'} 231 | 232 | except json.JSONDecodeError: 233 | return {'error': 'Failed to parse the response from Kahoot servers.'} 234 | 235 | except Exception as e: 236 | if attempt < max_retries - 1: 237 | print(f"Attempt {attempt + 1} failed: {e}") 238 | time.sleep(2) 239 | continue 240 | else: 241 | return {'error': f'Unexpected error: {str(e)}'} 242 | 243 | return {'error': 'All retry attempts failed'} 244 | 245 | @staticmethod 246 | def get_quiz_by_id(quiz_id): 247 | if not re.fullmatch(r"^[A-Za-z0-9-]*$", quiz_id): 248 | return {'error': 'Invalid quiz ID format'} 249 | 250 | api = KahootAPI() 251 | url = f"{api.BASE_API_URL}{quiz_id}" 252 | return api._make_request(url) 253 | 254 | @staticmethod 255 | def get_quiz_id_from_pin(pin): 256 | if not pin.isdigit(): 257 | return {'error': 'PIN must contain only digits'} 258 | 259 | api = KahootAPI() 260 | url = f"{api.CHALLENGE_API_URL}{pin}" 261 | result = api._make_request(url) 262 | 263 | if 'error' not in result and 'id' in result: 264 | return {'quiz_id': result['id']} 265 | elif 'error' not in result: 266 | return {'error': 'No quiz ID found in response'} 267 | 268 | return result 269 | 270 | class KahootQuiz: 271 | def __init__(self, quiz_data): 272 | self.data = quiz_data 273 | self.valid = 'error' not in quiz_data and 'uuid' in quiz_data 274 | 275 | def get_quiz_details(self): 276 | if not self.valid: 277 | return None 278 | 279 | return { 280 | "uuid": self.data["uuid"], 281 | "creator_username": self.data.get("creator_username", "Unknown"), 282 | "title": self.data.get("title", "Untitled Quiz"), 283 | "description": self.data.get("description", ""), 284 | "cover": self.data.get("cover", ""), 285 | "question_count": len(self.data.get("questions", [])), 286 | "visibility": self.data.get("visibility", "Unknown"), 287 | "created": self.data.get("created", "Unknown date") 288 | } 289 | 290 | def get_questions(self): 291 | if not self.valid: 292 | return [] 293 | return self.data.get("questions", []) 294 | 295 | def get_quiz_length(self): 296 | if not self.valid: 297 | return 0 298 | return len(self.data.get("questions", [])) 299 | 300 | def _clean_text(self, text): 301 | if not text: 302 | return "" 303 | 304 | text = str(text) 305 | 306 | replacements = [ 307 | ("

", ""), ("

", ""), 308 | ("", ""), ("", ""), 309 | ("", ""), ("", ""), 310 | ("
", "\n"), ("
", "\n"), 311 | ("", ""), ("", ""), 312 | ("", ""), ("", ""), 313 | ("", ""), ("", ""), 314 | ("", ""), ("", ""), 315 | ("", ""), ("", ""), 316 | ("", ""), ("", ""), 317 | ("", ""), ("", ""), 318 | ("", ""), ("", ""), 319 | ("", ""), ("", "") 320 | ] 321 | 322 | for old, new in replacements: 323 | text = text.replace(old, new) 324 | 325 | text = re.sub(r'<[^>]+>', '', text) 326 | 327 | text = text.replace('\\"', '"') 328 | 329 | return text.strip() 330 | 331 | def get_question_details(self, question_index): 332 | if not self.valid or question_index >= self.get_quiz_length(): 333 | return None 334 | 335 | question = self.data["questions"][question_index] 336 | question_type = question.get("type", "unknown") 337 | 338 | details = { 339 | "type": question_type, 340 | "layout": question.get("layout"), 341 | "image": question.get("image"), 342 | "pointsMultiplier": question.get("pointsMultiplier", 1), 343 | "time": question.get("time"), 344 | "media": question.get("media") 345 | } 346 | 347 | if question_type == "content": 348 | details.update({ 349 | "title": self._clean_text(question.get("title", "")), 350 | "description": self._clean_text(question.get("description", "")) 351 | }) 352 | else: 353 | # Process question and choices 354 | details.update({ 355 | "question": self._clean_text(question.get("question", "")), 356 | "choices": [], 357 | "amount_of_answers": len(question.get("choices", [])), 358 | "amount_of_correct_answers": 0 359 | }) 360 | 361 | # Process each answer choice 362 | for choice in question.get("choices", []): 363 | cleaned_choice = { 364 | "answer": self._clean_text(choice.get("answer", "")), 365 | "correct": choice.get("correct", False) 366 | } 367 | 368 | details["choices"].append(cleaned_choice) 369 | if cleaned_choice["correct"]: 370 | details["amount_of_correct_answers"] += 1 371 | 372 | return details 373 | 374 | def get_answer(self, question_index): 375 | details = self.get_question_details(question_index) 376 | 377 | if not details: 378 | return None 379 | 380 | if details["type"] == "content": 381 | return None # Content slides don't have answers 382 | 383 | answers = [] 384 | 385 | if details["type"] == "jumble": 386 | for choice in details["choices"]: 387 | answers.append(choice["answer"]) 388 | else: 389 | for choice in details["choices"]: 390 | if choice["correct"]: 391 | answers.append(choice["answer"]) 392 | 393 | return answers if answers else None 394 | 395 | def export_answers_to_file(self, filename="kahoot_answers.txt"): 396 | if not self.valid: 397 | return False 398 | 399 | try: 400 | with open(filename, 'w', encoding='utf-8') as f: 401 | quiz_details = self.get_quiz_details() 402 | f.write(f"KAHOOT QUIZ ANSWERS\n") 403 | f.write(f"=================\n\n") 404 | f.write(f"Title: {quiz_details['title']}\n") 405 | f.write(f"Creator: {quiz_details['creator_username']}\n") 406 | f.write(f"Quiz ID: {quiz_details['uuid']}\n") 407 | if quiz_details['description']: 408 | f.write(f"Description: {quiz_details['description']}\n") 409 | f.write(f"Question Count: {quiz_details['question_count']}\n\n") 410 | f.write(f"QUESTIONS AND ANSWERS\n") 411 | f.write(f"====================\n\n") 412 | 413 | for i in range(self.get_quiz_length()): 414 | details = self.get_question_details(i) 415 | 416 | if details["type"] == "content": 417 | f.write(f"SLIDE {i+1}: {details['title']}\n") 418 | if details['description']: 419 | f.write(f"Description: {details['description']}\n") 420 | else: 421 | f.write(f"QUESTION {i+1}: {details['question']}\n") 422 | f.write(f"Type: {details['type']}\n") 423 | 424 | answers = self.get_answer(i) 425 | if answers: 426 | f.write(f"Correct Answer(s): {', '.join(answers)}\n") 427 | else: 428 | f.write(f"No correct answers found.\n") 429 | 430 | f.write("\n") 431 | 432 | return True 433 | except Exception as e: 434 | print(f"Failed to export answers: {str(e)}") 435 | return False 436 | 437 | class KahootClientUI: 438 | @staticmethod 439 | def display_intro(): 440 | PlatformManager.clear_screen() 441 | 442 | print("NOTICE: This is an enhanced version of the Kitty-Tools Kahoot client.") 443 | 444 | Write.Print(f""" 445 | _______________________ 446 | || Enter your quiz ID || 447 | || below! <3 || 448 | |// 449 | (>﹏<) 450 | -------------------------------------- 451 | ---- Kitty-Tools | By <> CPScript ---- 452 | ---- Enhanced Edition v1.0 ---------- 453 | -------------------------------------- 454 | \n""", Colors.orange, interval=0.000) 455 | 456 | @staticmethod 457 | def get_quiz_id(): 458 | while True: 459 | Write.Print(f"┌─[Enter Kahoot-ID] <> [User-Input]\n", Colors.white, interval=0.000) 460 | Write.Print(f"└─────► ", Colors.white, interval=0.000) 461 | user_input = input(ColorScheme.PRETTY) 462 | 463 | if user_input.isdigit(): 464 | print(f"{ColorScheme.ORANGE}({ColorScheme.GREEN}!{ColorScheme.ORANGE}) Detected a game PIN. Attempting to fetch the quiz ID...") 465 | result = KahootAPI.get_quiz_id_from_pin(user_input) 466 | 467 | if 'error' in result: 468 | print(f"{ColorScheme.RED}Error: {result['error']}") 469 | retry = input(f"{ColorScheme.YELLOW}Try again? (y/n): {ColorScheme.RESET}").lower() 470 | if retry != 'y': 471 | return None 472 | else: 473 | quiz_id = result['quiz_id'] 474 | print(f"{ColorScheme.GREEN}Successfully found quiz ID: {quiz_id}") 475 | time.sleep(1) 476 | return quiz_id 477 | else: 478 | if re.fullmatch(r"^[A-Za-z0-9-]*$", user_input): 479 | return user_input 480 | else: 481 | print(f"{ColorScheme.RED}Invalid quiz ID format. It should contain only letters, numbers, and hyphens.") 482 | retry = input(f"{ColorScheme.YELLOW}Try again? (y/n): {ColorScheme.RESET}").lower() 483 | if retry != 'y': 484 | return None 485 | 486 | @staticmethod 487 | def display_answers(kahoot): 488 | """Display quiz answers with proper formatting and color coding.""" 489 | if not kahoot.valid: 490 | print(f"{ColorScheme.RED} Failed to retrieve quiz data. Please check the Quiz ID and try again.") 491 | return 492 | 493 | quiz_details = kahoot.get_quiz_details() 494 | 495 | print(f"\n{ColorScheme.CYAN}========= QUIZ INFORMATION =========") 496 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}[{ColorScheme.RESET}Title{ColorScheme.ORANGE}]{ColorScheme.GREEN}--{ColorScheme.ORANGE}[{ColorScheme.RESET}{quiz_details['title']}{ColorScheme.ORANGE}]{ColorScheme.RESET}") 497 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}[{ColorScheme.RESET}Creator{ColorScheme.ORANGE}]{ColorScheme.GREEN}--{ColorScheme.ORANGE}[{ColorScheme.RESET}{quiz_details['creator_username']}{ColorScheme.ORANGE}]{ColorScheme.RESET}") 498 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}[{ColorScheme.RESET}Questions{ColorScheme.ORANGE}]{ColorScheme.GREEN}--{ColorScheme.ORANGE}[{ColorScheme.RESET}{quiz_details['question_count']}{ColorScheme.ORANGE}]{ColorScheme.RESET}") 499 | print(f"{ColorScheme.CYAN}====================================\n") 500 | 501 | output_lock = threading.Lock() 502 | 503 | for i in range(kahoot.get_quiz_length()): 504 | question_details = kahoot.get_question_details(i) 505 | 506 | with output_lock: 507 | if question_details["type"] == "content": 508 | print(f"{ColorScheme.YELLOW}SLIDE {i+1}: {question_details['title']}") 509 | if question_details.get('description'): 510 | print(f"{ColorScheme.GRAY}Description: {question_details['description']}{ColorScheme.RESET}\n") 511 | else: 512 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}[{ColorScheme.RESET}Question {i+1}{ColorScheme.ORANGE}]{ColorScheme.GREEN}--{ColorScheme.ORANGE}[{ColorScheme.RESET}{question_details['question']}{ColorScheme.ORANGE}]{ColorScheme.RESET}") 513 | 514 | answers = kahoot.get_answer(i) 515 | if answers: 516 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}[{ColorScheme.RESET}Answer{ColorScheme.ORANGE}]{ColorScheme.GREEN}--{ColorScheme.ORANGE}[{ColorScheme.RESET}{', '.join(answers)}{ColorScheme.ORANGE}]{ColorScheme.RESET}\n") 517 | else: 518 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}[{ColorScheme.RESET}Answer{ColorScheme.ORANGE}]{ColorScheme.GREEN}--{ColorScheme.ORANGE}[{ColorScheme.RESET}No correct answers found{ColorScheme.ORANGE}]{ColorScheme.RESET}\n") 519 | 520 | time.sleep(0.010) 521 | 522 | @staticmethod 523 | def display_options(kahoot): 524 | if not kahoot.valid: 525 | return 526 | 527 | print(f"\n{ColorScheme.CYAN}========= ADDITIONAL OPTIONS =========") 528 | print(f"{ColorScheme.YELLOW}1. {ColorScheme.RESET}Export answers to a text file") 529 | print(f"{ColorScheme.YELLOW}2. {ColorScheme.RESET}Return to main menu") 530 | print(f"{ColorScheme.YELLOW}3. {ColorScheme.RESET}Exit") 531 | print(f"{ColorScheme.CYAN}======================================\n") 532 | 533 | choice = input(f"{ColorScheme.PRETTY}Select an option: {ColorScheme.RESET}") 534 | 535 | if choice == "1": 536 | filename = input(f"{ColorScheme.PRETTY}Enter filename (default: kahoot_answers.txt): {ColorScheme.RESET}") or "kahoot_answers.txt" 537 | if kahoot.export_answers_to_file(filename): 538 | print(f"{ColorScheme.GREEN}Answers successfully exported to {filename}") 539 | else: 540 | print(f"{ColorScheme.RED}Failed to export answers.") 541 | elif choice == "2": 542 | return "menu" 543 | else: 544 | return "exit" 545 | 546 | def start_kahoot(): 547 | try: 548 | while True: 549 | KahootClientUI.display_intro() 550 | 551 | quiz_id = KahootClientUI.get_quiz_id() 552 | if not quiz_id: 553 | print(f"{ColorScheme.RED}Operation cancelled.") 554 | break 555 | 556 | print(f"{ColorScheme.PRETTY}{ColorScheme.ORANGE}({ColorScheme.GREEN}!{ColorScheme.ORANGE}) Fetching Answers From: {ColorScheme.ORANGE}[{ColorScheme.RESET}Quiz-ID: {quiz_id}{ColorScheme.ORANGE}]\n") 557 | 558 | quiz_data = KahootAPI.get_quiz_by_id(quiz_id) 559 | 560 | if 'error' in quiz_data: 561 | print(f"{ColorScheme.RED}Error: {quiz_data['error']}") 562 | retry = input(f"{ColorScheme.YELLOW}Try again? (y/n): {ColorScheme.RESET}").lower() 563 | if retry != 'y': 564 | break 565 | continue 566 | 567 | kahoot = KahootQuiz(quiz_data) 568 | 569 | KahootClientUI.display_answers(kahoot) 570 | 571 | result = KahootClientUI.display_options(kahoot) 572 | 573 | if result == "exit": 574 | break 575 | elif result != "menu": 576 | input(f"\n{ColorScheme.CYAN}Press any key to exit...{ColorScheme.RESET}") 577 | break 578 | 579 | except KeyboardInterrupt: 580 | print(f"\n{ColorScheme.YELLOW}Operation cancelled by user.{ColorScheme.RESET}") 581 | except Exception as e: 582 | print(f"\n{ColorScheme.RED}An unexpected error occurred: {str(e)}{ColorScheme.RESET}") 583 | 584 | print(f""" 585 | {ColorScheme.RED}||========================================================= 586 | ||Thanks for using Kitty-Tools <3 587 | ||Please *STAR* this repo and follow the creator on github! 588 | ||=========================================================\n 589 | {ColorScheme.RESET}""") 590 | 591 | if __name__ == "__main__": 592 | start_kahoot() 593 | -------------------------------------------------------------------------------- /docs/index.css: -------------------------------------------------------------------------------- 1 | .header-header { 2 | flex: 0 0 auto; 3 | width: 100%; 4 | height: 75px; 5 | display: flex; 6 | padding: var(--dl-space-space-unitandhalf); 7 | z-index: 1; 8 | max-width: 1320px; 9 | align-items: center; 10 | margin-bottom: 0.75rem; 11 | flex-direction: row; 12 | justify-content: space-between; 13 | } 14 | .header-container { 15 | display: flex; 16 | align-items: center; 17 | flex-direction: row; 18 | justify-content: space-between; 19 | } 20 | .header-navlink { 21 | display: contents; 22 | } 23 | .header-heading { 24 | color: var(--dl-color-gray-white); 25 | font-weight: 700; 26 | margin-right: var(--dl-space-space-unit); 27 | text-decoration: none; 28 | } 29 | .header-link { 30 | display: contents; 31 | } 32 | .header-container1 { 33 | display: flex; 34 | align-items: center; 35 | margin-left: var(--dl-space-space-halfunit); 36 | flex-direction: row; 37 | text-decoration: none; 38 | } 39 | .header-icon { 40 | fill: var(--dl-color-gray-900); 41 | width: 13px; 42 | } 43 | .header-text { 44 | color: var(--dl-color-gray-white); 45 | margin-left: var(--dl-space-space-halfunit); 46 | } 47 | .header-burger-menu { 48 | display: none; 49 | align-items: center; 50 | flex-direction: row; 51 | justify-content: space-between; 52 | } 53 | .header-icon05 { 54 | width: 24px; 55 | height: 24px; 56 | } 57 | .header-container2 { 58 | flex: 0 0 auto; 59 | display: flex; 60 | align-items: center; 61 | flex-direction: row; 62 | } 63 | .header-link1 { 64 | display: contents; 65 | } 66 | .header-icon07 { 67 | fill: var(--dl-color-gray-900); 68 | width: 24px; 69 | height: 24px; 70 | margin-top: var(--dl-space-space-halfunit); 71 | margin-left: 0.75rem; 72 | margin-right: 0.75rem; 73 | margin-bottom: var(--dl-space-space-halfunit); 74 | text-decoration: none; 75 | } 76 | .header-mobile-menu { 77 | top: 0px; 78 | flex: 0 0 auto; 79 | left: 0px; 80 | width: 100%; 81 | height: 100vh; 82 | display: none; 83 | padding: var(--dl-space-space-unitandhalf); 84 | z-index: 100; 85 | position: absolute; 86 | align-items: flex-start; 87 | flex-direction: column; 88 | background-color: #fff; 89 | } 90 | .header-top { 91 | width: 100%; 92 | display: flex; 93 | align-items: center; 94 | margin-bottom: var(--dl-space-space-unit); 95 | flex-direction: row; 96 | justify-content: space-between; 97 | } 98 | .header-navlink1 { 99 | display: contents; 100 | } 101 | .header-heading1 { 102 | color: var(--dl-color-secondary-400); 103 | font-weight: 700; 104 | margin-right: var(--dl-space-space-unit); 105 | text-decoration: none; 106 | } 107 | .header-close-menu { 108 | display: flex; 109 | align-items: center; 110 | flex-direction: row; 111 | justify-content: space-between; 112 | } 113 | .header-icon09 { 114 | width: 24px; 115 | height: 24px; 116 | } 117 | .header-mid { 118 | display: flex; 119 | align-items: flex-start; 120 | flex-direction: column; 121 | justify-content: space-between; 122 | } 123 | .header-navlink2 { 124 | display: contents; 125 | } 126 | .header-container3 { 127 | display: flex; 128 | align-items: center; 129 | margin-bottom: 8px; 130 | flex-direction: row; 131 | text-decoration: none; 132 | } 133 | .header-icon11 { 134 | fill: var(--dl-color-secondary-400); 135 | width: 13px; 136 | } 137 | .header-text1 { 138 | color: var(--dl-color-secondary-400); 139 | margin-left: var(--dl-space-space-halfunit); 140 | } 141 | .header-navlink3 { 142 | display: contents; 143 | } 144 | .header-container4 { 145 | display: flex; 146 | align-items: center; 147 | flex-direction: row; 148 | text-decoration: none; 149 | } 150 | .header-icon13 { 151 | fill: var(--dl-color-secondary-400); 152 | width: 13px; 153 | } 154 | .header-text2 { 155 | color: var(--dl-color-secondary-400); 156 | margin-left: var(--dl-space-space-halfunit); 157 | } 158 | .header-bot { 159 | flex: 0 0 auto; 160 | display: flex; 161 | margin-top: auto; 162 | align-items: center; 163 | flex-direction: row; 164 | } 165 | .header-icon18 { 166 | fill: var(--dl-color-secondary-400); 167 | width: 24px; 168 | height: 24px; 169 | margin-top: var(--dl-space-space-halfunit); 170 | margin-right: 0.75rem; 171 | margin-bottom: var(--dl-space-space-halfunit); 172 | } 173 | .header-icon20 { 174 | fill: var(--dl-color-secondary-400); 175 | width: 24px; 176 | height: 24px; 177 | margin-top: var(--dl-space-space-halfunit); 178 | margin-left: 0.75rem; 179 | margin-right: 0.75rem; 180 | margin-bottom: var(--dl-space-space-halfunit); 181 | } 182 | .header-icon22 { 183 | fill: var(--dl-color-secondary-400); 184 | width: 24px; 185 | height: 24px; 186 | margin-top: var(--dl-space-space-halfunit); 187 | margin-left: 0.75rem; 188 | margin-right: 0.75rem; 189 | margin-bottom: var(--dl-space-space-halfunit); 190 | } 191 | .header-root-class-name { 192 | margin-bottom: 0px; 193 | } 194 | @media(max-width: 991px) { 195 | .header-header { 196 | max-width: 1320px; 197 | margin-bottom: var(--dl-space-space-triplequarter); 198 | } 199 | .header-icon07 { 200 | margin-top: 0px; 201 | margin-bottom: 0px; 202 | } 203 | .header-icon18 { 204 | margin-top: 0px; 205 | margin-bottom: 0px; 206 | } 207 | .header-icon20 { 208 | margin-top: 0px; 209 | margin-bottom: 0px; 210 | } 211 | .header-icon22 { 212 | margin-top: 0px; 213 | margin-bottom: 0px; 214 | } 215 | } 216 | @media(max-width: 767px) { 217 | .header-header { 218 | background-color: var(--dl-color-gray-white); 219 | } 220 | .header-heading { 221 | color: var(--dl-color-secondary-400); 222 | } 223 | .header-container1 { 224 | display: none; 225 | } 226 | .header-burger-menu { 227 | display: flex; 228 | } 229 | .header-icon05 { 230 | fill: var(--dl-color-secondary-400); 231 | } 232 | .header-container2 { 233 | display: none; 234 | } 235 | .header-root-class-name { 236 | margin-bottom: 0px; 237 | } 238 | } 239 | 240 | .label-container { 241 | display: flex; 242 | position: relative; 243 | } 244 | .label-text { 245 | color: var(--dl-color-pimary-500); 246 | font-style: normal; 247 | font-weight: 700; 248 | line-height: 1; 249 | padding-top: 0.25rem; 250 | padding-left: var(--dl-space-space-halfunit); 251 | border-radius: var(--dl-radius-radius-radius25); 252 | padding-right: var(--dl-space-space-halfunit); 253 | padding-bottom: 0.25rem; 254 | text-transform: uppercase; 255 | background-color: var(--dl-color-pimary-700); 256 | } 257 | 258 | .member-details-container { 259 | display: flex; 260 | align-items: center; 261 | flex-direction: column; 262 | justify-content: center; 263 | } 264 | .member-details-image { 265 | width: 100px; 266 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 267 | object-fit: cover; 268 | border-radius: var(--dl-radius-radius-round); 269 | } 270 | .member-details-text { 271 | color: var(--dl-color-secondary-100); 272 | text-align: center; 273 | padding-top: var(--dl-space-space-unitandhalf); 274 | } 275 | .member-details-text1 { 276 | color: var(--dl-color-secondary-700); 277 | text-align: center; 278 | text-transform: uppercase; 279 | } 280 | 281 | .footer-container { 282 | width: 100%; 283 | display: flex; 284 | padding: var(--dl-space-space-doubleunit); 285 | align-items: center; 286 | flex-direction: column; 287 | justify-content: center; 288 | background-color: var(--dl-color-pimary-900); 289 | } 290 | .footer-container1 { 291 | width: 100%; 292 | display: flex; 293 | max-width: 1320px; 294 | align-items: flex-start; 295 | flex-direction: row; 296 | justify-content: space-between; 297 | } 298 | .footer-container2 { 299 | flex: 0 0 auto; 300 | display: flex; 301 | align-items: flex-start; 302 | flex-direction: column; 303 | } 304 | .footer-text { 305 | color: var(--dl-color-secondary-400); 306 | margin-top: var(--dl-space-space-unit); 307 | font-weight: 600; 308 | } 309 | .footer-text1 { 310 | color: var(--dl-color-secondary-500); 311 | margin-top: var(--dl-space-space-halfunit); 312 | margin-bottom: var(--dl-space-space-halfunit); 313 | } 314 | .footer-container3 { 315 | display: flex; 316 | margin-top: var(--dl-space-space-unitandhalf); 317 | align-items: flex-start; 318 | flex-direction: row; 319 | } 320 | .footer-link { 321 | display: contents; 322 | } 323 | .footer-container4 { 324 | flex: 0 0 auto; 325 | width: 2.5rem; 326 | height: 2.5rem; 327 | display: flex; 328 | box-shadow: 5px 5px 10px 0px #d4d4d4; 329 | align-items: center; 330 | margin-left: var(--dl-space-space-halfunit); 331 | border-radius: var(--dl-radius-radius-round); 332 | flex-direction: row; 333 | justify-content: center; 334 | text-decoration: none; 335 | background-color: var(--dl-color-gray-white); 336 | } 337 | .footer-icon { 338 | width: 16px; 339 | height: 16px; 340 | } 341 | .footer-container5 { 342 | display: flex; 343 | align-items: flex-start; 344 | flex-direction: row; 345 | justify-content: flex-start; 346 | } 347 | .footer-container6 { 348 | flex: 0 0 auto; 349 | display: flex; 350 | align-items: flex-start; 351 | margin-right: 6rem; 352 | flex-direction: column; 353 | } 354 | .footer-text2 { 355 | color: var(--dl-color-secondary-400); 356 | font-weight: 600; 357 | padding-bottom: var(--dl-space-space-halfunit); 358 | } 359 | .footer-link1 { 360 | color: var(--dl-color-secondary-500); 361 | padding-bottom: var(--dl-space-space-halfunit); 362 | text-decoration: none; 363 | } 364 | .footer-container7 { 365 | flex: 0 0 auto; 366 | display: flex; 367 | align-items: flex-start; 368 | flex-direction: column; 369 | } 370 | .footer-text3 { 371 | color: var(--dl-color-secondary-400); 372 | font-weight: 600; 373 | padding-bottom: var(--dl-space-space-halfunit); 374 | } 375 | .footer-link2 { 376 | color: var(--dl-color-secondary-500); 377 | padding-bottom: var(--dl-space-space-halfunit); 378 | text-decoration: none; 379 | } 380 | .footer-link3 { 381 | color: var(--dl-color-secondary-500); 382 | padding-bottom: var(--dl-space-space-halfunit); 383 | text-decoration: none; 384 | } 385 | .footer-link4 { 386 | color: var(--dl-color-secondary-500); 387 | text-decoration: none; 388 | } 389 | .footer-container8 { 390 | flex: 0 0 auto; 391 | width: 100%; 392 | height: 1px; 393 | display: flex; 394 | margin-top: var(--dl-space-space-tripleunit); 395 | align-items: flex-start; 396 | margin-bottom: var(--dl-space-space-tripleunit); 397 | flex-direction: column; 398 | background-color: #e3e8efff; 399 | } 400 | .footer-text4 { 401 | color: var(--dl-color-secondary-500); 402 | align-self: center; 403 | } 404 | @media(max-width: 991px) { 405 | .footer-container1 { 406 | align-items: center; 407 | flex-direction: column; 408 | } 409 | .footer-container2 { 410 | align-items: center; 411 | margin-bottom: var(--dl-space-space-doubleunit); 412 | } 413 | .footer-container6 { 414 | align-items: center; 415 | } 416 | .footer-container7 { 417 | align-items: center; 418 | } 419 | } 420 | @media(max-width: 767px) { 421 | .footer-text1 { 422 | text-align: center; 423 | } 424 | .footer-container5 { 425 | align-items: center; 426 | flex-direction: column; 427 | } 428 | .footer-container6 { 429 | align-items: center; 430 | margin-right: 0px; 431 | margin-bottom: var(--dl-space-space-doubleunit); 432 | } 433 | .footer-container7 { 434 | align-items: center; 435 | } 436 | } 437 | 438 | .home-container { 439 | width: 100%; 440 | height: auto; 441 | display: flex; 442 | min-height: 100vh; 443 | align-items: flex-start; 444 | flex-direction: column; 445 | } 446 | .home-hero { 447 | flex: 0 0 auto; 448 | width: 100%; 449 | height: 80vh; 450 | display: flex; 451 | position: relative; 452 | align-items: center; 453 | flex-direction: column; 454 | background-size: cover; 455 | background-image: url('https://kahoot.com/files/2023/09/desktop-mosaic-HE-bts-v2.jpg'); 456 | } 457 | .home-bg { 458 | flex: 0 0 auto; 459 | width: 100%; 460 | height: 100%; 461 | display: flex; 462 | opacity: 0.7; 463 | position: absolute; 464 | align-items: flex-start; 465 | flex-direction: column; 466 | background-color: var(--dl-color-gray-black); 467 | } 468 | .home-container01 { 469 | top: auto; 470 | left: auto; 471 | right: 0px; 472 | width: 100%; 473 | bottom: 0px; 474 | height: 100%; 475 | display: flex; 476 | position: absolute; 477 | align-items: center; 478 | flex-direction: column; 479 | justify-content: center; 480 | } 481 | .home-container02 { 482 | display: flex; 483 | align-items: center; 484 | padding-left: var(--dl-space-space-tripleunit); 485 | padding-right: var(--dl-space-space-tripleunit); 486 | flex-direction: column; 487 | justify-content: center; 488 | } 489 | .home-text { 490 | color: var(--dl-color-gray-white); 491 | text-align: center; 492 | } 493 | .home-text01 { 494 | color: var(--dl-color-gray-900); 495 | max-width: 800px; 496 | text-align: center; 497 | } 498 | .home-image { 499 | top: auto; 500 | left: auto; 501 | right: 0px; 502 | width: 100%; 503 | bottom: -1px; 504 | position: absolute; 505 | object-fit: cover; 506 | } 507 | .home-image1 { 508 | left: auto; 509 | right: 0px; 510 | width: 100%; 511 | bottom: 0px; 512 | display: none; 513 | position: absolute; 514 | object-fit: cover; 515 | } 516 | .home-section1 { 517 | flex: 0 0 auto; 518 | width: 100%; 519 | display: flex; 520 | position: relative; 521 | align-items: center; 522 | padding-top: var(--dl-space-space-tripleunit); 523 | padding-left: var(--dl-space-space-doubleunit); 524 | padding-right: var(--dl-space-space-doubleunit); 525 | flex-direction: column; 526 | padding-bottom: var(--dl-space-space-fiveunits); 527 | background-color: var(--dl-color-pimary-900); 528 | } 529 | .home-container03 { 530 | width: 100%; 531 | height: 572px; 532 | display: flex; 533 | max-width: 1320px; 534 | align-items: center; 535 | flex-direction: column; 536 | } 537 | .home-container04 { 538 | width: 66%; 539 | display: flex; 540 | align-items: center; 541 | padding-left: var(--dl-space-space-unit); 542 | padding-right: var(--dl-space-space-unit); 543 | flex-direction: column; 544 | } 545 | .home-text02 { 546 | color: var(--dl-color-pimary-500); 547 | font-size: 0.875em; 548 | font-style: normal; 549 | font-weight: 700; 550 | text-transform: uppercase; 551 | } 552 | .home-text03 { 553 | color: var(--dl-color-secondary-400); 554 | text-align: center; 555 | } 556 | .home-text04 { 557 | color: var(--dl-color-secondary-700); 558 | text-align: center; 559 | margin-bottom: 0.25rem; 560 | } 561 | .home-cards-container { 562 | display: flex; 563 | margin-top: var(--dl-space-space-tripleunit); 564 | align-items: flex-start; 565 | padding-top: var(--dl-space-space-tripleunit); 566 | margin-bottom: var(--dl-space-space-tripleunit); 567 | flex-direction: row; 568 | padding-bottom: var(--dl-space-space-tripleunit); 569 | justify-content: space-between; 570 | } 571 | .home-card1 { 572 | flex: 0 0 auto; 573 | width: 30%; 574 | display: flex; 575 | padding: var(--dl-space-space-unit); 576 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 577 | align-items: center; 578 | border-radius: var(--dl-radius-radius-radius50); 579 | flex-direction: column; 580 | background-color: var(--dl-color-gray-white); 581 | } 582 | .home-container05 { 583 | flex: 0 0 auto; 584 | width: 3rem; 585 | height: 3rem; 586 | display: flex; 587 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 588 | align-items: center; 589 | border-radius: var(--dl-radius-radius-round); 590 | flex-direction: column; 591 | justify-content: center; 592 | background-image: linear-gradient(180deg, #f87171, #dc2626); 593 | } 594 | .home-icon { 595 | fill: var(--dl-color-gray-white); 596 | width: 24px; 597 | height: 24px; 598 | } 599 | .home-text05 { 600 | color: var(--dl-color-secondary-100); 601 | margin-top: var(--dl-space-space-unit); 602 | text-align: center; 603 | font-family: Open Sans; 604 | } 605 | .home-text06 { 606 | color: var(--dl-color-secondary-700); 607 | font-size: 1rem; 608 | margin-top: var(--dl-space-space-halfunit); 609 | text-align: center; 610 | font-family: "Open Sans"; 611 | line-height: 1.625rem; 612 | } 613 | .home-card2 { 614 | flex: 0 0 auto; 615 | width: 30%; 616 | display: flex; 617 | padding: var(--dl-space-space-unit); 618 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 619 | align-items: center; 620 | border-radius: var(--dl-radius-radius-radius50); 621 | flex-direction: column; 622 | background-color: var(--dl-color-gray-white); 623 | } 624 | .home-container06 { 625 | flex: 0 0 auto; 626 | width: 3rem; 627 | height: 3rem; 628 | display: flex; 629 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 630 | align-items: center; 631 | border-radius: var(--dl-radius-radius-round); 632 | flex-direction: column; 633 | justify-content: center; 634 | background-image: linear-gradient(180deg, #38bdf8, #0284c7); 635 | } 636 | .home-icon02 { 637 | fill: var(--dl-color-gray-white); 638 | width: 24px; 639 | height: 24px; 640 | } 641 | .home-text07 { 642 | color: var(--dl-color-secondary-100); 643 | margin-top: var(--dl-space-space-unit); 644 | text-align: center; 645 | font-family: Open Sans; 646 | } 647 | .home-text08 { 648 | color: var(--dl-color-secondary-700); 649 | font-size: 1rem; 650 | margin-top: var(--dl-space-space-halfunit); 651 | text-align: center; 652 | font-family: "Open Sans"; 653 | line-height: 1.625rem; 654 | } 655 | .home-card3 { 656 | flex: 0 0 auto; 657 | width: 30%; 658 | display: flex; 659 | padding: var(--dl-space-space-unit); 660 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 661 | align-items: center; 662 | border-radius: var(--dl-radius-radius-radius50); 663 | flex-direction: column; 664 | background-color: var(--dl-color-gray-white); 665 | } 666 | .home-container07 { 667 | flex: 0 0 auto; 668 | width: 3rem; 669 | height: 3rem; 670 | display: flex; 671 | box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05); 672 | align-items: center; 673 | border-radius: var(--dl-radius-radius-round); 674 | flex-direction: column; 675 | justify-content: center; 676 | background-image: linear-gradient(180deg, #34d399, #059669); 677 | } 678 | .home-icon04 { 679 | fill: var(--dl-color-gray-white); 680 | width: 24px; 681 | height: 24px; 682 | } 683 | .home-text11 { 684 | color: var(--dl-color-secondary-100); 685 | margin-top: var(--dl-space-space-unit); 686 | text-align: center; 687 | font-family: Open Sans; 688 | } 689 | .home-text12 { 690 | color: var(--dl-color-secondary-700); 691 | font-size: 1rem; 692 | margin-top: var(--dl-space-space-halfunit); 693 | text-align: center; 694 | font-family: "Open Sans"; 695 | line-height: 1.625rem; 696 | } 697 | .home-image2 { 698 | top: auto; 699 | left: auto; 700 | right: 0px; 701 | width: 100%; 702 | bottom: -1px; 703 | position: absolute; 704 | object-fit: cover; 705 | } 706 | .home-section2 { 707 | flex: 0 0 auto; 708 | width: 100%; 709 | display: flex; 710 | align-self: center; 711 | align-items: center; 712 | padding-top: var(--dl-space-space-fiveunits); 713 | flex-direction: column; 714 | padding-bottom: var(--dl-space-space-fiveunits); 715 | } 716 | .home-container08 { 717 | width: 897px; 718 | display: flex; 719 | align-items: center; 720 | padding-left: var(--dl-space-space-unit); 721 | padding-right: var(--dl-space-space-unit); 722 | flex-direction: column; 723 | } 724 | .home-text13 { 725 | color: var(--dl-color-secondary-400); 726 | margin-top: var(--dl-space-space-halfunit); 727 | text-align: center; 728 | line-height: 2.5rem; 729 | } 730 | .home-text14 { 731 | line-height: 1.25; 732 | } 733 | .home-text15 { 734 | color: var(--dl-color-secondary-400); 735 | line-height: 2.5rem; 736 | } 737 | .home-text16 { 738 | color: var(--dl-color-secondary-700); 739 | text-align: center; 740 | margin-bottom: var(--dl-space-space-unitandhalf); 741 | } 742 | .home-container09 { 743 | flex: 0 0 auto; 744 | width: 66%; 745 | display: flex; 746 | margin-top: var(--dl-space-space-fiveunits); 747 | align-items: center; 748 | margin-bottom: var(--dl-space-space-fiveunits); 749 | flex-direction: column; 750 | } 751 | .home-text17 { 752 | color: var(--dl-color-secondary-400); 753 | font-size: 33.6px; 754 | text-align: center; 755 | } 756 | .home-text18 { 757 | color: var(--dl-color-secondary-700); 758 | text-align: center; 759 | font-weight: 400; 760 | margin-bottom: 0.25rem; 761 | } 762 | .home-team { 763 | flex: 0 0 auto; 764 | width: 100%; 765 | display: flex; 766 | align-items: flex-start; 767 | flex-direction: row; 768 | justify-content: center; 769 | } 770 | .home-container10 { 771 | width: 100%; 772 | display: flex; 773 | max-width: 1320px; 774 | align-items: flex-start; 775 | padding-left: var(--dl-space-space-doubleunit); 776 | padding-right: var(--dl-space-space-doubleunit); 777 | flex-direction: row; 778 | } 779 | .home-container11 { 780 | width: 50%; 781 | display: flex; 782 | align-items: center; 783 | padding-left: var(--dl-space-space-unit); 784 | padding-right: var(--dl-space-space-unit); 785 | flex-direction: column; 786 | justify-content: center; 787 | } 788 | .home-container12 { 789 | flex: 0 0 auto; 790 | display: flex; 791 | margin-top: var(--dl-space-space-unitandhalf); 792 | align-items: flex-start; 793 | flex-direction: row; 794 | } 795 | .home-link { 796 | display: contents; 797 | } 798 | .home-container13 { 799 | flex: 0 0 auto; 800 | width: 2.5rem; 801 | height: 2.5rem; 802 | display: flex; 803 | box-shadow: 5px 5px 10px 0px #d4d4d4; 804 | align-items: center; 805 | margin-left: 0px; 806 | border-radius: var(--dl-radius-radius-round); 807 | flex-direction: row; 808 | justify-content: center; 809 | text-decoration: none; 810 | background-color: var(--dl-color-gray-white); 811 | } 812 | .home-icon06 { 813 | width: 16px; 814 | height: 16px; 815 | } 816 | .home-container14 { 817 | width: 50%; 818 | display: flex; 819 | align-items: center; 820 | padding-left: var(--dl-space-space-unit); 821 | padding-right: var(--dl-space-space-unit); 822 | flex-direction: column; 823 | justify-content: center; 824 | } 825 | .home-container15 { 826 | flex: 0 0 auto; 827 | display: flex; 828 | margin-top: var(--dl-space-space-unitandhalf); 829 | align-items: flex-start; 830 | flex-direction: row; 831 | } 832 | .home-link1 { 833 | display: contents; 834 | } 835 | .home-container16 { 836 | flex: 0 0 auto; 837 | width: 2.5rem; 838 | height: 2.5rem; 839 | display: flex; 840 | box-shadow: 5px 5px 10px 0px #d4d4d4; 841 | align-items: center; 842 | margin-left: 0px; 843 | border-radius: var(--dl-radius-radius-round); 844 | flex-direction: row; 845 | justify-content: center; 846 | text-decoration: none; 847 | background-color: var(--dl-color-gray-white); 848 | } 849 | .home-icon08 { 850 | width: 16px; 851 | height: 16px; 852 | } 853 | .home-container17 { 854 | width: 50%; 855 | display: flex; 856 | align-items: center; 857 | padding-left: var(--dl-space-space-unit); 858 | padding-right: var(--dl-space-space-unit); 859 | flex-direction: column; 860 | justify-content: center; 861 | } 862 | .home-container18 { 863 | flex: 0 0 auto; 864 | display: flex; 865 | margin-top: var(--dl-space-space-unitandhalf); 866 | align-items: flex-start; 867 | flex-direction: row; 868 | } 869 | .home-link2 { 870 | display: contents; 871 | } 872 | .home-container19 { 873 | flex: 0 0 auto; 874 | width: 2.5rem; 875 | height: 2.5rem; 876 | display: flex; 877 | box-shadow: 5px 5px 10px 0px #d4d4d4; 878 | align-items: center; 879 | margin-left: 0px; 880 | border-radius: var(--dl-radius-radius-round); 881 | flex-direction: row; 882 | justify-content: center; 883 | text-decoration: none; 884 | background-color: var(--dl-color-gray-white); 885 | } 886 | .home-icon10 { 887 | width: 16px; 888 | height: 16px; 889 | } 890 | .home-container20 { 891 | width: 50%; 892 | display: flex; 893 | align-items: center; 894 | padding-left: var(--dl-space-space-unit); 895 | padding-right: var(--dl-space-space-unit); 896 | flex-direction: column; 897 | justify-content: center; 898 | } 899 | .home-container21 { 900 | flex: 0 0 auto; 901 | display: flex; 902 | margin-top: var(--dl-space-space-unitandhalf); 903 | align-items: flex-start; 904 | flex-direction: row; 905 | } 906 | .home-link3 { 907 | display: contents; 908 | } 909 | .home-container22 { 910 | flex: 0 0 auto; 911 | width: 2.5rem; 912 | height: 2.5rem; 913 | display: flex; 914 | box-shadow: 5px 5px 10px 0px #d4d4d4; 915 | align-items: center; 916 | margin-left: 0px; 917 | border-radius: var(--dl-radius-radius-round); 918 | flex-direction: row; 919 | justify-content: center; 920 | text-decoration: none; 921 | background-color: var(--dl-color-gray-white); 922 | } 923 | .home-icon12 { 924 | width: 16px; 925 | height: 16px; 926 | } 927 | .home-container23 { 928 | width: 50%; 929 | display: flex; 930 | align-items: center; 931 | padding-left: var(--dl-space-space-unit); 932 | padding-right: var(--dl-space-space-unit); 933 | flex-direction: column; 934 | justify-content: center; 935 | } 936 | .home-container24 { 937 | flex: 0 0 auto; 938 | display: flex; 939 | margin-top: var(--dl-space-space-unitandhalf); 940 | align-items: flex-start; 941 | flex-direction: row; 942 | } 943 | .home-link4 { 944 | display: contents; 945 | } 946 | .home-container25 { 947 | flex: 0 0 auto; 948 | width: 2.5rem; 949 | height: 2.5rem; 950 | display: flex; 951 | box-shadow: 5px 5px 10px 0px #d4d4d4; 952 | align-items: center; 953 | margin-left: 0px; 954 | border-radius: var(--dl-radius-radius-round); 955 | flex-direction: row; 956 | justify-content: center; 957 | text-decoration: none; 958 | background-color: var(--dl-color-gray-white); 959 | } 960 | .home-icon14 { 961 | width: 16px; 962 | height: 16px; 963 | } 964 | .home-image3 { 965 | width: 100%; 966 | align-self: center; 967 | object-fit: cover; 968 | } 969 | @media(max-width: 991px) { 970 | .home-cards-container { 971 | align-items: center; 972 | flex-direction: column; 973 | } 974 | .home-card1 { 975 | width: 90%; 976 | margin-bottom: var(--dl-space-space-fiveunits); 977 | } 978 | .home-card2 { 979 | width: 90%; 980 | margin-bottom: var(--dl-space-space-fiveunits); 981 | } 982 | .home-card3 { 983 | width: 90%; 984 | } 985 | .home-section2 { 986 | padding-left: var(--dl-space-space-doubleunit); 987 | padding-right: var(--dl-space-space-doubleunit); 988 | } 989 | .home-text13 { 990 | text-align: center; 991 | } 992 | } 993 | @media(max-width: 767px) { 994 | .home-section1 { 995 | padding-left: var(--dl-space-space-doubleunit); 996 | padding-right: var(--dl-space-space-doubleunit); 997 | } 998 | .home-container04 { 999 | width: 100%; 1000 | } 1001 | .home-container08 { 1002 | width: 100%; 1003 | } 1004 | .home-container09 { 1005 | width: auto; 1006 | padding-left: var(--dl-space-space-unit); 1007 | padding-right: var(--dl-space-space-unit); 1008 | } 1009 | .home-container10 { 1010 | flex-wrap: wrap; 1011 | flex-direction: row; 1012 | } 1013 | .home-container11 { 1014 | width: 50%; 1015 | margin-bottom: var(--dl-space-space-tripleunit); 1016 | } 1017 | .home-container14 { 1018 | width: 50%; 1019 | margin-bottom: var(--dl-space-space-tripleunit); 1020 | } 1021 | .home-container17 { 1022 | width: 50%; 1023 | padding-bottom: var(--dl-space-space-tripleunit); 1024 | } 1025 | .home-container20 { 1026 | width: 50%; 1027 | padding-bottom: var(--dl-space-space-tripleunit); 1028 | } 1029 | .home-container23 { 1030 | width: 50%; 1031 | padding-bottom: var(--dl-space-space-tripleunit); 1032 | } 1033 | } 1034 | @media(max-width: 479px) { 1035 | .home-container02 { 1036 | padding-left: var(--dl-space-space-doubleunit); 1037 | padding-right: var(--dl-space-space-doubleunit); 1038 | } 1039 | .home-card1 { 1040 | margin-bottom: var(--dl-space-space-tripleunit); 1041 | } 1042 | .home-text06 { 1043 | text-align: left; 1044 | } 1045 | .home-card2 { 1046 | margin-bottom: var(--dl-space-space-tripleunit); 1047 | } 1048 | .home-text08 { 1049 | text-align: left; 1050 | } 1051 | .home-text12 { 1052 | text-align: left; 1053 | } 1054 | .home-container10 { 1055 | align-items: center; 1056 | flex-direction: column; 1057 | } 1058 | } 1059 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | Kitty Tools 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 39 | 43 | 48 | 52 | 53 | 54 | 55 |
56 | 57 | 58 |
59 |
60 |
61 |
62 | 91 |
92 | 93 | 96 | 97 |
98 | 112 |
113 |
114 | 115 |

116 | Kitty Tools 117 |

118 |
119 |
120 | 121 | 124 | 125 |
126 |
127 | 158 |
159 | 160 | 164 | 171 | 174 | 175 |
176 |
177 |
178 |
179 |
180 |

181 | Elevate Entertainment and Enjoyment with Our Tool. 182 |

183 | 184 | Kitty Tools is a straightforward and reliable open-source hack 185 | for Kahoot that operates seamlessly in both web browsers and 186 | desktop environments. The tool includes an answer bot utilizing 187 | the Kahoot API, ensuring its continued functionality unless 188 | there are significant changes to the Kahoot API by its 189 | developers. 190 | 191 |
192 | image 193 | image 198 |
199 |
200 |
201 |
202 |
203 |
features
204 |

'What tools are there?' You ask!

205 | 206 | Kitty Tools undergoes regular updates, incorporating new tools 207 | and patches. Currently, its primary elements are outlined below. 208 | 209 |
210 |
211 |
212 |
213 | 214 | 217 | 218 |
219 |
Securing First Place
220 | 221 | Coming in first place has never been easyer! Using the fully automated answer hack you can be swiftly be propeld 222 | to the top position with impeccable scores. 223 | 224 |
225 |
226 |
227 | 228 | 231 | 232 |
233 |
Compatible With All Devices!
234 | 235 | 236 | Compatible with all devices! From Desktop to Mobile with LITE, you can now use this client on mostly any device! (I-phone version in development!) 237 | 238 |
239 |
240 |
241 |
242 |
243 | 244 | 247 | 248 |
249 |
Looks Official
250 | 251 | Gives the appearance of an official Kahoot client, eliminating 252 | concerns about your identity being sniffed out. 253 | 254 |
255 |
256 |
257 | image 258 |
259 |
260 |
261 |
262 |
Open Source?
263 |
264 |

265 | 266 | Absolutely! We are entirely open source. 267 | 268 |
269 |

270 | 271 | We highly value contributions from individuals who enhance the 272 | project by introducing new features and addressing bugs. That's 273 | why we've opted to make the project open source. 274 | 275 |
276 |
277 |

Contributers

278 | 279 | These are people who have been helpful and supported the project, 280 | making it grow. 281 | 282 |
283 |
284 |
285 |
286 |
287 | image 292 |

293 | CPScript 294 |

295 |

296 | Project Lead 297 |

298 |
299 | 318 |
319 |
320 |
321 | image 326 |

327 | Kira Kenjiro 328 |

329 |

330 | Web & Hybrid Dev 331 |

332 |
333 | 352 |
353 |
354 |
355 | image 360 |

361 | Cheepling 362 |

363 |

364 | Contributor 365 |

366 |
367 | 386 |
387 |
388 |
389 | image 394 |

395 | Zacky2613 396 |

397 |

398 | Contributor 399 |

400 |
401 | 420 |
421 |
422 |
423 | image 428 |

429 | Ccode-lang 430 |

431 |

432 | Contributor 433 |

434 |
435 | 454 |
455 |
456 |
457 |
458 | image 459 | 531 |
532 |
533 | 534 | 535 | 536 | --------------------------------------------------------------------------------