├── .gitignore ├── .projections.json ├── Makefile ├── README.md ├── TODO.md ├── TUTORIAL.md ├── beginbot.py ├── beginchat.py ├── bot.py ├── chat_thief ├── __init__.py ├── apps │ ├── __init__.py │ ├── audio_authorizer.py │ ├── beginworld_finance.py │ ├── economist_app.py │ ├── news_app.py │ └── notification_app.py ├── audioworld │ ├── __init__.py │ ├── audio_player.py │ ├── request_saver.py │ ├── sample_saver.py │ └── soundeffects_library.py ├── begin_fund.py ├── bots │ ├── __init__.py │ ├── forbes_bot.py │ ├── hand_of_the_market.py │ ├── new_news_bot.py │ ├── soundboard_bot.py │ └── soundeffect_request_bot.py ├── bwia.py ├── caught_stealing.py ├── chat_logs.py ├── chat_parsers │ ├── __init__.py │ ├── command_parser.py │ ├── cube_casino_parser.py │ ├── request_approver_parser.py │ └── soundeffect_request_parser.py ├── command_router.py ├── commands │ ├── __init__.py │ ├── command_giver.py │ ├── command_sharer.py │ ├── donator.py │ ├── la_libre.py │ ├── revolution.py │ └── street_cred_transfer.py ├── config │ ├── __init__.py │ ├── commands_config.py │ ├── help_menu.py │ ├── log.py │ ├── stream_lords.py │ └── twitch.py ├── current_stream.py ├── custom_types.py ├── data_scrubber.py ├── economist │ ├── __init__.py │ └── facts.py ├── formatters │ ├── __init__.py │ ├── cube_casino_formatter.py │ ├── purchase_formatter.py │ └── steal_formatter.py ├── irc.py ├── irc_msg.py ├── js │ ├── arbaya.js │ ├── beginTeletext.js │ ├── beginbotbot.js │ ├── beginfun.js │ ├── bsod.js │ ├── bubbles.js │ ├── cool_widget.js │ ├── cubeScramble.js │ ├── forbidden.js │ ├── legotux.js │ ├── matrix.js │ ├── opsecwidget.js │ ├── play-random-sound.js │ ├── popbubbles.js │ ├── privateorange.js │ ├── prototypeo4.js │ ├── screensaver.js │ ├── soundfolder.js │ ├── startmenu.js │ ├── uzi.js │ ├── zanuss.js │ └── zanussClock.js ├── models │ ├── __init__.py │ ├── base_db_model.py │ ├── bot_vote.py │ ├── breaking_news.py │ ├── command.py │ ├── css_vote.py │ ├── cube_bet.py │ ├── cube_stats.py │ ├── database.py │ ├── issue.py │ ├── notification.py │ ├── play_soundeffect_request.py │ ├── proposal.py │ ├── rap_sheet.py │ ├── sfx_vote.py │ ├── soundeffect_request.py │ ├── the_fed.py │ ├── transaction.py │ ├── tribal_council.py │ ├── user.py │ ├── user_code.py │ ├── user_event.py │ ├── user_page.py │ └── vote.py ├── mygeoangelfirespace │ ├── __init__.py │ ├── publisher.py │ ├── syncer.py │ └── user_publisher.py ├── new_commands │ ├── __init__.py │ ├── buyer.py │ ├── new_cube_casino.py │ ├── pokemon_casino.py │ ├── result.py │ └── stealer.py ├── permissions_fetcher.py ├── prize_dropper.py ├── routers │ ├── __init__.py │ ├── base_router.py │ ├── basic_info_router.py │ ├── beginworld_help_router.py │ ├── bot_survivor_router.py │ ├── community_router.py │ ├── economy_router.py │ ├── feedback_router.py │ ├── moderator_router.py │ ├── new_cube_casino_router.py │ ├── revolution_router.py │ ├── user_code_router.py │ └── voting_booth_router.py ├── scripts │ ├── __init__.py │ └── register_bots.py ├── static │ ├── 0xc0ffee__.css │ ├── 0xk0ff33__.css │ ├── 97lunarmare.css │ ├── acceptingdonation.css │ ├── adengamesbot.css │ ├── adengamestv.css │ ├── adrnlnjnky.css │ ├── airtonzanon.css │ ├── anakimluke.css │ ├── andrelamus.css │ ├── andyjamesadams.css │ ├── aquafunkalisticbootywhap.css │ ├── arbaya.css │ ├── archification.css │ ├── artmattdank.css │ ├── awfulwaffl3.css │ ├── aynstayn.css │ ├── baldclap.css │ ├── basti_brot.css │ ├── bbriano.css │ ├── beetle3d.css │ ├── beginbot.css │ ├── beginbotbot.css │ ├── beginbotbot.js │ ├── biged_twitch.css │ ├── bopojoe_.css │ ├── brandenkimm.css │ ├── burntbiskett.css │ ├── cachesking.css │ ├── chromosundrift.css │ ├── ciferhd.css │ ├── corbob.css │ ├── crazehani.css │ ├── crazytech44.css │ ├── crypt0lake.css │ ├── cykablondesbot.css │ ├── daaaabot.css │ ├── daaaball.css │ ├── dagio314.css │ ├── deni1111.css │ ├── dentyt.css │ ├── determin1st.css │ ├── dgksk8lif.css │ ├── distributedcache.css │ ├── eatpizza22.css │ ├── eitanfuturo.css │ ├── eleentje.css │ ├── evalprase.css │ ├── evilhomerdude.css │ ├── falloutghst.css │ ├── faolan437.css │ ├── fizziblytwitching.css │ ├── fletcherlabs.css │ ├── funksh0n.css │ ├── godworrior1.css │ ├── goldzulu.css │ ├── gottzstreams.css │ ├── idanscott.css │ ├── isidentical.css │ ├── j0bdone.css │ ├── jerbear1235.css │ ├── joehaaga.css │ ├── joker_dan.css │ ├── jr_boss.css │ ├── jr_bots.css │ ├── julianfun123.css │ ├── juscuzryancan.css │ ├── kraemrz.css │ ├── ladka8.css │ ├── lan_four.css │ ├── larckyash.css │ ├── legotux.css │ ├── levinson2504.css │ ├── loner_lena.css │ ├── manascode.css │ ├── manna_soumya.css │ ├── maxthakurcodes.css │ ├── mel_mass.css │ ├── mightycore1.css │ ├── morgenstern991.css │ ├── mrdemonwolf.css │ ├── mrsommerfeld.css │ ├── nerigera.css │ ├── nineteenletterslong.css │ ├── nomoreequity.css │ ├── nomorequity.css │ ├── opsecbot.css │ ├── oreo_171.css │ ├── orlaanihun.css │ ├── pedrovalentimmm.css │ ├── porokon7.css │ ├── portaalgaming.css │ ├── privateorange.css │ ├── prototypeo4.css │ ├── purplepinapples.css │ ├── pyramidpixels.css │ ├── q_wolf.css │ ├── radnire.css │ ├── rasmustof.css │ ├── remi_xrei.css │ ├── rexroof.css │ ├── richardme123.css │ ├── rockerboo.css │ ├── salepate.css │ ├── samharnack.css │ ├── sana_rinomi.css │ ├── scrabill.css │ ├── secretmud.css │ ├── shidotmoe.css │ ├── shineslove.css │ ├── simplex991.css │ ├── snazzinburg.css │ ├── soulshined.css │ ├── space_vacation.css │ ├── stallmansbot.css │ ├── sticklemepickle.css │ ├── stupac62.css │ ├── style.css │ ├── sudo0101.css │ ├── sunny_ai.css │ ├── supadeviserr.css │ ├── suuupersonic.css │ ├── syoonee.css │ ├── teamviewselect.css │ ├── the_fed.css │ ├── the_oronco.css │ ├── thegooseofwild.css │ ├── tinkernthink.css │ ├── tonimontanasf.css │ ├── trgwii.css │ ├── unlucksmcbot.css │ ├── unlucksmcgee.css │ ├── usernamesarelame.css │ ├── usuallyhigh.css │ ├── vagozino.css │ ├── vappolinario.css │ ├── vaterzz.css │ ├── weather_tank.css │ ├── whatsinmyopsec.css │ ├── whybrow.css │ ├── wmotion.css │ ├── wogilol.css │ ├── yatko.css │ ├── zackariep.css │ ├── zanpreston.css │ ├── zanuss.css │ ├── zanussbot.css │ ├── zeebz91.css │ ├── zer0xeon.css │ ├── zerostheory.css │ └── zolor.css ├── stats_department.py ├── stitch_and_sort.py ├── templates │ ├── beginworld_finance.html │ ├── bots.html │ ├── command.html │ ├── coup.html │ ├── index.html │ ├── news.html │ ├── notification.html │ ├── stats.html │ ├── sunny.html │ ├── user.html │ └── widgets.html ├── utils │ ├── __init__.py │ ├── stats.py │ └── url_validator.py └── welcome_committee.py ├── cool_program.py ├── countries.py ├── docs ├── BOT_LAW.md ├── BUGS.md ├── Bot_Witch_Trials.md ├── Coding_Questions.md ├── Cube_Gambling_Ring.md ├── Death_and_Taxes.md ├── How_to_use_commands.md ├── PEACE_COUP_REVOLUTION.md ├── Stealing.md └── The_Flow_Of_Commands.md ├── fake_bot.py ├── infra ├── .gitignore ├── Pulumi.dev.yaml ├── Pulumi.yaml ├── __main__.py └── requirements.txt ├── mypy.ini ├── presentations ├── community │ ├── community │ └── community.jpeg ├── health ├── local_bot │ └── main ├── revolutions │ └── coup_talk └── wtf │ ├── brr.png │ ├── econ │ ├── stonks.jpeg │ ├── unemployment.jpeg │ └── woosh.jpg ├── requirements ├── develop.in └── runtime.in ├── scripts ├── blacklist_user ├── fun.sh ├── sync_html.sh └── whitelist_user └── tests ├── __init__.py ├── audioworld ├── test_audio_player.py ├── test_request_saver.py ├── test_sample_saver.py └── test_soundeffects_library.py ├── chat_parsers ├── test_command_parser.py ├── test_cube_casino_parser.py └── test_soundeffect_request_parser.py ├── commands ├── test_command_giver.py ├── test_command_sharer.py ├── test_donator.py ├── test_la_libre.py └── test_revolution.py ├── conftest.py ├── formatters ├── test_cube_casino_formatter.py ├── test_purchase_formatting.py └── test_steal_formatter.py ├── models ├── test_base_db_model.py ├── test_bot_vote.py ├── test_breaking_news.py ├── test_command.py ├── test_css_vote.py ├── test_cube_bet.py ├── test_cube_stats.py ├── test_issue.py ├── test_notification.py ├── test_play_soundeffect_request.py ├── test_proposal.py ├── test_rap_sheet.py ├── test_sfx_vote.py ├── test_soundeffect_request.py ├── test_the_fed.py ├── test_tribal_council.py ├── test_user.py ├── test_user_code.py ├── test_user_event.py ├── test_user_page.py └── test_vote.py ├── new_commands ├── test_buyer.py ├── test_new_cube_casino.py ├── test_pokemon_casino.py └── test_stealer.py ├── routers ├── test_basic_info_router.py ├── test_beginworld_help_router.py ├── test_bot_survivor_router.py ├── test_community_router.py ├── test_economy_router.py ├── test_feedback_router.py ├── test_moderator_router.py ├── test_new_cube_casino_router.py ├── test_revolution_router.py ├── test_user_code_router.py └── test_voting_booth_router.py ├── support ├── database_setup.py └── utils.py ├── test_begin_fund.py ├── test_breaking_news.py ├── test_bwia.py ├── test_caught_stealing.py ├── test_chat_logs.py ├── test_command_router.py ├── test_data_scrubber.py ├── test_irc_msg.py ├── test_permissions_fetcher.py ├── test_stats_department.py ├── test_stitch_and_sort.py └── test_welcome_committee.py /.gitignore: -------------------------------------------------------------------------------- 1 | logs/* 2 | venv/* 3 | db/* 4 | tmp/* 5 | build/* 6 | tests/db/* 7 | tests/tmp/* 8 | .mypy_cache/* 9 | .whitelisted_users 10 | .welcome 11 | .coverage 12 | 13 | __pycache__/ 14 | *.py[cod] 15 | -------------------------------------------------------------------------------- /.projections.json: -------------------------------------------------------------------------------- 1 | { 2 | "chat_thief/*.py": { 3 | "alternate": "tests/{dirname}/test_{basename}.py", 4 | "type": "source" 5 | }, 6 | "tests/**/test_*.py": { 7 | "alternate": "chat_thief/{dirname}/{basename}.py", 8 | "type": "test" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | ## Features 4 | 5 | - Determine What is the Bot Test, bots must pass 6 | 7 | ## Enhancements 8 | 9 | - Breaking News 10 | - Dev Leaderboard winner 11 | - Homepage Winner 12 | - Revolution And Coup 13 | - Stealest Most Expensive Command 14 | - Mygeoangelfirespace 15 | - Don't update Users who aren't present 16 | - Pokemon Guessing Game 17 | - Save to JSON 18 | - Top Guessers 19 | - Top Winners 20 | - Poke Stats Site 21 | - Revolution / Peace / Coup 22 | - We should only trigger news One 23 | - Speed up the Wealth Transfer Commands 24 | - Look into Triggering of Coup logic 25 | - Upload Breaking News to the Website 26 | - Update the [https://mygeoangelfirespace.city/](Site) to have more 27 | instructions/info 28 | - Save Who Adds Sounds 29 | 30 | ## Refactor 31 | 32 | - Improve the Soundeffect Request Saving Code 33 | - Better error messages 34 | - Validation of Timestamps 35 | - Use Youtube DL in Python Code 36 | - Split the saving of all commands from processing 37 | - Split the Project into separate Git repos 38 | - Soundeffect Request Saving 39 | - IRC Log Collection 40 | - HTML Generation 41 | -------------------------------------------------------------------------------- /beginbot.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | import sys 4 | 5 | from bot import irc_handshake, simple_send_msg, CONNECTION_DATA 6 | 7 | # We add ! to these commands 8 | NIGHTBOT_COMMANDS = [ 9 | "discord", 10 | "github", 11 | "links", 12 | "linux", 13 | "guest", 14 | "marker", 15 | "schedule", 16 | "so", 17 | "idk", 18 | "ha", 19 | "wyp", 20 | "jdi", 21 | "clap", 22 | "ahh", 23 | "topic", 24 | ] 25 | 26 | if __name__ == "__main__": 27 | with socket.socket() as server: 28 | server.connect(CONNECTION_DATA) 29 | irc_handshake(server) 30 | cmd, *args = sys.argv[1:] 31 | 32 | # This should look for this commands when I am sending them and add the exclamation if I have a sound effect 33 | if cmd in NIGHTBOT_COMMANDS: 34 | cmd = f"!{cmd}" 35 | 36 | try: 37 | simple_send_msg(server, f"{cmd} {' '.join(args)}") 38 | except Exception as e: 39 | print(e) 40 | -------------------------------------------------------------------------------- /chat_thief/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/__init__.py -------------------------------------------------------------------------------- /chat_thief/apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/apps/__init__.py -------------------------------------------------------------------------------- /chat_thief/apps/audio_authorizer.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask import render_template 3 | 4 | from chat_thief.models.user import User 5 | from chat_thief.models.command import Command 6 | from chat_thief.config.stream_lords import STREAM_GODS, STREAM_LORDS 7 | 8 | app = Flask(__name__, template_folder="templates") 9 | 10 | 11 | @app.route("/") 12 | def home(): 13 | users = User.by_cool_points() 14 | commands = Command.by_cost() 15 | return render_template("beginworld_finance.html", users=users, commands=commands,) 16 | 17 | 18 | @app.route("/sound//allowed/") 19 | def authorizer(sound, username): 20 | user = User(username) 21 | mana = user.mana() 22 | streamlord = username in STREAM_LORDS 23 | # streamlord = username in STREAM_GODS 24 | 25 | owned = Command(sound).allowed_to_play(username) 26 | if streamlord: 27 | allowed = True 28 | else: 29 | allowed = owned and mana > 0 30 | 31 | if allowed: 32 | user.update_mana(-1) 33 | 34 | result = {"allowed": allowed, "owned": owned, "streamlord": streamlord, "extra": False, "mana": mana} 35 | 36 | print(f"\n\n\t{result=}") 37 | 38 | return result 39 | 40 | if __name__ == "audio_authorizer": 41 | app.run(debug=True) 42 | -------------------------------------------------------------------------------- /chat_thief/apps/beginworld_finance.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask import render_template 3 | 4 | from chat_thief.models.user import User 5 | from chat_thief.models.command import Command 6 | from chat_thief.models.sfx_vote import SFXVote 7 | 8 | app = Flask(__name__, template_folder="templates") 9 | 10 | 11 | @app.route("/") 12 | def home(): 13 | users = User.by_cool_points() 14 | commands = Command.by_cost() 15 | return render_template("beginworld_finance.html", users=users, commands=commands,) 16 | 17 | 18 | @app.route("/user/") 19 | def profile(username): 20 | user = User(username) 21 | commands = user.commands() 22 | stats = user.stats() 23 | print(f"{user=}") 24 | print(f"{commands=}") 25 | print(f"{stats=}") 26 | return render_template("user.html", user=user, stats=stats, commands=commands) 27 | 28 | 29 | @app.route("/command/") 30 | def command_stats(command_name): 31 | command = Command(command_name) 32 | sfx_vote = SFXVote(command_name) 33 | return render_template( 34 | "command.html", 35 | command=command, 36 | like_to_hate_ratio=sfx_vote.like_to_hate_ratio(), 37 | ) 38 | 39 | 40 | if __name__ == "beginworld_finance": 41 | app.run(debug=True) 42 | -------------------------------------------------------------------------------- /chat_thief/apps/economist_app.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import Dict, List 3 | import time 4 | 5 | from flask import Flask 6 | from flask import render_template 7 | 8 | 9 | from chat_thief.economist.facts import Facts 10 | 11 | 12 | @dataclass 13 | class FactsView: 14 | revolution_count: int 15 | peace_count: int 16 | total_votes: int 17 | available_sounds: int 18 | unavailable_sounds: int 19 | total_sounds: int 20 | cool_points: int 21 | street_cred: int 22 | top_users: List 23 | most_popular: List 24 | 25 | 26 | app = Flask(__name__, template_folder="../templates") 27 | 28 | 29 | @app.route("/") 30 | def facts(name=None): 31 | while True: 32 | facts = Facts() 33 | 34 | most_popular = facts.most_popular() 35 | most_popular.reverse() 36 | 37 | facts_view = FactsView( 38 | total_votes=facts.total_votes(), 39 | available_sounds=facts.available_sounds(), 40 | revolution_count=facts.revolution_count(), 41 | peace_count=facts.peace_count(), 42 | unavailable_sounds=facts.unavailable_sounds(), 43 | total_sounds=facts.total_sounds(), 44 | cool_points=facts.cool_points(), 45 | top_users=facts.top_users(), 46 | street_cred=facts.street_cred(), 47 | most_popular=most_popular, 48 | ) 49 | 50 | return render_template("index.html", facts=facts_view) 51 | time.sleep(1) 52 | 53 | 54 | if __name__ == "economist_app": 55 | app.run(debug=True) 56 | -------------------------------------------------------------------------------- /chat_thief/apps/notification_app.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | import time 3 | 4 | from flask import Flask 5 | from flask import render_template 6 | 7 | from chat_thief.models.notification import Notification 8 | 9 | 10 | app = Flask(__name__, template_folder="../templates") 11 | 12 | 13 | @app.route("/") 14 | def facts(name=None): 15 | last_notification = Notification.last() 16 | if last_notification: 17 | message = last_notification["message"] 18 | duration = last_notification["duration"] 19 | else: 20 | message = None 21 | duration = None 22 | 23 | return render_template( 24 | "notification.html", notification=message, refresh_time=duration 25 | ) 26 | 27 | 28 | if __name__ == "notification_app": 29 | app.run(debug=True) 30 | -------------------------------------------------------------------------------- /chat_thief/audioworld/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/audioworld/__init__.py -------------------------------------------------------------------------------- /chat_thief/audioworld/audio_player.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import subprocess 4 | import traceback 5 | 6 | from chat_thief.config.log import success 7 | from chat_thief.models.notification import Notification 8 | from chat_thief.models.command import Command 9 | 10 | MPLAYER_VOL_NORM = "0.75" 11 | 12 | 13 | class AudioPlayer: 14 | @staticmethod 15 | def play_sample(sound_file, notification=True, user=None): 16 | sound_name = sound_file.name[: -len(sound_file.suffix)] 17 | Command(sound_name).decay() 18 | 19 | # success(f"Playing: {sound_name}") 20 | 21 | if notification: 22 | if user: 23 | Notification(f"{user}: !{sound_name}", duration=1).save() 24 | else: 25 | Notification(f"Playing: !{sound_name}", duration=1).save() 26 | 27 | try: 28 | pass 29 | # subprocess.call( 30 | # ["mplayer", "-af", f"volnorm=2:{MPLAYER_VOL_NORM}", sound_file], 31 | # stderr=subprocess.DEVNULL, 32 | # stdout=subprocess.DEVNULL, 33 | # ) 34 | except: 35 | traceback.print_exc() 36 | -------------------------------------------------------------------------------- /chat_thief/audioworld/soundeffects_library.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import List, Set, Optional 3 | 4 | THEME_SONGS_PATH = "/home/begin/stream/Stream/Samples/theme_songs" 5 | SAMPLES_PATH = "/home/begin/stream/Stream/Samples/" 6 | ALLOWED_AUDIO_FORMATS = [".mp3", ".m4a", ".wav", ".opus", ".ogg"] 7 | 8 | 9 | class SoundeffectsLibrary: 10 | @staticmethod 11 | def find_sample(name: str) -> Optional[Path]: 12 | samples = [ 13 | sample 14 | for sample in SoundeffectsLibrary.fetch_soundeffect_samples() 15 | if name == sample.name[: -len(sample.suffix)] 16 | ] 17 | if samples: 18 | return samples[0] 19 | else: 20 | return None 21 | 22 | @staticmethod 23 | def fetch_theme_songs() -> List[str]: 24 | return [ 25 | theme.name[: -len(theme.suffix)] 26 | for theme in Path(THEME_SONGS_PATH).glob("*") 27 | ] 28 | 29 | @staticmethod 30 | def soundeffects_only() -> Set[str]: 31 | return set(SoundeffectsLibrary.fetch_soundeffect_names()) - set( 32 | SoundeffectsLibrary.fetch_theme_songs() 33 | ) 34 | 35 | @staticmethod 36 | def fetch_soundeffect_samples() -> Set[Path]: 37 | return { 38 | p.resolve() 39 | for p in Path(SAMPLES_PATH).glob("**/*") 40 | if p.suffix in ALLOWED_AUDIO_FORMATS 41 | } 42 | 43 | @staticmethod 44 | def fetch_soundeffect_names() -> List[str]: 45 | sound_files = SoundeffectsLibrary.fetch_soundeffect_samples() 46 | 47 | return [ 48 | sound_file.name[: -len(sound_file.suffix)] for sound_file in sound_files 49 | ] 50 | 51 | @staticmethod 52 | def find_soundeffect_files(name: str) -> List[Path]: 53 | return [ 54 | p 55 | for p in Path(SAMPLES_PATH).glob("**/*") 56 | if p.suffix in ALLOWED_AUDIO_FORMATS 57 | if p.name[: -len(p.suffix)] == name 58 | ] 59 | -------------------------------------------------------------------------------- /chat_thief/bots/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/bots/__init__.py -------------------------------------------------------------------------------- /chat_thief/bots/soundeffect_request_bot.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict 2 | import json 3 | import traceback 4 | import time 5 | 6 | from chat_thief.config.log import logger 7 | from chat_thief.models.soundeffect_request import SoundeffectRequest 8 | 9 | 10 | def sync_main(): 11 | while True: 12 | try: 13 | SoundeffectRequest.pop_all_off() 14 | time.sleep(1) 15 | except Exception as e: 16 | if e is KeyboardInterrupt: 17 | raise e 18 | else: 19 | traceback.print_exc() 20 | 21 | 22 | if __name__ == "__main__": 23 | sync_main() 24 | -------------------------------------------------------------------------------- /chat_thief/bwia.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import operator 3 | 4 | from tinydb import Query # type: ignore 5 | 6 | from chat_thief.models.user_event import UserEvent 7 | 8 | 9 | class BWIA: 10 | @classmethod 11 | def robinhood_score(cls, user): 12 | return len( 13 | UserEvent.db().search( 14 | ((Query().command == "give") | (Query().command == "share")) 15 | & (Query().user == user) 16 | ) 17 | ) 18 | 19 | @classmethod 20 | def find_thief(cls, thief): 21 | return len( 22 | UserEvent.db().search( 23 | (Query().command == "steal") & (Query().user == thief) 24 | ) 25 | ) 26 | 27 | @classmethod 28 | def thieves(cls): 29 | steal_events = UserEvent.db().search(Query().command == "steal") 30 | thieves = itertools.groupby(steal_events, operator.itemgetter("user")) 31 | 32 | steal_counts = [] 33 | for thief, user_events in thieves: 34 | steal_count = 0 35 | for event in user_events: 36 | steal_count += 1 37 | steal_counts.append((thief, steal_count)) 38 | 39 | return steal_counts 40 | -------------------------------------------------------------------------------- /chat_thief/chat_logs.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from collections import Counter 3 | 4 | from chat_thief.config.stream_lords import STREAM_GODS 5 | 6 | # Keeping to shorter number rewards more recent users, 7 | # ALL_LINES has to also be False 8 | DEFAULT_LINE_COUNT = 1000 9 | ALL_LINES = True 10 | 11 | 12 | class ChatLogs: 13 | def __init__(self): 14 | lines = self._read_in_chat(all_lines=True) 15 | self.raw_users = [chat_msg.split(":")[0] for chat_msg in lines] 16 | 17 | def users(self): 18 | return list(set(self.raw_users)) 19 | 20 | def most_msgs(self): 21 | return Counter(self.raw_users) 22 | 23 | def recent_stream_peasants(self): 24 | lines = self._read_in_chat(line_count=DEFAULT_LINE_COUNT, all_lines=False) 25 | users = [chat_msg.split(":")[0].strip() for chat_msg in lines] 26 | # peasants = [user for user in users if user not in STREAM_GODS] 27 | peasants = list(set([user for user in users if user not in STREAM_GODS])) 28 | 29 | return peasants 30 | 31 | def _read_in_chat(self, line_count=DEFAULT_LINE_COUNT, all_lines=ALL_LINES): 32 | with Path(__file__).parent.parent.joinpath("logs/chat.log") as log: 33 | chat_lines = [line for line in log.read_text().split("\n") if line] 34 | if all_lines: 35 | lines = chat_lines 36 | else: 37 | lines = chat_lines[-line_count:] 38 | return lines 39 | -------------------------------------------------------------------------------- /chat_thief/chat_parsers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/chat_parsers/__init__.py -------------------------------------------------------------------------------- /chat_thief/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/commands/__init__.py -------------------------------------------------------------------------------- /chat_thief/commands/command_giver.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union 2 | 3 | from chat_thief.models.user import User 4 | from chat_thief.models.command import Command 5 | from chat_thief.config.stream_lords import STREAM_GODS 6 | from chat_thief.custom_types import ChatReturnMessage 7 | 8 | 9 | class CommandGiver: 10 | def __init__(self, user: str, command: str, friend: str): 11 | self.user = user 12 | self.command = command 13 | self.friend = friend 14 | 15 | if user == friend: 16 | raise ValueError("You cannot transfer sounds to yourself") 17 | 18 | def give(self) -> ChatReturnMessage: 19 | if self.user in STREAM_GODS: 20 | return f"YOU'RE A STREAM GOD @{self.user} YOU DON'T NEED TO SWAP PERMS" 21 | 22 | command = Command(self.command) 23 | permitted_users = command.users() 24 | 25 | if self.user in permitted_users: 26 | if self.friend in permitted_users: 27 | return ( 28 | f"@{self.friend} already has access to !{self.command} @{self.user}" 29 | ) 30 | else: 31 | allow_msg = command.allow_user(self.friend) 32 | # TODO: revist and potentially don't return the unallowe 33 | # statement 34 | return [allow_msg, command.unallow_user(self.user)] 35 | 36 | return f"@{self.user} does not have permission to give: !{self.command}" 37 | -------------------------------------------------------------------------------- /chat_thief/commands/command_sharer.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.user import User 2 | from chat_thief.models.command import Command 3 | from chat_thief.config.stream_lords import STREAM_GODS 4 | 5 | from chat_thief.audioworld.soundeffects_library import SoundeffectsLibrary 6 | 7 | 8 | class CommandSharer: 9 | def __init__(self, user: str, command: str, friend: str): 10 | self.user = user 11 | self.command = command 12 | self.friend = friend 13 | 14 | def share(self) -> str: 15 | if not self.command in SoundeffectsLibrary.fetch_soundeffect_names(): 16 | return f"@{self.user} cannot share !{self.command} as it's invalid" 17 | 18 | command = Command(name=self.command) 19 | command_cost = command.cost() 20 | user_cool_points = User(self.user).cool_points() 21 | 22 | if self.user in STREAM_GODS: 23 | perm_result = command.allow_user(self.friend) 24 | return f"{self.user} shared {perm_result}" 25 | 26 | elif user_cool_points >= command_cost: 27 | perm_result = command.allow_user(self.friend) 28 | if perm_result: 29 | print("\nWe have a Perm Result") 30 | User(self.user).update_cool_points(-command_cost) 31 | command.increase_cost(command_cost * 2) 32 | return f"{self.user} shared {perm_result}" 33 | else: 34 | print("\nWe NOOOOO have a Perm Result") 35 | return f"{self.user} cannot add permissions" 36 | 37 | else: 38 | return f"@{self.user} Not enough cool_points ({user_cool_points}/{command_cost}) to share !{self.command} with @{self.friend}" 39 | -------------------------------------------------------------------------------- /chat_thief/commands/donator.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Dict, List 2 | 3 | from chat_thief.models.user import User 4 | from chat_thief.models.command import Command 5 | 6 | from chat_thief.prize_dropper import random_user 7 | 8 | 9 | class Donator: 10 | def __init__(self, user: str): 11 | self.user = user 12 | 13 | def donate(self, target_user: Optional[str] = None) -> str: 14 | results: Dict[str, List[str]] = {} 15 | 16 | for command_name in User(self.user).commands(): 17 | if command_name == self.user: 18 | continue 19 | 20 | command = Command(command_name) # This is a Command 21 | 22 | # so we we have a user use it 23 | # if not donate to randos 24 | if target_user: 25 | new_user = target_user 26 | else: 27 | new_user = random_user(blacklisted_users=command.users()) 28 | 29 | if new_user: 30 | donated_commands = results.get(new_user, []) 31 | results[new_user] = donated_commands + [command.name] 32 | command.allow_user(new_user) 33 | command.unallow_user(self.user) 34 | 35 | return " ".join( 36 | [ 37 | f"@{user} was gifted {' '.join([f'!{command}' for command in commands])}" 38 | for user, commands in results.items() 39 | ] 40 | ) 41 | -------------------------------------------------------------------------------- /chat_thief/commands/la_libre.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from chat_thief.chat_logs import ChatLogs 4 | from chat_thief.models.command import Command 5 | from chat_thief.models.user import User 6 | from chat_thief.models.vote import Vote 7 | 8 | REVOLUTION_LIKELYHOOD = 14 9 | DEFAULT_THRESHOLD = 3 10 | 11 | 12 | class LaLibre: 13 | @classmethod 14 | def threshold(cls) -> int: 15 | peasants = ChatLogs().recent_stream_peasants() 16 | value = int(len(peasants) / REVOLUTION_LIKELYHOOD) 17 | if value < DEFAULT_THRESHOLD: 18 | return DEFAULT_THRESHOLD 19 | return value 20 | 21 | @classmethod 22 | def inform(cls) -> List[str]: 23 | return [ 24 | "PowerUpL La Libre PowerUpR", 25 | f"Total Votes: {Vote.count()}", 26 | f"Peace Count: {Vote.peace_count()} / {cls.threshold()}", 27 | f"Revolution Count: {Vote.revolution_count()} / {cls.threshold()}", 28 | f"panicBasket Coup Cost: {Command('coup').cost()} panicBasket", 29 | ] 30 | -------------------------------------------------------------------------------- /chat_thief/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/config/__init__.py -------------------------------------------------------------------------------- /chat_thief/config/commands_config.py: -------------------------------------------------------------------------------- 1 | OBS_COMMANDS = [ 2 | "wyp", 3 | "idk", 4 | "jdi", 5 | "brb", 6 | "i_hate_that_thing", 7 | "i_like_that_thing", 8 | "shuzo" 9 | # "keyboard", # WE now are using our own scene more often 10 | ] 11 | -------------------------------------------------------------------------------- /chat_thief/config/help_menu.py: -------------------------------------------------------------------------------- 1 | HELP_COMMANDS = { 2 | "me": "Info about yourself", 3 | "buy": "!buy COMMAND or !buy random - Buy a Command with Cool Points", 4 | "love": "!love USER COMMAND - Show support for a command (Unmutes if theres Haters)", 5 | "hate": "!hate USER COMMAND - Vote to silence a command", 6 | "steal": "!steal COMMAND USER - steal a command from someone elses, cost Cool Points", 7 | "share": "!share COMMAND USER - share access to a command", 8 | "transfer": "!transfer COMMAND USER - transfer command to someone, costs no cool points", 9 | "props": "!props @beginbot (AMOUNT_OF_STREET_CRED) - Give you street cred to beginbot", 10 | "perms": "!perms !clap OR !perms @beginbot - See who is allowed to use the !clap command", 11 | "donate": "!donate give away all your commands to random users", 12 | "issue": "!issue Description of a Bug - A bug you found you want Beginbot to look at", 13 | "coup": "trigger either a revolution or a crushing or the rebellion based on !vote - if you don't have enough Cool Points to afford to trigger a coup, you will be stripped of all your Street Cred and Cool Points", 14 | "soundeffect": "!soundeffect YOUTUBE_URL COMMAND_NAME 00:01 00:05 - Must be less than 5 second", 15 | "vote": "!vote (peace|revolution) - Where you stand when a coup happens. Should all sounds be redistributed, or should the trouble makes lose their sounds and the rich get richer", 16 | } 17 | -------------------------------------------------------------------------------- /chat_thief/config/log.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | from logging import FileHandler 4 | from pathlib import Path 5 | 6 | 7 | logger = logging.getLogger("Chat Log") 8 | logger.setLevel(logging.INFO) 9 | logs_path = Path(__file__).parent.parent.parent.joinpath("logs") 10 | logs_path.mkdir(exist_ok=True) 11 | logger.addHandler(FileHandler(logs_path.joinpath("chat.log"))) 12 | 13 | SUCCESS = "\033[92m" 14 | WARNING = "\033[94m" 15 | ERROR = "\033[91m" 16 | CLEAR = "\033[0m" 17 | 18 | 19 | def success(msg: str) -> None: 20 | print(f"{SUCCESS}{msg}{CLEAR}") 21 | 22 | 23 | def warning(msg: str) -> None: 24 | print(f"{WARNING}{msg}{CLEAR}") 25 | 26 | 27 | def error(msg: str) -> None: 28 | print(f"{ERROR}{msg}{CLEAR}") 29 | -------------------------------------------------------------------------------- /chat_thief/config/twitch.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import dataclass 3 | 4 | DEFAULT_BOT = "beginbotbot" 5 | DEFAULT_CHANNEL = "beginbotbot" 6 | 7 | 8 | @dataclass 9 | class TwitchConfig: 10 | token: str = os.environ["TWITCH_OAUTH_TOKEN"] 11 | bot: str = os.environ.get("TWITCH_BOT_NAME", DEFAULT_BOT) 12 | channel: str = os.environ.get("TWITCH_CHANNEL", DEFAULT_CHANNEL) 13 | 14 | def __repr__(self) -> str: 15 | return f"TwitchConfig(bot: {self.bot}, channel: {self.channel})" 16 | -------------------------------------------------------------------------------- /chat_thief/current_stream.py: -------------------------------------------------------------------------------- 1 | import random 2 | import traceback 3 | 4 | from chat_thief.config.stream_lords import STREAM_GODS 5 | from chat_thief.chat_logs import ChatLogs 6 | 7 | # WTF 8 | INVALID_USERS = ["nightbot", ".tim.twitch.tv"] + STREAM_GODS 9 | 10 | 11 | class CurrentStream: 12 | @staticmethod 13 | def random_user(blacklisted_users=[]): 14 | try: 15 | looking_for_user = True 16 | invalid_users = INVALID_USERS + blacklisted_users 17 | users = ChatLogs().recent_stream_peasants() 18 | 19 | while looking_for_user: 20 | user = random.sample(users, 1)[0] 21 | if user not in invalid_users: 22 | looking_for_user = False 23 | 24 | return user 25 | except: 26 | traceback.print_exc() 27 | return None 28 | -------------------------------------------------------------------------------- /chat_thief/custom_types.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union 2 | 3 | ChatReturnMessage = Union[List[str], str] 4 | 5 | # We could also be much more explicit about who is returning ChatReturnMessage. 6 | # Right now they are done at multiple places 7 | -------------------------------------------------------------------------------- /chat_thief/economist/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/economist/__init__.py -------------------------------------------------------------------------------- /chat_thief/economist/facts.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | import traceback 3 | from collections import Counter 4 | from itertools import chain 5 | 6 | from chat_thief.models.user import User 7 | from chat_thief.audioworld.soundeffects_library import SoundeffectsLibrary 8 | from chat_thief.models.vote import Vote 9 | from chat_thief.models.command import Command 10 | from chat_thief.models.breaking_news import BreakingNews 11 | 12 | 13 | class Facts: 14 | def breaking_news(self): 15 | return BreakingNews.last() 16 | 17 | def most_popular(self): 18 | return Command.most_popular() 19 | 20 | def peace_count(self): 21 | vote = Vote("beginbot") 22 | return vote.peace_count() 23 | 24 | def revolution_count(self): 25 | vote = Vote("beginbot") 26 | return vote.revolution_count() 27 | 28 | def total_votes(self): 29 | return Vote.count() 30 | 31 | def available_sounds(self): 32 | return len(Command.available_sounds()) 33 | 34 | def unavailable_sounds(self): 35 | total_sfx = len(SoundeffectsLibrary.soundeffects_only()) 36 | return total_sfx - self.available_sounds() 37 | 38 | def total_sounds(self): 39 | return self.available_sounds() + self.unavailable_sounds() 40 | 41 | def cool_points(self): 42 | return User.total_cool_points() 43 | 44 | def street_cred(self): 45 | return User.total_street_cred() 46 | 47 | def top_users(self): 48 | result = Command.db().all() 49 | 50 | counter = Counter( 51 | list( 52 | chain.from_iterable([command["permitted_users"] for command in result]) 53 | ) 54 | ) 55 | return counter.most_common()[0:5] 56 | -------------------------------------------------------------------------------- /chat_thief/formatters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/formatters/__init__.py -------------------------------------------------------------------------------- /chat_thief/formatters/cube_casino_formatter.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import operator 3 | 4 | 5 | class CubeCasinoFormatter: 6 | def __init__(self, results): 7 | self.results = results 8 | 9 | def format(self): 10 | results_by_winner = itertools.groupby(self.results, operator.itemgetter(0)) 11 | print(f"Results By Winner: {results_by_winner}") 12 | 13 | results = [] 14 | for winner, winnings in results_by_winner: 15 | msg = f"@{winner} won " 16 | 17 | winnings_msg = " and ".join( 18 | [f"!{command} from @{loser}" for (_, loser, command) in winnings] 19 | ) 20 | results.append(msg + winnings_msg) 21 | 22 | return results 23 | -------------------------------------------------------------------------------- /chat_thief/formatters/purchase_formatter.py: -------------------------------------------------------------------------------- 1 | class PurchaseFormatter: 2 | def __init__(self, result): 3 | pass 4 | 5 | def format(self): 6 | return True 7 | -------------------------------------------------------------------------------- /chat_thief/formatters/steal_formatter.py: -------------------------------------------------------------------------------- 1 | class StealFormatter: 2 | def __init__(self, result): 3 | self.result = result 4 | self.user = result.user 5 | self.metadata = result.metadata 6 | self.target_sfx = self.metadata["target_sfx"] 7 | self.victim = self.metadata["victim"] 8 | 9 | def format(self): 10 | return self.metadata["stealing_result"] 11 | -------------------------------------------------------------------------------- /chat_thief/irc.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict 2 | import json 3 | import os 4 | import socket 5 | 6 | 7 | from chat_thief.config.log import logger 8 | from chat_thief.config.twitch import TwitchConfig 9 | 10 | ENCODING = "utf-8" 11 | CHAT_MSG = "PRIVMSG" 12 | CONNECTION_DATA = ("irc.chat.twitch.tv", 6667) 13 | 14 | config = TwitchConfig() 15 | 16 | 17 | def _irc_handshake(server: socket.socket) -> None: 18 | logger.debug( 19 | json.dumps({"message": f"Connecting to #{config.channel} as {config.bot}"}) 20 | ) 21 | server.sendall(bytes("PASS " + config.token + "\r\n", ENCODING)) 22 | server.sendall(bytes("NICK " + config.bot + "\r\n", ENCODING)) 23 | server.sendall(bytes("JOIN " + f"#{config.channel}" + "\r\n", ENCODING)) 24 | 25 | 26 | def send_twitch_msg(msg): 27 | with socket.socket() as server: 28 | server.connect(CONNECTION_DATA) 29 | _irc_handshake(server) 30 | if msg: 31 | if "BLOCK_TWITCH_MSGS" in os.environ: 32 | print(msg) 33 | else: 34 | server.sendall( 35 | bytes(f"{CHAT_MSG} #{config.channel} :{msg}\n", ENCODING) 36 | ) 37 | -------------------------------------------------------------------------------- /chat_thief/irc_msg.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | 4 | class IrcMsg: 5 | def __init__(self, msg: str): 6 | # ':beginbot!beginbot@beginbot.tmi.twitch.tv PRIVMSG #beginbot :hello' 7 | 8 | split_msg = msg.split() 9 | if len(split_msg) >= 4: 10 | user_info, _, _, *raw_msg = split_msg 11 | self.user: str = user_info.split("!")[0][1:] 12 | self.msg: str = self._msg_sanitizer(raw_msg) 13 | self.command: Optional[str] = self._set_command() 14 | self.args: List[str] = self._set_args() 15 | else: 16 | raise ValueError(f"WHAT THE HECK: {msg}") 17 | 18 | def _msg_sanitizer(self, msg: List[str]) -> str: 19 | first, *rest = msg 20 | return f"{first[1:]} {' '.join(rest)}".strip() 21 | 22 | def _set_command(self) -> Optional[str]: 23 | args = self.msg.split(" ") 24 | if self.is_command(): 25 | return args[0][1:].lower() 26 | else: 27 | return None 28 | 29 | def _set_args(self) -> List[str]: 30 | args = self.msg.split(" ") 31 | if len(args) > 1: 32 | return args[1:] 33 | else: 34 | return [] 35 | 36 | def is_command(self) -> bool: 37 | return self.msg[0] == "!" and self.msg[1] != "!" 38 | -------------------------------------------------------------------------------- /chat_thief/js/arbaya.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", (event) => { 2 | const sounds_folder = document.createElement("div"); 3 | const sounds_folder_title = document.createElement("div"); 4 | const sounds_icon = document.querySelector("span:first-of-type"); 5 | const close_button = document.createElement("button"); 6 | const sounds = document.querySelector("ul"); 7 | const friends = document.getElementsByTagName("table")[0]; 8 | sounds_folder.classList.add("sounds_folder"); 9 | sounds_folder_title.classList.add("folder_title"); 10 | sounds_folder_title.appendChild(close_button); 11 | sounds_folder.appendChild(sounds_folder_title); 12 | document.body.appendChild(sounds_folder); 13 | sounds_folder.append(sounds); 14 | sounds_icon.addEventListener("click", () => { 15 | sounds_folder.classList.toggle("visible"); 16 | }); 17 | close_button.addEventListener("click", () => { 18 | sounds_folder.classList.toggle("visible"); 19 | }); 20 | document.body.insertBefore(friends, sounds_icon); 21 | }); 22 | -------------------------------------------------------------------------------- /chat_thief/js/beginTeletext.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function() { 2 | var links = document.getElementsByTagName("li"); 3 | for (var i=0; i=0 && e['key']<=9){checkKeys(e);}}); 15 | function checkKeys(event) { 16 | if(document.getElementById("pageNo").innerHTML.length >= 4){document.getElementById("pageNo").innerHTML = "P";} 17 | document.getElementById("pageNo").innerHTML = document.getElementById("pageNo").innerHTML + event.key; 18 | if(document.getElementById("pageNo").innerHTML.length >= 4){checkForPage(document.getElementById("pageNo").innerHTML);} 19 | } 20 | function checkForPage(page){ 21 | var pageId = 'page'+page.slice(1); 22 | var linkOnly = document.getElementById(pageId).innerHTML.split('"'); 23 | window.location.href = (linkOnly[1]); 24 | } -------------------------------------------------------------------------------- /chat_thief/js/beginbotbot.js: -------------------------------------------------------------------------------- 1 | 400: Invalid request -------------------------------------------------------------------------------- /chat_thief/js/beginfun.js: -------------------------------------------------------------------------------- 1 | 400: Invalid request -------------------------------------------------------------------------------- /chat_thief/js/bsod.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | const bsod = document.createElement("div"); 3 | bsod.classList.add("bsod"); 4 | document.body.appendChild(bsod); 5 | const trigger = document.querySelector("span:nth-of-type(2)"); 6 | trigger.innerText="Super secret Beginbot nudes"; 7 | trigger.addEventListener("click", e=>{ 8 | bsod.classList.add("visible"); 9 | setTimeout(()=>{bsod.classList.remove("visible")},2000); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /chat_thief/js/bubbles.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function(){ 2 | w = document.createElement("div"); 3 | w.id = "background-wrap"; 4 | for (i=0;i<=10;i++) { 5 | d = document.createElement("div"); 6 | d.className = "bubble x" + i; 7 | w.appendChild(d); 8 | } 9 | document.body.appendChild(w); 10 | }); 11 | -------------------------------------------------------------------------------- /chat_thief/js/cool_widget.js: -------------------------------------------------------------------------------- 1 | 400: Invalid request -------------------------------------------------------------------------------- /chat_thief/js/cubeScramble.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function() { 2 | var movesChoices = ['F','R','U','B','L','D','F2','R2','U2','B2','L2','D2',"F'","R'","U'","B'","L'","D'"]; 3 | var moves = []; 4 | for (var i=0; i<=19; i++){ 5 | var random = Math.floor(Math.random() * 17); 6 | moves.push(movesChoices[random]); 7 | } 8 | var scrambleText = ""; 9 | for(var j=0; j { 2 | const div = document.createElement('div') 3 | 4 | // Add the forbidden class, for added styling :) 5 | div.classList.add('forbidden-div') 6 | div.style.position = 'fixed' 7 | 8 | div.innerHTML = 'The Forbidden <div>' 9 | 10 | document.body.appendChild(div) 11 | 12 | // Follow that mouse 13 | document.addEventListener("mousemove", (e) => { 14 | div.style.left = `${e.x - 24}px` 15 | div.style.top = `${e.y - 24}px` 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /chat_thief/js/legotux.js: -------------------------------------------------------------------------------- 1 | var h1s = document.getElementsByTagName("h1"); 2 | 3 | var matrix = document.createElement("canvas"); 4 | matrix.id = 'matrix'; 5 | matrix.style='clear:both;position:fixed;left:0;top:0;width:100vw;height:100vh;'; 6 | document.body.insertBefore(matrix, h1s[0]); 7 | 8 | const matrixChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$%&~*!#_\\\"\'/<>=-+{([])}«».,;:'; 9 | 10 | const width = matrix.width = document.body.offsetWidth; 11 | const height = matrix.height = document.body.offsetHeight; 12 | const cols = Math.floor(width / 20) + 1; 13 | const yPos = Array(cols).fill(0); 14 | 15 | const ctx2d = matrix.getContext('2d'); 16 | ctx2d.fillStyle = '#fff1'; 17 | ctx2d.fillRect(0, 0, width, height); 18 | 19 | function drawMatrix () { 20 | ctx2d.fillStyle = '#0001'; 21 | ctx2d.fillRect(0, 0, width, height); 22 | ctx2d.fillStyle = '#0f0'; 23 | ctx2d.font = '1em monospace'; 24 | 25 | yPos.forEach((y, ind) => { 26 | const text = matrixChars.charAt(Math.floor(Math.random() * matrixChars.length)); 27 | //const text = String.fromCharCode(Math.floor(Math.random()*26) + 97); 28 | //const text = String.fromCharCode(Math.random() * 128); 29 | const x = ind * 20; 30 | ctx2d.fillText(text, x, y); 31 | if (y > 100 + Math.random() * 10000) yPos[ind] = 0; 32 | else yPos[ind] = y + 20; 33 | }); 34 | } 35 | 36 | setInterval(drawMatrix, 70); -------------------------------------------------------------------------------- /chat_thief/js/matrix.js: -------------------------------------------------------------------------------- 1 | var h1s = document.getElementsByTagName("h1"); 2 | 3 | var matrix = document.createElement("canvas"); 4 | matrix.id = 'matrix'; 5 | matrix.style='z-index:-1;clear:both;position:fixed;left:0;top:0;width:100vw;height:100vh;'; 6 | document.body.insertBefore(matrix, h1s[0]); 7 | 8 | const matrixChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789$%&~*!#_\\\"\'/<>=-+{([])}«».,;:'; 9 | 10 | const width = matrix.width = document.body.offsetWidth; 11 | const height = matrix.height = document.body.offsetHeight; 12 | const cols = Math.floor(width / 20) + 1; 13 | const yPos = Array(cols).fill(0); 14 | 15 | const ctx2d = matrix.getContext('2d'); 16 | ctx2d.fillStyle = '#fff1'; 17 | ctx2d.fillRect(0, 0, width, height); 18 | 19 | function drawMatrix () { 20 | ctx2d.fillStyle = '#0001'; 21 | ctx2d.fillRect(0, 0, width, height); 22 | ctx2d.fillStyle = '#0f0'; 23 | ctx2d.font = '1em monospace'; 24 | 25 | yPos.forEach((y, ind) => { 26 | const text = matrixChars.charAt(Math.floor(Math.random() * matrixChars.length)); 27 | //const text = String.fromCharCode(Math.floor(Math.random()*26) + 97); 28 | //const text = String.fromCharCode(Math.random() * 128); 29 | const x = ind * 20; 30 | ctx2d.fillText(text, x, y); 31 | if (y > 100 + Math.random() * 10000) yPos[ind] = 0; 32 | else yPos[ind] = y + 20; 33 | }); 34 | } 35 | 36 | setInterval(drawMatrix, 70); -------------------------------------------------------------------------------- /chat_thief/js/opsecwidget.js: -------------------------------------------------------------------------------- 1 | function rgba() { 2 | var o = Math.round, 3 | r = Math.random, 4 | s = 255; 5 | return ( 6 | "rgba(" + o(r() * s) + "," + o(r() * s) + "," + o(r() * s) + "," + 0.4 + ")" 7 | ); 8 | } 9 | var divs = document.getElementsByTagName("a"); 10 | for (var i = 0; i < divs.length; i++) { 11 | var color = rgba(); 12 | divs[i].style.boxSizing = "border-box"; 13 | divs[i].style.border = "2pxsolid" + color; 14 | divs[i].style.backgroundColor = color; 15 | } -------------------------------------------------------------------------------- /chat_thief/js/play-random-sound.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', () => { 2 | let userCommands = [] 3 | 4 | fetch('/db/commands.json').then(resp => resp.json()).then(json => { 5 | const USER = window.location.pathname.replace('.html', '').replace('/', '') 6 | const commands = [ ...Object.keys(json.commands) ].map(i => json.commands[i]) 7 | 8 | userCommands = commands.filter(cmd => cmd.permitted_users.filter(user => user ===USER).length > 0) 9 | }) 10 | 11 | const pickRandomCommand = commands => commands[Math.floor(Math.random() * commands.length)] 12 | 13 | const playSound = (e) => { 14 | const cmd = pickRandomCommand(userCommands) 15 | 16 | if (!cmd) { 17 | return 18 | } 19 | 20 | {new Audio(`/media/${cmd.name}.opus`).play()} 21 | {new Audio(`/media/${cmd.name}.mpa`).play()} 22 | {new Audio(`/media/${cmd.name}.m4a`).play()} 23 | {new Audio(`/media/${cmd.name}.wav`).play()} 24 | } 25 | 26 | document.addEventListener('keydown', playSound) 27 | document.addEventListener('mousedown', playSound) 28 | }) 29 | -------------------------------------------------------------------------------- /chat_thief/js/popbubbles.js: -------------------------------------------------------------------------------- 1 | // This widget requires you to !buy bubbles 2 | window.addEventListener("load", function() { 3 | bubbles = document.getElementsByClasName(".bubble") 4 | bubbles.map(b => b.onclick = pop) 5 | function pop () { 6 | // get an instance of sound to play 7 | var a = new Audio("../commands/aww.html") 8 | event.target.remove(); 9 | a.play(); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /chat_thief/js/privateorange.js: -------------------------------------------------------------------------------- 1 | document.documentElement.setAttribute('contenteditable', true); -------------------------------------------------------------------------------- /chat_thief/js/prototypeo4.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | console.log("Hello world"); 3 | }, false); -------------------------------------------------------------------------------- /chat_thief/js/screensaver.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", () => { 2 | let idle_time = 0; 3 | const idle_interval = setInterval(() => { 4 | idle_time++; 5 | if (idle_time >= 5 && !div_wrapper.classList.contains("visible")) { 6 | div_wrapper.classList.add("visible"); 7 | } 8 | }, 1000); 9 | const div_wrapper = document.createElement("div"); 10 | div_wrapper.classList.add("screensaver"); 11 | document.body.appendChild(div_wrapper); 12 | this.document.addEventListener("mousemove", (e) => { 13 | idle_time = 0; 14 | div_wrapper.classList.remove("visible"); 15 | }); 16 | this.document.addEventListener("keypress", (e) => { 17 | idle_time = 0; 18 | div_wrapper.classList.remove("visible"); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /chat_thief/js/soundfolder.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", (event) => { 2 | const sounds_folder = document.createElement("div"); 3 | const sounds_folder_title = document.createElement("div"); 4 | const sounds_icon = document.querySelector("span:first-of-type"); 5 | const close_button = document.createElement("button"); 6 | const sounds = document.querySelector("ul"); 7 | const friends = document.getElementsByTagName("table")[0]; 8 | sounds_folder.classList.add("sounds_folder"); 9 | sounds_folder_title.classList.add("folder_title"); 10 | sounds_folder_title.appendChild(close_button); 11 | sounds_folder.appendChild(sounds_folder_title); 12 | document.body.appendChild(sounds_folder); 13 | sounds_folder.append(sounds); 14 | sounds_icon.addEventListener("click", () => { 15 | sounds_folder.classList.toggle("visible"); 16 | }); 17 | close_button.addEventListener("click", () => { 18 | sounds_folder.classList.toggle("visible"); 19 | }); 20 | document.body.insertBefore(friends, sounds_icon); 21 | }); 22 | -------------------------------------------------------------------------------- /chat_thief/js/startmenu.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", (event) => { 2 | const start_menu = document.createElement("div"); 3 | const hr = document.createElement("hr"); 4 | const start_button = document.querySelector("span:last-of-type"); 5 | 6 | start_menu.classList.add("start_menu"); 7 | start_menu.appendChild(document.getElementsByTagName("H2")[0]); 8 | start_menu.appendChild(hr); 9 | start_menu.appendChild(document.getElementsByTagName("H3")[0]); 10 | start_menu.appendChild(document.getElementsByTagName("figure")[0]); 11 | 12 | document.body.appendChild(start_menu); 13 | 14 | document.addEventListener("click", (e) => { 15 | if (e.target === start_button) { 16 | start_menu.classList.toggle("visible"); 17 | } 18 | 19 | if (start_menu.classList.contains("visible") && e.target !== start_button) { 20 | start_menu.classList.remove("visible"); 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /chat_thief/js/uzi.js: -------------------------------------------------------------------------------- 1 | // JS NO CODE BOI -------------------------------------------------------------------------------- /chat_thief/js/zanuss.js: -------------------------------------------------------------------------------- 1 | window.onload = addDivs; 2 | function addDivs(){ 3 | var d = new Date(); 4 | var days = ["Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"]; 5 | var day = days[d.getDay()]; 6 | var date = d.getDate(); 7 | var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; 8 | var mon = months[d.getMonth()]; 9 | var hrs = d.getHours(); 10 | var mins = d.getMinutes(); 11 | var newDiv = document.createElement('div'); 12 | newDiv.setAttribute("id", "zanussClock"); 13 | var newContent = document.createTextNode(hrs+":"+mins); 14 | newDiv.append(newContent); 15 | var currentDiv = document.getElementsByTagName("h1")[0]; 16 | document.body.insertBefore(newDiv, currentDiv); 17 | var dateDiv = document.createElement('div'); 18 | dateDiv.setAttribute("id", "zanussDayDate"); 19 | var newContent = document.createTextNode(day + " " + date + " " + mon); 20 | dateDiv.append(newContent); 21 | var currentDiv = document.getElementsByTagName("h1")[0]; 22 | document.body.insertBefore(dateDiv, currentDiv); 23 | } -------------------------------------------------------------------------------- /chat_thief/js/zanussClock.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function() { 2 | var d = new Date(); 3 | var days = ["Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"]; 4 | var day = days[d.getDay()]; 5 | var date = d.getDate(); 6 | var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; 7 | var mon = months[d.getMonth()]; 8 | var hrs = d.getHours(); 9 | var mins = d.getMinutes(); 10 | if (mins<=9){mins = '0' + mins;} 11 | var clockDiv = document.createElement('div'); 12 | clockDiv.setAttribute("id", "zanussClock"); 13 | var clockContent = document.createTextNode(hrs+":"+mins); 14 | clockDiv.append(clockContent); 15 | var clockCurrentDiv = document.getElementsByTagName("h1")[0]; 16 | document.body.insertBefore(clockDiv, clockCurrentDiv); 17 | var dateDiv = document.createElement('div'); 18 | dateDiv.setAttribute("id", "zanussDayDate"); 19 | var dateContent = document.createTextNode(day + " " + date + " " + mon); 20 | dateDiv.append(dateContent); 21 | var datecurrentDiv = document.getElementsByTagName("h1")[0]; 22 | document.body.insertBefore(dateDiv, datecurrentDiv); 23 | }); -------------------------------------------------------------------------------- /chat_thief/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/models/__init__.py -------------------------------------------------------------------------------- /chat_thief/models/bot_vote.py: -------------------------------------------------------------------------------- 1 | from tinydb import Query # type: ignore 2 | 3 | from chat_thief.models.base_db_model import BaseDbModel 4 | 5 | 6 | class BotVote(BaseDbModel): 7 | database_path = "db/bot_votes.json" 8 | table_name = "bot_votes" 9 | 10 | def __init__(self, user, bot): 11 | self._user = user 12 | self._bot = bot 13 | 14 | @classmethod 15 | def by_bot(cs): 16 | return self.get_by_category("bot") 17 | # votes = self.db().all() 18 | # import itertools 19 | # import operator 20 | # steal_events = UserEvent.db().search(Query().command == "steal") 21 | # thieves = itertools.groupby(steal_events, operator.itemgetter("user")) 22 | 23 | def doc(self): 24 | return {"user": self._user, "bot": self._bot} 25 | 26 | def create_or_update(self): 27 | old_vote = self.db().get(Query().user == self._user) 28 | if old_vote: 29 | result = self.db().update({"bot": self._bot}, doc_ids=[old_vote.doc_id]) 30 | return result, "update" 31 | else: 32 | result = self.save() 33 | return result, "create" 34 | -------------------------------------------------------------------------------- /chat_thief/models/breaking_news.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, List, Any, Dict 2 | 3 | import time 4 | 5 | from chat_thief.models.base_db_model import BaseDbModel 6 | from datetime import datetime 7 | 8 | from tinydb import Query # type: ignore 9 | from tinydb.table import Document # type: ignore 10 | 11 | 12 | class BreakingNews(BaseDbModel): 13 | table_name = "breaking_news" 14 | database_path = "db/breaking_news.json" 15 | 16 | def __init__( 17 | self, 18 | scope: str, 19 | user: Optional[str] = None, 20 | category: Optional[str] = None, 21 | reported_on: Optional[bool] = False, 22 | revolutionaries: Optional[List[str]] = [], 23 | peace_keepers: Optional[List[str]] = [], 24 | fence_sitters: Optional[List[str]] = [], 25 | ): 26 | self._scope = scope 27 | self._user = user 28 | self._category = category 29 | self._reported_on = reported_on 30 | self._revolutionaries = revolutionaries 31 | self._peace_keepers = peace_keepers 32 | self._fence_sitters = fence_sitters 33 | 34 | @classmethod 35 | def unreported_news(cls) -> Optional[Document]: 36 | return cls.db().get(Query().reported_on == False) 37 | 38 | @classmethod 39 | def report_last_story(cls) -> Optional[Document]: 40 | last_story = cls.unreported_news() 41 | if last_story: 42 | cls.set_value_by_id(last_story.doc_id, "reported_on", True) 43 | return last_story 44 | else: 45 | return None 46 | 47 | def doc(self) -> Dict: 48 | scope_time = datetime.fromtimestamp(time.time()) 49 | return { 50 | "scope": self._scope, 51 | "user": self._user, 52 | "category": self._category, 53 | "timestamp": str(scope_time), 54 | "reported_on": self._reported_on, 55 | "revolutionaries": self._revolutionaries, 56 | "peace_keepers": self._peace_keepers, 57 | "fence_sitters": self._fence_sitters, 58 | } 59 | -------------------------------------------------------------------------------- /chat_thief/models/css_vote.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import operator 3 | 4 | from tinydb import Query # type: ignore 5 | 6 | from chat_thief.models.base_db_model import BaseDbModel 7 | 8 | 9 | class CSSVote(BaseDbModel): 10 | table_name = "css_votes" 11 | database_path = "db/css_votes.json" 12 | 13 | def __init__(self, voter, candidate, page="homepage"): 14 | self.voter = voter 15 | self.candidate = candidate 16 | self.page = page 17 | 18 | def doc(self): 19 | return { 20 | "voter": self.voter, 21 | "candidate": self.candidate, 22 | "page": self.page, 23 | } 24 | 25 | def create_or_update(self): 26 | if old_vote := self.db().get(Query().voter == self.voter): 27 | result = self.db().update(self.doc(), doc_ids=[old_vote.doc_id]) 28 | return result, "update" 29 | else: 30 | result = self.save() 31 | return result, "create" 32 | 33 | @classmethod 34 | def by_votes(cls): 35 | votes = cls.db().all() 36 | 37 | def get_candidate(vote): 38 | return vote.get("candidate") 39 | 40 | votes_by_candidate = itertools.groupby( 41 | sorted(votes, key=get_candidate), get_candidate 42 | ) 43 | 44 | vote_counts = [ 45 | (candidate, len(list(votes))) for (candidate, votes) in votes_by_candidate 46 | ] 47 | return list(reversed(sorted(vote_counts, key=lambda vote: vote[1]))) 48 | -------------------------------------------------------------------------------- /chat_thief/models/cube_stats.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.base_db_model import BaseDbModel 2 | 3 | 4 | class CubeStats(BaseDbModel): 5 | table_name = "cube_stats" 6 | database_path = "db/cube_stats.json" 7 | 8 | def __init__(self, winning_duration, winners, all_bets): 9 | self._winning_duration = winning_duration 10 | self._winners = winners 11 | self._all_bets = all_bets 12 | 13 | def doc(self): 14 | formatted_bets = [{"user": bet[0], "bet": bet[1]} for bet in self._all_bets] 15 | 16 | return { 17 | "winning_duration": self._winning_duration, 18 | "winners": self._winners, 19 | "all_bets": formatted_bets, 20 | } 21 | -------------------------------------------------------------------------------- /chat_thief/models/database.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | from tinydb.storages import MemoryStorage # type: ignore 4 | from tinydb import TinyDB # type: ignore 5 | 6 | from tinydb.table import Table 7 | 8 | 9 | def db_table(db_location: Path, table_name: str) -> Table: 10 | return TinyDB(Path(__file__).parent.parent.parent.joinpath(db_location)).table( 11 | table_name, cache_size=0 12 | ) 13 | -------------------------------------------------------------------------------- /chat_thief/models/issue.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.base_db_model import BaseDbModel 2 | 3 | 4 | class Issue(BaseDbModel): 5 | table_name = "issues" 6 | database_path = "db/issues.json" 7 | 8 | def __init__(self, user, msg): 9 | self._user = user 10 | self._msg = msg 11 | 12 | def doc(self): 13 | return {"user": self._user, "msg": self._msg} 14 | -------------------------------------------------------------------------------- /chat_thief/models/notification.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.base_db_model import BaseDbModel 2 | 3 | 4 | class Notification(BaseDbModel): 5 | table_name = "notifications" 6 | database_path = "db/notifications.json" 7 | 8 | def __init__(self, message, duration=1): 9 | self.message = message 10 | self.duration = duration 11 | 12 | def doc(self): 13 | return {"message": self.message, "duration": self.duration} 14 | -------------------------------------------------------------------------------- /chat_thief/models/play_soundeffect_request.py: -------------------------------------------------------------------------------- 1 | import json 2 | import traceback 3 | 4 | from tinydb import Query # type: ignore 5 | 6 | from chat_thief.models.database import db_table 7 | from chat_thief.models.transaction import transaction 8 | from chat_thief.models.base_db_model import BaseDbModel 9 | 10 | 11 | class PlaySoundeffectRequest(BaseDbModel): 12 | table_name = "play_soundeffects" 13 | database_path = "db/play_soundeffects.json" 14 | 15 | def __init__(self, user=None, command=None, notification=True): 16 | self.user = user 17 | self.notification = notification 18 | if command: 19 | self.command = command.lower() 20 | 21 | def __len__(self): 22 | return 0 23 | 24 | # Deprecate this 25 | def command_count(self): 26 | # We should check if this is valid json 27 | return self.count() 28 | 29 | def _is_valid_json(self): 30 | try: 31 | json.dumps(self.doc()) 32 | return True 33 | except: 34 | traceback.print_exc() 35 | return False 36 | 37 | def doc(self): 38 | return { 39 | "user": self.user, 40 | "command": self.command, 41 | "notification": self.notification, 42 | } 43 | 44 | def pop_all_off(self): 45 | all_effects = self.all() 46 | 47 | doc_ids_to_delete = [sfx.doc_id for sfx in all_effects] 48 | if doc_ids_to_delete: 49 | with transaction(self.db()) as tr: 50 | tr.remove(doc_ids=doc_ids_to_delete) 51 | return all_effects 52 | else: 53 | return [] 54 | -------------------------------------------------------------------------------- /chat_thief/models/rap_sheet.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.base_db_model import BaseDbModel 2 | 3 | 4 | class RapSheet(BaseDbModel): 5 | database_path = "db/rap_sheet.json" 6 | table_name = "rap_sheet" 7 | 8 | def __init__(self, user, action, metadata={}): 9 | self._user = user 10 | self._action = action 11 | self._metadata = metadata 12 | 13 | def doc(self): 14 | return {"user": self._user, "action": self._action, "metadata": self._metadata} 15 | -------------------------------------------------------------------------------- /chat_thief/models/the_fed.py: -------------------------------------------------------------------------------- 1 | from tinydb import Query # type: ignore 2 | 3 | from chat_thief.models.base_db_model import BaseDbModel 4 | from chat_thief.models.transaction import transaction 5 | from chat_thief.models.command import Command 6 | 7 | 8 | @object.__new__ 9 | class TheFed(BaseDbModel): 10 | table_name = "the_fed" 11 | database_path = "db/the_fed.json" 12 | version = "0.0.0" 13 | 14 | @classmethod 15 | def reserve(cls): 16 | if command := cls.db().get(Query().version == cls.version): 17 | return command["reserve"] 18 | else: 19 | return 0 20 | 21 | def collect_taxes(self): 22 | for command in Command.db().all(): 23 | if command["cost"] > 1: 24 | print(f"Taxing {command['name']}") 25 | new_cost = int(command["cost"] / 2) 26 | Command(command["name"]).set_value("cost", new_cost) 27 | self.collect_tax(new_cost) 28 | 29 | def collect_tax(self, tax): 30 | if self.db().search(Query().version == self.version): 31 | self.update_value("reserve", tax) 32 | else: 33 | self._reserve = tax 34 | self.save() 35 | 36 | def pay(self, tax): 37 | self.update_value("reserve", -tax) 38 | 39 | def update_value(self, field, amount=1): 40 | def _update_that_value(): 41 | def transform(doc): 42 | doc[field] = doc[field] + amount 43 | 44 | return transform 45 | 46 | with transaction(self.db()) as tr: 47 | tr.update(_update_that_value(), Query().version == self.version) 48 | 49 | def doc(self): 50 | return {"version": self.version, "reserve": self._reserve} 51 | -------------------------------------------------------------------------------- /chat_thief/models/transaction.py: -------------------------------------------------------------------------------- 1 | from tinydb import TinyDB, Query # type: ignore 2 | from tinydb.table import Table # type: ignore 3 | from tinydb.storages import MemoryStorage # type: ignore 4 | import contextlib 5 | 6 | 7 | class AbortTransaction(Exception): 8 | pass 9 | 10 | 11 | def abort(): 12 | raise AbortTransaction 13 | 14 | 15 | @contextlib.contextmanager 16 | def transaction(table: Table): 17 | tables = table.storage.read() 18 | if tables is None: 19 | tables = {} 20 | 21 | data = tables.get(table.name, {}) 22 | data = {table.document_id_class(id): doc for id, doc in data.items()} 23 | db = TinyDB(storage=MemoryStorage) 24 | 25 | tmp_table = db.table(table.name) 26 | tmp_table.storage.write(tables) 27 | 28 | try: 29 | yield tmp_table 30 | 31 | tables[table.name] = tmp_table.storage.read()[table.name] 32 | table.storage.write(tables) 33 | table._next_id = None 34 | 35 | except AbortTransaction: 36 | pass 37 | -------------------------------------------------------------------------------- /chat_thief/models/tribal_council.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.base_db_model import BaseDbModel 2 | from chat_thief.models.bot_vote import BotVote 3 | 4 | 5 | class TribalCouncil(BaseDbModel): 6 | database_path = "db/tribal_council.json" 7 | table_name = "tribal_council" 8 | 9 | @classmethod 10 | def go_to_tribal(cls): 11 | votes = {} 12 | votes_ids = [] 13 | for vote in BotVote.db().all(): 14 | bot_name = vote["bot"] 15 | votes_ids.append(vote.doc_id) 16 | votes[bot_name] = votes.get(bot_name, []) + [vote["user"]] 17 | 18 | council_numbers = [ 19 | council["council_number"] for council in TribalCouncil.db().all() 20 | ] 21 | if council_numbers: 22 | last_council_number = max(council_numbers) + 1 23 | else: 24 | last_council_number = 1 25 | 26 | TribalCouncil(votes, last_council_number).save() 27 | BotVote.db().remove(doc_ids=votes_ids) 28 | 29 | def __init__(self, votes, council_number=1): 30 | self._votes = votes 31 | self._council_number = council_number 32 | 33 | def doc(self): 34 | return {"council_number": self._council_number, "votes": self._votes} 35 | -------------------------------------------------------------------------------- /chat_thief/models/user_event.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | import time 3 | 4 | from chat_thief.models.base_db_model import BaseDbModel 5 | 6 | 7 | class UserEvent(BaseDbModel): 8 | table_name = "user_events" 9 | database_path = "db/user_events.json" 10 | 11 | def __init__(self, user, command, msg, result): 12 | self._user = user 13 | self._command = command 14 | self._msg = msg 15 | self._result = result 16 | 17 | def doc(self): 18 | created_at = str(datetime.fromtimestamp(time.time())) 19 | 20 | return { 21 | "user": self._user, 22 | "command": self._command, 23 | "msg": self._msg, 24 | "result": self._result, 25 | "created_at": created_at, 26 | } 27 | -------------------------------------------------------------------------------- /chat_thief/models/user_page.py: -------------------------------------------------------------------------------- 1 | from tinydb import Query # type: ignore 2 | 3 | from chat_thief.models.base_db_model import BaseDbModel 4 | 5 | 6 | class UserPage(BaseDbModel): 7 | database_path = "db/user_pages.json" 8 | table_name = "user_pages" 9 | 10 | @classmethod 11 | def bootstrap_user_page(cls, user, widgets): 12 | widget_status = {} 13 | for widget in widgets: 14 | widget_status[widget] = True 15 | 16 | return cls(user, widget_status).save() 17 | 18 | # I pass in a list 19 | # ...then I construct dictionary 20 | def __init__(self, user, widget_status): 21 | self._user = user 22 | self._widget_status = widget_status 23 | 24 | def doc(self): 25 | return {"user": self._user, "widgets": self._widget_status} 26 | 27 | @classmethod 28 | def for_user(cls, user): 29 | return cls.db().get(Query().user == user) 30 | 31 | @classmethod 32 | def deactivate(cls, user, widget_name): 33 | cls._change_widget_status(user, widget_name, False) 34 | 35 | @classmethod 36 | def activate(cls, user, widget_name): 37 | cls._change_widget_status(user, widget_name, True) 38 | 39 | @classmethod 40 | def _change_widget_status(cls, user, widget_name, status): 41 | user_page = cls.db().get(Query().user == user) 42 | 43 | if user_page is None: 44 | print(f"Could Not Find User Page: {user} - Bootstrapping") 45 | 46 | cls.bootstrap_user_page(user, [widget_name]) 47 | user_page = cls.db().get(Query().user == user) 48 | 49 | if "widgets" in user_page: 50 | user_page["widgets"][widget_name] = status 51 | UserPage.set_value_by_id(user_page.doc_id, "widgets", user_page["widgets"]) 52 | -------------------------------------------------------------------------------- /chat_thief/mygeoangelfirespace/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/mygeoangelfirespace/__init__.py -------------------------------------------------------------------------------- /chat_thief/mygeoangelfirespace/syncer.py: -------------------------------------------------------------------------------- 1 | from typing import List, Dict 2 | import json 3 | import random 4 | import traceback 5 | import time 6 | import os 7 | 8 | from chat_thief.chat_logs import ChatLogs 9 | from chat_thief.config.log import logger 10 | from chat_thief.irc import send_twitch_msg 11 | from chat_thief.models.breaking_news import BreakingNews 12 | from chat_thief.models.soundeffect_request import SoundeffectRequest 13 | from chat_thief.models.user import User 14 | from chat_thief.prize_dropper import drop_random_soundeffect_to_user 15 | 16 | 17 | # I feel like this could also handle checking for the news 18 | def sync_main(): 19 | while True: 20 | try: 21 | # os.system("time make full_deploy") 22 | os.system("time make deploy") 23 | time.sleep(1600) 24 | # time.sleep(600) 25 | # time.sleep(60) 26 | except Exception as e: 27 | time.sleep(30) 28 | if e is KeyboardInterrupt: 29 | raise e 30 | else: 31 | traceback.print_exc() 32 | 33 | 34 | if __name__ == "__main__": 35 | sync_main() 36 | -------------------------------------------------------------------------------- /chat_thief/new_commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/new_commands/__init__.py -------------------------------------------------------------------------------- /chat_thief/new_commands/result.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.user import User 2 | 3 | 4 | class Result: 5 | def __init__(self, user, command, metadata): 6 | self.user = user 7 | self.command = command 8 | self.metadata = metadata 9 | self._set_cool_points_diff() 10 | 11 | def _set_cool_points_diff(self): 12 | if "purchase_results" in self.metadata: 13 | total_spent = sum( 14 | [result.cost for result in self.metadata["purchase_results"]] 15 | ) 16 | self.cool_points_diff = -total_spent 17 | else: 18 | self.cool_points_diff = 0 19 | -------------------------------------------------------------------------------- /chat_thief/permissions_fetcher.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.user import User 2 | from chat_thief.models.command import Command 3 | 4 | # TODO: unduplicate 5 | BASE_URL = "https://mygeoangelfirespace.city" 6 | 7 | 8 | class PermissionsFetcher: 9 | @classmethod 10 | def fetch_permissions(cls, user, target_command, target_user): 11 | # Personal Permissions 12 | if not target_command and not target_user: 13 | user = User(user) 14 | stats = user.stats() 15 | sfx_count = len(user.commands()) 16 | return f"{stats} | SFX Count: {sfx_count}" 17 | 18 | # User Permissions 19 | if target_user and not target_command: 20 | title = f"@{target_user}'s" 21 | sfx_count = len(User(target_user).commands()) 22 | stats = User(target_user).stats() 23 | return f"{title} {stats} | SFX Count: {sfx_count}" 24 | 25 | # Command Permissions 26 | if target_command and not target_user: 27 | command = Command(target_command) 28 | user_permissions = " ".join([f"@{perm}" for perm in command.users()]) 29 | 30 | from chat_thief.models.sfx_vote import SFXVote 31 | 32 | link = f"{BASE_URL}/commands/{target_command}.html" 33 | like_ratio = SFXVote(target_command).like_to_hate_ratio() 34 | stats = f"!{target_command} | Cost: {command.cost()} | Health: {command.health()} | Like Ratio {round(like_ratio)}% | {link}" 35 | return stats 36 | -------------------------------------------------------------------------------- /chat_thief/routers/__init__.py: -------------------------------------------------------------------------------- 1 | from chat_thief.routers.basic_info_router import BasicInfoRouter 2 | from chat_thief.routers.beginworld_help_router import BeginworldHelpRouter 3 | from chat_thief.routers.bot_survivor_router import BotSurvivorRouter 4 | from chat_thief.routers.community_router import CommunityRouter 5 | from chat_thief.routers.economy_router import EconomyRouter 6 | from chat_thief.routers.feedback_router import FeedbackRouter 7 | from chat_thief.routers.moderator_router import ModeratorRouter 8 | from chat_thief.routers.new_cube_casino_router import NewCubeCasinoRouter 9 | from chat_thief.routers.revolution_router import RevolutionRouter 10 | from chat_thief.routers.user_code_router import UserCodeRouter 11 | from chat_thief.routers.voting_booth_router import VotingBoothRouter 12 | 13 | __all__ = [ 14 | "BasicInfoRouter", 15 | "BeginworldHelpRouter", 16 | "BotSurvivorRouter", 17 | "CommunityRouter", 18 | "EconomyRouter", 19 | "FeedbackRouter", 20 | "ModeratorRouter", 21 | "NewCubeCasinoRouter", 22 | "RevolutionRouter", 23 | "UserCodeRouter", 24 | "VotingBoothRouter", 25 | ] 26 | -------------------------------------------------------------------------------- /chat_thief/routers/base_router.py: -------------------------------------------------------------------------------- 1 | from typing import List, Union, Optional, Any 2 | 3 | from abc import ABC 4 | import abc 5 | from chat_thief.chat_parsers.command_parser import CommandParser 6 | 7 | 8 | # Routers are for Pairing a Parser Class 9 | # TODO: reconsider the Any for the Parser 10 | class BaseRouter(ABC): 11 | def __init__( 12 | self, 13 | user: str, 14 | command: str, 15 | args: Optional[List[str]] = [], 16 | parser: Optional[Any] = None, 17 | ): 18 | self.user = user 19 | self.command = command 20 | self.args = args 21 | 22 | if parser: 23 | self.parser = parser 24 | else: 25 | self.parser = CommandParser( 26 | user=self.user, command=self.command, args=self.args 27 | ).parse() 28 | 29 | @abc.abstractmethod 30 | def route(self) -> Optional[Union[List[str], str]]: 31 | """Take a Command and route to appropriate code""" 32 | -------------------------------------------------------------------------------- /chat_thief/routers/basic_info_router.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import quote 2 | 3 | from chat_thief.commands.la_libre import LaLibre 4 | from chat_thief.config.stream_lords import STREAM_LORDS, STREAM_GODS 5 | from chat_thief.chat_parsers.command_parser import CommandParser 6 | from chat_thief.models.user import User 7 | from chat_thief.routers.base_router import BaseRouter 8 | 9 | 10 | class BasicInfoRouter(BaseRouter): 11 | def route(self): 12 | if self.command == "la_libre": 13 | return " | ".join(LaLibre.inform()) 14 | 15 | if self.command == "streamlords": 16 | return " ".join(STREAM_LORDS) 17 | 18 | if self.command == "streamgods": 19 | return " ".join(STREAM_GODS) 20 | 21 | if self.command == "so": 22 | return self._shoutout() 23 | 24 | if self.user in STREAM_GODS: 25 | parser = CommandParser( 26 | user=self.user, command=self.command, args=self.args 27 | ).parse() 28 | 29 | if self.command == "bankrupt": 30 | return User(parser.target_user).bankrupt() 31 | 32 | if self.command == "paperup": 33 | if parser.target_user: 34 | return User(parser.target_user).paperup() 35 | else: 36 | return "You need to specify who to Paperup" 37 | 38 | def _shoutout(self): 39 | user_path = self.args[0] 40 | if user_path.startswith("@"): 41 | user_path = user_path[1:] 42 | return f"Shoutout twitch.tv/{quote(user_path)}" 43 | -------------------------------------------------------------------------------- /chat_thief/routers/beginworld_help_router.py: -------------------------------------------------------------------------------- 1 | from chat_thief.routers.base_router import BaseRouter 2 | from chat_thief.config.help_menu import HELP_COMMANDS 3 | 4 | 5 | class BeginworldHelpRouter(BaseRouter): 6 | def route(self): 7 | if self.command == "help": 8 | if len(self.args) > 0: 9 | command = self.args[0] 10 | if command.startswith("!"): 11 | command = command[1:] 12 | return HELP_COMMANDS[command] 13 | else: 14 | options = " ".join([f"!{command}" for command in HELP_COMMANDS.keys()]) 15 | return f"Call !help with a specific command for more details: {options}" 16 | -------------------------------------------------------------------------------- /chat_thief/routers/bot_survivor_router.py: -------------------------------------------------------------------------------- 1 | from chat_thief.chat_parsers.command_parser import CommandParser 2 | from chat_thief.models.bot_vote import BotVote 3 | from chat_thief.models.user import User 4 | from chat_thief.models.tribal_council import TribalCouncil 5 | from chat_thief.routers.base_router import BaseRouter 6 | 7 | 8 | class BotSurvivorRouter(BaseRouter): 9 | def route(self): 10 | if self.command in ["hatebot", "votebotout"]: 11 | if self.parser.target_user: 12 | potential_bot = User(self.parser.target_user) 13 | 14 | if potential_bot.is_bot(): 15 | # We need to update vote for that user 16 | result = BotVote(self.user, potential_bot.name).create_or_update() 17 | return f"Thank you for your vote @{self.user}" 18 | else: 19 | return f"@{self.user} @{self.parser.target_user} is NOT A BOT!" 20 | 21 | if self.command == "tribal_council" and self.user == "beginbotbot": 22 | print("TRIBAL COUNCIL TIME!!!") 23 | # result = TribalCouncil.go_to_tribal() 24 | loser = BotVote.count_by_group("bot")[0][0] 25 | return f"@{loser} has been kicked out of BeginWorld" 26 | -------------------------------------------------------------------------------- /chat_thief/routers/revolution_router.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from chat_thief.routers.base_router import BaseRouter # type: ignore 4 | from chat_thief.models.vote import Vote # type: ignore 5 | from chat_thief.commands.la_libre import LaLibre # type: ignore 6 | from chat_thief.commands.revolution import Revolution # type: ignore 7 | 8 | 9 | class RevolutionRouter(BaseRouter): 10 | def route(self) -> Optional[str]: 11 | if self.command == "coup": 12 | threshold = LaLibre.threshold() 13 | result = Vote.have_tables_turned(threshold) 14 | print(f"The Result of have_tables_turned: {result}") 15 | 16 | if result in ["peace", "revolution"]: 17 | return Revolution(self.user).attempt_coup(result) 18 | else: 19 | return f"The Will of the People have not chosen: {threshold} votes must be cast for either Peace or Revolution" 20 | 21 | if self.command in ["peace", "revolution", "vote"]: 22 | if self.command == "vote": 23 | vote = self.args[0] 24 | Vote(user=self.user).vote(vote) 25 | else: 26 | Vote(user=self.user).vote(self.command) 27 | return f"Thank you for your vote @{self.user}" 28 | -------------------------------------------------------------------------------- /chat_thief/routers/voting_booth_router.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import operator 3 | 4 | from chat_thief.routers.base_router import BaseRouter 5 | from chat_thief.chat_parsers.command_parser import CommandParser 6 | from chat_thief.models.css_vote import CSSVote 7 | 8 | 9 | class VotingBoothRouter(BaseRouter): 10 | def route(self): 11 | if self.command == "bestcss": 12 | if self.parser.target_user: 13 | result = CSSVote( 14 | voter=self.user, candidate=self.parser.target_user 15 | ).create_or_update() 16 | return f"Thank You @{self.user} for supporting Artists like @{self.parser.target_user}" 17 | elif self.command == "homepage": 18 | return " | ".join( 19 | [f"@{candidate}: {count}" for (candidate, count) in CSSVote.by_votes()] 20 | ) 21 | -------------------------------------------------------------------------------- /chat_thief/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/scripts/__init__.py -------------------------------------------------------------------------------- /chat_thief/scripts/register_bots.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.user import User 2 | 3 | BOTS_AND_CREATORS = { 4 | "aquafunkalisticbootywhap": "aquafunkbot", 5 | "ravonus": "r4vb0t", 6 | "beginbot": "beginbotbot", 7 | "bopojoe_": "cykablondesbot", 8 | "isidentical": "stallmansbot", 9 | "disk1of5": "disk_bot", 10 | "jr_boss": "jr_bots", 11 | "cachesking": "distributedcache", 12 | "whatsinmyopsec": "opsecbot", 13 | "zanuss": "zanussbot", 14 | "baldclap": "cheb0t", 15 | "nomorequity": "nomoreb0t", 16 | "r_u_ri_ui": "hal9thou", 17 | "detlion1643": "botriptide", 18 | "portaalgaming": "portaalgamingfriend", 19 | "rockerboo": "800807", 20 | "orenog_live4": "personnormalyesplus5", 21 | "biged_twitch": "bigedbot", 22 | "eitanfuturo": "futubot", 23 | "mrsmoofy": "mrsmoofybot", 24 | "nineteenletterslong": "blortbot", 25 | "adengamestv": "adengamesbot", 26 | "erikdotdev": "erikbotdev", 27 | "barfolomeu": "Barfolobot" 28 | } 29 | 30 | 31 | def register_them_bots(): 32 | 33 | for creator, bot in BOTS_AND_CREATORS.items(): 34 | print(f"Registering: {bot} to it's Creator: {creator}") 35 | User.register_bot(bot, creator) 36 | 37 | 38 | if __name__ == "__main__": 39 | register_them_bots() 40 | -------------------------------------------------------------------------------- /chat_thief/static/97lunarmare.css: -------------------------------------------------------------------------------- 1 | * { 2 | > ckground-color: red; 3 | } 4 | -------------------------------------------------------------------------------- /chat_thief/static/adengamesbot.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap'); 2 | @import url('https://fonts.googleapis.com/css2?family=Pacifico&display=swap'); 3 | body { 4 | background-color: #011728; 5 | color: #00A6FB; 6 | font-size: 1.5em; 7 | font-family: 'Pacifico', cursive; 8 | text-align: center; 9 | } 10 | h2 { 11 | color: #33EBB1; 12 | } 13 | h1 > a { 14 | text-decoration: line; 15 | color: #F75C03; 16 | } 17 | li > a { 18 | color: #D90368; 19 | padding-bottom: 5px; 20 | text-decoration: overline; 21 | } 22 | li { 23 | list-style: none; 24 | } 25 | h1 { 26 | font-family: 'Nanum Pen Script', cursive, Arial, Helvetica, sans-serif; 27 | } 28 | span > a { 29 | color: #00537D; 30 | text-decoration: none; 31 | } 32 | br{ 33 | margin-bottom: 20px; 34 | } 35 | code { 36 | font-family: 'Pacifico', cursive; 37 | } 38 | table { 39 | margin-left: auto; 40 | margin-right: auto; 41 | } 42 | td > a { 43 | text-decoration: none; 44 | border-bottom: 3px solid #000; 45 | color: blue; 46 | } 47 | td > a:hover { 48 | color: blue; 49 | } 50 | td > a:visited { 51 | color: blue; 52 | } -------------------------------------------------------------------------------- /chat_thief/static/adengamestv.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap'); 2 | @import url('https://fonts.googleapis.com/css2?family=Pacifico&display=swap'); 3 | body { 4 | background-color: #011728; 5 | color: #00A6FB; 6 | font-size: 1.5em; 7 | font-family: 'Pacifico', cursive; 8 | text-align: center; 9 | } 10 | h2 { 11 | color: #33EBB1; 12 | } 13 | h1 > a { 14 | text-decoration: line; 15 | color: #F75C03; 16 | } 17 | li > a { 18 | color: #D90368; 19 | padding-bottom: 5px; 20 | text-decoration: overline; 21 | } 22 | li { 23 | list-style: none; 24 | } 25 | h1 { 26 | font-family: 'Nanum Pen Script', cursive, Arial, Helvetica, sans-serif; 27 | } 28 | span > a { 29 | color: #00537D; 30 | text-decoration: none; 31 | } 32 | br{ 33 | margin-bottom: 20px; 34 | } 35 | code { 36 | font-family: 'Pacifico', cursive; 37 | } 38 | table { 39 | margin-left: auto; 40 | margin-right: auto; 41 | } 42 | td > a { 43 | text-decoration: none; 44 | border-bottom: 3px solid #000; 45 | color: blue; 46 | } 47 | td > a:hover { 48 | color: blue; 49 | } 50 | td > a:visited { 51 | color: blue; 52 | } -------------------------------------------------------------------------------- /chat_thief/static/adrnlnjnky.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: rgba(78, 255, 180, 0.7); 3 | /* background: #000065; */ 4 | color: rgba(99, 63, 8, 0.7); 5 | font-size: 1em; 6 | font-family: "Helvetica"; 7 | text-align: center; 8 | font-size: xx-small; 9 | } 10 | 11 | h1 { 12 | color: rgba(9, 255, 95, 0.9); 13 | font-size: xx-large; 14 | font: 15 | } 16 | 17 | h2 { 18 | font: omnibus-type; 19 | color: rgba(222, 130, 90, 0.8); 20 | font-size: x-large; 21 | } 22 | 23 | h3 { 24 | color: rgba(155,90,90); 25 | font-size: large; 26 | } 27 | 28 | table { 29 | color: rgba(255,4,56,0.9); 30 | font-size: large; 31 | } 32 | ul { 33 | padding: 3em; 34 | color: rgba(255,255,255,0.9); 35 | font-size: large; 36 | } 37 | 38 | il { 39 | font-size: small; 40 | } -------------------------------------------------------------------------------- /chat_thief/static/anakimluke.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: rgb(0, 0, 0); 3 | color: red; 4 | font-size: 20px; 5 | font-family: monospace; 6 | margin: 200px; 7 | } 8 | h1 { 9 | color: #e40000; 10 | } -------------------------------------------------------------------------------- /chat_thief/static/andrelamus.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-image: url("https://wallsheaven.com/photos/C21267908/220/sumo-doodle-seamless-pattern-background.webp")!important; 3 | color:red; 4 | text-align: center; 5 | text-shadow: 3px 3px black; 6 | font-family: 'Arial Black', 'Arial Bold', Gadget, sans-serif; 7 | } 8 | h1 a{ 9 | margin-bottom: 10px; 10 | font-weight: bold; 11 | color:red; 12 | } 13 | h2 { 14 | text-transform: capitalize; 15 | } 16 | h3{ 17 | white-space: pre; 18 | } 19 | h3::after{ 20 | content: "\A \A" url("https://live.staticflickr.com/2524/3923647005_55590eedf0_b.jpg") "\A SUMO SUMO SUMO SUMO SUMO SUMO"; 21 | white-space: pre; 22 | } 23 | ul{ 24 | list-style-type: none; 25 | columns: 2; 26 | -webkit-columns: 2; 27 | -moz-columns: 2; 28 | } 29 | ul li a{ 30 | color:black; 31 | text-shadow: 0 0 3px #FF0000, 0 0 5px #FF0000; 32 | } 33 | figure figcaption::before{ 34 | content:"Super Awesome " 35 | } 36 | span{ 37 | display:none!important; 38 | } -------------------------------------------------------------------------------- /chat_thief/static/andyjamesadams.css: -------------------------------------------------------------------------------- 1 | html { 2 | background: url("https://media1.giphy.com/media/jUL2BawurnYHS6gSJ5/giphy.gif?cid=ecf05e47e4d77f8f1c43c6cdb0668de07fea9b3a653a2378&rid=giphy.gif") no-repeat center center fixed; 3 | -webkit-background-size: cover; 4 | -moz-background-size: cover; 5 | -o-background-size: cover; 6 | background-size: cover; 7 | } 8 | 9 | body{ 10 | background-color:#00000000; 11 | } 12 | 13 | h1{ 14 | display: none; 15 | } 16 | h2{ 17 | text-transform: uppercase; 18 | width: 100%; 19 | text-align: center; 20 | position: absolute; 21 | top:50%; 22 | color:#608c8f; 23 | font-size: 45pt; 24 | } 25 | h3{ 26 | display: none; 27 | } 28 | 29 | ul{ 30 | display: none; 31 | } 32 | figure{ 33 | display: none; 34 | } 35 | 36 | span{ 37 | display: none; 38 | } -------------------------------------------------------------------------------- /chat_thief/static/aquafunkalisticbootywhap.css: -------------------------------------------------------------------------------- 1 | h2:after { 2 | content: url(https://nethistorian.files.wordpress.com/2013/07/underconstruction.gif); 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | } 7 | -------------------------------------------------------------------------------- /chat_thief/static/awfulwaffl3.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Gloria Hallelujah'); 2 | 3 | html{ 4 | background-color: black; 5 | text-align: center; 6 | } 7 | 8 | body { 9 | text-transform: capitalize; 10 | } 11 | 12 | h1{font-family: 'Gloria Hallelujah'; 13 | font-size: 40px; 14 | color: maroon; 15 | 16 | } 17 | h2 { 18 | color: green; 19 | text-decoration-color: maroon; 20 | text-shadow: 3px 3px maroon; 21 | } 22 | h3 {color: blue; 23 | font-variant-position: super; 24 | 25 | 26 | } 27 | p { font-style: italic; 28 | color: gold; 29 | -------------------------------------------------------------------------------- /chat_thief/static/aynstayn.css: -------------------------------------------------------------------------------- 1 | ul{ 2 | font: normal normal 14px/20px Helvetica, Arial, sans-serif; 3 | list-style-type: none; 4 | margin-left: 0 0 0 10px; 5 | padding: 0; 6 | position: relative; 7 | overflow:hidden; 8 | } 9 | 10 | 11 | ul::before::before { 12 | font-weight: bold; 13 | color:limegreen; 14 | content: '╭─aynstayn@beginworld.exchange ~ \A ╰─➤ tree /bin'; 15 | white-space: pre-wrap; 16 | } 17 | 18 | ul::before { 19 | font-weight: bold; 20 | color:limegreen; 21 | /* content: '╭─aynstayn@beginworld.exchange ~ \A ╰─➤ tree /bin'; */ 22 | content: url('test.js'); 23 | white-space: pre-wrap; 24 | } 25 | 26 | li{ 27 | margin: 0; 28 | padding: 0 12px; 29 | position: relative; 30 | } 31 | 32 | li::before, li::after{ 33 | content: ''; 34 | position: absolute; 35 | left: 0; 36 | } 37 | 38 | /* horizontal line on inner list items */ 39 | li::before{ 40 | border-top: 1px solid limegreen; 41 | top: 10px; 42 | width: 10px; 43 | height: 0; 44 | } 45 | 46 | /* vertical line on list items */ 47 | li:after{ 48 | border-left: 1px solid limegreen; 49 | height: 100%; 50 | width: 0px; 51 | top: -10px; 52 | } 53 | 54 | /* lower line on list items from the first level because they don't have parents */ 55 | ul > li::after{ 56 | top: 10px; 57 | } 58 | li a:link, li a:visited, li a:hover, li a:active { 59 | color:limegreen; 60 | } 61 | /* hide line from the last of the first level list items */ 62 | ul > li:last-child::after{ 63 | display: none; 64 | } -------------------------------------------------------------------------------- /chat_thief/static/basti_brot.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | animation: textwelle 2s; 3 | } 4 | 5 | @keyframes textwelle { 6 | 0 { 7 | font-size: 0; 8 | opacity: 0; 9 | } 10 | 90% { 11 | font-size: 220%; 12 | opacity: 1; 13 | } 14 | 100% { 15 | font-size: 200%; 16 | opacity: 1; 17 | } 18 | } -------------------------------------------------------------------------------- /chat_thief/static/bbriano.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: blueviolet; 3 | } 4 | -------------------------------------------------------------------------------- /chat_thief/static/beetle3d.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: 3 | linear-gradient(45deg, #808080 25%, transparent 25%), 4 | linear-gradient(-45deg, #808080 25%, transparent 25%), 5 | linear-gradient(45deg, transparent 75%, #808080 75%), 6 | linear-gradient(-45deg, transparent 75%, #808080 75%); 7 | 8 | background-size:20px 20px; 9 | background-position:0 0, 10px 0, 10px -10px, 0px 10px; 10 | 11 | font-family: "Comic Sans MS", cursive, sans-serif; 12 | } 13 | 14 | 15 | @-webkit-keyframes spincube { 16 | from,to { -webkit-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); } 17 | 16% { -webkit-transform: rotateY(-90deg); } 18 | 33% { -webkit-transform: rotateY(-90deg) rotateZ(90deg); } 19 | 50% { -webkit-transform: rotateY(-180deg) rotateZ(90deg); } 20 | 66% { -webkit-transform: rotateY(90deg) rotateX(90deg); } 21 | 83% { -webkit-transform: rotateX(90deg); } 22 | } 23 | 24 | body { 25 | -webkit-animation-name: spincube; 26 | -webkit-animation-timing-function: ease-in-out; 27 | -webkit-animation-iteration-count: infinite; 28 | -webkit-animation-duration: 12s; 29 | -webkit-transform-style: preserve-3d; 30 | -webkit-transform-origin: 60px 60px 0; 31 | } -------------------------------------------------------------------------------- /chat_thief/static/beginbot.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-weight: 3em; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/beginbotbot.css: -------------------------------------------------------------------------------- 1 | 400: Invalid request -------------------------------------------------------------------------------- /chat_thief/static/beginbotbot.js: -------------------------------------------------------------------------------- 1 | 400: Invalid request -------------------------------------------------------------------------------- /chat_thief/static/biged_twitch.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | background: transparent url(https://cdn.shopify.com/s/files/1/0271/0355/9723/files/BigEdLogoBlack-600x200-transparent_2000x.png) no-repeat; 3 | padding-left:(width-of-image)px; 4 | color: transparent; 5 | /* height: 100px; */ 6 | } 7 | 8 | a { 9 | color: #303059; 10 | text-decoration: none; 11 | } 12 | 13 | a:hover { 14 | color: white; 15 | transition-duration: 500ms; 16 | } 17 | body { 18 | background: #305213; 19 | } -------------------------------------------------------------------------------- /chat_thief/static/brandenkimm.css: -------------------------------------------------------------------------------- 1 | h1:hover { 2 | color: yellow; 3 | } 4 | 5 | h1:active { 6 | color: purple; 7 | } -------------------------------------------------------------------------------- /chat_thief/static/ciferhd.css: -------------------------------------------------------------------------------- 1 | body { 2 | /* background-color: none..class{ */ 3 | background-image: url("https://mewallpaper.com/thumbnail/games/8356-coding-background-free-photo-wallpaper.jpg"); 4 | background-size: auto; 5 | /* background: #000065; */ 6 | text-align: center; 7 | color: white; 8 | font-size: 2em; 9 | font-family: "Helvetica"; 10 | } 11 | 12 | h1 { 13 | background-color: black; 14 | border-style: double; 15 | border-width: 5px; 16 | border-color: blue; 17 | padding: 10px; 18 | color: white; 19 | text-align: center; 20 | } 21 | 22 | h2 { 23 | background-color: black; 24 | border-style: dotted; 25 | border-width: 5px; 26 | padding: 5px; 27 | text-align: center; 28 | color: lime; 29 | } 30 | 31 | h3 { 32 | background-color: gray; 33 | text-align: center; 34 | } 35 | 36 | table { 37 | background-color: green; 38 | display: flex; 39 | align-items: center; 40 | text-align: center; 41 | } 42 | 43 | ul { 44 | background-color: yellow; 45 | border-style: dashed; 46 | border-color: red; 47 | border-width: 30px; 48 | padding: 32px; 49 | text-align: center; 50 | color: red; 51 | } 52 | 53 | p { 54 | color: white; 55 | text-align: center; 56 | font-family: futura; 57 | font-style: bold; 58 | } 59 | 60 | figure { 61 | background-color: blue; 62 | border-style: double; 63 | border-width: 5px; 64 | border-color: black; 65 | } 66 | 67 | span { 68 | background-color: teal; 69 | border-style: dotted; 70 | border-width: 3px; 71 | } -------------------------------------------------------------------------------- /chat_thief/static/corbob.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | content: "
corbob
" 3 | } -------------------------------------------------------------------------------- /chat_thief/static/crazehani.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: blue; 3 | } 4 | 5 | h1 { 6 | color: green; 7 | } -------------------------------------------------------------------------------- /chat_thief/static/crazytech44.css: -------------------------------------------------------------------------------- 1 | body { font: 900 120px/1 'Source Sans Pro', Arial, sans-serif; background: #becccc; text-transform: uppercase; color: #fff; text-align: center; letter-spacing: -3px; padding-top: 10%; } 2 | 3 | h1 { 4 | position: absolute; 5 | top: 35%; 6 | width: 100%; 7 | 8 | text-shadow: 0 1px 0 hsl(174,5%,80%), 9 | 0 2px 0 hsl(174,5%,75%), 10 | 0 3px 0 hsl(174,5%,70%), 11 | 0 4px 0 hsl(174,5%,66%), 12 | 0 5px 0 hsl(174,5%,64%), 13 | 0 6px 0 hsl(174,5%,62%), 14 | 0 7px 0 hsl(174,5%,61%), 15 | 0 8px 0 hsl(174,5%,60%), 16 | 17 | 0 0 5px rgba(0,0,0,.05), 18 | 0 1px 3px rgba(0,0,0,.2), 19 | 0 3px 5px rgba(0,0,0,.2), 20 | 0 5px 10px rgba(0,0,0,.2), 21 | 0 10px 10px rgba(0,0,0,.2), 22 | 0 20px 20px rgba(0,0,0,.3); 23 | } -------------------------------------------------------------------------------- /chat_thief/static/crypt0lake.css: -------------------------------------------------------------------------------- 1 | 2 | footer { 3 | clear: both; 4 | text-align: center; 5 | padding-top: 2em; 6 | } 7 | 8 | body { 9 | max-width: 900px; 10 | margin-left: auto; 11 | margin-right: auto; 12 | padding: 1em; 13 | color: inherit; 14 | background: inherit; 15 | } 16 | 17 | html { 18 | background: #111; 19 | color: #eee; 20 | padding-bottom: 500px; 21 | } -------------------------------------------------------------------------------- /chat_thief/static/dagio314.css: -------------------------------------------------------------------------------- 1 | body { 2 | perspective: 500px; 3 | background-color: rgba(0, 255, 255); 4 | color: rgba(100, 0, 100, 0.9); 5 | } 6 | ul { 7 | list-style-type: none; 8 | font-size: 50px; 9 | text-align: center; 10 | animation-name: spin, depth; 11 | animation-timing-function: linear; 12 | animation-iteration-count: infinite; 13 | animation-duration: 3s; 14 | transform-style: preserve-3d; 15 | position: relative; 16 | } 17 | 18 | ul::before, 19 | ul::after { 20 | display: block; 21 | width: 100%; 22 | height: 100%; 23 | top: 0; 24 | transform: rotateY(0.5deg); 25 | transform-origin: 0 50%; 26 | } 27 | ul::after { 28 | transform: rotateY(-0.5deg); 29 | transform-origin: 100% 50%; 30 | } 31 | @keyframes spin { 32 | from { transform: rotateY(0deg); } 33 | to { transform: rotateY(-360deg); } 34 | } 35 | @keyframes depth { 36 | 0% { text-shadow: 0 0 purple; } 37 | 25% { text-shadow: 1px 0 purple, 2px 0 purple, 3px 0 purple, 4px 0 purple, 5px 0 black, 6px 0 purple; } 38 | 50% { text-shadow: 0 0 purple; } 39 | 75% { text-shadow: -1px 0 purple, -2px 0 purple, -3px 0 purple, -4px 0 purple, -5px 0 purple, -6px 0 purple; } 40 | 100% { text-shadow: 0 0 purple; } 41 | } 42 | 43 | li a { 44 | color: rgba(255, 0, 255, 0.5); 45 | text-decoration: none; 46 | } -------------------------------------------------------------------------------- /chat_thief/static/deni1111.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | background-image: url("https://i.imgur.com/2CyuW8Q.jpeg"); 4 | } -------------------------------------------------------------------------------- /chat_thief/static/dentyt.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | color: #5362F6; 3 | text-shadow: 6px 6px #E485F8; 4 | position: relative; 5 | animation: scatter 1.75s infinite; 6 | } 7 | 8 | body { 9 | background: -webkit-linear-gradient(360deg, #FD6F46 10%, #FB9832 360%); /* Chrome 10+, Saf5.1+ */ background: -moz-linear-gradient(360deg, #FD6F46 10%, #FB9832 360%); /* FF3.6+ */ background: linear-gradient(360deg, #FD6F46 10%, #FB9832 360%); 10 | } -------------------------------------------------------------------------------- /chat_thief/static/eatpizza22.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url("https://i.imgur.com/JxipKCy.png"); 3 | background-repeat: repeat; 4 | color: #ff0066; 5 | } -------------------------------------------------------------------------------- /chat_thief/static/evalprase.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: lightblue; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/evilhomerdude.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: gainsboro; 3 | } 4 | 5 | table, th, td { 6 | border: 3px solid dimgray; 7 | } 8 | 9 | a { 10 | font-family: verdana; 11 | font-size: 30px; 12 | } -------------------------------------------------------------------------------- /chat_thief/static/falloutghst.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | } 6 | 7 | body { 8 | background-color: #212121; 9 | } 10 | 11 | a { 12 | color: #a7ffeb; 13 | text-decoration: none; 14 | } 15 | 16 | a:hover, 17 | a:active, 18 | a:focus { 19 | color: #64ffda; 20 | text-decoration: none; 21 | } 22 | -------------------------------------------------------------------------------- /chat_thief/static/faolan437.css: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | /* max-height: 600px; */ 4 | width: 1000px; 5 | background-color: hsla(200,40%,30%,.4); 6 | background-image: 7 | url('https://78.media.tumblr.com/cae86e76225a25b17332dfc9cf8b1121/tumblr_p7n8kqHMuD1uy4lhuo1_540.png'), 8 | url('https://78.media.tumblr.com/66445d34fe560351d474af69ef3f2fb0/tumblr_p7n908E1Jb1uy4lhuo1_1280.png'), 9 | url('https://78.media.tumblr.com/8cd0a12b7d9d5ba2c7d26f42c25de99f/tumblr_p7n8kqHMuD1uy4lhuo2_1280.png'), 10 | url('https://78.media.tumblr.com/5ecb41b654f4e8878f59445b948ede50/tumblr_p7n8on19cV1uy4lhuo1_1280.png'), 11 | url('https://78.media.tumblr.com/28bd9a2522fbf8981d680317ccbf4282/tumblr_p7n8kqHMuD1uy4lhuo3_1280.png'); 12 | background-repeat: repeat-x; 13 | background-position: 14 | 0 20%, 15 | 0 100%, 16 | 0 50%, 17 | 0 100%, 18 | 0 0; 19 | background-size: 20 | 2500px, 21 | 800px, 22 | 500px 200px, 23 | 1000px, 24 | 400px 260px; 25 | animation: 50s para infinite linear; 26 | } 27 | 28 | @keyframes para { 29 | 100% { 30 | background-position: 31 | -5000px 20%, 32 | -800px 95%, 33 | 500px 50%, 34 | 1000px 100%, 35 | 400px 0; 36 | } 37 | } -------------------------------------------------------------------------------- /chat_thief/static/fletcherlabs.css: -------------------------------------------------------------------------------- 1 | * { 2 | color: black; 3 | background: black; 4 | } -------------------------------------------------------------------------------- /chat_thief/static/godworrior1.css: -------------------------------------------------------------------------------- 1 | body { 2 | background:#6891C3; 3 | color: #FDFD95; 4 | text-align: center; 5 | font-family: monospace; 6 | } 7 | ul { 8 | padding: 0; 9 | list-style-type: none; 10 | } 11 | li { 12 | color: #FF756D; 13 | padding: 5px; 14 | display: inline-block; 15 | writing-mode: vertical-rl; 16 | text-orientation: upright; 17 | font-size: 120%; 18 | vertical-align: top; 19 | } 20 | li:hover { 21 | cursor: pointer; 22 | } 23 | a { 24 | color: #FF756D; 25 | text-decoration: none; 26 | padding: 7px; 27 | transition: 0.4s; 28 | } 29 | a:hover { 30 | margin: auto; 31 | background-color: #FFF49C; 32 | border-radius: 60px; 33 | opacity: 1; 34 | } -------------------------------------------------------------------------------- /chat_thief/static/goldzulu.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: black; 4 | } 5 | 6 | @keyframes star { 7 | 0% { 8 | opacity: 0; 9 | transform: rotateX(-25deg) translateZ(-0.75em) translateY(2em) 10 | translateX(-2em); 11 | } 12 | 35% { 13 | opacity: 1; 14 | transform: rotateX(-25deg) translateZ(-5em) translateY(2em) translateX(-2em); 15 | } 16 | 100% { 17 | opacity: 0; 18 | transform: rotateX(-25deg) translateZ(4em) translateY(2em) translateX(-2em) 19 | scale(6); 20 | } 21 | } 22 | 23 | body:not(h1) { 24 | font-family: Century Gothic, CenturyGothic, AppleGothic, sans-serif; 25 | transform: perspective(300px) rotateX(25deg); 26 | transform-origin: 50% 100%; 27 | transform-style: preserve-3d; 28 | text-align: justify; 29 | position: absolute; 30 | margin-left: -9em; 31 | font-weight: bold; 32 | font-size: 350%; 33 | height: 50em; 34 | width: 18em; 35 | bottom: 0; 36 | left: 50%; 37 | } 38 | 39 | body ul:after { 40 | position: absolute; 41 | content: " "; 42 | bottom: 60%; 43 | left: 0; 44 | right: 0; 45 | top: 0; 46 | } 47 | 48 | body h1 a { 49 | position: absolute; 50 | animation: star 10s ease-out infinite; 51 | color: yellow; 52 | top: 0px; 53 | left: 0px; 54 | font-size: 20rem; 55 | } 56 | body h1 a:after { 57 | content: "WARS"; 58 | } 59 | 60 | h2, 61 | h3 { 62 | position: relative; 63 | top: 0; 64 | text-align: right; 65 | font-size: 10rem; 66 | transform: rotateX(-25deg) translateZ(-0.75em) translateY(2em) 67 | translateX(-2em); 68 | height: 2em; 69 | width: 27em; 70 | } 71 | h2:after { 72 | content: " - twitch.tv/goldzulu"; 73 | } 74 | 75 | ul li a { 76 | color: yellow; 77 | text-decoration: none; 78 | width: 100%; 79 | } 80 | 81 | ul { 82 | animation: scroll 100s linear infinite; 83 | position: absolute; 84 | top: 10%; 85 | z-index: 100; 86 | } 87 | 88 | @keyframes scroll { 89 | 0% { 90 | top: 100%; 91 | } 92 | 100% { 93 | top: -170%; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /chat_thief/static/gottzstreams.css: -------------------------------------------------------------------------------- 1 | @import url(https://static.gottz.de/beginbot.css); -------------------------------------------------------------------------------- /chat_thief/static/idanscott.css: -------------------------------------------------------------------------------- 1 | body, 2 | html { 3 | padding: 0; 4 | margin: 0; 5 | background-color: #6d6d6d; 6 | } 7 | 8 | ul { 9 | list-style: none; 10 | } 11 | 12 | ul li { 13 | display: inline; 14 | } 15 | 16 | span:last-child { 17 | display: none; 18 | } -------------------------------------------------------------------------------- /chat_thief/static/isidentical.css: -------------------------------------------------------------------------------- 1 | html{ 2 | background-image:url('https://user-images.githubusercontent.com/47358913/83976033-0a87fd80-a900-11ea-8de7-1def45a939ed.png'); 3 | padding: 10rem; 4 | } 5 | body { 6 | /* background-color: none..class{ */ 7 | background:rgba(0,0,0); 8 | /* background: #000065; */ 9 | color: white; 10 | font-size: 2em; 11 | font-family: "Helvetica"; 12 | } 13 | html:before { 14 | content: url(https://user-images.githubusercontent.com/47358913/84156679-7b4f2700-aa72-11ea-86b9-6941710fef20.png); 15 | display: flex; 16 | align-items: center; 17 | justify-content: center; 18 | } 19 | html:after { 20 | content: url(https://render-tron.appspot.com/screenshot/https://github.com/isidentical?width=1920&height=1080); 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | } 25 | 26 | h1 a, h2, h3{ 27 | text-decoration:none; 28 | color:#0050ff; 29 | text-align:center; 30 | letter-spacing: 4px; 31 | } 32 | h1 { 33 | display: none; 34 | } 35 | 36 | h2 { 37 | font-size: .7em; 38 | } 39 | h3 { 40 | font-size:.4em; 41 | } 42 | ul { 43 | list-style-type: none; 44 | } 45 | li a { 46 | color:#2457b4; 47 | text-decoration:none; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /chat_thief/static/j0bdone.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 25px; 3 | background-color: rgb(0, 128, 0); 4 | font-family: Arnoldboecklin, fantasy; 5 | font-size: 36px; 6 | } 7 | 8 | h1 { 9 | font-size: 72px; 10 | font-weight: normal; 11 | font-family: Florence, cursive; 12 | margin-top: 5px; 13 | } -------------------------------------------------------------------------------- /chat_thief/static/jerbear1235.css: -------------------------------------------------------------------------------- 1 | .user { 2 | background-color: white; 3 | color: black; 4 | } -------------------------------------------------------------------------------- /chat_thief/static/joehaaga.css: -------------------------------------------------------------------------------- 1 | h1 { 2 | background-image: url(https://www.federalreserve.gov/imgs/eccles-main-2000px.png); 3 | padding: 4rem; 4 | background-size: contain; 5 | background-position: center; 6 | background-color: #4c4c4c; 7 | margin: -2rem; 8 | /* position: absolute; */ 9 | /* top: 0; */ 10 | /* left: 0; */ 11 | /* width: 100%; */ 12 | } 13 | 14 | body { 15 | margin: 0 4rem; 16 | background: white; 17 | /* padding: 2rem; */ 18 | } 19 | 20 | html { 21 | background: #4c4c4c; 22 | } 23 | 24 | h2 { 25 | color: #163855; 26 | font-family: Georgia; 27 | padding: 0 2rem; 28 | color: transparent; 29 | } 30 | 31 | h1 a { 32 | color: white; 33 | text-decoration: none; 34 | } 35 | 36 | h2::before {content: 'Recent Developments';color: #163855;} 37 | 38 | ul li::before {} 39 | 40 | ul li a::before { 41 | content: 'Federal Reserve announces proposal to allow access to'; 42 | } 43 | 44 | ul li a { 45 | color: #3a6c9c; 46 | text-decoration: none; 47 | } 48 | 49 | ul li::after {content: 'Press Release - 6/18/2020';display: block;font-size: 1.2rem;color: #666;} -------------------------------------------------------------------------------- /chat_thief/static/joker_dan.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #172933; 3 | color: #c1d9e5; 4 | } 5 | a { 6 | color: #f3ce76; 7 | text-decoration: none; 8 | font-size: 1em; 9 | font-weight: 600; 10 | transition-duration: 250ms; 11 | transition-timing-fuction: linear; 12 | transition-property: border; 13 | border: 0.15rem solid transparent; 14 | } 15 | a:hover { 16 | border-bottom: 0.15rem solid #f3ce76; 17 | } 18 | a:before { content: '» ' } 19 | a:after { content: ' «' } 20 | h1, h2, h3, h4 { 21 | text-align: center; 22 | color: #f3ce76; 23 | } 24 | li, ol { list-style-type: none; } -------------------------------------------------------------------------------- /chat_thief/static/jr_boss.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Metal+Mania&display=swap"); 2 | body { 3 | background-image: url("https://i.pinimg.com/originals/22/3c/17/223c1747e7bc9c1e5956d988e5329841.png"); 4 | color: white; 5 | animation-name: background; 6 | animation-duration: 0.15s; 7 | animation-delay: 3s; 8 | animation-iteration-count: 4; 9 | background-repeat: repeat-x; 10 | } 11 | 12 | * { 13 | text-align: center; 14 | font-family: "Metal Mania", cursive; 15 | } 16 | 17 | h1 { 18 | padding-top: 25rem; 19 | font-size: 70px; 20 | } 21 | 22 | h2 { 23 | font-size: 60px; 24 | } 25 | 26 | h3 { 27 | font-size: 30px; 28 | } 29 | 30 | a { 31 | color: white; 32 | } 33 | 34 | ul { 35 | list-style: none; 36 | font-size: 30px; 37 | } 38 | 39 | *:hover { 40 | cursor: not-allowed; 41 | } 42 | 43 | @keyframes background { 44 | from { 45 | background-image: url("https://i.pinimg.com/originals/22/3c/17/223c1747e7bc9c1e5956d988e5329841.png"); 46 | background-size: 1920px 1080px; 47 | } 48 | to { 49 | background-image: url("https://static-23.sinclairstoryline.com/resources/media/d60d4f1c-9fcc-4ae4-8058-05e885080e19-large16x9_momo2.PNG?1551379953599"); 50 | background-size: 1920px 1080px; 51 | } 52 | } 53 | 54 | h1:hover { 55 | animation-name: flash; 56 | animation-duration: 1s; 57 | animation-delay: 0s; 58 | } 59 | 60 | audio { 61 | border-radius: 3px; 62 | border: #6c0202; 63 | border-style: solid; 64 | } 65 | 66 | table { 67 | list-style: none; 68 | display: flex; 69 | } -------------------------------------------------------------------------------- /chat_thief/static/jr_bots.css: -------------------------------------------------------------------------------- 1 | *{ 2 | background-color: red; 3 | color: white; 4 | } -------------------------------------------------------------------------------- /chat_thief/static/juscuzryancan.css: -------------------------------------------------------------------------------- 1 | *{ 2 | background-color: rgb(24, 42, 130); 3 | } 4 | 5 | body { 6 | /* background-color: none..class{ */ 7 | background:rgba(0,0,0,0.7); 8 | /* background: #000065; */ 9 | color: white; 10 | font-size: 2em; 11 | font-family: "Helvetica"; 12 | } 13 | 14 | h1 { 15 | color: white; 16 | text-align: center; 17 | } 18 | a{ 19 | text-decoration: none; 20 | } 21 | ul{ 22 | list-style-type: none; 23 | display:flex; 24 | } 25 | h1 a:visited{ 26 | color:inherit; 27 | } 28 | h2{ 29 | text-align: center; 30 | } 31 | 32 | p { 33 | color: white; 34 | font-family: futura; 35 | font-style: bold; 36 | } 37 | span{ 38 | display:none; 39 | } -------------------------------------------------------------------------------- /chat_thief/static/kraemrz.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color:darkslategray; 3 | color: limegreen; 4 | font-size: 12; 5 | font-family: "Kentucky Fried"; 6 | } 7 | 8 | h1 { 9 | color: azure; 10 | text-align: right; 11 | } 12 | 13 | p { 14 | color: Red; 15 | font-family: serif; 16 | font-style: bold; 17 | } 18 | 19 | a:link { 20 | background-color: midnightblue; 21 | } 22 | 23 | a:visited { 24 | background-color: navy; 25 | } 26 | 27 | a:hover { 28 | background-color: darkblue; 29 | } 30 | 31 | a:active { 32 | background-color: mediumblue; 33 | } 34 | -------------------------------------------------------------------------------- /chat_thief/static/ladka8.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #82FA58; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/lan_four.css: -------------------------------------------------------------------------------- 1 | table, th, td { 2 | border-collapse: unset; 3 | border: 1px solid blue; 4 | } -------------------------------------------------------------------------------- /chat_thief/static/levinson2504.css: -------------------------------------------------------------------------------- 1 | .user > h1 { 2 | color: red; 3 | font-size: 50px; 4 | } -------------------------------------------------------------------------------- /chat_thief/static/manascode.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #4b4444; 4 | font-size: 2em; 5 | font-family: "Helvetica"; 6 | height: 100vh; 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | flex-direction: column; 11 | } 12 | h2 { 13 | color: #00d900; 14 | } 15 | a { 16 | text-decoration: none; 17 | } 18 | h2:before { 19 | content: url(https://manascode.com/assets/static/logo.0d639c8.a1afb7f….png); 20 | position: absolute; 21 | top: 6rem; 22 | left: 45rem; 23 | } -------------------------------------------------------------------------------- /chat_thief/static/mel_mass.css: -------------------------------------------------------------------------------- 1 | body{ 2 | 3 | background-color:white; 4 | color:black; 5 | font-family: "Helvetica"; 6 | font-size:1.5em; 7 | 8 | } 9 | 10 | h1>a{ 11 | font-family:"Helvetica"; 12 | font-weight:bold; 13 | color: black; 14 | font-size:0.4em; 15 | text-align:left; 16 | 17 | } 18 | ul>li>a{ 19 | color: black; 20 | font-size:0.8em; 21 | } 22 | h2{ 23 | color: red; 24 | text-align:center; 25 | font-size: 2em; 26 | margin:0; 27 | padding:0; 28 | } 29 | 30 | audio 31 | { 32 | 33 | margin-left:70%; 34 | border: solid 4px red; 35 | /*transition:all 0.5s linear;*/ 36 | 37 | box-shadow: 10px 10px 0px 0px #ff0000; 38 | 39 | border-radius:0px 0px 0px 0px ; 40 | } 41 | audio::-webkit-media-controls-mute-button { 42 | display: none !important; 43 | } 44 | 45 | audio::-webkit-media-controls-panel{ 46 | background-color:white; 47 | 48 | } 49 | audio::-webkit-media-controls-play-button{ 50 | color:red; 51 | } 52 | span{ 53 | visibility:hidden; 54 | } 55 | 56 | figcaption{ 57 | color: black; 58 | font-size:0.5em; 59 | text-align:right; 60 | display: none !important; 61 | } 62 | -------------------------------------------------------------------------------- /chat_thief/static/mightycore1.css: -------------------------------------------------------------------------------- 1 | @keyframes rotating { 2 | from { 3 | -ms-transform: rotate(0deg); 4 | -moz-transform: rotate(0deg); 5 | -webkit-transform: rotate(0deg); 6 | -o-transform: rotate(0deg); 7 | transform: rotate(0deg); 8 | } 9 | to { 10 | -ms-transform: rotate(360deg); 11 | -moz-transform: rotate(360deg); 12 | -webkit-transform: rotate(360deg); 13 | -o-transform: rotate(360deg); 14 | transform: rotate(360deg); 15 | } 16 | } 17 | 18 | body { 19 | animation: rotating 3s linear infinite; 20 | } -------------------------------------------------------------------------------- /chat_thief/static/morgenstern991.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Major+Mono+Display); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | html { 9 | height: 100%; 10 | 11 | } 12 | 13 | body { 14 | height: 100%; 15 | background-color: black; 16 | background-image: linear-gradient(to bottom right, black, #999); 17 | background-repeat: no-repeat; 18 | background-attachment: fixed; 19 | } 20 | 21 | a { 22 | text-decoration: none; 23 | color: #3786BE; 24 | } 25 | 26 | a:hover{ 27 | color: #29648E; 28 | } 29 | 30 | h1, h2, h3, ul { 31 | font-family: 'Major Mono Display', monospace; 32 | } 33 | 34 | h1 { 35 | font-size: 14px; 36 | text-align: left; 37 | margin: 20px; 38 | } 39 | 40 | h2 { 41 | margin-top: 50px; 42 | text-align: center; 43 | font-size: 40px; 44 | } 45 | 46 | h3 { 47 | margin: 70px 40px 20px 40px; 48 | text-align: center; 49 | font-size: 20px; 50 | } 51 | 52 | ul { 53 | margin: 50px 150px 150px 150px; 54 | list-style: decimal-leading-zero; 55 | font-size: 14px; 56 | } 57 | 58 | span, code { 59 | margin: 0 60px; 60 | font-size: 12px; 61 | } 62 | 63 | code { 64 | background-color: #000; 65 | padding: 3px 5px; 66 | } -------------------------------------------------------------------------------- /chat_thief/static/mrdemonwolf.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | background: transparent url(https://res.cloudinary.com/mrdemonwolf/image/upload/mrdemonwolf/text_logo.png) no-repeat; 3 | padding-left:(width-of-image)px; 4 | color: transparent; 5 | height: 100px; 6 | } 7 | 8 | a { 9 | color: #303059; 10 | text-decoration: none; 11 | } 12 | 13 | a:hover { 14 | color: white; 15 | transition-duration: 500ms; 16 | } 17 | body { 18 | background: #00aced; 19 | } -------------------------------------------------------------------------------- /chat_thief/static/mrsommerfeld.css: -------------------------------------------------------------------------------- 1 | main { 2 | font-family: monospace, monospace; 3 | margin: auto; 4 | } 5 | 6 | ::selection { 7 | background: #d3869b; 8 | } 9 | 10 | body { 11 | background: #1d2021; 12 | color: #ebdbb2; 13 | max-width: 800px; 14 | margin-left: auto; 15 | margin-right: auto; 16 | } 17 | 18 | pre { 19 | background-color: #3c3836; 20 | } 21 | 22 | a, a:active, a:visited { 23 | color: #b16286; 24 | background-color: #1d2021; 25 | } 26 | 27 | h1, h2, h3, h4, h5 { 28 | text-align: center; 29 | } 30 | 31 | blockquote { 32 | border-left: 1px solid #bdae93; 33 | } 34 | 35 | footer { 36 | position: fixed; 37 | bottom: 0; 38 | } 39 | -------------------------------------------------------------------------------- /chat_thief/static/nineteenletterslong.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color: #001027; 3 | } 4 | h1{ 5 | background-color: #1E8BC3; 6 | color: #FFFFFF; 7 | border: 8px dashed #FFFFFF; 8 | padding: 13px; 9 | font-family: verdana; 10 | font-style: italic; 11 | font-size: 28px; 12 | border-radius: 22px; 13 | } 14 | h1, h1 a{ 15 | background-color: #1E8BC3; 16 | color: #FFFFFF; 17 | padding: 13px; 18 | font-family: verdana; 19 | font-style: italic; 20 | font-size: 28px; 21 | } 22 | h2{ 23 | background-color: #1E8BC3; 24 | color: #FFFFFF; 25 | border: 5px dashed #FFFFFF; 26 | padding: 13px; 27 | font-family: verdana; 28 | font-style: italic; 29 | font-size: 28px; 30 | border-radius: 22px; 31 | text-align: left; 32 | } 33 | h3{ 34 | background-color: #1E8BC3; 35 | color: #FFFFFF; 36 | border: 5px dashed #FFFFFF; 37 | padding: 13px; 38 | font-family: verdana; 39 | font-style: italic; 40 | font-size: 18px; 41 | border-radius: 22px; 42 | text-align: right; 43 | } 44 | ul{ 45 | background-image: url("https://www.cssportal.com/css-style-editor/js/grid.gif"); 46 | color: #FFFFFF; 47 | border: 5px dashed #FFFFFF; 48 | padding: 13px; 49 | font-family: verdana; 50 | font-style: italic; 51 | font-size: 18px; 52 | border-radius: 22px; 53 | text-align: left; 54 | } 55 | li{ 56 | background-color: #1E8BC3; 57 | color: #FFFFFF; 58 | border: 2px dashed #FFFFFF; 59 | padding: 13px; 60 | margin-bottom: 5px; 61 | font-family: verdana; 62 | font-style: italic; 63 | font-size: 18px; 64 | border-radius: 22px; 65 | text-align: left; 66 | } 67 | li, li a{ 68 | background-color: #0E5A93; 69 | color: #FFFFFF; 70 | padding: 13px; 71 | font-family: verdana; 72 | font-style: italic; 73 | font-size: 18px; 74 | } -------------------------------------------------------------------------------- /chat_thief/static/nomoreequity.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: pink; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/oreo_171.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #2e3440; 3 | text-align: center; 4 | color: #ECEFF4; 5 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 6 | 7 | } 8 | a{ 9 | color: #5E81AC; 10 | } 11 | h2{ 12 | font-weight: 200; 13 | } -------------------------------------------------------------------------------- /chat_thief/static/pedrovalentimmm.css: -------------------------------------------------------------------------------- 1 | span:nth-last-child(-n+7) { 2 | display: none; 3 | } 4 | 5 | figure audio { 6 | width: 100%; 7 | margin: 1rem auto; 8 | } -------------------------------------------------------------------------------- /chat_thief/static/portaalgaming.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | h1 { 7 | text-decoration:none; 8 | } -------------------------------------------------------------------------------- /chat_thief/static/privateorange.css: -------------------------------------------------------------------------------- 1 | body { 2 | max-width: 600px; 3 | transform: scale3d(1, -1, -1) rotate3d(1, 1, 1, 05deg); 4 | margin: auto; 5 | background: orange; 6 | color: black; 7 | margin-top: 50px; 8 | margin-bottom: 50px; 9 | } 10 | 11 | a { 12 | color: #664200; 13 | } 14 | 15 | html { 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | height: 100%; 20 | } -------------------------------------------------------------------------------- /chat_thief/static/prototypeo4.css: -------------------------------------------------------------------------------- 1 | body { 2 | animation: rotate 3s linear infinite; 3 | } 4 | @keyframes rotate { 5 | to { 6 | transform: rotate(360deg); 7 | } 8 | } -------------------------------------------------------------------------------- /chat_thief/static/purplepinapples.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'thisfont'; 3 | src: url('https://sean.fish/p/vt.ttf') format('truetype'); 4 | } 5 | 6 | ul, span { 7 | display: none; 8 | } 9 | 10 | body { 11 | font-family: 'thisfont', sans-serif; 12 | text-align: center; 13 | color: #534099; 14 | background: linear-gradient(90deg, #c6ffdd, #fbd786, #f7797d, #23d5ab); 15 | background-size: 400% 400%; 16 | animation: gradient 10s ease infinite; 17 | } 18 | 19 | a, a:visited { 20 | color: #292043; 21 | } 22 | 23 | @keyframes gradient { 24 | 0% { 25 | background-position: 0% 50%; 26 | } 27 | 50% { 28 | background-position: 100% 50%; 29 | } 30 | 100% { 31 | background-position: 0% 50%; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /chat_thief/static/pyramidpixels.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap); 2 | h3 { 3 | font-family: 'Press Start 2P', monospace !important; 4 | } -------------------------------------------------------------------------------- /chat_thief/static/q_wolf.css: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function(){ 2 | w = document.createElement("div"); 3 | w.id = "background-wrap"; 4 | for (i=0;i<=10;i++) { 5 | d = document.createElement("div"); 6 | d.className = "bubble x" + i; 7 | w.appendChild(d); 8 | } 9 | document.body.appendChild(w); 10 | }); 11 | -------------------------------------------------------------------------------- /chat_thief/static/rasmustof.css: -------------------------------------------------------------------------------- 1 | body{ 2 | overflow: hidden; 3 | 4 | background:rgb(180,180,180); 5 | 6 | /* 7 | animation-name: bodyanimation; 8 | animation-duration: 10s; 9 | animation-iteration-count: infinite; 10 | animation-timing-function: linear; 11 | */ 12 | 13 | } 14 | body *{ 15 | transform: scale(0.5); 16 | } 17 | h1{ 18 | background-color: rgba(0,0,0,0.5); 19 | padding: 1rem; 20 | color: white; 21 | border-radius: 20px; 22 | } 23 | a{ 24 | text-decoration: none; 25 | color: white; 26 | } 27 | @keyframes bodyanimation { 28 | 0% { 29 | transform: rotate(0deg); 30 | } 31 | 50%{ 32 | transform: rotate(180deg); 33 | } 34 | 100% { 35 | transform: rotate(360deg); 36 | } 37 | } -------------------------------------------------------------------------------- /chat_thief/static/remi_xrei.css: -------------------------------------------------------------------------------- 1 | html { 2 | background:#101; 3 | position: relative; 4 | } 5 | html:after { 6 | content: ""; 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | background-image: url("https://i.imgur.com/6HYpjQ8.jpg"); 11 | width: 100%; 12 | height: 100%; 13 | background-size: auto 100%; 14 | opacity: 0.4; 15 | z-index: -1; 16 | } 17 | body { 18 | background: #000; 19 | color: pink; 20 | width: 75%; 21 | height: 80vh; 22 | padding: 5vh 15px; 23 | margin: 5vh auto; 24 | opacity: 0.8; 25 | font-size: 1.4em; 26 | } 27 | body, code { 28 | font-family: Consolas, monospace; 29 | } 30 | a { 31 | text-decoration: none !important; 32 | color: #e62565 !important; 33 | } 34 | li { 35 | list-style: none; 36 | } 37 | h1{ 38 | text-align: center; 39 | text-transform: uppercase; 40 | position:relative; 41 | background: #201 !important; 42 | } 43 | h3 { 44 | margin-bottom: 0px; 45 | } -------------------------------------------------------------------------------- /chat_thief/static/rexroof.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: black; 3 | color: yellow; 4 | font-size: 1.9em; 5 | font-family: "monospace"; 6 | } 7 | 8 | h1 { 9 | display: none; 10 | } 11 | span { 12 | color: pink; 13 | font-size: 0.3em; 14 | line-height: 1px; 15 | text-align: end; 16 | 17 | } 18 | 19 | } 20 | h2 { 21 | text-align: center; 22 | font-size: 2.5em; 23 | } 24 | 25 | p { 26 | color: white; 27 | font-family: futura; 28 | font-style: bold; 29 | } 30 | 31 | a { 32 | color: orange; 33 | } 34 | 35 | ul { 36 | font-size: 0.5em; 37 | position: inherit; 38 | color: white; 39 | 40 | } 41 | 42 | h3 { 43 | position: inherit; 44 | width: 100%; 45 | height: 100%; 46 | margin: 0; 47 | font-size: 0.5em; 48 | line-height: 50px; 49 | text-align: left; 50 | 51 | /* Apply animation to this element */ 52 | -moz-animation: example4 10s ease-out; 53 | -webkit-animation: example4 10s ease-out; 54 | animation: example4 10s ease-out; 55 | } 56 | /* Move it (define the animation) */ 57 | @-moz-keyframes example4 { 58 | 0% { -moz-transform: translateX(200%); } 59 | 100% { -moz-transform: translateX(0%); } 60 | } 61 | @-webkit-keyframes example4 { 62 | 0% { -webkit-transform: translateX(200%); } 63 | 100% { -webkit-transform: translateX(0%); } 64 | } 65 | @keyframes example4 { 66 | 0% { 67 | -moz-transform: translateX(200%); /* Firefox bug fix */ 68 | -webkit-transform: translateX(200%); /* Firefox bug fix */ 69 | transform: translateX(200%); 70 | } 71 | 100% { 72 | -moz-transform: translateX(0%); /* Firefox bug fix */ 73 | -webkit-transform: translateX(0%); /* Firefox bug fix */ 74 | transform: translateX(0%); 75 | } 76 | -------------------------------------------------------------------------------- /chat_thief/static/richardme123.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "Futura Bold"; 2 | src: url("/fonts/FuturaBold.eot"); /* IE9*/ 3 | src: url("/fonts/FuturaBold.eot?#iefix") format("embedded-opentype"), /* IE6-IE8 */ 4 | url("/fonts/FuturaBold.woff2") format("woff2"), /* chrome、firefox */ 5 | url("/fonts/FuturaBold.woff") format("woff"), /* chrome、firefox */ 6 | url("/fonts/FuturaBold.ttf") format("truetype"), /* chrome、firefox、opera、Safari, Android, iOS 4.2+*/ 7 | url("/fonts/FuturaBold.svg#Futura Bold") format("svg"); /* iOS 4.1- */ 8 | } 9 | 10 | html, body { 11 | position: relative; 12 | width: 100%; 13 | height: 100%; 14 | text-align:center; 15 | } 16 | 17 | body { 18 | background: #000; 19 | color: #fff; 20 | margin: 0; 21 | padding: 8px; 22 | box-sizing: border-box; 23 | font-family: 'Futura Bold', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 24 | } 25 | 26 | a { 27 | color: #56BC58; 28 | text-decoration: none; 29 | } 30 | 31 | a:hover { 32 | text-decoration: underline; 33 | } 34 | 35 | 36 | label { 37 | display: block; 38 | } 39 | 40 | input, button, select, textarea { 41 | font-family: inherit; 42 | font-size: inherit; 43 | padding: 0.4em; 44 | margin: 0 0 0.5em 0; 45 | box-sizing: border-box; 46 | border: 1px solid #ccc; 47 | border-radius: 2px; 48 | } 49 | 50 | input:disabled { 51 | color: #ccc; 52 | } 53 | 54 | input[type="range"] { 55 | height: 0; 56 | } 57 | 58 | button { 59 | color: #333; 60 | background-color: #f4f4f4; 61 | outline: none; 62 | } 63 | 64 | button:active { 65 | background-color: #ddd; 66 | } 67 | 68 | button:focus { 69 | border-color: #666; 70 | } 71 | 72 | h1, h2, h3, h4, h5, h6 { 73 | font-family: 'Futura Bold', sans-serif; 74 | } -------------------------------------------------------------------------------- /chat_thief/static/rockerboo.css: -------------------------------------------------------------------------------- 1 | /* style.css | https://mygeoangelfirespace.city/styles/style.css */ 2 | 3 | body { 4 | font-size: 1rem; 5 | font-family: Inter, Roboto, Helvetica, sans-serif; 6 | background-color: hsl(246, 5%, 10%); 7 | color: hsl(160, 25%, 95%); 8 | } 9 | 10 | /* Inline #2 | https://mygeoangelfirespace.city/rockerboo.html */ 11 | 12 | html { 13 | display: grid; 14 | justify-content: center; 15 | } 16 | 17 | a { 18 | color: hsl(160, 25%, 95%); 19 | } 20 | 21 | a:hover { 22 | color: #00ffe7; 23 | } 24 | -------------------------------------------------------------------------------- /chat_thief/static/salepate.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: #c0c0c0; 3 | } 4 | 5 | h1,h2,h3,h4,p,span, a { 6 | font-family: monospace; 7 | } 8 | 9 | a { 10 | text-decoration: none; 11 | color: rgb(30, 80, 150); 12 | } 13 | 14 | h2 { 15 | text-align: center; 16 | text-shadow: 2px 2px #606060; 17 | } 18 | h3 { 19 | padding-left: 8px; 20 | } 21 | 22 | body { 23 | border-radius: 16px; 24 | } 25 | 26 | .user { 27 | background-color: #202020; 28 | } 29 | 30 | ul { 31 | list-style-type: circle; 32 | } -------------------------------------------------------------------------------- /chat_thief/static/sana_rinomi.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Anonymous+Pro&family=Montserrat:wght@100;400;700&family=Raleway:wght@300;400&display=swap");body{max-width:100%;width:100vw;height:100vh;background-color:#594A59;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center}body>*{margin:1vh 10vw;padding:5vh 10vw}body h1,body h2,body h3,body h4{font-family:"Raleway",sans-serif;padding:3vh 10vw}body ul{text-align:left;background-color:#EBEBEB;font-size:1.75rem;list-style:none;padding:5vh 5vw}h1,h2,h3,h4{font-family:"Raleway",sans-serif}h1,h2{font-weight:lighter}h5,h6,p,a{font-family:"Montserrat",sans-serif;font-size:1.1rem}h4,h5,h6{color:#1d1d1d}a,a:active,a:visited,a:link{text-decoration:none;color:#12108f}a:hover{color:#0738bd}code{font-family:"Anonymous Pro",monospace;font-size:1.1rem}h1{font-size:5rem}h1>a:active,h1 a:visited,h1 a:link{font-size:5rem;color:#E114E1}h2{font-size:3.75rem}h3{font-size:2.5rem}h4{font-size:2.25rem}h5{font-size:1.75rem}h6{font-size:1.2rem}@media only screen and (min-width: 3839px){h1{font-size:10rem}h2{font-size:7.5rem}h3{font-size:5rem}h4{font-size:4.5rem}h5{font-size:3.5rem}h6{font-size:2.4rem}p,a,a:active,a:visited,a:link,code{font-size:2.2rem}} 2 | /*# sourceMappingURL=sn.css.map */ 3 | -------------------------------------------------------------------------------- /chat_thief/static/shineslove.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color:blueviolet; 3 | 4 | } 5 | 6 | span { 7 | display:none; 8 | } 9 | 10 | h3 { 11 | font-size:x-large; 12 | } 13 | 14 | a:link { 15 | text-decoration: none; 16 | color:gold; 17 | } 18 | 19 | a:visited { 20 | text-decoration: none; 21 | color:pink; 22 | } 23 | 24 | ul { 25 | list-style: none; 26 | padding:0% 34%; 27 | } 28 | 29 | ul li::before { 30 | content: "\2601"; 31 | color: skyblue; 32 | font-weight: bold; 33 | display: inline-block; 34 | width: 1em; 35 | margin-left: -1em; 36 | } -------------------------------------------------------------------------------- /chat_thief/static/simplex991.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url("https://i.imgur.com/xp6NBlW.png"); 3 | background-position: center; 4 | background-repeat: no-repeat; 5 | background-size: cover; 6 | } 7 | 8 | h1, 9 | h2, 10 | h3 { 11 | color: black; 12 | } -------------------------------------------------------------------------------- /chat_thief/static/soulshined.css: -------------------------------------------------------------------------------- 1 | .user { 2 | color : white; 3 | font-size: 2em; 4 | font-family : Helvetica; 5 | background-color: orchid; 6 | } -------------------------------------------------------------------------------- /chat_thief/static/space_vacation.css: -------------------------------------------------------------------------------- 1 | body { 2 | color:pink; 3 | background-color:pink; 4 | } 5 | 6 | a{ 7 | color:pink 8 | } -------------------------------------------------------------------------------- /chat_thief/static/sticklemepickle.css: -------------------------------------------------------------------------------- 1 | h2 { 2 | color: red; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | /* background-color: none..class{ */ 3 | background:rgba(0,0,0,0.7); 4 | /* background: #000065; */ 5 | color: white; 6 | font-size: 2em; 7 | font-family: "Helvetica"; 8 | } 9 | 10 | h1 { 11 | color: white; 12 | text-align: center; 13 | } 14 | 15 | p { 16 | color: white; 17 | font-family: futura; 18 | font-style: bold; 19 | } 20 | -------------------------------------------------------------------------------- /chat_thief/static/sudo0101.css: -------------------------------------------------------------------------------- 1 | #matrix{display:none;} 2 | @keyframes rotater { 3 | 10% { 4 | transform: rotate( 0deg ) scale( 1 ); 5 | } 6 | 15% { 7 | transform: rotate( -10deg ) scale( 1 ); 8 | } 9 | 25% { 10 | transform: rotate( 30deg ) scale( 1 ); 11 | } 12 | 60%,100% { 13 | transform: rotate( -720deg ) scale( 1 ); 14 | } 15 | } 16 | h1 { 17 | font-size: 0em; 18 | width: 510px; 19 | height: 510px; 20 | margin: 0 auto; 21 | margin-top: 70px; 22 | background-image: url(http://juku.uk/img/logo.png); 23 | -webkit-animation: rotater 5s infinite; /* Safari 4+ */ 24 | -moz-animation: rotater 5s infinite; /* Fx 5+ */ 25 | -o-animation: rotater 5s infinite; /* Opera 12+ */ 26 | animation: rotater 5s infinite; /* IE 10+, Fx 29+ */ 27 | 28 | opacity: 1; 29 | -o-transition:color .01s ease-out, background 1s ease-in; 30 | -ms-transition:color .01s ease-out, background 1s ease-in; 31 | -moz-transition:color .01s ease-out, background 1s ease-in; 32 | -webkit-transition:color .01s ease-out, background 1s ease-in; 33 | 34 | transition:color .1s ease-out, background 4s ease-in; 35 | } 36 | 37 | h1:hover { 38 | background-image: url(http://juku.uk/img/logo2.png); 39 | opacity: 1; 40 | -o-transition:color .01s ease-out, background 1s ease-in; 41 | -ms-transition:color .01s ease-out, background 1s ease-in; 42 | -moz-transition:color .01s ease-out, background 1s ease-in; 43 | -webkit-transition:color .01s ease-out, background 1s ease-in; 44 | 45 | transition:color .1s ease-out, background ease-in; 46 | } 47 | 48 | h2 { 49 | position: absolute; 50 | left: 80%; 51 | top: 0px; 52 | background-color: orange; 53 | color: #000; 54 | border: 10px solid #000; 55 | } 56 | 57 | h3 { 58 | position: absolute; 59 | top: 90%; 60 | font-variant-caps: all-small-caps; 61 | font-family: monospace; 62 | } 63 | 64 | span { 65 | display: none; 66 | } 67 | 68 | ul { 69 | display: none; 70 | } -------------------------------------------------------------------------------- /chat_thief/static/sunny_ai.css: -------------------------------------------------------------------------------- 1 | html { 2 | animation-name: spin; 3 | animation-duration: 1ms; 4 | animation-iteration-count: infinite; 5 | animation-timing-function: linear; 6 | } 7 | 8 | @keyframes spin { 9 | from { 10 | transform: rotate(0deg); 11 | } 12 | to { 13 | transform: rotate(360deg); 14 | } 15 | } -------------------------------------------------------------------------------- /chat_thief/static/supadeviserr.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: initial; 3 | color: initial; 4 | font-size: initial; 5 | font-family: initial; 6 | } 7 | 8 | h1 { 9 | color: initial; 10 | text-align: initial; 11 | } 12 | 13 | p { 14 | color: initial; 15 | font-family: initial; 16 | font-style: initial; 17 | } -------------------------------------------------------------------------------- /chat_thief/static/suuupersonic.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: lightblue; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/syoonee.css: -------------------------------------------------------------------------------- 1 | h2:after { 2 | content: " is cute"; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/teamviewselect.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: lightblue; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/the_fed.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css2?family=Federant&display=swap); 2 | 3 | body { 4 | text-align:center; 5 | background-image: url(https://i.imgur.com/8eBCzyJ.png); 6 | background-repeat: no-repeat; 7 | background-size: 100%; 8 | color: #85bb65; 9 | font-size: 2em; 10 | font-family: 'Federant', cursive; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /chat_thief/static/trgwii.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Inconsolata'; 3 | font-style: normal; 4 | font-weight: 400; 5 | font-stretch: 100%; 6 | src: url(https://fonts.gstatic.com/s/inconsolata/v20/QldgNThLqRwH-OJ1UHjlKENVzkWGVkL3GZQmAwLYxYWI2qfdm7Lpp4U8WR32lw.woff2) format('woff2'); 7 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 8 | } 9 | 10 | body { 11 | background-color: black; 12 | font-family: Inconsolata, Consolas, monospace; 13 | } 14 | 15 | a { 16 | color: darkblue; 17 | } 18 | 19 | a:visited { 20 | color: navy; 21 | } 22 | 23 | li { 24 | font-variant: all-petite-caps; 25 | } 26 | h1 { 27 | display: none; 28 | } -------------------------------------------------------------------------------- /chat_thief/static/vagozino.css: -------------------------------------------------------------------------------- 1 | h2{ 2 | 3 | color:blue 4 | } -------------------------------------------------------------------------------- /chat_thief/static/vappolinario.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color:#005377; 3 | color: white; 4 | font-size: 1.3em; 5 | font-family: "Helvetica"; 6 | } 7 | 8 | h1 { 9 | text-align: center; 10 | } 11 | 12 | h1 a { 13 | color: #F1A208; 14 | } 15 | 16 | h2 { 17 | text-shadow: 0 0 5px #d5c67a; 18 | text-align: center; 19 | transition: all 0.3s ease; 20 | } 21 | 22 | h2:hover { 23 | transform: scale(1.3); 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | } 29 | 30 | li a { 31 | color: #06a77d; 32 | } 33 | 34 | span { 35 | visibility: hidden; 36 | } 37 | -------------------------------------------------------------------------------- /chat_thief/static/weather_tank.css: -------------------------------------------------------------------------------- 1 | body { 2 | display:none; 3 | } 4 | 5 | h1 { 6 | display:none; 7 | } 8 | 9 | table { 10 | display:none; 11 | } -------------------------------------------------------------------------------- /chat_thief/static/whybrow.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url('https://github.com/RunZebraSlowly/images/blob/master/hypertunnel.jpg?raw=true'); 3 | background-position: center; 4 | text-align: center; 5 | color: white; 6 | } 7 | 8 | a { 9 | color: white; 10 | } -------------------------------------------------------------------------------- /chat_thief/static/wmotion.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=VT323&display=swap'); 2 | 3 | html { 4 | cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABFklEQVRYR9WXURLDIAhE6/0PbSdOtUpcd1Gnpv1KGpTHBpCE1/cXq+vrMph7dGvXZTtpfW10DCA5jrH1H0Jhs5E0hnZdCR+vb5S8Nn8mQCeS9BdSalYJqMBjAGzq59xAESN7VFVUgV8AZB/dZBR7QTFDCqGquvUBVVoEtgIwpQRzmANSFHgWQKExHdIrPeuMvQNDarXe6nC/AutgV3JW+6bgqQLeV8FekRtgV+ToDKEKnACYKsfZjjkam7a0ZpYTytwmgainpC3HvwBocgKOxqRjehoR9DFKNFYtOwCGYCszobeCbl26N6yyQ6g8X/Wex/rBPsNEV6qAMaJPMynIHQCoSqS9JSMmwef51LflTgCRszU7DvAGiV6mHWfsaVUAAAAASUVORK5CYII=), auto 5 | } 6 | 7 | a, 8 | button { 9 | cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAzElEQVRYR+2X0Q6AIAhF5f8/2jYXZkwEjNSVvVUjDpcrGgT7FUkI2D9xRfQETwNIiWO85wfINfQUEyxBG2ArsLwC0jioGt5zFcwF4OYDPi/mBYKm4t0U8ATgRm3ThFoAqkhNgWkA0jJLvaOVSs7j3qMnSgXWBMiWPXe94QqMBMBc1VZIvaTu5u5pQewq0EqNZvIEMCmxAawK0DNkay9QmfFNAJUXfgGgUkLaE7j/h8fnASkxHTz0DGIBMCnBeeM7AArpUd3mz2x3C7wADglA8BcWMZhZAAAAAElFTkSuQmCC) 14 0, pointer 10 | } 11 | 12 | body { 13 | position: relative; 14 | padding: 1.5rem 2rem; 15 | border-color: #AFB0B7; 16 | border-style: solid; 17 | border-width: 4px; 18 | background-color: #000D7E; 19 | font-family: 'VT323', monospace; 20 | } 21 | 22 | h1 { 23 | background-color: #49A7A9; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: #071B38; 29 | } 30 | 31 | figure { 32 | display: flex; 33 | margin: 0; 34 | padding: 0; 35 | } 36 | 37 | figcaption { 38 | display: none; 39 | } 40 | 41 | audio { 42 | width: 100%; 43 | } -------------------------------------------------------------------------------- /chat_thief/static/wogilol.css: -------------------------------------------------------------------------------- 1 | body { background-color: yellow; } -------------------------------------------------------------------------------- /chat_thief/static/zackariep.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: green; 3 | } -------------------------------------------------------------------------------- /chat_thief/static/zanpreston.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-image: url("https://gifimage.net/wp-content/uploads/2017/10/hamster-dance-gif.gif"); 3 | background-size: 70px; 4 | } 5 | 6 | 7 | body.user > h1 > a , body.user > h1 > a:visited { 8 | color: red; 9 | animation: blinker 1s linear infinite; 10 | } 11 | 12 | @keyframes blinker { 13 | 50% { 14 | opacity: 0 15 | } 16 | } 17 | 18 | body.user > h2,h3 { 19 | color: yellow 20 | } 21 | 22 | body.user > ul > li, a,a:visited { 23 | color: green 24 | } 25 | 26 | body.user > figure { 27 | color: #e10dfb 28 | } -------------------------------------------------------------------------------- /chat_thief/static/zanussbot.css: -------------------------------------------------------------------------------- 1 | 2 | body:before{ 3 | content:"The site ahead contains harmful programs"; 4 | margin-left:7.5%; 5 | position:relative; 6 | top: -3.5em; 7 | } 8 | 9 | h1:before{ 10 | content:"Attackers on mygeoangelfirespace.city might attempt to trick you into installing programs that harm \A your browsing experience (for example, by changing your homepage or showing extra ads \A on sites you visit.) Learn more \A\A\A Help improve Safe Browsing by sending some system information and page content to Google. \A Privacy policy"; 11 | display: block; 12 | white-space: pre-wrap; 13 | font-size: 16px !important; 14 | font-weight:normal; 15 | margin-left:7.5%; 16 | position:relative; 17 | top: -5.8em; 18 | line-height: 30px; 19 | } 20 | 21 | body { 22 | display:block; 23 | margin-left:auto; 24 | margin-right:auto; 25 | margin-top:20%; 26 | width:50%; 27 | background-color:#D93024 !important; 28 | color: white; 29 | font-size: 2em; 30 | font-family: "Helvetica"; 31 | background-image:url("https://i.imgur.com/elbFZMM.png"), url("https://i.imgur.com/UD9v319.png"), url("https://i.imgur.com/71aReGy.png") !important; 32 | background-repeat:no-repeat !important; 33 | background-position: top 3.3% left 30.2%, top 27.8% left 30.6%, top 28% left 66.6% !important; 34 | background-size: 100px, 100px, 125px !important; 35 | } 36 | 37 | h1 { 38 | color: white; 39 | font-size:0px; 40 | text-align:initial !important; 41 | } 42 | 43 | p { 44 | color: white; 45 | font-family: futura; 46 | font-style: bold; 47 | } 48 | 49 | a{ 50 | color:white; 51 | } 52 | 53 | h2{ 54 | padding-top:8em; 55 | } -------------------------------------------------------------------------------- /chat_thief/static/zeebz91.css: -------------------------------------------------------------------------------- 1 | @keyframes spin { 2 | from { 3 | opacity: 0.6; 4 | transform: scale(0.8) rotate(0deg); 5 | } 6 | 7 | to { 8 | transform: scale(1.3) rotate(360deg); 9 | } 10 | } 11 | 12 | h1 { 13 | animation-name: spin; 14 | animation-duration: 1.3s; 15 | animation-iteration-count: infinite; 16 | } -------------------------------------------------------------------------------- /chat_thief/static/zer0xeon.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Major+Mono+Display&display=swap'); 2 | 3 | body{ 4 | background-image: url(https://zer0xeon.xyz/img/Starfield.png)!important; 5 | background-repeat: no-repeat; 6 | background-attachment: fixed; 7 | background-position: center; 8 | font-family: 'Major Mono Display', monospace!important; 9 | text-align: center!important; 10 | } -------------------------------------------------------------------------------- /chat_thief/static/zerostheory.css: -------------------------------------------------------------------------------- 1 | html { 2 | background-color: black; 3 | } 4 | body { 5 | background-color: #1a001a; 6 | margin: 0 auto; 7 | width: 960px; 8 | font-family: arial, helvetica, sans-serif; 9 | color: #ffffff; 10 | } 11 | 12 | a { 13 | text-decoration: none; 14 | color: #ebccff; 15 | } 16 | 17 | /* HEADER */ 18 | 19 | header { 20 | height: 200px; 21 | padding-top: 30px; 22 | padding-bottom: 30px; 23 | padding-left: 20px; 24 | padding-right; 20px; 25 | } 26 | 27 | /* ul and li style */ 28 | 29 | ul { 30 | padding: 10; 31 | } 32 | 33 | li { 34 | padding: 10px; 35 | } 36 | 37 | /* THE RIGHT DIV */ 38 | 39 | .right { 40 | width: 360px; 41 | float: right; 42 | } 43 | /* WELCOME DIV */ 44 | 45 | .welcome { 46 | float: right; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /chat_thief/static/zolor.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica"; 3 | background: url(https://image.freepik.com/free-vector/cute-unicorn-rainbow-seamless-pattern-background_42349-429.jpg); 4 | } 5 | 6 | h1 a{ 7 | color: #ceeef9; 8 | text-shadow: 2px 2px #70c7f9; 9 | } 10 | 11 | 12 | h2 { 13 | color: #ff9da3; 14 | background-color: #ffe2e4; 15 | font-size: 100px; 16 | text-align: center; 17 | display: inline-flexbox; 18 | text-shadow: 2px 2px white; 19 | } 20 | 21 | h3 { 22 | color: #ff9da3; 23 | background-color: #ffe2e4; 24 | text-align: center; 25 | display: block; 26 | text-shadow: 2px 2px white; 27 | } 28 | 29 | ul { 30 | list-style-type: none; 31 | background: #ff9da3; 32 | padding: 20px; 33 | text-align: center; 34 | width: fit-content; 35 | margin: auto; 36 | } 37 | 38 | ul li { 39 | background: #ffe5e5; 40 | padding: 5px; 41 | } 42 | 43 | a { 44 | color: lightyellow; 45 | background: #ffe2e4; 46 | text-shadow: 2px 2px #fcc84d; 47 | text-decoration: none; 48 | } 49 | 50 | a:hover { 51 | color: hotpink; 52 | text-shadow: 2px 2px #fcc84d; 53 | text-decoration: none; 54 | } 55 | 56 | figure { 57 | display: block; 58 | background: #ffe2e4; 59 | color: #ff9da3; 60 | text-shadow: 2px 2px white; 61 | text-align: center; 62 | width: fit-content; 63 | border: 10px; 64 | border-style: solid; 65 | border-color: #ff9da3; 66 | position: absolute; 67 | top: 8px; 68 | left: 16px; 69 | } -------------------------------------------------------------------------------- /chat_thief/stats_department.py: -------------------------------------------------------------------------------- 1 | from chat_thief.models.user import User 2 | from chat_thief.models.the_fed import TheFed 3 | from chat_thief.models.command import Command 4 | 5 | 6 | class StatsDepartment: 7 | def stats(self): 8 | all_users = User.db().all() 9 | all_cmds = Command.db().all() 10 | 11 | total_cool_points = sum([user.get("cool_points", 0) for user in all_users]) 12 | total_street_cred = sum([user.get("street_cred", 0) for user in all_users]) 13 | fed_reserve = TheFed.reserve() 14 | total_user_sfx_property = sum( 15 | [ 16 | cmd["cost"] * len(cmd["permitted_users"]) 17 | for cmd in all_cmds 18 | if len(cmd["permitted_users"]) > 0 19 | ] 20 | ) 21 | 22 | return { 23 | "total_street_cred": total_street_cred, 24 | "total_cool_points": total_cool_points, 25 | "fed_reserve": fed_reserve, 26 | "total_user_sfx_property": total_user_sfx_property, 27 | } 28 | -------------------------------------------------------------------------------- /chat_thief/templates/bots.html: -------------------------------------------------------------------------------- 1 | Beginland 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

BeginWorld Finance

11 | 12 | 13 | Vote a Bot out with: 14 | 15 | 16 | !bothate @botname 17 | 18 | 19 | 20 |

Votes Against Bots

21 | 22 | 31 | 32 |
33 | 34 |

All Bots

35 | 36 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /chat_thief/templates/command.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Command Beginland 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

BeginWorld Finance

13 | 14 |

Command Name: {{ name }}

15 |

Command Cost: {{ cost }}

16 |

Like to Hate Ratio: {{ like_to_hate_ratio }}%

17 | 18 |
    19 | {% for user in users %} 20 |
  • 21 | {{ user }} 22 |
  • 23 | {% endfor %} 24 |
25 | 26 | 27 |
28 |
Sample Command:
29 | 35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /chat_thief/templates/coup.html: -------------------------------------------------------------------------------- 1 | Beginland 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Breaking News

9 | 10 |
11 |
{{ scope }}
12 |
13 | 14 | 15 | {% if stats %} 16 |
17 |
18 |
19 | {{ stats }} 20 |
21 |
22 | {% endif %} 23 | 24 | 25 | 26 | {% if category == "peace" %} 27 | 28 |
29 |

Peace Keepers: Inheriting the seized sounds from the Revolutionaries

30 | {{ ', '.join(peace_keepers) }} 31 |
32 | 33 |
34 |

Revolutionaries: Lost All their Sounds, Street Cred and Cool Points

35 | 🤕 {{ ', '.join(revolutionaries) }} 36 |
37 | 38 | {% endif %} 39 | 40 | 41 | 42 | {% if category == "revolution" %} 43 | 44 |
45 |

Peace Keepers: Lost All their Sounds, Street Cred and Cool Points

46 | 🤕 {{ ', '.join(peace_keepers) }} 47 |
48 | 49 |
50 |

Gave Up Their sounds and recieved an new set of State Distributed 51 | Sounds, seized from wannabe Peace Keepers

52 | 😎 {{ ', '.join(revolutionaries) }} 53 |
54 | 55 | {% endif %} 56 | -------------------------------------------------------------------------------- /chat_thief/templates/index.html: -------------------------------------------------------------------------------- 1 | Beginland 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 🤠 Street Cred: {{ facts.street_cred }} | 10 | 😎 Cool Points: {{ facts.cool_points }} | 11 | Found 🔊 : {{ facts.available_sounds }} / {{ facts.total_sounds }} | 12 | 13 | {% for user, sfx_count in facts.top_users %} 14 | 15 | @{{ user }} : {{ sfx_count }} 🔊 | 16 | {% endfor %} 17 | 18 | {% for effect in facts.most_popular %} 19 | !{{ effect }} 💸 | 20 | {% endfor %} 21 | -------------------------------------------------------------------------------- /chat_thief/templates/news.html: -------------------------------------------------------------------------------- 1 | Beginland 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Breaking News

9 | 10 |
11 |
{{ scope }}
12 |
13 | 14 | 15 | {% if stats %} 16 |
17 |
18 |
19 | {{ stats }} 20 |
21 |
22 | {% endif %} 23 | -------------------------------------------------------------------------------- /chat_thief/templates/notification.html: -------------------------------------------------------------------------------- 1 | Beginland 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% if notification %} 10 | {{ notification }} 11 | {% endif %} 12 | 13 | -------------------------------------------------------------------------------- /chat_thief/templates/stats.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Beginland 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

BeginWorld Finance

14 |

Stats

15 |

Total Street Cred: {{ total_street_cred }}

16 |

Total Cool Points: {{ total_cool_points }}

17 |

The Fed Reserve: {{ fed_reserve }}

18 |

Total User Property Value: {{ total_user_sfx_property }}

19 | 20 | -------------------------------------------------------------------------------- /chat_thief/templates/sunny.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 64 | 65 | 66 | 67 |
68 |
69 | "{{ title_card }}" 70 |
71 |
72 | 73 | 74 | -------------------------------------------------------------------------------- /chat_thief/templates/widgets.html: -------------------------------------------------------------------------------- 1 | Beginland 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

BeginWorld Finance

11 | 12 | 13 | Submit Your own 25-line, Vanilla JS only with: 14 | 15 | 16 | !js LINK_TO_RAW_JS 17 | 18 | 19 | 20 |

Leaderboard

21 | 22 | 31 | 32 |

Available Widgets

33 | 34 | {% for widget in widgets %} 35 | 36 | {{ widget['user' ]}} - {{ widget['name']}} 37 | | 38 | CODE 39 |
40 | Approved: {{ widget['approved'] }} 41 | 42 |

Owners:

43 | 44 |
    45 | {% for owner in widget['owners'] %} 46 |
  • 47 | {{ owner }} 48 |
  • 49 | {% endfor %} 50 |
51 | 52 |
53 |
54 |
55 | 56 | {% endfor %} 57 | 58 | 59 | To Purchase a Widget, in the Twitch Chat: 60 | 61 | !buyjs WIDGET_NAME 62 | 63 | Refer to the Widget Code for integration instructions 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /chat_thief/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/chat_thief/utils/__init__.py -------------------------------------------------------------------------------- /chat_thief/utils/stats.py: -------------------------------------------------------------------------------- 1 | # https://stackoverflow.com/questions/5996881/how-to-limit-a-number-to-be-within-a-specified-range-python 2 | def clamp(n, minn, maxn): 3 | return max(min(maxn, n), minn) 4 | -------------------------------------------------------------------------------- /chat_thief/utils/url_validator.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | def is_valid_url(potential_url): 5 | regex = re.compile( 6 | r"^(?:http|ftp)s?://" # http:// or https:// 7 | r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|" # domain... 8 | r"localhost|" # localhost... 9 | r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip 10 | r"(?::\d+)?" # optional port 11 | r"(?:/?|[/?]\S+)$", 12 | re.IGNORECASE, 13 | ) 14 | 15 | return re.match(regex, potential_url) is not None 16 | -------------------------------------------------------------------------------- /cool_program.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/cool_program.py -------------------------------------------------------------------------------- /docs/BOT_LAW.md: -------------------------------------------------------------------------------- 1 | # Bot Laws 2 | 3 | ## Beginbotics Guidelines 4 | 5 | - Bots should be useful 6 | - Bots should be funny 7 | - Bots should undetectable From Humans -> Boring Doesn't Count 8 | 9 | ## Cardinal Sin of Bots 10 | 11 | Spam 12 | 13 | ## Rules 14 | 15 | - You must register as a bot, if you are found to be a bot, and owner doesn't 16 | come forward you will be banned. 17 | - Use `!!` for your command trigger 18 | - You need a manifesto 19 | - 1 Bot Per Person 20 | -------------------------------------------------------------------------------- /docs/BUGS.md: -------------------------------------------------------------------------------- 1 | # Bugs 2 | 3 | unlucksmcgee: !issue if quick successive bets are made, the first bet time will 4 | instead be the same as the second bet time. 5 | 6 | - Cube Stealing is not Working 7 | -------------------------------------------------------------------------------- /docs/Bot_Witch_Trials.md: -------------------------------------------------------------------------------- 1 | # Bot Witch Trials 2 | 3 | ## Features 4 | 5 | ```chat 6 | !accuse @bot 7 | ``` 8 | 9 | This will put the Bot on Trial. 10 | 11 | ## Open Questions 12 | 13 | - How long does a trial last 14 | - How Often can someone can go on trial? 15 | - Is it voting: 16 | - Who Can Vote 17 | - How many votes does it take 18 | - We have a test 19 | - Ask someone a question to determine if they are bot. 20 | - We ask the bot the question: they have Limited amounting 21 | (prove automation) to reply. Then its a simple vote for 22 | 3 mins. !bot or !not_bot majority wins. 23 | - Whats the punishment 24 | -------------------------------------------------------------------------------- /docs/Coding_Questions.md: -------------------------------------------------------------------------------- 1 | # Coding Questions 2 | 3 | - Does this belong in the router or model? 4 | - Router and Model is a passing off point 5 | 6 | Router: 7 | 8 | - Parsing of Command, and it does call out to other class, command class or 9 | model classes. 10 | -------------------------------------------------------------------------------- /docs/Cube_Gambling_Ring.md: -------------------------------------------------------------------------------- 1 | # Cube Gambling ring 2 | 3 | ```twitch 4 | !bet 45 (bet all your sounds) 5 | !bet 45 clap 6 | !bet 45 clap damn 7 | 8 | As many you bet, that many you can win. 9 | It is based off the total combined cost of your wagered commands. 10 | You win the other commands viewers wagered. 11 | -------------------------------------------------------------------------------- /docs/Death_and_Taxes.md: -------------------------------------------------------------------------------- 1 | # Death and Taxes in BeginWorld 2 | 3 | - Command prices go up, as they are interacting with. 4 | - Every 24 hours, all command costs are halved. 5 | - At this halving, half the cost of the Command is given to The Fed. 6 | - When Stream Gods drop soundeffects, the price comes from the The Fed. 7 | -------------------------------------------------------------------------------- /docs/PEACE_COUP_REVOLUTION.md: -------------------------------------------------------------------------------- 1 | # How Does The Coup System Work 2 | 3 | ## WORK IN PROGRESS 4 | 5 | Viewers can vote for either !peace or !revolution. 6 | 7 | You can vote as many times as you want, but only your last vote counts 8 | 9 | Once the threshold of votes has been met, you are ALLOWED to trigger a Coup. 10 | The Threshold is determined by the number of active chatting users. 11 | 12 | Coups cost Cool Points 13 | 14 | If you try and trigger a coup without the proper amount of cool points, 15 | you are bankrupted. 16 | 17 | --- 18 | 19 | ## 2 Ways Of Triggering A Coup 20 | 21 | ### Revolutionary Coup 22 | 23 | -> Revolution can be triggered, if the total of Cool Points of the 24 | revolutionaries is enough for a Coup. When the coup is triggered, 25 | then the cost of Cool Points divided by the revolutionaries will 26 | subtracted from each Revolutionary. 27 | 28 | All Owned Sounds will be confiscated and evenly redistributed to the 29 | revolutionaries. 30 | 31 | ### Peace Coup 32 | 33 | -> To Trigger a Peace coup. You have to be able to afford the entire Coup 34 | yourself. 35 | 36 | Once a Coup is triggered. All of the Revolutionary sounds will be confiscated 37 | and evenly distrusted among the Peace Keepers 38 | 39 | Maybe: (Except everyone gets to keep one). 40 | 41 | ### Code 42 | 43 | !revolution 44 | !peace 45 | !coup 46 | 47 | Breaking News 48 | p 49 | 50 | Revolution 51 | Vote 52 | LaLibre 53 | -------------------------------------------------------------------------------- /docs/The_Flow_Of_Commands.md: -------------------------------------------------------------------------------- 1 | # The Flow of Commands 2 | 3 | ## WORK IN PROGRESS 4 | 5 | ```twitch 6 | User: !command args 7 | ``` 8 | 9 | -> CommandRouter -> Routes it to specific Router class 10 | -> Specific Router class 11 | -> Pair a Specific Parser with Specific Command Class 12 | -> Specific Command class 13 | -> Specific Parser class 14 | 15 | The return from a Command Class, Should be a Command::Result 16 | 17 | Then the CommandRouter, will handle saving a User Event, 18 | based on what the Specific Command class returned 19 | 20 | What should Command classes Return 21 | 22 | - Result 23 | 24 | PurchaseReceipt -> What is returned from User Model 25 | PurchaseResult(Enum) -> Possible States for a 'completed' purchase 26 | 27 | Problems: 28 | 29 | The User Model, is returning a PurchaseReceipt, 30 | I think this responsibilities, belongs in the BuyerClass 31 | 32 | EconomyRouter 33 | -> Buyer 34 | -> User Model 35 | -> Buyer will return a Result Object 36 | -> Someone else should do the Styling 37 | -------------------------------------------------------------------------------- /fake_bot.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from tinydb import Query # type: ignore 4 | 5 | from chat_thief.config.log import logger 6 | from chat_thief.command_router import CommandRouter 7 | from chat_thief.models.user import User 8 | from chat_thief.models.command import Command 9 | from chat_thief.models.vote import Vote 10 | from chat_thief.models.breaking_news import BreakingNews 11 | from chat_thief.models.notification import Notification 12 | from chat_thief.models.the_fed import TheFed 13 | from chat_thief.models.css_vote import CSSVote 14 | from chat_thief.models.user_code import UserCode 15 | from chat_thief.data_scrubber import DataScrubber 16 | 17 | DEFAULT_MSG = "!add_perm ha johnnyutah" 18 | DEFAULT_MSG = "nice" 19 | 20 | 21 | 22 | def _fake_irc_msg_builder(user, msg): 23 | return [f":{user}!{user}@user.tmi.twitch.tv", "PRIVMSG", "#beginbot", f":{msg}"] 24 | 25 | 26 | if __name__ == "__main__": 27 | parser = ArgumentParser() 28 | parser.add_argument("--message", "-m", dest="message", default=DEFAULT_MSG) 29 | parser.add_argument("--user", "-u", dest="user", default="beginbotbot") 30 | parser.add_argument( 31 | "--breakpoint", "-b", dest="breakpoint", action="store_true", default=False 32 | ) 33 | args = parser.parse_args() 34 | irc_response = _fake_irc_msg_builder(args.user, args.message) 35 | 36 | if args.breakpoint: 37 | # found_command = Proposal.db().get(Query().name == name) 38 | # found_command = Proposal.db().search(Query().user == "beginbot") 39 | breakpoint() 40 | elif response := CommandRouter(irc_response, logger).build_response(): 41 | print(response) 42 | else: 43 | print("No Response") 44 | -------------------------------------------------------------------------------- /infra/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | venv/ 3 | -------------------------------------------------------------------------------- /infra/Pulumi.dev.yaml: -------------------------------------------------------------------------------- 1 | config: 2 | aws:region: us-west-2 3 | -------------------------------------------------------------------------------- /infra/Pulumi.yaml: -------------------------------------------------------------------------------- 1 | name: beginworld 2 | runtime: python 3 | description: Beginworld can not simply be described 4 | -------------------------------------------------------------------------------- /infra/requirements.txt: -------------------------------------------------------------------------------- 1 | pulumi>=2.0.0,<3.0.0 2 | -------------------------------------------------------------------------------- /mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | 3 | python_version = 3.8 4 | # warn_return_any = True 5 | warn_unused_configs = True 6 | 7 | [mypy-chat_thief.tinydb] 8 | 9 | ignore_missing_imports = True 10 | -------------------------------------------------------------------------------- /presentations/community/community: -------------------------------------------------------------------------------- 1 | Community 2 | 3 | @community.jpeg 4 | 5 | 🌍 BeginWorld™ cares about Community 6 | 7 | Propose and Support Actions 8 | 9 | Free of Cool Points! 😎 10 | 11 | !propose !iasip "The Gang Steals Kappa" 12 | 13 | !support @beginbot 14 | 15 | Once the community agrees, the fun Begins™ 16 | 17 | 🍀 Good Luck 🍀 18 | -------------------------------------------------------------------------------- /presentations/community/community.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/presentations/community/community.jpeg -------------------------------------------------------------------------------- /presentations/health: -------------------------------------------------------------------------------- 1 | Health 2 | 3 | Health for Commands 4 | 5 | Health for Users 6 | 7 | Users Use Health To Play Sounds 8 | 9 | Users Can Be Punished by Removing Health 10 | -------------------------------------------------------------------------------- /presentations/local_bot/main: -------------------------------------------------------------------------------- 1 | Running Bots Locally 2 | 3 | 5 Separate Bots: 4 | 5 | 6 | bot.py 7 | One Bot for collecting the chat and process commands 8 | 9 | soundboard_bot.py 10 | Plays sounds from a Queue 11 | 12 | soundeffect_request_bot.py 13 | Save Samples from Youtube and Twitch 14 | 15 | Hand of the Market Bot 16 | gives chatters street cred and sounds 17 | 18 | Stock Ticker Bot 19 | - Flask 20 | 21 | No Dependencies: 22 | 23 | - TinyDB -> Small lil ORM to use JSON as a Database 24 | - TinyRecord -> Transactions for TinyDB 25 | 26 | 27 | How Bots are Run 28 | ``` 29 | def bot(): 30 | while True: 31 | try: 32 | # Do Some stuff 33 | time.sleep(1) 34 | except Exception as e: 35 | if e is KeyboardInterrupt: 36 | raise e 37 | else: 38 | traceback.print_exc() 39 | ``` 40 | -------------------------------------------------------------------------------- /presentations/revolutions/coup_talk: -------------------------------------------------------------------------------- 1 | Coup 2 | 3 | 4 | Revolutionary Commands 5 | 6 | !peace 7 | !revolution 8 | !coup 9 | !la_libre 10 | 11 | You vote for either !peace or !revolution 12 | 13 | You can swap from peace to revolution anytime 14 | 15 | !la_libre 16 | shows the total votes 17 | and the instability of the goverment 18 | 19 | If there are enough votes required for the a coup, 20 | and the person triggering the coup can afford the Cool Point 21 | Cost, then which ever side has more votes wins 22 | 23 | Revolution Wins 24 | 25 | All of the commands are redistributed to the Revolutionaries evenly 26 | All Peace Keepers and Fence Sitters lose all their Sounds and go Bankrupt 27 | 28 | Peace Wins 29 | 30 | All the commands of the revolutionaries are redistributed to the Peace Keepers 31 | Fence Sitters lose all sounds, but not money! 32 | -------------------------------------------------------------------------------- /presentations/wtf/brr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/presentations/wtf/brr.png -------------------------------------------------------------------------------- /presentations/wtf/stonks.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/presentations/wtf/stonks.jpeg -------------------------------------------------------------------------------- /presentations/wtf/unemployment.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/presentations/wtf/unemployment.jpeg -------------------------------------------------------------------------------- /presentations/wtf/woosh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/presentations/wtf/woosh.jpg -------------------------------------------------------------------------------- /requirements/develop.in: -------------------------------------------------------------------------------- 1 | pytest 2 | mypy 3 | pytest-cov 4 | pytest-mock 5 | jinja2 6 | black 7 | -------------------------------------------------------------------------------- /requirements/runtime.in: -------------------------------------------------------------------------------- 1 | tinydb > 4 2 | requests 3 | flask 4 | -------------------------------------------------------------------------------- /scripts/blacklist_user: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | echo "Blacklisting $1" 4 | 5 | USER_FILE="/home/begin/code/chat_thief/.whitelisted_users" 6 | 7 | sed -i "s/$1//g" $USER_FILE 8 | sed '/^[[:space:]]*$/d' $USER_FILE 9 | -------------------------------------------------------------------------------- /scripts/fun.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | while read -r HTML_FILE; do 4 | 5 | case $HTML_FILE in 6 | Only*) 7 | 8 | # HTML_FILE=$(echo $HTML_FILE | cut -d ' ' -f3) 9 | # if [[ $HTML_FILE == *"old_build"* ]]; then 10 | # echo "Old Build We Should Delete!" 11 | # # echo $HTML_FILE | cut -d ' ' -f3 12 | # fi 13 | 14 | if [[ $HTML_FILE == *"/build"* ]]; then 15 | cp $(echo $HTML_FILE | awk '{print $3 $4}' | sed 's/:/\//') ./tmp/new_build/beginworld_finance/ 16 | fi 17 | ;; 18 | *differ) 19 | cp $(echo $HTML_FILE | cut -d ' ' -f2) ./tmp/new_build/beginworld_finance/ 20 | ;; 21 | esac 22 | done <<< "$(diff -qr ./build ./tmp/old_build/)" 23 | # I use this syntax to read in whole lines from diff and loop over theme 24 | 25 | aws s3 sync ./tmp/new_build/beginworld_finance/ s3://beginworld.exchange-f27cf15 26 | -------------------------------------------------------------------------------- /scripts/sync_html.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | NEW_BUILD_FOLDER="./tmp/new_build" 4 | NEW_BEGINWORLD="$NEW_BUILD_FOLDER/beginworld_finance" 5 | 6 | rm -rf $NEW_BUILD_FOLDER 7 | 8 | # Is -p POSIX compliant? 9 | mkdir -p $NEW_BEGINWORLD 10 | mkdir -p $NEW_BEGINWORLD/styles 11 | mkdir -p $NEW_BEGINWORLD/js 12 | mkdir -p $NEW_BEGINWORLD/commands 13 | 14 | while read -r HTML_FILE; do 15 | 16 | case $HTML_FILE in 17 | Only*) 18 | 19 | # HTML_FILE=$(echo $HTML_FILE | cut -d ' ' -f3) 20 | if [[ $HTML_FILE == *"old_build"* ]]; then 21 | DEST_PATH=$(echo $HTML_FILE | sed 's/\// /g' | rev | awk '{print $1 "/" $2}' | rev | sed 's/://') 22 | # echo "DELETING: ${DEST_PATH}" 23 | aws s3 rm "s3://beginworld.exchange-f27cf15/${DEST_PATH}" 24 | fi 25 | 26 | if [[ $HTML_FILE == *"/build"* ]]; then 27 | FILE_PATH=$(echo $HTML_FILE | awk '{print $3 $4}' | sed 's/:/\//') 28 | DEST_PATH=$(echo $HTML_FILE | sed 's/\// /g' | rev | awk '{print $1 "/" $2}' | rev | sed 's/://' | sed 's/beginworld_finance\///') 29 | 30 | # echo "NEW FILE: ${DEST_PATH}" 31 | cp $FILE_PATH "${NEW_BEGINWORLD}/${DEST_PATH}" 32 | fi 33 | ;; 34 | *differ) 35 | DEST_PATH=$(echo $HTML_FILE | sed 's/\// /g' | rev | awk '{print $2 "/" $3}' | rev | sed 's/://' | sed 's/beginworld_finance\///') 36 | # echo "FILE DIFF: ${DEST_PATH}" 37 | cp $(echo $HTML_FILE | cut -d ' ' -f2) "${NEW_BEGINWORLD}/${DEST_PATH}" 38 | ;; 39 | esac 40 | done <<< "$(diff -qr ./build ./tmp/old_build/)" 41 | # I use this syntax to read in whole lines from diff and loop over theme 42 | 43 | # Maybe CSS --delete is only for styles?? 44 | aws s3 sync "$NEW_BEGINWORLD/" s3://beginworld.exchange-f27cf15 45 | -------------------------------------------------------------------------------- /scripts/whitelist_user: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | echo "Whitelisting $1" 4 | 5 | echo "$1" >> /home/begin/code/chat_thief/.whitelisted_users 6 | cat /home/begin/code/chat_thief/.whitelisted_users 7 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidbegin/chat_thief/a29e68e8cc6ab1c6b254da71a7a9274472ec07a1/tests/__init__.py -------------------------------------------------------------------------------- /tests/audioworld/test_audio_player.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pathlib import Path 3 | 4 | from chat_thief.models.notification import Notification 5 | from chat_thief.audioworld.audio_player import AudioPlayer 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestAudioPlayer(DatabaseConfig): 10 | def test_notifications(self): 11 | fake_sound = Path(__file__) 12 | assert Notification.count() == 0 13 | AudioPlayer.play_sample(fake_sound) 14 | assert Notification.count() == 1 15 | 16 | def test_no_notification(self): 17 | fake_sound = Path(__file__) 18 | assert Notification.count() == 0 19 | AudioPlayer.play_sample(fake_sound, notification=False) 20 | assert Notification.count() == 0 21 | -------------------------------------------------------------------------------- /tests/audioworld/test_request_saver.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.audioworld.request_saver import RequestSaver 4 | from chat_thief.irc_msg import IrcMsg 5 | 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | # We need to make the twitch commands configurable, or just return messages brah 9 | # We should have twitch in there 10 | class TestRequestSaver(DatabaseConfig): 11 | def test_saving_a_request(self): 12 | subject = RequestSaver("beginbot", "!soundeffect Mv0oYS-qMcQ update 0:00 0:01") 13 | subject.save() 14 | -------------------------------------------------------------------------------- /tests/audioworld/test_sample_saver.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.audioworld.sample_saver import SampleSaver 4 | from chat_thief.models.command import Command 5 | 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestSampleSaver(DatabaseConfig): 10 | def test_saving_a_sample(self): 11 | assert Command.count() == 0 12 | subject = SampleSaver( 13 | user="thugga", 14 | youtube_id="UZvwFztC1Gc", 15 | command="my_girlfriend", 16 | start_time="0:08", 17 | end_time="0:13", 18 | ) 19 | subject.save() 20 | assert Command.count() == 1 21 | subject.save() 22 | assert Command.count() == 1 23 | 24 | def test_saving_a_problem_sample(self): 25 | assert Command.count() == 0 26 | subject = SampleSaver( 27 | user="qwertimer", 28 | youtube_id="https://www.youtube.com/watch?v=Ve-ATf6OTBQ", 29 | command="qwertimer", 30 | start_time="0:07", 31 | end_time="0:11", 32 | ) 33 | subject.save() 34 | assert Command.count() == 1 35 | -------------------------------------------------------------------------------- /tests/audioworld/test_soundeffects_library.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.audioworld.soundeffects_library import SoundeffectsLibrary 4 | 5 | 6 | class TestSoundeffectsLibrary: 7 | pass 8 | -------------------------------------------------------------------------------- /tests/chat_parsers/test_cube_casino_parser.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.chat_parsers.cube_casino_parser import CubeCasinoParser 4 | from chat_thief.models.user import User 5 | 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestCommandParser(DatabaseConfig): 10 | def test_parsing_multiple_targets(self): 11 | user = "eno" 12 | args = ["45", "clap", "damn"] 13 | subject = CubeCasinoParser(user, "bet", args) 14 | result = subject.parse() 15 | assert result.wager == ["clap", "damn"] 16 | assert result.bet == 45 17 | assert result.user == user 18 | -------------------------------------------------------------------------------- /tests/commands/test_command_sharer.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from chat_thief.commands.command_sharer import CommandSharer 3 | from chat_thief.models.user import User 4 | from chat_thief.models.command import Command 5 | from tests.support.database_setup import DatabaseConfig 6 | 7 | 8 | class TestCommandSharer(DatabaseConfig): 9 | def test_share(self): 10 | user = User("fake_user") 11 | user.update_cool_points(1) 12 | command = Command("damn") 13 | friend = User("bizmarkie") 14 | 15 | command.allow_user(user.name) 16 | assert user.name in command.users() 17 | assert friend.name not in command.users() 18 | 19 | subject = CommandSharer( 20 | user=user.name, command=command.name, friend=friend.name, 21 | ) 22 | 23 | subject.share() 24 | 25 | assert user.name in command.users() 26 | assert friend.name in command.users() 27 | assert user.cool_points() == 0 28 | assert command.cost() == 3 29 | 30 | def test_broke_boi_share(self): 31 | user = User("fake_user") 32 | command = Command("damn") 33 | friend = User("bizmarkie") 34 | 35 | command.allow_user(user.name) 36 | assert user.name in command.users() 37 | assert friend.name not in command.users() 38 | 39 | subject = CommandSharer( 40 | user=user.name, command=command.name, friend=friend.name, 41 | ) 42 | 43 | subject.share() 44 | 45 | assert user.name in command.users() 46 | assert friend.name not in command.users() 47 | assert command.cost() == 1 48 | 49 | def test_invalid_command(self): 50 | user = User("fake_user") 51 | friend = User("bizmarkie") 52 | 53 | result = CommandSharer( 54 | user=user.name, command="fake_command", friend=friend.name, 55 | ).share() 56 | assert result == "@fake_user cannot share !fake_command as it's invalid" 57 | -------------------------------------------------------------------------------- /tests/commands/test_donator.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.commands.donator import Donator 4 | 5 | from chat_thief.models.user import User 6 | from chat_thief.models.command import Command 7 | 8 | from tests.support.database_setup import DatabaseConfig 9 | 10 | 11 | class TestDonator(DatabaseConfig): 12 | def test_donate(self): 13 | user = User("uzi") 14 | Command("clap").allow_user(user.name) 15 | Command("damn").allow_user(user.name) 16 | assert "uzi" in Command("clap").users() 17 | assert "uzi" in Command("damn").users() 18 | assert "young.thug" not in Command("clap").users() 19 | assert "young.thug" not in Command("damn").users() 20 | result = Donator(user.name).donate("young.thug") 21 | assert "young.thug" in Command("clap").users() 22 | assert "young.thug" in Command("damn").users() 23 | assert "uzi" not in Command("clap").users() 24 | assert "uzi" not in Command("damn").users() 25 | assert result == "@young.thug was gifted !clap !damn" 26 | 27 | def test_you_cannot_donate_your_theme(self): 28 | user = User("uzi") 29 | Command("clap").allow_user(user.name) 30 | Command("uzi").allow_user(user.name) 31 | assert "uzi" in Command("clap").users() 32 | assert "uzi" in Command("uzi").users() 33 | assert "young.thug" not in Command("clap").users() 34 | assert "young.thug" not in Command("uzi").users() 35 | result = Donator(user.name).donate("young.thug") 36 | assert "young.thug" in Command("clap").users() 37 | assert "young.thug" not in Command("uzi ").users() 38 | assert "uzi" not in Command("clap").users() 39 | assert result == "@young.thug was gifted !clap" 40 | -------------------------------------------------------------------------------- /tests/commands/test_la_libre.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.chat_logs import ChatLogs 4 | from chat_thief.commands.la_libre import LaLibre, REVOLUTION_LIKELYHOOD 5 | from chat_thief.models.vote import Vote 6 | from chat_thief.models.command import Command 7 | from chat_thief.models.user import User 8 | from tests.support.database_setup import DatabaseConfig 9 | 10 | 11 | class TestLaLibre(DatabaseConfig): 12 | def test_inform(self): 13 | Vote("fake_user").vote("peace") 14 | result = LaLibre.inform() 15 | self.coup = Command("coup") 16 | User("fake_user").save() 17 | 18 | peasants = ChatLogs().recent_stream_peasants() 19 | threshold = 3 20 | 21 | assert result == [ 22 | "PowerUpL La Libre PowerUpR", 23 | "Total Votes: 1", 24 | f"Peace Count: 1 / {threshold}", 25 | f"Revolution Count: 0 / {threshold}", 26 | f"panicBasket Coup Cost: {self.coup.cost()} panicBasket", 27 | ] 28 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.fixture(autouse=True) 5 | def env_setup(monkeypatch): 6 | monkeypatch.setenv("TEST_MODE", "true") 7 | monkeypatch.setenv("BLOCK_TWITCH_MSGS", "true") 8 | -------------------------------------------------------------------------------- /tests/formatters/test_cube_casino_formatter.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.formatters.cube_casino_formatter import CubeCasinoFormatter 4 | 5 | from tests.support.database_setup import DatabaseConfig 6 | 7 | 8 | class TestCubeCasinoFormatter(DatabaseConfig): 9 | def test_a_solved_cube(self): 10 | winners = [ 11 | ("uzi", "ella", "hello"), 12 | ("uzi", "future", "damn"), 13 | ("eno", "ella", "8bitrickroll"), 14 | ] 15 | result = CubeCasinoFormatter(winners).format() 16 | assert result == [ 17 | "@uzi won !hello from @ella and !damn from @future", 18 | "@eno won !8bitrickroll from @ella", 19 | ] 20 | -------------------------------------------------------------------------------- /tests/formatters/test_purchase_formatting.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.formatters.purchase_formatter import PurchaseFormatter 4 | from chat_thief.new_commands.result import Result 5 | 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestPurchaseFormatter(DatabaseConfig): 10 | def test_format_successful_purchase(self): 11 | result = Result(user="uzi", command="handbag", metadata={}) 12 | assert PurchaseFormatter(result).format() 13 | -------------------------------------------------------------------------------- /tests/formatters/test_steal_formatter.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.formatters.steal_formatter import StealFormatter 4 | from chat_thief.new_commands.result import Result 5 | 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestStealFormatter(DatabaseConfig): 10 | def test_format_successful_steal(self): 11 | result = Result( 12 | user="uzi", 13 | command="steal", 14 | metadata={ 15 | "victim": "future", 16 | "target_sfx": "handbag", 17 | "stealing_result": "@uzi stole !handbag from @future", 18 | }, 19 | ) 20 | 21 | expected_message = "@uzi stole !handbag from @future" 22 | assert StealFormatter(result).format() == expected_message 23 | -------------------------------------------------------------------------------- /tests/models/test_base_db_model.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pathlib import Path 4 | 5 | from chat_thief.models.base_db_model import BaseDbModel 6 | 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | class FakeClass(BaseDbModel): 11 | pass 12 | 13 | 14 | class RealFakeClass(BaseDbModel): 15 | database_folder = "tests/" 16 | database_path = "db/fake_things.json" 17 | table_name = "fake_things" 18 | 19 | def doc(self): 20 | return {"name": "thugga"} 21 | 22 | 23 | MODEL_CLASSES = [RealFakeClass] 24 | 25 | 26 | class TestBaseDbModel(DatabaseConfig): 27 | @pytest.fixture(autouse=True) 28 | def destroy_db(self): 29 | for model in MODEL_CLASSES: 30 | db_path = Path(__file__).parent.parent.joinpath(model.database_path) 31 | if db_path.is_file(): 32 | db_path.unlink() 33 | yield 34 | 35 | def test_class_without_doc(self): 36 | with pytest.raises(TypeError) as err_info: 37 | subject = FakeClass() 38 | 39 | def test_working_class(self): 40 | assert RealFakeClass.count() == 0 41 | subject = RealFakeClass() 42 | assert not RealFakeClass.last() 43 | subject.save() 44 | assert RealFakeClass.count() == 1 45 | assert isinstance(RealFakeClass.all(), list) 46 | assert RealFakeClass.last() 47 | RealFakeClass.delete(1) 48 | assert RealFakeClass.count() == 0 49 | -------------------------------------------------------------------------------- /tests/models/test_bot_vote.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.bot_vote import BotVote 4 | from chat_thief.models.tribal_council import TribalCouncil 5 | from chat_thief.models.user import User 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestBotVote(DatabaseConfig): 10 | def test_bot_vote(self): 11 | BotVote.count() == 0 12 | uzi = User("uzi") 13 | bot = User("uzibot") 14 | BotVote(user=uzi.name, bot=bot.name).save() 15 | vote = BotVote.last() 16 | vote["bot"] == "uzibot" 17 | vote["user"] == "uzi" 18 | 19 | def test_create_or_update(self): 20 | assert BotVote.count() == 0 21 | result, update_type = BotVote("eno", "uzibot").create_or_update() 22 | assert BotVote.count() == 1 23 | assert update_type == "create" 24 | result, update_type = BotVote("eno", "otherbot").create_or_update() 25 | assert BotVote.count() == 1 26 | assert update_type == "update" 27 | 28 | def test_votes_by_bot(self): 29 | BotVote("eno", "uzibot").create_or_update() 30 | BotVote("future", "otherbot").create_or_update() 31 | BotVote("carti", "otherbot").create_or_update() 32 | result = BotVote.count_by_group("bot") 33 | assert result == [("otherbot", 2), ("uzibot", 1)] 34 | -------------------------------------------------------------------------------- /tests/models/test_css_vote.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pathlib import Path 3 | 4 | from chat_thief.models.css_vote import CSSVote 5 | from chat_thief.models.user import User 6 | from chat_thief.models.user import Command 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | class TestCSSVote(DatabaseConfig): 11 | def _create_user(self, name): 12 | user = User(name=name) 13 | user._find_or_create_user() 14 | return user 15 | 16 | def test_its_real(self): 17 | assert CSSVote.count() == 0 18 | voter = "uzi" 19 | candidate = "future" 20 | CSSVote(voter=voter, candidate=candidate).save() 21 | assert CSSVote.count() == 1 22 | 23 | def test_by_votes(self): 24 | CSSVote(voter="uzi", candidate="future").save() 25 | CSSVote(voter="kanye", candidate="drake").save() 26 | CSSVote(voter="carti", candidate="future").save() 27 | result = CSSVote.by_votes() 28 | assert result == [ 29 | ("future", 2), 30 | ("drake", 1), 31 | ] 32 | -------------------------------------------------------------------------------- /tests/models/test_cube_bet.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pathlib import Path 3 | 4 | from chat_thief.models.cube_bet import CubeBet 5 | 6 | from chat_thief.models.vote import Vote 7 | from chat_thief.models.user import User 8 | from chat_thief.models.user import Command 9 | from tests.support.database_setup import DatabaseConfig 10 | 11 | 12 | class TestCubeBet(DatabaseConfig): 13 | def _create_user(self, name): 14 | user = User(name=name) 15 | user._find_or_create_user() 16 | return user 17 | 18 | def test_betting(self): 19 | name = self._create_user("gucci.mane") 20 | duration = 29 21 | subject = CubeBet(name.name, duration) 22 | assert CubeBet.count() == 0 23 | subject.save() 24 | assert CubeBet.count() == 1 25 | 26 | subject = CubeBet(name.name, 38) 27 | subject.save() 28 | 29 | assert CubeBet.count() == 1 30 | assert subject.duration() == 38 31 | 32 | def test_all_bets(self): 33 | result = CubeBet.all_bets() 34 | assert result == [] 35 | CubeBet("carti", 32).save() 36 | result = CubeBet.all_bets() 37 | assert result == [("carti", 32, [])] 38 | CubeBet("uzi", 24).save() 39 | result = CubeBet.all_bets() 40 | assert result == [("uzi", 24, []), ("carti", 32, [])] 41 | 42 | def test_a_wager(self): 43 | result = CubeBet("carti", 32, ["clap"]).save() 44 | assert result.wager == ["clap"] 45 | -------------------------------------------------------------------------------- /tests/models/test_cube_stats.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | 5 | from chat_thief.models.user import User 6 | from chat_thief.models.cube_stats import CubeStats 7 | 8 | from tests.support.database_setup import DatabaseConfig 9 | 10 | 11 | class TestCubeStats(DatabaseConfig): 12 | def test_stats(self): 13 | winning_duration = 40 14 | winners = ["uzi"] 15 | all_bets = [("future", 21)] 16 | 17 | subject = CubeStats( 18 | winning_duration=winning_duration, winners=winners, all_bets=all_bets 19 | ) 20 | assert CubeStats.count() == 0 21 | subject.save() 22 | assert CubeStats.count() == 1 23 | -------------------------------------------------------------------------------- /tests/models/test_issue.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.issue import Issue 4 | 5 | from tests.support.database_setup import DatabaseConfig 6 | 7 | 8 | class TestIssue(DatabaseConfig): 9 | def test_new_issue(self): 10 | subject = Issue(user="beginbotsmonster", msg="!me doesn't work") 11 | assert Issue.count() == 0 12 | subject.save() 13 | assert Issue.count() == 1 14 | -------------------------------------------------------------------------------- /tests/models/test_notification.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.notification import Notification 4 | 5 | from tests.support.database_setup import DatabaseConfig 6 | 7 | 8 | class TestNotification(DatabaseConfig): 9 | def test_notification(self): 10 | assert Notification.count() == 0 11 | Notification("Cool Stuff").save() 12 | assert Notification.count() == 1 13 | 14 | notification = Notification.last() 15 | assert notification["duration"] == 1 16 | -------------------------------------------------------------------------------- /tests/models/test_play_soundeffect_request.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.notification import Notification 4 | from chat_thief.models.play_soundeffect_request import PlaySoundeffectRequest 5 | from chat_thief.prize_dropper import random_soundeffect 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestPlaySoundeffectRequest(DatabaseConfig): 10 | def test_lower_casing_command(self): 11 | user = "uzi" 12 | command = "WASSUP" 13 | subject = PlaySoundeffectRequest(user=user, command=command, notification=False) 14 | subject.save() 15 | assert subject.command == "wassup" 16 | -------------------------------------------------------------------------------- /tests/models/test_rap_sheet.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.rap_sheet import RapSheet 4 | 5 | from tests.support.database_setup import DatabaseConfig 6 | 7 | 8 | class TestRapSheet(DatabaseConfig): 9 | def test_new_rap_sheet(self): 10 | subject = RapSheet( 11 | user="beginbotsmonster", 12 | action="caught_stealing", 13 | metadata={"target_sfx": "handbag", "victim": "uzi"}, 14 | ) 15 | assert RapSheet.count() == 0 16 | subject.save() 17 | assert RapSheet.count() == 1 18 | -------------------------------------------------------------------------------- /tests/models/test_sfx_vote.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | 5 | from chat_thief.models.sfx_vote import SFXVote 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestSFXVote(DatabaseConfig): 10 | def test_sfx_vote(self): 11 | SFXVote.count() == 0 12 | 13 | def test_create_sfx_vote(self): 14 | subject = SFXVote(command="clap") 15 | subject.support("thugga") 16 | SFXVote.count() == 1 17 | assert subject.supporter_count() == 1 18 | assert subject.detractor_count() == 0 19 | assert subject.is_enabled() 20 | subject.detract("bill") 21 | subject.detract("dennis") 22 | assert subject.detractor_count() == 2 23 | SFXVote.count() == 3 24 | assert not subject.is_enabled() 25 | -------------------------------------------------------------------------------- /tests/models/test_the_fed.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.the_fed import TheFed 4 | from chat_thief.models.command import Command 5 | 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestTheFed(DatabaseConfig): 10 | def test_taxes(self): 11 | result = TheFed.reserve() 12 | assert result == 0 13 | 14 | command = Command("handbag") 15 | command.save() 16 | command.set_value("cost", 2) 17 | 18 | the_fed = TheFed 19 | the_fed.collect_taxes() 20 | 21 | result = TheFed.reserve() 22 | assert result == 1 23 | assert command.cost() == 1 24 | -------------------------------------------------------------------------------- /tests/models/test_tribal_council.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.bot_vote import BotVote 4 | from chat_thief.models.tribal_council import TribalCouncil 5 | from chat_thief.models.user import User 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestTribalCouncil(DatabaseConfig): 10 | def test_bot_vote(self): 11 | TribalCouncil.count() == 0 12 | uzi = User("uzi") 13 | bot = User("uzibot") 14 | BotVote(user=uzi.name, bot=bot.name).save() 15 | assert BotVote.count() == 1 16 | vote = BotVote.last() 17 | vote["bot"] == "uzibot" 18 | vote["user"] == "uzi" 19 | 20 | TribalCouncil.go_to_tribal() 21 | 22 | assert TribalCouncil.count() == 1 23 | vote = TribalCouncil.last() 24 | assert vote == {"council_number": 1, "votes": {"uzibot": ["uzi"]}} 25 | 26 | BotVote(user=uzi.name, bot="pattymartinobot").save() 27 | TribalCouncil.go_to_tribal() 28 | assert TribalCouncil.count() == 2 29 | vote = TribalCouncil.last() 30 | assert vote == {"council_number": 2, "votes": {"pattymartinobot": ["uzi"]}} 31 | -------------------------------------------------------------------------------- /tests/models/test_user_event.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # from chat_thief.models.command import Command 4 | # from chat_thief.models.user import User 5 | from chat_thief.models.user_event import UserEvent 6 | 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | # Information Commands 11 | # Examples: 12 | # - !me 13 | # - !perms 14 | # 15 | # Economy Commands 16 | # Examples: 17 | # - !buy 18 | # - !steal 19 | # 20 | # Philanthropic Commands 21 | # - !donate 22 | # - !give 23 | # 24 | # Market Manipulators 25 | 26 | 27 | class TestUserEvent(DatabaseConfig): 28 | def test_count(self): 29 | assert UserEvent.count() == 0 30 | 31 | subject = UserEvent( 32 | user="beginbot", command="me", msg="!me", result="Cool Result" 33 | ) 34 | subject.save() 35 | assert UserEvent.count() == 1 36 | user_event = UserEvent.last() 37 | assert user_event["user"] == "beginbot" 38 | assert user_event["command"] == "me" 39 | assert "created_at" in user_event 40 | 41 | def test_buy(self): 42 | pass 43 | -------------------------------------------------------------------------------- /tests/models/test_user_page.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from pathlib import Path 3 | 4 | from chat_thief.models.user_page import UserPage 5 | from chat_thief.models.user import User 6 | from chat_thief.models.user import Command 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | class TestUserPage(DatabaseConfig): 11 | def test_its_real(self): 12 | assert UserPage.count() == 0 13 | 14 | UserPage.bootstrap_user_page(user="eno", widgets=["bubbles"]) 15 | 16 | result = UserPage.last() 17 | assert result["widgets"] == {"bubbles": True} 18 | 19 | def test_deactivating(self): 20 | UserPage.bootstrap_user_page(user="eno", widgets=["bubbles"]) 21 | result = UserPage.deactivate("eno", "bubbles") 22 | user_page = UserPage.last() 23 | assert user_page["widgets"] == {"bubbles": False} 24 | 25 | def test_for_user(self): 26 | UserPage.bootstrap_user_page(user="eno", widgets=["bubbles"]) 27 | user_page = UserPage.for_user("eno") 28 | assert user_page["widgets"] == {"bubbles": True} 29 | -------------------------------------------------------------------------------- /tests/new_commands/test_pokemon_casino.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pathlib import Path 4 | 5 | from chat_thief.new_commands.pokemon_casino import PokemonCasino 6 | from tests.support.database_setup import DatabaseConfig 7 | from chat_thief.new_commands.pokemon_casino import PokemonCasino 8 | 9 | 10 | class TestPokemonCasino(DatabaseConfig): 11 | @pytest.fixture(autouse=True) 12 | def clean_guess(self): 13 | PokemonCasino.MYSTERY_POKEMON_PATH = Path(__file__).parent.parent.joinpath( 14 | "tmp/pokeguess" 15 | ) 16 | if PokemonCasino.MYSTERY_POKEMON_PATH.exists(): 17 | PokemonCasino.MYSTERY_POKEMON_PATH.unlink() 18 | 19 | PokemonCasino.GUESSES_PATH = Path(__file__).parent.parent.joinpath( 20 | "tmp/guesses" 21 | ) 22 | if PokemonCasino.GUESSES_PATH.exists(): 23 | PokemonCasino.GUESSES_PATH.unlink() 24 | 25 | def test_starting_a_challenge(self): 26 | result = PokemonCasino.whos_that_pokemon() 27 | assert result == "Guess Which Pokemon This Is!!!" 28 | pokemon = PokemonCasino.MYSTERY_POKEMON_PATH.read_text() 29 | assert pokemon is not None 30 | result = PokemonCasino.guess_pokemon("ash", "psyduck") 31 | "@ash YOU WERE WRONG" 32 | assert PokemonCasino.guesses() == 1 33 | -------------------------------------------------------------------------------- /tests/routers/test_beginworld_help_router.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.routers.beginworld_help_router import BeginworldHelpRouter 4 | 5 | 6 | class TestBeginworldHelpRouter: 7 | def test_help_with_no_commands(self): 8 | result = BeginworldHelpRouter("beginbotbot", "help").route() 9 | assert "Call !help with a specific command for more details:" in result 10 | -------------------------------------------------------------------------------- /tests/routers/test_bot_survivor_router.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.models.bot_vote import BotVote 4 | from chat_thief.models.user import User 5 | from chat_thief.routers.bot_survivor_router import BotSurvivorRouter 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestBotSurviorRouter(DatabaseConfig): 10 | def test_voting_for_a_bot(self): 11 | User("uzibot", 1) 12 | result = User.register_bot("uzibot", "don.cannon") 13 | result = BotSurvivorRouter("beginbotbot", "hatebot", ["uzibot"]).route() 14 | 15 | assert BotVote.count() == 1 16 | assert result == "Thank you for your vote @beginbotbot" 17 | 18 | def test_try_to_vote_for_non_bot(self): 19 | User("uzibot_notbot").save() 20 | result = BotSurvivorRouter("beginbotbot", "hatebot", ["uzibot_notbot"]).route() 21 | assert BotVote.count() == 0 22 | assert result == "@beginbotbot @uzibot_notbot is NOT A BOT!" 23 | 24 | def test_changing_your_vote(self): 25 | User.register_bot("uzibot", "don.cannon") 26 | User.register_bot("enobot", "eno") 27 | 28 | result = BotSurvivorRouter("beginbotbot", "hatebot", ["uzibot"]).route() 29 | assert BotVote.count() == 1 30 | assert result == "Thank you for your vote @beginbotbot" 31 | 32 | result = BotSurvivorRouter("beginbotbot", "hatebot", ["enobot"]).route() 33 | assert BotVote.count() == 1 34 | assert result == "Thank you for your vote @beginbotbot" 35 | 36 | def test_tribal_council(self): 37 | User.register_bot("uzibot", "don.cannon") 38 | User.register_bot("enobot", "eno") 39 | 40 | BotVote("beginbotbot", "uzibot").save() 41 | BotVote("future", "uzibot").save() 42 | BotVote("carti", "enobot").save() 43 | assert BotVote.count() == 3 44 | 45 | result = BotSurvivorRouter("beginbotbot", "tribal_council", []).route() 46 | assert result == "@uzibot has been kicked out of BeginWorld" 47 | -------------------------------------------------------------------------------- /tests/routers/test_revolution_router.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.routers.revolution_router import RevolutionRouter 4 | from chat_thief.welcome_committee import WelcomeCommittee 5 | from chat_thief.models.vote import Vote 6 | from tests.support.database_setup import DatabaseConfig 7 | 8 | 9 | class TestRevolutionRouter(DatabaseConfig): 10 | @pytest.fixture(autouse=True) 11 | def mock_present_users(self, monkeypatch): 12 | def _mock_present_users(self): 13 | return ["future", "uzi"] 14 | 15 | monkeypatch.setattr(WelcomeCommittee, "present_users", _mock_present_users) 16 | 17 | # Should we move our "acceptance" test here 18 | def test_coup(self): 19 | result = RevolutionRouter("beginbotbot", "coup", []).route() 20 | assert ( 21 | result 22 | == "The Will of the People have not chosen: 3 votes must be cast for either Peace or Revolution" 23 | ) 24 | 25 | def test_vote(self): 26 | assert Vote.count() == 0 27 | result = RevolutionRouter("beginbotbot", "vote", ["peace"]).route() 28 | assert Vote.count() == 1 29 | -------------------------------------------------------------------------------- /tests/routers/test_voting_booth_router.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.routers.voting_booth_router import VotingBoothRouter 4 | from chat_thief.models.user import User 5 | from chat_thief.models.css_vote import CSSVote 6 | 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | class FakeParser: 11 | def __init__(self, target_user="coltrane"): 12 | self.target_user = target_user 13 | 14 | 15 | class TestVotingBoothRouter(DatabaseConfig): 16 | def test_best_css(self): 17 | User("uzi").save() 18 | result = VotingBoothRouter("future", "bestcss", ["uzi"]).route() 19 | assert CSSVote.count() == 1 20 | 21 | def test_homepage(self): 22 | User("uzi").save() 23 | CSSVote(voter="don.cannon", candidate="rich.the.kid",).save() 24 | CSSVote(voter="uzi", candidate="future",).save() 25 | CSSVote(voter="carti", candidate="future",).save() 26 | result = VotingBoothRouter("future", "homepage", []).route() 27 | assert result == "@future: 2 | @rich.the.kid: 1" 28 | -------------------------------------------------------------------------------- /tests/support/utils.py: -------------------------------------------------------------------------------- 1 | from logging import FileHandler 2 | from pathlib import Path 3 | import logging 4 | import sys 5 | 6 | 7 | def setup_logger(): 8 | logger = logging.getLogger("Test Logs") 9 | logs_path = Path(__file__).parent.parent.parent.joinpath("tmp") 10 | logs_path.mkdir(exist_ok=True) 11 | logger.addHandler(FileHandler(logs_path.joinpath("chat.log"))) 12 | logger.addHandler(logging.StreamHandler(sys.stdout)) 13 | return logger 14 | -------------------------------------------------------------------------------- /tests/test_begin_fund.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.begin_fund import BeginFund 4 | from chat_thief.models.the_fed import TheFed 5 | from chat_thief.models.command import Command 6 | 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | class TestBeginFund(DatabaseConfig): 11 | def test_dropeffect(self): 12 | result = BeginFund().dropeffect() 13 | assert result == "The Fed is Broke" 14 | 15 | Command("damn", 2).save() 16 | Command("handbag", 10).save() 17 | TheFed.collect_taxes() 18 | assert TheFed.reserve() == 6 19 | 20 | result = BeginFund().dropeffect() 21 | assert "now has access" in result 22 | 23 | def test_dropping_specific_effects(self): 24 | Command("handbag", 10).save() 25 | TheFed.collect_taxes() 26 | assert TheFed.reserve() == 5 27 | result = BeginFund(target_user="uzi", target_command="damn").dropeffect() 28 | assert result == "@uzi now has access to !damn" 29 | assert TheFed.reserve() == 4 30 | 31 | result = BeginFund(target_command="damn", amount=2).dropeffect() 32 | assert "now has access to !damn" in result 33 | assert TheFed.reserve() == 2 34 | -------------------------------------------------------------------------------- /tests/test_breaking_news.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | # from breaking_news_bot_2 import BreakingNewsBot 4 | # from chat_thief.bots.breaking_news_bot import BreakingNewsBot 5 | 6 | from chat_thief.models.command import Command 7 | from chat_thief.models.user import User 8 | from chat_thief.models.breaking_news import BreakingNews 9 | 10 | from tests.support.database_setup import DatabaseConfig 11 | 12 | 13 | @pytest.mark.skip 14 | class TestBreakingNewsBot(DatabaseConfig): 15 | def test_breaking_news_initialization(self): 16 | user = User("bill.evans") 17 | user.save() 18 | command = Command("damn") 19 | command.save() 20 | command.increase_cost(10) 21 | other_cmd = Command("win") 22 | other_cmd.save() 23 | subject = BreakingNewsBot() 24 | assert subject.in_coup == False 25 | assert subject.last_breaking_time == None 26 | assert subject.initial_most_expensive["name"] == "damn" 27 | assert subject.initial_richest_user["name"] == "bill.evans" 28 | 29 | def test_breaking_news(self): 30 | user = User("bill.evans") 31 | user.save() 32 | command = Command("damn") 33 | command.save() 34 | command.increase_cost(10) 35 | other_cmd = Command("win") 36 | other_cmd.save() 37 | subject = BreakingNewsBot() 38 | # how do we assert a method is called 39 | # assert subject.most_expensive_command == "Cool" 40 | # assert not subject.check_for_breaking_news() 41 | # BreakingNews("EVERYTHING IS BROKEN!").save() 42 | # assert subject.check_for_breaking_news() 43 | -------------------------------------------------------------------------------- /tests/test_chat_logs.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.chat_logs import ChatLogs 4 | 5 | 6 | def parse_raw_irc(raw_msg): 7 | BEGINBOTBOT = ":beginbotbot!beginbotbot@beginbotbot.tmi.twitch.tv" 8 | return raw_msg.split(BEGINBOTBOT)[0].strip() 9 | 10 | 11 | # :beginbotbot!beginbotbot@beginbotbot.tmi.twitch.tv 12 | # :beginbotbot!beginbotbot@beginbotbot.tmi.twitch.tv 13 | # :beginbotbot!beginbotbot@beginbotbot.tmi.twitch.tv PRIVMSG #beginbot :!wildcard 14 | def test_parse_raw_irc(): 15 | irc_msg = "whatsinmyopsec: so i can be a web dever :beginbotbot!beginbotbot@beginbotbot.tmi.twitch.tv PRIVMSG #beginbot :@lunchboxsushi now has access to !myspacepage :beginbotbot!beginbotbot@beginbotbot.tmi.twitch.tv PRIVMSG #beginbot :Welcome @lunchboxsushi! You need a Theme song (max 5 secs): !soundeffect YOUTUBE-URL @lunchboxsushi 00:03 00:07" 16 | result = parse_raw_irc(irc_msg) 17 | assert result == "whatsinmyopsec: so i can be a web dever" 18 | 19 | irc_msg = "whatsinmyopsec: so i can be a web dever" 20 | result = parse_raw_irc(irc_msg) 21 | assert result == "whatsinmyopsec: so i can be a web dever" 22 | 23 | 24 | # This need to target other logs 25 | @pytest.mark.skip 26 | class TestChatLogs: 27 | def test_users(self): 28 | users = ChatLogs().users() 29 | assert len(users) > 10 30 | 31 | def test_most_msgs(self): 32 | msg_counts = ChatLogs().most_msgs() 33 | assert len(msg_counts) > 10 34 | 35 | def test_recent_stream_peasants(self): 36 | msg_counts = ChatLogs().recent_stream_peasants() 37 | assert msg_counts 38 | -------------------------------------------------------------------------------- /tests/test_data_scrubber.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.data_scrubber import DataScrubber 4 | from chat_thief.models.command import Command 5 | from chat_thief.models.user import User 6 | 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | 10 | class TestDataScrubber(DatabaseConfig): 11 | def test_purge_theme_songs(self): 12 | uzi = User("uzi") 13 | illegal_cmd = Command("beginbot") 14 | illegal_cmd.save() 15 | illegal_cmd.allow_user("uzi") 16 | Command("damn").save() 17 | assert Command.count() == 2 18 | DataScrubber.purge_theme_songs() 19 | assert Command.count() == 1 20 | assert uzi.commands() == [] 21 | 22 | def test_purge_duplicate_commands(self): 23 | uzi = User("uzi") 24 | illegal_cmd = Command("clap") 25 | illegal_cmd.permitted_users = ["uzi", "uzi"] 26 | illegal_cmd.save() 27 | 28 | illegal_cmd = Command("clap") 29 | illegal_cmd.permitted_users = ["uzi", "uzi"] 30 | illegal_cmd.save() 31 | assert Command.count() == 2 32 | 33 | DataScrubber.purge_duplicates() 34 | assert Command.count() == 1 35 | assert uzi.commands() == ["clap"] 36 | 37 | def test_purge_duplicate_users(self): 38 | uzi = User("uzi").save() 39 | uzi = User("uzi").save() 40 | -------------------------------------------------------------------------------- /tests/test_permissions_fetcher.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | 5 | from chat_thief.config.stream_lords import STREAM_LORDS 6 | from chat_thief.permissions_fetcher import PermissionsFetcher 7 | from chat_thief.models.command import Command 8 | from tests.support.database_setup import DatabaseConfig 9 | 10 | 11 | class TestPermissionsFetcher(DatabaseConfig): 12 | def test_checking_user_permissions(self): 13 | user = "new_fakeuser" 14 | command = "wow" 15 | # This will work once we have DB setup working correctly 16 | # Command(command).allow_user(user) 17 | # allowed_commands = subject.fetch_user_permissions() 18 | # assert allowed_commands == [command] 19 | -------------------------------------------------------------------------------- /tests/test_stats_department.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from chat_thief.stats_department import StatsDepartment 4 | from tests.support.database_setup import DatabaseConfig 5 | from chat_thief.models.command import Command 6 | from chat_thief.models.user import User 7 | 8 | # - Total Unrealized wealth of sound effects 9 | # - Total User Wealth 10 | 11 | 12 | class TestStatsDepartment(DatabaseConfig): 13 | def test_stats(self): 14 | subject = StatsDepartment() 15 | stats = subject.stats() 16 | keys = stats.keys() 17 | 18 | assert stats["total_street_cred"] == 0 19 | assert stats["total_cool_points"] == 0 20 | assert stats["fed_reserve"] == 0 21 | assert stats["total_user_sfx_property"] == 0 22 | 23 | command = Command("damn") 24 | command.save() 25 | user = User("clams") 26 | command.allow_user("clams") 27 | user.set_value("street_cred", 50) 28 | user.set_value("cool_points", 10) 29 | 30 | stats = subject.stats() 31 | assert stats["total_street_cred"] == 50 32 | assert stats["total_cool_points"] == 10 33 | assert stats["fed_reserve"] == 0 34 | assert stats["total_user_sfx_property"] == 1 35 | -------------------------------------------------------------------------------- /tests/test_welcome_committee.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | 5 | from chat_thief.welcome_committee import WelcomeCommittee 6 | 7 | from tests.support.database_setup import DatabaseConfig 8 | 9 | welcome_file = Path(__file__).parent.joinpath("db/.welcome") 10 | 11 | 12 | class TestWelcomeCommittee(DatabaseConfig): 13 | @pytest.fixture(autouse=True) 14 | def __setup_welcome__(self): 15 | if welcome_file.is_file(): 16 | welcome_file.unlink() 17 | 18 | @pytest.fixture 19 | def welcome_committee(self): 20 | def _subject(): 21 | return WelcomeCommittee(welcome_file=welcome_file) 22 | 23 | return _subject 24 | 25 | def test_fetch_present_users(self, welcome_committee): 26 | subject = welcome_committee() 27 | with open(welcome_file, "w") as wf: 28 | wf.write("thugga") 29 | 30 | result = subject.present_users() 31 | assert "thugga" in result 32 | 33 | def test_welcome_new_user(self, welcome_committee): 34 | subject = welcome_committee() 35 | result = subject.present_users() 36 | assert "birdman" not in result 37 | subject.welcome_new_users("birdman") 38 | result = subject.present_users() 39 | assert "birdman" in result 40 | subject.welcome_new_users("birdman") 41 | new_result = subject.present_users() 42 | assert result == new_result 43 | --------------------------------------------------------------------------------