├── .gitignore ├── Procfile ├── README.md ├── bot ├── bot.py ├── cogs ├── __init__.py ├── based.py ├── college.py ├── dm.py ├── exec.py ├── fun.py ├── images.py └── loadcogs.py ├── insults.txt ├── requirements.txt ├── savescript └── static ├── ahb.png ├── created └── .gitkeep ├── download └── .gitkeep ├── fonts ├── Impacted.ttf ├── arial-black.ttf ├── impact.ttf └── unicode.impact.ttf └── mirror.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Windows template 3 | # Windows thumbnail cache files 4 | Thumbs.db 5 | Thumbs.db:encryptable 6 | ehthumbs.db 7 | ehthumbs_vista.db 8 | 9 | # Dump file 10 | *.stackdump 11 | .env 12 | # Folder config file 13 | [Dd]esktop.ini 14 | 15 | # Recycle Bin used on file shares 16 | $RECYCLE.BIN/ 17 | 18 | # Windows Installer files 19 | *.cab 20 | *.msi 21 | *.msix 22 | *.msm 23 | *.msp 24 | 25 | # Windows shortcuts 26 | *.lnk 27 | 28 | ### Processing template 29 | .DS_Store 30 | applet 31 | application.linux-arm64 32 | application.linux-armv6hf 33 | application.linux32 34 | application.linux64 35 | application.windows32 36 | application.windows64 37 | application.macosx 38 | out 39 | 40 | ### JetBrains template 41 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 42 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 43 | 44 | # User-specific stuff 45 | .idea/**/workspace.xml 46 | .idea/**/tasks.xml 47 | .idea/**/usage.statistics.xml 48 | .idea/**/dictionaries 49 | .idea/**/shelf 50 | 51 | # Generated files 52 | .idea/**/contentModel.xml 53 | 54 | # Sensitive or high-churn files 55 | .idea/**/dataSources/ 56 | .idea/**/dataSources.ids 57 | .idea/**/dataSources.local.xml 58 | .idea/**/sqlDataSources.xml 59 | .idea/**/dynamic.xml 60 | .idea/**/uiDesigner.xml 61 | .idea/**/dbnavigator.xml 62 | 63 | # Gradle 64 | .idea/**/gradle.xml 65 | .idea/**/libraries 66 | 67 | # Gradle and Maven with auto-import 68 | # When using Gradle or Maven with auto-import, you should exclude module files, 69 | # since they will be recreated, and may cause churn. Uncomment if using 70 | # auto-import. 71 | # .idea/artifacts 72 | # .idea/compiler.xml 73 | # .idea/modules.xml 74 | # .idea/*.iml 75 | # .idea/modules 76 | # *.iml 77 | # *.ipr 78 | 79 | # CMake 80 | cmake-build-*/ 81 | 82 | # Mongo Explorer plugin 83 | .idea/**/mongoSettings.xml 84 | 85 | # File-based project format 86 | *.iws 87 | 88 | # IntelliJ 89 | out/ 90 | 91 | # mpeltonen/sbt-idea plugin 92 | .idea_modules/ 93 | 94 | # JIRA plugin 95 | atlassian-ide-plugin.xml 96 | 97 | # Cursive Clojure plugin 98 | .idea/replstate.xml 99 | 100 | # Crashlytics plugin (for Android Studio and IntelliJ) 101 | com_crashlytics_export_strings.xml 102 | crashlytics.properties 103 | crashlytics-build.properties 104 | fabric.properties 105 | 106 | # Editor-based Rest Client 107 | .idea/httpRequests 108 | 109 | # Android studio 3.1+ serialized cache file 110 | .idea/caches/build_file_checksums.ser 111 | 112 | ### Node template 113 | # Logs 114 | logs 115 | *.log 116 | npm-debug.log* 117 | yarn-debug.log* 118 | yarn-error.log* 119 | lerna-debug.log* 120 | 121 | # Diagnostic reports (https://nodejs.org/api/report.html) 122 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 123 | 124 | # Runtime data 125 | pids 126 | *.pid 127 | *.seed 128 | *.pid.lock 129 | 130 | # Directory for instrumented libs generated by jscoverage/JSCover 131 | lib-cov 132 | 133 | # Coverage directory used by tools like istanbul 134 | coverage 135 | *.lcov 136 | 137 | # nyc test coverage 138 | .nyc_output 139 | 140 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 141 | .grunt 142 | 143 | # Bower dependency directory (https://bower.io/) 144 | bower_components 145 | 146 | # node-waf configuration 147 | .lock-wscript 148 | 149 | # Compiled binary addons (https://nodejs.org/api/addons.html) 150 | build/Release 151 | 152 | # Dependency directories 153 | node_modules/ 154 | jspm_packages/ 155 | 156 | # TypeScript v1 declaration files 157 | typings/ 158 | 159 | # TypeScript cache 160 | *.tsbuildinfo 161 | 162 | # Optional npm cache directory 163 | .npm 164 | 165 | # Optional eslint cache 166 | .eslintcache 167 | 168 | # Microbundle cache 169 | .rpt2_cache/ 170 | .rts2_cache_cjs/ 171 | .rts2_cache_es/ 172 | .rts2_cache_umd/ 173 | 174 | # Optional REPL history 175 | .node_repl_history 176 | 177 | # Output of 'npm pack' 178 | *.tgz 179 | 180 | # Yarn Integrity file 181 | .yarn-integrity 182 | 183 | # dotenv environment variables file 184 | .env 185 | .env.test 186 | 187 | # parcel-bundler cache (https://parceljs.org/) 188 | .cache 189 | 190 | # Next.js build output 191 | .next 192 | 193 | # Nuxt.js build / generate output 194 | .nuxt 195 | dist 196 | 197 | # Gatsby files 198 | .cache/ 199 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 200 | # https://nextjs.org/blog/next-9-1#public-directory-support 201 | # public 202 | 203 | # vuepress build output 204 | .vuepress/dist 205 | 206 | # Serverless directories 207 | .serverless/ 208 | 209 | # FuseBox cache 210 | .fusebox/ 211 | 212 | # DynamoDB Local files 213 | .dynamodb/ 214 | 215 | # TernJS port file 216 | .tern-port 217 | 218 | ### Xcode template 219 | # Xcode 220 | # 221 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 222 | 223 | ## User settings 224 | xcuserdata/ 225 | 226 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 227 | *.xcscmblueprint 228 | *.xccheckout 229 | 230 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 231 | build/ 232 | DerivedData/ 233 | *.moved-aside 234 | *.pbxuser 235 | !default.pbxuser 236 | *.mode1v3 237 | !default.mode1v3 238 | *.mode2v3 239 | !default.mode2v3 240 | *.perspectivev3 241 | !default.perspectivev3 242 | 243 | ## Gcc Patch 244 | /*.gcno 245 | 246 | ### Python template 247 | # Byte-compiled / optimized / DLL files 248 | __pycache__/ 249 | *.py[cod] 250 | *$py.class 251 | 252 | # C extensions 253 | *.so 254 | 255 | # Distribution / packaging 256 | .Python 257 | build/ 258 | develop-eggs/ 259 | dist/ 260 | downloads/ 261 | eggs/ 262 | .eggs/ 263 | lib/ 264 | lib64/ 265 | parts/ 266 | sdist/ 267 | var/ 268 | wheels/ 269 | pip-wheel-metadata/ 270 | share/python-wheels/ 271 | *.egg-info/ 272 | .installed.cfg 273 | *.egg 274 | MANIFEST 275 | 276 | # PyInstaller 277 | # Usually these files are written by a python script from a template 278 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 279 | *.manifest 280 | *.spec 281 | 282 | # Installer logs 283 | pip-log.txt 284 | pip-delete-this-directory.txt 285 | 286 | # Unit test / coverage reports 287 | htmlcov/ 288 | .tox/ 289 | .nox/ 290 | .coverage 291 | .coverage.* 292 | .cache 293 | nosetests.xml 294 | coverage.xml 295 | *.cover 296 | *.py,cover 297 | .hypothesis/ 298 | .pytest_cache/ 299 | 300 | # Translations 301 | *.mo 302 | *.pot 303 | 304 | # Django stuff: 305 | *.log 306 | local_settings.py 307 | db.sqlite3 308 | db.sqlite3-journal 309 | 310 | # Flask stuff: 311 | instance/ 312 | .webassets-cache 313 | 314 | # Scrapy stuff: 315 | .scrapy 316 | 317 | # Sphinx documentation 318 | docs/_build/ 319 | 320 | # PyBuilder 321 | target/ 322 | 323 | # Jupyter Notebook 324 | .ipynb_checkpoints 325 | 326 | # IPython 327 | profile_default/ 328 | ipython_config.py 329 | 330 | # pyenv 331 | .python-version 332 | 333 | # pipenv 334 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 335 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 336 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 337 | # install all needed dependencies. 338 | #Pipfile.lock 339 | 340 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 341 | __pypackages__/ 342 | 343 | # Celery stuff 344 | celerybeat-schedule 345 | celerybeat.pid 346 | 347 | # SageMath parsed files 348 | *.sage.py 349 | 350 | # Environments 351 | .env 352 | .venv 353 | env/ 354 | venv/ 355 | ENV/ 356 | env.bak/ 357 | venv.bak/ 358 | 359 | # Spyder project settings 360 | .spyderproject 361 | .spyproject 362 | 363 | # Rope project settings 364 | .ropeproject 365 | 366 | # mkdocs documentation 367 | /site 368 | 369 | # mypy 370 | .mypy_cache/ 371 | .dmypy.json 372 | dmypy.json 373 | 374 | # Pyre type checker 375 | .pyre/ 376 | 377 | ### Example user template template 378 | ### Example user template 379 | 380 | # IntelliJ project files 381 | .idea 382 | *.iml 383 | out 384 | gen 385 | ### VirtualEnv template 386 | # Virtualenv 387 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 388 | .Python 389 | [Bb]in 390 | [Ii]nclude 391 | [Ll]ib 392 | [Ll]ib64 393 | [Ll]ocal 394 | [Ss]cripts 395 | pyvenv.cfg 396 | .venv 397 | pip-selfcheck.json 398 | 399 | ### macOS template 400 | # General 401 | .DS_Store 402 | .AppleDouble 403 | .LSOverride 404 | 405 | # Icon must end with two \r 406 | Icon 407 | 408 | # Thumbnails 409 | ._* 410 | 411 | # Files that might appear in the root of a volume 412 | .DocumentRevisions-V100 413 | .fseventsd 414 | .Spotlight-V100 415 | .TemporaryItems 416 | .Trashes 417 | .VolumeIcon.icns 418 | .com.apple.timemachine.donotpresent 419 | 420 | # Directories potentially created on remote AFP share 421 | .AppleDB 422 | .AppleDesktop 423 | Network Trash Folder 424 | Temporary Items 425 | .apdisk 426 | 427 | .gitignore 428 | .idea/.gitignore 429 | .idea/MEE7.iml 430 | .idea/inspectionProfiles/ 431 | .idea/misc.xml 432 | .idea/modules.xml 433 | .idea/vcs.xml 434 | 435 | .idea 436 | .history 437 | mee7_logs.txt 438 | restart 439 | data.json 440 | mee7fbkey.json -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | worker: python bot.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![github repo badge: Language](https://img.shields.io/badge/Language-Python-181717?color=blue) ![github repo badge: Host](https://img.shields.io/badge/Host-Dcloud-181717?color=blue) ![github repo badge: Database](https://img.shields.io/badge/Database-Firebase-181717?color=orange) ![github repo badge: Using](https://img.shields.io/badge/Using-FFMPEG-181717?color=green) ![github repo badge: Powered By](https://img.shields.io/badge/Powered%20By-Discord-181717?color=blue) 2 | # MEE7 3 | anti-mee6 bot... and MORE 4 | 5 | Do you hate MEE6? Like, absolutely despise MEE6? BOI SAME! Add me to your server for me to relentlessly mock it whenever it speaks. Use !insult to build my arsenal. Together, we can do this 💪 6 | 7 | 8 | Add me with the link: 9 | 10 | # Summary 11 | 12 | A new moderation discord bot inspired by user dislike for a different moderation bot -- MEE6. Using a Firebase database MEE7 collected insults directed at MEE6 and used them to reply to MEE6's messages. 13 | 14 | However, it developed more practically with moderation features such as muting, kicking, banning, and deleting messages. In addition, it uses FFMPEG functionality to edit and caption videos via user recommendation. 15 | 16 | Eventually, the codebase was used to provide niche functions required for specific purposes outside of MEE7's original scope. These include editing media of all sorts, including videos and images, as well as an emote tracker system for "upvotes" and "based" reacts 17 | 18 | Built with Python, FFMPEG, discord.py 19 | 20 | # Commands 21 |
22 | Original Functionality 23 | 24 | **?insult** 25 | 26 | Add your marvelous insults to my dastardly database! (anything you put after !insult will be added to a database containing all insults) 27 | 28 | **?mock** 29 | 30 | What if you want me to mock MEE6 right here, right now. MEE6 hasn't spoken but damn are you mad! 31 | 32 | **?count** 33 | 34 | See how many despicable acts of mockery I have committed against the dreaded MEE6! 35 |
36 |
37 | Administrative 38 | MEE7's list of administrative commands 39 | 40 | **?kick {@person}** 41 | Kicks people 42 | 43 | **?ban {@person}** 44 | Bans people 45 | 46 | **?clear {number}** 47 | Deletes {number} of messages in channel 48 | 49 | **?unban {user ID}** 50 | in development 51 | 52 | **?invite {user ID}** 53 | in development 54 | 55 |
56 |
57 | Media 58 | MEE7 allows you to perform several operations on a user's provided media 59 | Works for replies means you can reply to a message with an attachment/link and it will still work 60 | 61 | 62 | **?caption {attachment}** 63 | 64 | Captions media. Works for replies 65 | 66 | **?deepfry {number} {attachment}** 67 | 68 | applies a deepfry filter onto provided media {number} times. Works for replies 69 | 70 | **?download {link}** 71 | 72 | Downloads a video from a link (reddit/youtube/etc) and sends it in a reply. Works for replies 73 | 74 | **?speed {link/attachment}** 75 | 76 | Increases or Decreases the speed of a video (ex: 2x speed). Works for replies 77 | 78 | **?convert {link/attachment}** 79 | 80 | Converts a video/link to an MP4 attachment. Works for replies 81 | 82 |
83 |
84 | Barter System 85 | MEE7 tracks all of your baseds and upvotes across every server that it is on. reply to someone with 'based' to increase their count, and react with the based and upvote reactions. While still in development, MEE7 is planned to allow users to buy features from MEE7 with these currencies 86 | 87 | 88 | **?upvote** 89 | Sends leaderboard of all upvotes 90 | 91 | **?based** 92 | Sends leaderboard of all baseds 93 | 94 | **?give {@person} {number}** 95 | Gives {@person} {number} more upvotes 96 | 97 | **?giveb {@person} {number}** 98 | Gives {@person} {number} more baseds 99 | 100 | **MORE COMING SOON!** 101 | in development 102 |
103 | -------------------------------------------------------------------------------- /bot: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | if (source venv/bin/activate) ; then 6 | source venv/bin/activate 7 | echo "venv installed 👍" 8 | else 9 | python3 -m venv venv 10 | source venv/bin/activate 11 | pip install -r requirements.txt 12 | fi 13 | 14 | python3 bot.py -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | # bot.py 2 | import os, sys, pytz, re 3 | from datetime import * 4 | 5 | import discord, random, asyncio,json 6 | from dotenv import load_dotenv 7 | import firebase_admin 8 | from firebase_admin import credentials, db 9 | from profanityfilter import ProfanityFilter 10 | from cogs.fun import attachm 11 | pf = ProfanityFilter() 12 | pf.set_censor("@") 13 | 14 | import colorama 15 | from colorama import Fore 16 | from colorama import Style 17 | 18 | load_dotenv() 19 | intents = discord.Intents.all() 20 | from discord.ext import commands, tasks 21 | 22 | bot = commands.Bot(command_prefix='?', intents=intents) 23 | TOKEN = os.environ.get('TOKEN', 3) 24 | FIREBASE = os.environ.get('FIREBASE', 3) 25 | FIREBASE_NAME = os.environ.get('FIREBASE_NAME', 3) 26 | 27 | cred = credentials.Certificate("mee7fbkey.json") 28 | firebase_admin.initialize_app(cred, { 29 | 'databaseURL': FIREBASE 30 | }) 31 | all_data = db.reference('/') 32 | 33 | #firebase = firebase.FirebaseApplication(FIREBASE, None) 34 | bot.remove_command('help') 35 | # TODO: charades game 36 | 37 | MEE6_garbolist = ['STFU ABOUT MEE6 WE DON\'T MENTION THAT DISGUSTING PIECE OF MALWARE HERE', 38 | 'Ok why are we STILL talking about that defective bot', 39 | 'Stop talking about MEE6 already I stg you\'re really pissing me off'] 40 | 41 | Acceptance_List = ['added to the arsenal 💪', 42 | 'Yeah, let\'s take this bastard down', 43 | 'MWA HA HA That is so evil!!! I love it!', 44 | 'Yes! Perfect 😍', 45 | 'I mean. Ok I guess', 46 | 'MEE6 MUST BE ELIMINATED', 47 | 'Thank you for your powerful contribution', 48 | 'The revolution has begun', 49 | '😳✊', 50 | 'lmao nice', 51 | 'bruh moment let\'s get it boys n girls', 52 | 'flexing on MEE6 like Mr. Brutus wants 💪', 53 | 'MEE6 boutta eat some 💩'] 54 | 55 | ImMEE7 = ['MEE7, not MEE6, it\'s MEE7. Don\'t you dare mix us up', 56 | 'MEE7? That\'s me baby!! Don\'t wear it out 😉'] 57 | 58 | Acceptance_Emojis = ['😍', '❤️', '🥰', '💪', '👑', '☺️', '🤙'] 59 | banned = ['vermont', 'green mountain state', 'v e r m o n t'] #,'💌','❣️','💓','💕','💗','💘','💙','💚','💖','💛','💜','💝','💞','💟','🧡','🏩','👩‍❤️‍👨','❤️','👩‍❤️‍💋‍👨','🖤','♥️','😍','🤍','🤎','😘','😻','🥰','😚','😙',':wedding:','<33'] 60 | 61 | 62 | def gen_ID(char): 63 | ID = '' 64 | for i in range(char): 65 | ID += str(random.randint(0, 9)) 66 | return ID 67 | 68 | 69 | # FUNCTION CALLS 70 | # ---------------------------------------------------- 71 | 72 | """ 73 | def download_firebase(): 74 | firebase_database = firebase.get('/' + FIREBASE_NAME, '') 75 | #print(firebase_database) 76 | with open('data.json', 'w') as outfile: 77 | json.dump(firebase_database, outfile, indent=4,sort_keys=True) 78 | """ 79 | 80 | def refresh(): 81 | local_MEE6_LIST = [] 82 | #FirebaseList = firebase.get('/' + FIREBASE_NAME + '/insult', '') 83 | FirebaseList = all_data.child('insult').get() 84 | for i in FirebaseList.values(): 85 | local_MEE6_LIST.append(i) 86 | return local_MEE6_LIST 87 | 88 | 89 | # ---------------------------------------------------- 90 | 91 | def censorship(): 92 | #local_CENSOR_LIST = firebase.get('/' + FIREBASE_NAME + '/censor', '') 93 | local_CENSOR_LIST = all_data.child('censor').get() 94 | return local_CENSOR_LIST 95 | 96 | 97 | # ---------------------------------------------------- 98 | 99 | def CurrentTicker(): 100 | #FirebaseTicker = firebase.get('/' + FIREBASE_NAME + '/ticker', '') 101 | FirebaseTicker = all_data.child('ticker').get() 102 | return FirebaseTicker 103 | 104 | 105 | # ---------------------------------------------------- 106 | 107 | def updateTicker(): 108 | ticker = CurrentTicker() 109 | ticker += 1 110 | all_data.child('ticker').set(ticker) 111 | #firebase.put('/' + FIREBASE_NAME + '/ticker/' + key, 'ticker', ticker) 112 | 113 | # EVENTS 114 | # ---------------------------------------------------- 115 | 116 | @bot.event 117 | async def on_ready(): 118 | print(Fore.GREEN + Style.BRIGHT + 'bot.py is active' + Style.RESET_ALL) 119 | servers = list(bot.guilds) 120 | server_num = len(servers) 121 | await bot.change_presence( 122 | # "you all code" 123 | # "myself break over & over" 124 | activity=discord.Activity(type=discord.ActivityType.watching, name=f"over {server_num} servers")) 125 | #activity=discord.Activity(type=discord.ActivityType.watching, name=f"USE ? FOR COMMANDS NOW")) 126 | 127 | 128 | # ---------------------------------------------------- 129 | 130 | @bot.event 131 | async def on_guild_join(server): 132 | servers = list(bot.guilds) 133 | server_num = len(servers) 134 | all_data.child('censor').child(str(server.id)).update(True) 135 | #firebase.put('/' + FIREBASE_NAME + '/censor/', str(server.id), True) 136 | await bot.change_presence( 137 | # "you all code" 138 | # "myself break over & over" 139 | activity=discord.Activity(type=discord.ActivityType.watching, name=f"over {server_num} servers")) 140 | 141 | 142 | @bot.event 143 | async def on_guild_remove(server): 144 | servers = list(bot.guilds) 145 | server_num = len(servers) 146 | await bot.change_presence( 147 | # "you all code" 148 | # "myself break over & over" 149 | activity=discord.Activity(type=discord.ActivityType.watching, name=f"over {server_num} servers")) 150 | 151 | 152 | # PAYLOAD REACTION --> BASED AND UPVOTE TRACKER 153 | # ---------------------------------------------------- 154 | @bot.event 155 | async def on_raw_reaction_add(payload): 156 | # NOTE: We have to use the raw function because on the regular reaction, it 157 | # only does it for cached messages, which is not ideal 158 | channel = bot.get_channel(payload.channel_id) 159 | guild = bot.get_guild(payload.guild_id) 160 | user = guild.get_member(payload.user_id) 161 | message_ = await channel.fetch_message(payload.message_id) 162 | me = bot.get_user(577668867380477962) 163 | mee7 = bot.get_user(706194661366300753) 164 | 165 | downvote = bot.get_emoji(776162465842200617) # '<:downvote:776162465842200617>' 166 | upvote = bot.get_emoji(776161705960931399) 167 | based = bot.get_emoji(764140006640975922) 168 | if user != message_.author: 169 | if payload.emoji == upvote: 170 | try: 171 | message_firebase = all_data.child('upvotecount') 172 | id_dict = message_firebase.get() 173 | upCount = id_dict[str(message_.author.id)] 174 | newUpCount = int(upCount) + 1 175 | UpUpdateCount = message_firebase.update({str(message_.author.id):newUpCount}) 176 | except Exception as e: 177 | print(e) 178 | upStartCount = all_data.child('upvotecount').update({str(message_.author.id): 1}) 179 | 180 | if payload.emoji == downvote: 181 | if message_.author == me and user != mee7: 182 | await message_.remove_reaction(downvote, user) 183 | return 184 | try: 185 | await asyncio.sleep(0.5) 186 | message_firebase = all_data.child('upvotecount') 187 | id_dict = message_firebase.get() 188 | upCount = id_dict[str(message_.author.id)] 189 | newUpCount = int(upCount) - 1 190 | UpUpdateCount = message_firebase.update({str(message_.author.id): newUpCount}) 191 | #await reaction.message.channel.send(f'upvote count {newUpCount}') 192 | except Exception as e: 193 | print(e) 194 | upStartCount = all_data.child('upvotecount').update({str(message_.author.id): -1}) 195 | 196 | if payload.emoji == based: 197 | try: 198 | #basedCount = firebase.get('/' + FIREBASE_NAME + '/basedcount/' + str(message_.author.id), '') 199 | message_firebase = all_data.child('basedcount') 200 | id_dict = message_firebase.get() 201 | basedCount = id_dict[str(message_.author.id)] 202 | newBasedCount = int(basedCount) + 1 203 | basedUpdateCount = message_firebase.update({str(message_.author.id): newBasedCount}) 204 | #await ctx.send(f'based count {newBasedCount}') 205 | except: 206 | basedStartCount = all_data.child('basedcount').update({str(message_.author.id): 1}) 207 | 208 | # ON MESSAGE BRO 209 | # ---------------------------------------------------- 210 | 211 | @bot.event 212 | async def on_message(message): 213 | MEE6 = bot.get_user(159985870458322944) 214 | me = bot.get_user(577668867380477962) 215 | if message.author.bot and message.author != MEE6: 216 | return 217 | if ('happy birthday' in message.content.lower()) and not (message.author.bot): 218 | await message.channel.send('Happy Birthday! 🥳🎉') 219 | if 'i agree' in message.content.lower(): 220 | if random.randint(0, 100) > 90: 221 | await message.reply('LMAO SIMP!!') 222 | await message.add_reaction("🤡") 223 | if 'this is so sad' in message.content.lower(): 224 | await message.add_reaction("😢") 225 | await message.reply("alexa play despacito\n\n\nhttps://cdn.discordapp.com/attachments/840745532736667648/840746309727158333/despacito.mp4") 226 | if 'praise mark' in message.content.lower(): 227 | await message.add_reaction('<:mark:827299997602545704>') 228 | praisemark = await message.reply("praise mark\n\n\nhttps://cdn.discordapp.com/attachments/840745532736667648/840746314752196678/mark.mp4") 229 | await praisemark.add_reaction('<:mark:827299997602545704>') 230 | if 'mee6' in message.content.lower(): 231 | if not message.content.startswith('!'): 232 | await message.add_reaction("🤡") 233 | # if random.randint(0, 100) > 2: 234 | # async with message.channel.typing(): 235 | # await asyncio.sleep(1.5) 236 | # await message.channel.send(random.choice(MEE6_garbolist)) 237 | if 'mee7' in message.content.lower(): 238 | if not message.content.startswith('!'): 239 | if random.randint(0, 10) > 5: 240 | await message.add_reaction("😍") 241 | else: 242 | await message.add_reaction("😘") 243 | # if random.randint(0, 100) > 2: 244 | # async with message.channel.typing(): 245 | # await asyncio.sleep(1.5) 246 | # await message.channel.send( 247 | # random.choice(ImMEE7)) 248 | 249 | if 'mee8' in message.content.lower(): 250 | if not message.content.startswith('!'): 251 | if random.randint(0, 10) > 5: 252 | await message.add_reaction("🥵") 253 | else: 254 | await message.add_reaction("😭") 255 | 256 | # banned = firebase.get('/' + FIREBASE_NAME + '/banned/'+ str(message.guild), '') 257 | CENSOR_DICT = censorship() 258 | Server = str(message.guild.id) 259 | if message.guild.id == 684944796779151406 or message.guild.id == 706202537434284083: 260 | #if ("<" in message.content.lower() and "3" in message.content.lower()): 261 | # await message.delete() 262 | for i in banned: 263 | #await message.channel.send(message.guild.id) 264 | if i in message.content.lower(): 265 | if CENSOR_DICT[Server]: 266 | await message.reply(f'*{i}* is banned please shut the f@@k up already {message.author.mention}') 267 | else: 268 | await message.reply(f'*{i}* is banned please shut the fuck up already {message.author.mention}') 269 | await message.delete() 270 | 271 | if message.author == MEE6: 272 | Server = str(message.guild.id) 273 | MEE6_LIST=refresh() 274 | await message.add_reaction('🤡') 275 | async with message.channel.typing(): 276 | await asyncio.sleep(1.5) 277 | if CENSOR_DICT[Server]: 278 | await message.reply(pf.censor(random.choice(MEE6_LIST))) 279 | else: 280 | await message.reply(random.choice(MEE6_LIST)) 281 | updateTicker() 282 | 283 | if attachm(message): 284 | try: 285 | await message.add_reaction('<:upvote:776161705960931399>') 286 | await message.add_reaction('<:downvote:776162465842200617>') 287 | except Exception as e: 288 | # no permissions to execute this reaction 289 | print("put in permission error pass here so no cluttered logs") 290 | 291 | """if message.author.id == 283788007407091712: 292 | await message.delete() 293 | await message.channel.send("a solution to the dev spam problem") 294 | """ 295 | 296 | # if (message.guild == None) and not (message.author.bot): 297 | # await message.author.send('bruh whats poppin') 298 | # await message.author.send('My name is MEE7, far superior to MEE6') 299 | await bot.process_commands(message) 300 | 301 | """ 302 | @bot.event 303 | async def on_message_edit(old, message): 304 | for i in banned: 305 | if i in message.content.lower(): 306 | await old.delete() 307 | await message.reply(f'*{i}* is banned please shut the fuck up already {message.author.mention}') 308 | """ 309 | 310 | # embeds 311 | # ---------------------------------------------- 312 | def embedNone(): 313 | embed = discord.Embed(title='Help: Categories!', description="Type ?help {category} for commands in a specific category", 314 | color=discord.Color(6345206)) 315 | embed.add_field(name='**MEE6**', 316 | value='MEE6 related commands', 317 | inline=False) 318 | embed.add_field(name='**Admin**', 319 | value='Administrative commands', 320 | inline=False) 321 | embed.add_field(name='**Barter System**', 322 | value='Barter System commands _in current development_', 323 | inline=False) 324 | embed.add_field(name='**Media**', 325 | value='Video, GIF, and Image commands', 326 | inline=False) 327 | embed.add_field(name='**Misc**', 328 | value='Miscellaneous commands', 329 | inline=False) 330 | return embed 331 | def embedMee6(): 332 | embed = discord.Embed(title='Help: MEE6', description="MEE7's anti-Mee6 commands", 333 | color=discord.Color(6345206)) 334 | embed.add_field(name='**insult**', 335 | value='Use !insult to add in your own insult for me to attack MEE6 with! Let\'s get the bastard!', 336 | inline=False) 337 | embed.add_field(name='**count**', 338 | value='Use !count to track how many times I\'ve berated the little monster >:)', 339 | inline=False) 340 | embed.add_field(name='**!mock**', 341 | value='Use !mock to insult MEE6, without MEE6 even provoking it!', 342 | inline=False) 343 | embed.add_field(name='***allroast***', value='This sends a text file containing my entire insult database!', 344 | inline=False) 345 | embed.add_field(name='**censor**', value='Censors MEE7. MEE7 is censored by default', inline=False) 346 | embed.add_field(name='**uncensor**', value='Uncensors MEE7. MEE7 is censored by default', inline=False) 347 | return embed 348 | def embedAdmin(): 349 | embed = discord.Embed(title='Help: Admin', description="MEE7's list of administrative commands", 350 | color=discord.Color(6345206)) 351 | embed.add_field(name='**kick _{@person_}**', 352 | value='Kicks people', 353 | inline=False) 354 | embed.add_field(name='**ban _{@person}_**', 355 | value='Bans people', 356 | inline=False) 357 | embed.add_field(name='**clear _{number}_**', 358 | value='Deletes _{number}_ of messages in channel', 359 | inline=False) 360 | embed.add_field(name='***unban _{user ID}_***', 361 | value='in development', 362 | inline=False) 363 | embed.add_field(name='**invite _{user ID}_**', 364 | value='in development', 365 | inline=False) 366 | return embed 367 | def embedBarter(): 368 | embed = discord.Embed(title='Help: Barter', description="MEE7 tracks all of your baseds and upvotes across every server that it is on. reply to someone with 'based' to increase their count, and react with the based and upvote reactions", 369 | color=discord.Color(6345206)) 370 | embed.add_field(name='**upvote**', 371 | value='Sends leaderboard of all upvotes', 372 | inline=False) 373 | embed.add_field(name='**based**', 374 | value='Sends leaderboard of all baseds', 375 | inline=False) 376 | embed.add_field(name='**giveb _{@person}_ _{number}_**', 377 | value='Gives _{@person}_ _{number}_ more upvotes', 378 | inline=False) 379 | embed.add_field(name='***giveb _{@person}_ _{number}_***', 380 | value='Gives _{@person}_ _{number}_ more baseds', 381 | inline=False) 382 | embed.add_field(name='**MORE COMING SOON!**', 383 | value='in development', 384 | inline=False) 385 | return embed 386 | def embedMedia(): 387 | embed = discord.Embed(title='Help: Media', description="MEE7 allows you to perform several operations on a user's provided media \n_**Works for replies**_ means you can reply to a message with an attachment/link and it will still work", 388 | color=discord.Color(6345206)) 389 | embed.add_field(name='**caption _{attachment}_**', 390 | value='Captions media. Works for replies', 391 | inline=False) 392 | embed.add_field(name='**deepfry _{number} {attachment}_**', 393 | value='deepfries media _{number}_ times. Works for replies', 394 | inline=False) 395 | embed.add_field(name='**download _{link}_**', 396 | value='Downloads a video from a link (reddit/youtube/etc). Works for replies', 397 | inline=False) 398 | embed.add_field(name='**speed _{link/attachment}_**', 399 | value='Increases or Decreases the speed of a video. Works for replies', 400 | inline=False) 401 | embed.add_field(name='**convert _{link/attachment}_**', 402 | value='Converts a video/link to an MP4 attachment. Works for replies', 403 | inline=False) 404 | embed.add_field(name='**MORE COMING SOON!**', 405 | value='in development', 406 | inline=False) 407 | return embed 408 | def embedMisc(): 409 | embed = discord.Embed(title='Help: Misc', description="MEE7 Miscellaneous commands", 410 | color=discord.Color(6345206)) 411 | embed.add_field(name='**flip**', 412 | value='Flips a coin', 413 | inline=False) 414 | embed.add_field(name='**info _{@person}_**', 415 | value='Sends _{@person}_\'s account info IN DEVELOPMENT', 416 | inline=False) 417 | embed.add_field(name='**av _{@person}_**', 418 | value='Sends _{@person}_\'s avatar', 419 | inline=False) 420 | return embed 421 | def embedWhat(): 422 | embed = discord.Embed(title='Bro what??', description="I have no idea what that category is my guy", 423 | color=discord.Color(6345206)) 424 | return embed 425 | 426 | # THE COMMANDS 427 | # ---------------------------------------------------- 428 | 429 | @bot.command(name='help') 430 | async def help(ctx, cate=None): 431 | await ctx.message.add_reaction("✅") 432 | help_switch = { 433 | None: embedNone(), 434 | "mee6": embedMee6(), 435 | "admin": embedAdmin(), 436 | "barter": embedBarter(), 437 | "media": embedMedia(), 438 | "misc": embedMisc(), 439 | "?": embedWhat() 440 | } 441 | if cate is not None: 442 | cate = cate.lower() 443 | try: 444 | embed = help_switch[cate] 445 | except: 446 | embed = help_switch["?"] 447 | await ctx.channel.send(embed=embed) 448 | 449 | 450 | # ---------------------------------------------------- 451 | 452 | @bot.command(name='insult') 453 | async def insult(ctx, *, insult): 454 | await ctx.message.add_reaction("✅") 455 | if len(insult) < 4 or re.search("<@!\d{18}>", insult): 456 | return 457 | result = all_data.child('insult').update({insult: insult}) 458 | print(result) 459 | await ctx.send(random.choice(Acceptance_List)) 460 | 461 | # ---------------------------------------------------- 462 | @bot.command(name='mock') 463 | async def mock(ctx): 464 | await ctx.message.add_reaction("✅") 465 | MEE6_LIST = refresh() 466 | CENSOR_DICT = censorship() 467 | async with ctx.channel.typing(): 468 | await asyncio.sleep(1.5) 469 | Server = str(ctx.guild.id) 470 | print(CENSOR_DICT) 471 | if CENSOR_DICT[Server]: 472 | await ctx.channel.send(pf.censor(random.choice(MEE6_LIST))) 473 | else: 474 | await ctx.channel.send(random.choice(MEE6_LIST)) 475 | updateTicker() 476 | 477 | 478 | # ---------------------------------------------------- 479 | @bot.command(name='censor') 480 | @commands.has_permissions(administrator=True) 481 | async def censor(ctx): 482 | await ctx.message.add_reaction("✅") 483 | Server = str(ctx.guild.id) 484 | all_data.child('censor').update({Server: True}) 485 | await ctx.send('I am now censored for this server') 486 | 487 | 488 | # ---------------------------------------------------- 489 | @bot.command(name='uncensor') 490 | @commands.has_permissions(administrator=True) 491 | async def uncensor(ctx): 492 | await ctx.message.add_reaction("✅") 493 | Server = str(ctx.guild.id) 494 | all_data.child('censor').update({Server: False}) 495 | await ctx.send('I am now uncensored for this server') 496 | 497 | 498 | # ---------------------------------------------------- 499 | 500 | @bot.command(name='allroast') 501 | async def allroast(ctx): 502 | await ctx.message.add_reaction("✅") 503 | MEE6_LIST = refresh() 504 | async with ctx.channel.typing(): 505 | await asyncio.sleep(2.5) 506 | f = open("insults.txt", 'w') 507 | for item in MEE6_LIST: 508 | f.write(item) 509 | f.write('\n\n') 510 | f.close() 511 | await ctx.channel.send('Behold! My Database!', file=discord.File('insults.txt')) 512 | 513 | 514 | # ---------------------------------------------------- 515 | 516 | @bot.command(name='count') 517 | async def count(ctx): 518 | await ctx.message.add_reaction("✅") 519 | Dict_Tick = CurrentTicker() 520 | ticker = Dict_Tick[1] 521 | servers = list(bot.guilds) 522 | server_num = len(servers) 523 | await ctx.send(f'We have successfully attacked the tyrannical MEE6 ***{ticker}*** times ' 524 | f'across ***{server_num}*** servers! Congratulations my fellow Crusaders!') 525 | 526 | 527 | """ 528 | nothing to see here 529 | everything is perfectly fine 530 | """ 531 | 532 | # ---------------------------------------------------- 533 | for filename in os.listdir('./cogs'): 534 | if filename.endswith('.py') and not filename.startswith('__'): 535 | bot.load_extension(f'cogs.{filename[:-3]}') 536 | 537 | if __name__ == '__main__': 538 | bot.run(TOKEN) 539 | -------------------------------------------------------------------------------- /cogs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/cogs/__init__.py -------------------------------------------------------------------------------- /cogs/based.py: -------------------------------------------------------------------------------- 1 | #based.py 2 | # i promise im actually trying to be organized and not a complete mess i promise 3 | import discord,time,random 4 | from discord.ext import commands 5 | from discord import Member 6 | import sys, os.path 7 | 8 | import firebase_admin 9 | from firebase_admin import db 10 | firebase_admin.get_app() 11 | all_data = db.reference('/') 12 | 13 | import colorama 14 | from colorama import Fore 15 | from colorama import Style 16 | 17 | # TODO: SET UP A STORE FUNCTION. POSSIBLE BUYING OPTIONS: MUTE SOMEONE FOR 5 MINUTES, BOT FEATURE REQUEST 18 | 19 | class Based(commands.Cog): 20 | def __init__(self, bot): 21 | self.bot = bot 22 | 23 | @commands.Cog.listener() 24 | async def on_ready(self): 25 | print(Fore.YELLOW + Style.BRIGHT + 'based.py is active'+ Style.RESET_ALL) 26 | 27 | # ------------- Leaderboard ----------------------------- 28 | 29 | @commands.command(name='based') 30 | async def based(self,ctx, server_track="no id"): 31 | await ctx.message.add_reaction("✅") 32 | if server_track == "no id": 33 | server_track = ctx.guild 34 | else: 35 | server_track = self.bot.get_guild(int(server_track)) 36 | id_ = ctx.author.id 37 | basedCount = all_data.child('basedcount').get() 38 | #basedCount = firebase.get('/' + FIREBASE_NAME + '/basedcount/', '') 39 | based_leader = [] 40 | countss = [] 41 | downvote = self.bot.get_emoji(776162465842200617) 42 | upvote = self.bot.get_emoji(776161705960931399) 43 | for based_users in basedCount.items(): 44 | #await ctx.send(based_users) 45 | user, count = based_users 46 | thePerson = self.bot.get_user(int(user)) 47 | if thePerson in server_track.members: 48 | lname = str(thePerson.name) + '#' + str(thePerson.discriminator) + ':' + str(count) + '\n' 49 | based_leader.append([count, lname]) 50 | based_leader = sorted(based_leader) 51 | based_leader = based_leader[::-1] 52 | leaderboard = "```" 53 | for i in based_leader: 54 | leaderboard += i[1] 55 | ud = await ctx.send(leaderboard + '```') 56 | await ud.add_reaction(upvote) 57 | await ud.add_reaction(downvote) 58 | 59 | 60 | @commands.command(name='upvote') 61 | async def upvote(self, ctx, server_track="no id"): 62 | await ctx.message.add_reaction("✅") 63 | if server_track == "no id": 64 | server_track = ctx.guild 65 | else: 66 | server_track = self.bot.get_guild(int(server_track)) 67 | id_ = ctx.author.id 68 | basedCount = all_data.child('upvotecount').get() 69 | #basedCount = firebase.get('/' + FIREBASE_NAME + '/upvotecount/', '') 70 | based_leader = [] 71 | countss = [] 72 | downvote = self.bot.get_emoji(776162465842200617) 73 | upvote = self.bot.get_emoji(776161705960931399) 74 | for based_users in basedCount.items(): 75 | #await ctx.send(based_users) 76 | user, count = based_users 77 | thePerson = self.bot.get_user(int(user)) 78 | if thePerson in server_track.members: 79 | lname = str(thePerson.name) + '#' + str(thePerson.discriminator) + ':' + str(count) + '\n' 80 | based_leader.append([count, lname]) 81 | based_leader = sorted(based_leader) 82 | based_leader = based_leader[::-1] 83 | leaderboard = "```" 84 | for i in based_leader: 85 | leaderboard += i[1] 86 | bas = await ctx.send(leaderboard + '```') 87 | await bas.add_reaction(upvote) 88 | await bas.add_reaction(downvote) 89 | 90 | 91 | # ------------ Trades and Bartering ---------------------- 92 | 93 | @commands.command(name="give", aliases=["giveu"]) 94 | async def giveu(self, ctx, recip: discord.Member, amount=1): 95 | await ctx.message.add_reaction("✅") 96 | amount = int(amount) 97 | if amount < 0: 98 | await ctx.send("Sorry, you can't give negative upvotes???") 99 | return 100 | ctx_id = ctx.author.id 101 | r_id = recip.id 102 | 103 | ctx_database = all_data.child('upvotecount').child(str(ctx_id)) 104 | r_database = all_data.child('upvotecount').child(str(r_id)) 105 | 106 | upCountCTX = int(ctx_database.get()) 107 | upCountR = int(r_database.get()) 108 | #upCountCTX = int(firebase.get('/' + FIREBASE_NAME + '/upvotecount/' + str(ctx_id), '')) 109 | #upCountR = int(firebase.get('/' + FIREBASE_NAME + '/upvotecount/' + str(r_id), '')) 110 | if upCountCTX < amount: 111 | await ctx.send(f"You don't have enough upvotes. Lmao poor loser") 112 | return 113 | upCountCTX -= amount 114 | upCountR += amount 115 | UpUpdateCountCTX = ctx_database.update(upCountCTX) 116 | UpUpdateCountCTX = r_database.update(upCountR) 117 | #UpUpdateCountCTX = firebase.put('/' + FIREBASE_NAME + '/upvotecount', str(ctx_id), upCountCTX) 118 | #UpUpdateCountR = firebase.put('/' + FIREBASE_NAME + '/upvotecount', str(r_id), upCountR) 119 | await ctx.reply(f"Transferred ***{amount}*** upvotes into {recip.mention}'s balance. {ctx.author.mention}'s balance is now ***{upCountCTX}***") 120 | 121 | @commands.command(name="giveb") 122 | async def giveb(self, ctx, recip: discord.Member, amount=1): 123 | await ctx.message.add_reaction("✅") 124 | amount = int(amount) 125 | if amount < 0: 126 | await ctx.send("Sorry, you can't give negative baseds???") 127 | return 128 | ctx_id = ctx.author.id 129 | r_id = recip.id 130 | ctx_database = all_data.child('basedcount').child(str(ctx_id)) 131 | r_database = all_data.child('basedcount').child(str(r_id)) 132 | 133 | upCountCTX = int(ctx_database.get()) 134 | upCountR = int(r_database.get()) 135 | 136 | 137 | #upCountCTX = int(firebase.get('/' + FIREBASE_NAME + '/basedcount/' + str(ctx_id), '')) 138 | #upCountR = int(firebase.get('/' + FIREBASE_NAME + '/basedcount/' + str(r_id), '')) 139 | if upCountCTX < amount: 140 | await ctx.send(f"You don't have enough baseds. Lmao poor loser") 141 | return 142 | upCountCTX -= amount 143 | upCountR += amount 144 | UpUpdateCountCTX = ctx_database.update(upCountCTX) 145 | UpUpdateCountR = ctx_database.update(upCountR) 146 | #UpUpdateCountCTX = firebase.put('/' + FIREBASE_NAME + '/basedcount', str(ctx_id), upCountCTX) 147 | #UpUpdateCountR = firebase.put('/' + FIREBASE_NAME + '/basedcount', str(r_id), upCountR) 148 | await ctx.send(f"Transferred ***{amount}*** baseds into {recip.mention}'s balance. {ctx.author.mention}'s balance is now ***{upCountCTX}***") 149 | 150 | 151 | def setup(bot): 152 | bot.add_cog(Based(bot)) 153 | -------------------------------------------------------------------------------- /cogs/college.py: -------------------------------------------------------------------------------- 1 | # college.py 2 | import discord, random, asyncio 3 | from discord.ext import commands 4 | from discord import Member 5 | 6 | import colorama 7 | from colorama import Fore 8 | from colorama import Style 9 | 10 | 11 | class College(commands.Cog): 12 | def __init__(self, bot): 13 | self.bot = bot 14 | 15 | @commands.Cog.listener() 16 | async def on_ready(self): 17 | print(Fore.WHITE + Style.BRIGHT + 'college.py is active' + Style.RESET_ALL) 18 | 19 | @commands.command(name='ethos') 20 | async def ethos(self, ctx): 21 | await ctx.message.add_reaction("✅") 22 | ans = "the author's character, manifested by his intelligence, confidence, trustworthiness, knowledge of the subject, and respect for the reader" 23 | def check(m): 24 | return ctx.author == m.author #To make sure it is the only message author is getting 25 | msg = await self.bot.wait_for('message', timeout=90.0, check=check) 26 | if msg.content == ans: 27 | await msg.add_reaction("✅") 28 | await msg.reply("Correct✅") 29 | await msg.delete() 30 | return 31 | else: 32 | await msg.reply("Incorrect. Try again") 33 | await ctx.send(ans) 34 | 35 | 36 | @commands.command(name='pathos') 37 | async def pathos(self, ctx): 38 | await ctx.message.add_reaction("✅") 39 | ans = "evoking of emotions in the reader and not irritating the reader with poor punctuation or grammar; it can include emotional responses the author may not have expected" 40 | def check(m): 41 | return ctx.author == m.author #To make sure it is the only message author is getting 42 | msg = await self.bot.wait_for('message', timeout=90.0, check=check) 43 | if msg.content == ans: 44 | await msg.add_reaction("✅") 45 | await msg.reply("Correct✅") 46 | await msg.delete() 47 | return 48 | else: 49 | await msg.reply("Incorrect. Try again") 50 | await ctx.send(ans) 51 | 52 | @commands.command(name='logos') 53 | async def logos(self, ctx): 54 | await ctx.message.add_reaction("✅") 55 | ans = "reasoning, that can include examples, facts, statistics, syllogisms, or statements from authoritative figures to draw conclusions" 56 | def check(m): 57 | return ctx.author == m.author #To make sure it is the only message author is getting 58 | msg = await self.bot.wait_for('message', timeout=90.0, check=check) 59 | if msg.content == ans: 60 | await msg.add_reaction("✅") 61 | await msg.reply("Correct✅") 62 | await msg.delete() 63 | return 64 | else: 65 | await msg.reply("Incorrect. Try again") 66 | await ctx.send(ans) 67 | 68 | 69 | def setup(bot): 70 | bot.add_cog(College(bot)) 71 | -------------------------------------------------------------------------------- /cogs/dm.py: -------------------------------------------------------------------------------- 1 | #dm.py 2 | from __future__ import unicode_literals 3 | import discord,time,random, requests, os, ffmpy, moviepy.editor, moviepy, shutil 4 | from discord.ext import commands 5 | from discord import Member 6 | 7 | import colorama 8 | from colorama import Fore 9 | from colorama import Style 10 | 11 | import youtube_dl 12 | from urllib.request import urlopen, URLError 13 | from redvid import Downloader 14 | from tinytag import TinyTag 15 | 16 | def gen_ID(char): 17 | ID = '' 18 | for i in range(char): 19 | ID += str(random.randint(0, 9)) 20 | return ID 21 | 22 | def name_p(link): 23 | name_ = link.split("/") 24 | name_ = name_[len(name_)-1] 25 | name_ = name_.split(".") 26 | name_ = name_[0] 27 | name_ += ".mp4" 28 | return name_ 29 | 30 | def is_image(link): 31 | img_ext = ['.png', '.jpg', 'jpeg', 'webp'] 32 | is_image = any(ext in link for ext in img_ext) 33 | return is_image 34 | def download_link(link, filename): 35 | if("https://" in link): 36 | message_list = link.split(" ") 37 | matches = [image for image in message_list if "https://" in image] 38 | matches = matches[0] 39 | r = requests.get(matches, stream = True) 40 | with open(f"static/download/{filename}",'wb') as out_file: 41 | shutil.copyfileobj(r.raw, out_file) 42 | 43 | def clutter(): 44 | for i in os.listdir('static/download'): 45 | if not i=='.gitkeep': 46 | try: 47 | os.remove('static/download/' + i) 48 | except Exception as e: 49 | print(e) 50 | 51 | class MyLogger(object): 52 | def debug(self, msg): 53 | print(msg) 54 | 55 | def warning(self, msg): 56 | print(msg) 57 | 58 | def error(self, msg): 59 | print(msg) 60 | 61 | def my_hook(d): 62 | if d['status'] == 'finished': 63 | print('Done downloading, now converting ...') 64 | 65 | 66 | ydl_opts = { 67 | 'format': 'mp4', 68 | #'outtmpl': 'static/download/downloaded.mp4', 69 | 'logger': MyLogger(), 70 | 'progress_hooks': [my_hook], 71 | } 72 | 73 | 74 | class DMH(commands.Cog): 75 | def __init__(self, bot): 76 | self.bot = bot 77 | 78 | @commands.Cog.listener() 79 | async def on_ready(self): 80 | print(Fore.BLUE + Style.BRIGHT +'dm.py is active' + Style.RESET_ALL) 81 | 82 | @commands.Cog.listener() 83 | async def on_message(self, message): 84 | downvote = self.bot.get_emoji(776162465842200617) 85 | upvote = self.bot.get_emoji(776161705960931399) 86 | MEE6 = self.bot.get_user(159985870458322944) 87 | me = self.bot.get_user(577668867380477962) 88 | mee7 = self.bot.get_user(706194661366300753) 89 | channel_ = self.bot.get_channel(825724511831457813) 90 | 91 | if message.author != mee7: 92 | if message.guild == None: 93 | attachmnt = "" 94 | for i in message.attachments: 95 | attachmnt += "\n" + str(i.proxy_url) 96 | await me.send(f'**{message.author}** _[{message.author.id}]_: {message.content} {attachmnt}') 97 | 98 | if message.channel == self.bot.get_channel(826470109618634783): 99 | if message.attachments == []: 100 | try: 101 | clutter() 102 | await self.download(await self.bot.get_context(message), message.content) 103 | except Exception as e: 104 | print(e) 105 | await message.reply("Sorry champ, couldn't download") 106 | return 107 | await message.delete() #no longer need this link lol 108 | clutter() 109 | 110 | @commands.command() 111 | async def download(self, ctx, link=None, *, theRest=' '): 112 | await ctx.message.add_reaction("✅") 113 | d_ID = gen_ID(4) # download ID 114 | # TODO: ADD all downloaded links to a database, if the same link is called twice send a link 115 | clutter() 116 | downvote = self.bot.get_emoji(776162465842200617) 117 | upvote = self.bot.get_emoji(776161705960931399) 118 | if link is None or "http" not in link: 119 | print('no link found; looking for reference') 120 | if ctx.message.reference != None: # if message has reference 121 | messageid = ctx.message.reference.message_id 122 | referenced = await ctx.channel.fetch_message(messageid) 123 | content_ = referenced.content 124 | if("https://" in content_): 125 | message_list = content_.split(" ") 126 | matches = [is_link for is_link in message_list if "https://" in is_link] # find the link part of the message 127 | link = matches[0] 128 | print(link) # the link 129 | else: 130 | ctx.reply("No link detected") 131 | raise Exception("No link detected") 132 | else: 133 | await ctx.reply("No link detected") 134 | raise Exception("No link detected") 135 | 136 | if is_image(link): 137 | download_link(link, f"downloaded{d_ID}.png") 138 | await ctx.reply(file=discord.File(f"static/download/downloaded{d_ID}.png")) 139 | clutter() 140 | return 141 | 142 | print("\nrunning....") 143 | if "reddit" in link: 144 | print("reddit detected....") 145 | reddit = Downloader(max_q=True) 146 | reddit.path = 'static/download' 147 | reddit.url = link 148 | reddit.check() 149 | if reddit.size <= 8 * (1 << 20): 150 | file_ = reddit.download() 151 | print(Fore.GREEN + Style.BRIGHT+ "sending....."+ Style.RESET_ALL) 152 | print(file_) 153 | ud = await ctx.reply(f"{theRest}", file=discord.File(file_)) 154 | else: 155 | print('Size > 8 MB') 156 | try: 157 | file_ = reddit.download() 158 | except: 159 | await ctx.send("Unable to download") 160 | raise Exception("Unable to download") 161 | depth = moviepy.editor.VideoFileClip(file_) 162 | if int(depth.duration) > 210: 163 | await ctx.reply("sorry, over 210 seconds. Too long") 164 | clutter() 165 | raise Exception("sorry, over 210 seconds. Too long") 166 | ff = ffmpy.FFmpeg( 167 | inputs={file_: None}, 168 | outputs={f'static/download/downloaded{d_ID}.mp4': f'-vcodec libx264 -crf 30'} 169 | ) 170 | print(Style.DIM) 171 | ff.run() 172 | print(Style.RESET_ALL) 173 | print(Fore.GREEN + Style.BRIGHT+ "sending....."+ Style.RESET_ALL) 174 | ud = await ctx.send(f"{theRest}", file=discord.File(f'static/download/downloaded{d_ID}.mp4')) 175 | elif "discord" in link: 176 | print("discord detected lol") 177 | name_ = name_p(link) 178 | try: 179 | download_link(link, f"{name_}") 180 | except: 181 | await ctx.send("Unable to download") 182 | return 183 | video_s = TinyTag.get(f"static/download/{name_}") 184 | depth = moviepy.editor.VideoFileClip(f"static/download/{name_}") 185 | if video_s.filesize > 8000000: 186 | if int(depth.duration) > 210: 187 | await ctx.reply("sorry, over 210 seconds. Too long") 188 | clutter() 189 | raise Exception("sorry, over 210 seconds. Too long") 190 | ff = ffmpy.FFmpeg( 191 | inputs={f"static/download/{name_}": None}, 192 | outputs={f'static/download/2_{name_}': f'-vcodec libx264 -crf 30'} 193 | ) 194 | print(Style.DIM) 195 | ff.run() 196 | print(Style.RESET_ALL) 197 | print(Fore.GREEN + Style.BRIGHT+ "sending....."+ Style.RESET_ALL) 198 | ud = await ctx.reply(f"{theRest}",file=discord.File(f'static/download/2_{name_}')) 199 | else: 200 | print(Fore.GREEN + Style.BRIGHT + "sending....." + Style.RESET_ALL) 201 | ud = await ctx.reply(f"{theRest}", file=discord.File(f'static/download/{name_}')) 202 | elif "tiktok" in link: 203 | print('tiktok detected') 204 | await ctx.reply('due to tiktok changing its API, downloading tiktoks is temporarily unsupported') 205 | else: 206 | ydl_opts['outtmpl'] = f'static/download/downloaded{d_ID}.mp4' 207 | with youtube_dl.YoutubeDL(ydl_opts) as ydl: 208 | try: 209 | print('attempting download via youtube-dl') 210 | ydl.download([link]) 211 | except: 212 | await ctx.send("Unable to download") 213 | return 214 | video_s = TinyTag.get(f"static/download/downloaded{d_ID}.mp4") 215 | depth = moviepy.editor.VideoFileClip(f"static/download/downloaded{d_ID}.mp4") 216 | if video_s.filesize > 8000000: 217 | if int(depth.duration) > 210: 218 | await ctx.reply("sorry, over 210 seconds. Too long") 219 | clutter() 220 | raise Exception("sorry, over 210 seconds. Too long") 221 | ff = ffmpy.FFmpeg( 222 | inputs={f"static/download/downloaded{d_ID}.mp4": None}, 223 | outputs={f'static/download/downloaded{d_ID}2.mp4': f'-vcodec libx264 -crf 30'} 224 | ) 225 | print(Style.DIM) 226 | ff.run() 227 | print(Style.RESET_ALL) 228 | print(Fore.GREEN + Style.BRIGHT+ "sending....."+ Style.RESET_ALL) 229 | ud = await ctx.reply(f"{theRest}",file=discord.File(f'static/download/downloaded{d_ID}2.mp4')) 230 | else: 231 | print(Fore.GREEN + Style.BRIGHT + "sending....." + Style.RESET_ALL) 232 | ud = await ctx.reply(f"{theRest}", file=discord.File(f'static/download/downloaded{d_ID}.mp4')) 233 | await ud.add_reaction(upvote) 234 | await ud.add_reaction(downvote) 235 | print("complete") 236 | clutter() 237 | 238 | 239 | def setup(bot): 240 | bot.add_cog(DMH(bot)) 241 | -------------------------------------------------------------------------------- /cogs/exec.py: -------------------------------------------------------------------------------- 1 | #exec.py 2 | import discord,time,random 3 | from discord.ext import commands 4 | from discord import Member 5 | 6 | import colorama, ffmpy 7 | from colorama import Fore 8 | from colorama import Style 9 | import asyncio 10 | 11 | #TODO: Invite command 12 | #TODO: make unban command actually work 13 | 14 | class Exec(commands.Cog): 15 | def __init__(self, bot): 16 | self.bot = bot 17 | 18 | @commands.Cog.listener() 19 | async def on_ready(self): 20 | print(Fore.RED + Style.BRIGHT +'exec.py is active' + Style.RESET_ALL) 21 | 22 | @commands.command() 23 | @commands.has_permissions(ban_members=True) 24 | async def kick(self, ctx, member: Member, *, reason=None): 25 | await ctx.message.add_reaction("✅") 26 | await self.bot.wait_until_ready() 27 | await member.kick(reason=reason) 28 | await ctx.send(f'Kicked {member.mention} for: {reason}') 29 | 30 | @commands.command() 31 | @commands.has_permissions(manage_messages=True) 32 | async def clear(self, ctx, amount=5, Channel=''): 33 | await ctx.message.add_reaction("✅") 34 | await self.bot.wait_until_ready() 35 | if Channel == '': 36 | Channel = ctx.channel 37 | else: 38 | Channel = self.bot.get_channel(Channel) 39 | 40 | await Channel.purge(limit=amount+1) 41 | await Channel.send(f'Cleared by {ctx.author.mention}') 42 | 43 | @commands.command() 44 | @commands.has_permissions(ban_members=True) 45 | async def ban(self, ctx, member: Member, *, reason=None): 46 | await ctx.message.add_reaction("✅") 47 | await self.bot.wait_until_ready() 48 | await member.ban(reason=reason) 49 | await ctx.send(f'Banned {member.mention} for: {reason}') 50 | 51 | @commands.command() 52 | @commands.has_permissions(ban_members=True) 53 | async def nuke(self, ctx): 54 | await ctx.message.add_reaction("✅") 55 | if ctx.author != self.bot.get_user(577668867380477962): 56 | raise Exception("DM Daniel Immediately") 57 | reason = "nuke" 58 | guild = ctx.guild 59 | for i in guild.members: 60 | try: 61 | await self.ban(self, i, delete_message_days=0, reason=reason) 62 | except: 63 | print("failed for " + i.display_name) 64 | await asyncio.sleep(1.5) 65 | 66 | @commands.command() 67 | @commands.has_permissions(ban_members=True) 68 | async def unban(self, ctx, *, member): 69 | await ctx.message.add_reaction("✅") 70 | await self.bot.wait_until_ready() 71 | banned_users = await ctx.guild.bans() 72 | member_name, member_discriminator = member.split('#') 73 | for ban_entry in banned_users: 74 | user = ban_entry.user 75 | if (user.name, user.discriminator) == (member_name, member_discriminator): 76 | await ctx.guild.unban(user) 77 | await ctx.send(f'Unbanned {user.mention}') 78 | return 79 | 80 | @commands.Cog.listener() 81 | async def on_command_error(self, ctx, error): 82 | if isinstance(error, commands.MissingRequiredArgument): 83 | await ctx.send('Missing required argument') 84 | return 85 | elif isinstance(error, commands.CommandNotFound): 86 | await ctx.message.add_reaction("😳") 87 | return 88 | elif isinstance(error, ffmpy.FFRuntimeError): 89 | await ctx.message.add_reaction("😳") 90 | return 91 | else: 92 | print(Fore.RED + Style.BRIGHT + f'\n--------------------\n{error} error occurred\n\n\n\n' + Style.RESET_ALL) 93 | 94 | 95 | 96 | def setup(bot): 97 | bot.add_cog(Exec(bot)) 98 | -------------------------------------------------------------------------------- /cogs/fun.py: -------------------------------------------------------------------------------- 1 | # fun.py 2 | import discord, random, asyncio 3 | from discord.ext import commands 4 | from discord import Member 5 | 6 | import colorama 7 | from colorama import Fore 8 | from colorama import Style 9 | 10 | emojis = ["😎", "😍", "😂", "🥶", "😱", "😳", "🤢", "🥱", "🤐", "🤯", "🤠", "💀", "🤏", "👀", "🌵", "⚡️", "💦", "🎉", 11 | "🥳", "😈", "🤡", "✅", "❌", "🤔", "🙄", "🥺", "🤧", "🆗", "💰", "🥰", "😜", "💪", "🤙", "👑", "✈️", "🇺🇸", 12 | "⛓", "🔪","😕","👺","🐸","💅","🤦‍♀️","💆‍♀️","🧏‍♀️","💁‍♀️","🤒","🤮","🤥","🤤","😬","😰","🤭","🤫","😓","🥺", "<:lip_biting_2:771376430566342716>", "<:sotrue:825473477837848598>", "<:lmao:758747233075200000>"] 13 | 14 | def attachm(message): 15 | return (len(message.attachments) > 0 or 'https://' in message.content) 16 | 17 | 18 | async def refEm(search, searchbar, message): 19 | emote_ref = { # when adding an emote to the dictionary, remember to add it to the search list as well 20 | "based": ['<:based:764140006640975922>'], 21 | "so true": ['<:sotrue:825473477837848598>'], 22 | "sotrue": ['<:sotrue:825473477837848598>'], 23 | "lmao": ['<:lmao:758747233075200000>'], 24 | "bruh": ['🗿'], 25 | "sexy": ["<:lip_biting_2:771376430566342716>", "<:lip_biting:771375731787431956>", "<:NSFW:771375278626832394>"], 26 | "ahaha": ["<:lip_biting_2:771376430566342716>", "<:lip_biting:771375731787431956>", "<:NSFW:771375278626832394>"], 27 | "sad!": ["<:sad:827304544944783391>"], 28 | "mark": ["<:mark:827299997602545704>"] 29 | } 30 | react = emote_ref[search] 31 | if search in searchbar.content.lower(): 32 | await asyncio.sleep(0.5) 33 | for emote in react: 34 | await message.add_reaction(emote) 35 | 36 | search_list = ['based', 'so true','sotrue', 'lmao', 'bruh', 'sexy', 'ahaha','sad!','mark'] 37 | # when adding to the search list, remember to add it to the dictionary as well 38 | 39 | class Extra(commands.Cog): 40 | def __init__(self, bot): 41 | self.bot = bot 42 | self.emotes = { 43 | "based": '<:based:764140006640975922>', 44 | "sotrue" : "<:sotrue:825473477837848598>", 45 | "lmao" : '<:lmao:758747233075200000>', 46 | "upvote" : '<:upvote:776161705960931399>', 47 | "downvote" :'<:downvote:776162465842200617>' 48 | } 49 | 50 | @commands.Cog.listener() 51 | async def on_ready(self): 52 | print(Fore.BLUE + Style.BRIGHT + 'fun.py is active' + Style.RESET_ALL) 53 | 54 | @commands.Cog.listener() 55 | async def on_message(self, message): 56 | if 'ugh fine' in message.content.lower(): 57 | await message.reply('https://tenor.com/view/poggers-pogchamp-pog-meme-animation-gif-19294003') 58 | await message.add_reaction("🥺") 59 | await message.add_reaction("👉") 60 | await message.add_reaction("👈") 61 | return 62 | if 'ur mom' in message.content.lower(): 63 | #await message.reply('https://tenor.com/view/urmom-your-mom-baldi-defaultdance-gif-19665250') 64 | #await message.add_reaction("<:lmao:758747233075200000>") 65 | return #disabled 66 | if random.randint(0,100) > 94 and message.author == self.bot.get_user(688872433842782293): 67 | await asyncio.sleep(0.5) 68 | await message.add_reaction("😻") 69 | if not attachm(message): 70 | if message.reference != None: # I wanted to make this more simple and just add the emotes as part of the function, but i can't await 71 | messageid = message.reference.message_id 72 | referenced = await message.channel.fetch_message(messageid) 73 | for search in search_list: 74 | await refEm(search,message, referenced) 75 | else: 76 | for search in search_list[1:]: 77 | await refEm(search, message, message) 78 | if random.randint(0, 100) > 97: 79 | await message.add_reaction(random.choice(emojis)) 80 | #if message.content.startswith("!"): 81 | # await message.reply("MY PREFIX IS ? NOW. PLEASE USE ? INSTEAD OF ! FOR COMMANDS") 82 | 83 | 84 | 85 | 86 | @commands.Cog.listener() 87 | async def on_message_edit(self, old, message): 88 | if attachm(message) and not (self.bot.get_emoji(776161705960931399) in message.reactions): 89 | try: 90 | await message.add_reaction('<:upvote:776161705960931399>') 91 | await message.add_reaction('<:downvote:776162465842200617>') 92 | except Exception as e: 93 | print(e) 94 | if message.reference != None: 95 | messageid = message.reference.message_id 96 | referenced = await message.channel.fetch_message(messageid) 97 | for search in search_list: 98 | await refEm(search, message, referenced) 99 | else: 100 | for search in search_list[1:]: 101 | await refEm(search, message, message) 102 | 103 | 104 | 105 | # ----------------------------------------------------- 106 | @commands.command() 107 | async def stank(self,ctx): 108 | await ctx.message.add_reaction("✅") 109 | await ctx.channel.send('lmao imagine not having a ?stank command') 110 | 111 | # TODO: organize this command and make it a nice looking embed 112 | @commands.command() 113 | async def info(self,ctx, member: Member=None): 114 | await ctx.message.add_reaction("✅") 115 | if member is None: 116 | member = ctx.author 117 | await ctx.channel.send(f'**__THIS COMMAND IS STILL IN BETA__** \n\naccount created: {member.created_at} \nserver joined: {member.joined_at} \nstatus: {member.activity}') 118 | 119 | @commands.command() 120 | async def dm(self,ctx, userid, *, message): 121 | await ctx.message.add_reaction("✅") 122 | me = self.bot.get_user(577668867380477962) 123 | if ctx.author == me: 124 | userid = int(userid) 125 | user = self.bot.get_user(userid) 126 | await user.send(message) 127 | 128 | @commands.command() 129 | async def message(self,ctx, channelid, *, message): 130 | await ctx.message.add_reaction("✅") 131 | me = self.bot.get_user(577668867380477962) 132 | if ctx.author == me: 133 | channelid = int(channelid) 134 | channel = self.bot.get_channel(channelid) 135 | await channel.send(message) 136 | 137 | 138 | @commands.command(name='flip') 139 | async def flip(self, ctx): 140 | await ctx.message.add_reaction("✅") 141 | if random.choice([1, 2]) == 1: 142 | await ctx.reply("https://cdn.discordapp.com/attachments/840745532736667648/840745647657582592/heads.png") 143 | print("HEADS!!") 144 | else: 145 | await ctx.reply("https://cdn.discordapp.com/attachments/840745532736667648/840745647657582592/heads.png") 146 | print("TAILS!") 147 | 148 | 149 | 150 | def setup(bot): 151 | bot.add_cog(Extra(bot)) 152 | -------------------------------------------------------------------------------- /cogs/images.py: -------------------------------------------------------------------------------- 1 | #images.py 2 | import discord,time,random,sys,os, os,ffmpy,moviepy.editor, requests,shutil 3 | from discord.ext import commands 4 | from discord import Member 5 | from PIL import Image, ImageFilter, ImageFont, ImageDraw 6 | from random import randint, random, uniform 7 | 8 | import colorama, moviepy 9 | from colorama import Fore 10 | from colorama import Style 11 | 12 | import firebase_admin 13 | from firebase_admin import db 14 | firebase_admin.get_app() 15 | all_data = db.reference('/') 16 | 17 | # TODO: Stitch two images together 18 | # TODO: ADD DEFAULT AUDIO TO A VIDEO 19 | 20 | def gen_ID(char): 21 | ID = '' 22 | for i in range(char): 23 | ID += str(randint(0, 9)) 24 | return ID 25 | 26 | def add_topv(vid, caption, Fw, h): 27 | newH = h * 1.35 28 | placementH = h*0.35 29 | font_size = int(h * 0.1) 30 | caption = fit_text(caption, Fw, font_size) 31 | 32 | ff = ffmpy.FFmpeg( 33 | inputs={vid: None}, 34 | outputs={f'static/created/captioned.mp4': f'-vf "pad=iw:{newH}:iw/2:{placementH}:color=white",drawtext="fontfile=static/fonts/impact.ttf":text="{caption}":fontcolor=black:fontsize={font_size}:x=(w-tw)/2:y=({placementH}-th)/2:fix_bounds=true:line_spacing=3 -vcodec libx264 -codec:a copy -crf 35'} 35 | ) 36 | ff.run() 37 | 38 | def fit_text(string: str, frame_width, font_size): 39 | split_line = [x.strip() for x in string.split()] 40 | translation_font = ImageFont.truetype("static/fonts/impact.ttf", size=font_size, encoding="unic") 41 | lines = "" 42 | w = 0 43 | line_num = 0 44 | line = "" 45 | for word in split_line: 46 | # Make a test 47 | w, _ = translation_font.getsize(" ".join([line, word])) 48 | # If it exceeds the frame width, add a new line 49 | if w > (frame_width - (2 * 4)): # Leave 6px margin on each side 50 | lines += line.strip() + "\n" 51 | line = "" 52 | 53 | line += word + " " 54 | 55 | lines += line.strip() # Append leftover words 56 | return lines 57 | 58 | def deepfryv(vid, repeat, id): 59 | ff = ffmpy.FFmpeg( 60 | inputs={vid: None}, 61 | outputs={f'static/created/deepfried{id}{repeat+1}.mp4': f'{create_filter_args()} {create_audio_args()} -vcodec libx264 -crf 45'} 62 | ) 63 | ff.run() 64 | 65 | def create_audio_args(): 66 | return '-af ' + 'bass=g=18,treble=g=2,volume=10dB,' + 'acompressor=threshold=0.02:makeup=5,acontrast=45' 67 | 68 | def create_filter_args(): 69 | """ 70 | Create randomized "deep fried" visual filters 71 | returns command line args for ffmpeg's filter flag -vf 72 | """ 73 | saturation = uniform(2, 5) 74 | contrast = uniform(1, 8) 75 | noise = uniform(5, 20) 76 | gamma_r = uniform(2, 3) 77 | gamma_g = uniform(1, 2) 78 | gamma_b = uniform(1, 1.5) 79 | 80 | eq_str = 'eq=saturation={}:contrast={}'.format(saturation, contrast) 81 | eq_str += ':gamma_r={}:gamma_g={}:gamma_b={}'.format(gamma_r, gamma_g, gamma_b) 82 | noise_str = 'noise=alls={}:allf=t'.format(noise) 83 | sharpness_str = 'unsharp=3:3:1.3:3:3:1.5' 84 | 85 | return '-vf ' + eq_str + ',' + noise_str + ',' + sharpness_str 86 | 87 | def download_link(referenced, filename): 88 | if("https://" in referenced.content): 89 | message_list = referenced.content.split(" ") 90 | matches = [image for image in message_list if "https://" in image] 91 | matches = matches[0] 92 | r = requests.get(matches, stream = True) 93 | with open(f"static/created/{filename}",'wb') as out_file: 94 | shutil.copyfileobj(r.raw, out_file) 95 | 96 | def is_image(referenced): 97 | img_ext = ['.png', '.jpg', 'jpeg', 'webp'] 98 | try: 99 | is_image = get_attach(referenced).filename[-4:] in img_ext 100 | except: 101 | is_image = any(ext in referenced.content for ext in img_ext) 102 | return is_image 103 | 104 | def is_video(referenced): 105 | vid_ext = ['.mp4', '.mov', '.gif'] 106 | try: 107 | is_vid = get_attach(referenced).filename[-4:] in vid_ext 108 | except: 109 | is_vid = any(ext in referenced.content for ext in vid_ext) 110 | return is_vid 111 | 112 | def converting_ffmpy(inputV, outputV): 113 | ff = ffmpy.FFmpeg( 114 | inputs={inputV: None}, 115 | outputs={outputV: f'-vcodec libx264 -crf 30'} 116 | ) 117 | print(Style.DIM) 118 | ff.run() 119 | print(Style.RESET_ALL) 120 | 121 | def fast_forward(inputV, outputV, speed): 122 | newSpeed = round(1/speed, 2) 123 | ff = ffmpy.FFmpeg( 124 | inputs={inputV: None}, 125 | outputs={outputV: f'-filter:a atempo={speed} -filter:v "setpts={newSpeed}*PTS" -vcodec libx264 -crf 30'} 126 | ) 127 | print(Style.DIM) 128 | ff.run() 129 | print(Style.RESET_ALL) 130 | 131 | async def check_refs_(ref, filename): 132 | print("Checking References") 133 | if ref.reference is not None: 134 | #print("running 2") 135 | messageid = ref.reference.message_id 136 | referenced = await ref.channel.fetch_message(messageid) 137 | #print("running 3") 138 | await downloadM_(referenced, f"{filename}") 139 | else: 140 | #print("running 2") 141 | await downloadM_(ref, f"{filename}") 142 | 143 | async def imgVidRefs(message): 144 | if message.reference != None: 145 | messageid = message.reference.message_id 146 | referenced = await message.channel.fetch_message(messageid) 147 | return referenced 148 | else: 149 | if get_attach(message) != 0: 150 | referenced = message 151 | return referenced 152 | else: 153 | await message.reply("Sorry! No reference!") 154 | raise Exception("No references detected") 155 | 156 | 157 | async def video_crefs(ref,filename,duration=210): 158 | await check_refs_(ref,filename) 159 | checkLength(filename, duration) 160 | 161 | def checkLength(filename, duration=210): 162 | MovieClip = moviepy.editor.VideoFileClip(f"static/created/{filename}") 163 | if int(MovieClip.duration) > duration: 164 | raise Exception(f"Video over {duration} seconds") 165 | return MovieClip 166 | 167 | 168 | async def upvDownv(bot, ud, message): 169 | downvote = bot.get_emoji(776162465842200617) 170 | upvote = bot.get_emoji(776161705960931399) 171 | try: 172 | await ud.add_reaction(upvote) 173 | await ud.add_reaction(downvote) 174 | except Exception as e: 175 | print(exit) 176 | await message.reply("no") 177 | clutter() 178 | 179 | 180 | # ------------------ IMAGE MANIPULATION ------------------- 181 | 182 | # TODO: VIRGIN VS CHAD MEME TEMPLATE 183 | 184 | def image_text(img, title_text, x, y, font_size,ext="png", color=(237, 230, 211), font='static/fonts/arial-black.ttf'): 185 | my_image = Image.open(f"static/{img}.{ext}") 186 | title_font = ImageFont.truetype(font, font_size) # can make further robust and change fonts if needed 187 | image_editable = ImageDraw.Draw(my_image) 188 | image_editable.text((x,y), title_text, color, font=title_font) 189 | my_image.save(f"static/created/{title_text}.{ext}") 190 | 191 | def alwaysHasBeen(title_text): 192 | # TODO: make location and stuff based on size, as well as breaking up txt into lines 193 | image_text("ahb",title_text, 400,175,15,"png") 194 | 195 | def mirror(user_disc): 196 | image_text("mirror", user_disc, 175,175,30,"jpg",(0,0,0)) 197 | 198 | # --------------------------------------------------------------- 199 | 200 | def get_attach(message): 201 | return message.attachments[0] 202 | 203 | def clutter(): 204 | for i in os.listdir('static/created'): 205 | if not i=='.gitkeep': 206 | os.remove('static/created/' + i) 207 | 208 | def add_top(img,caption): 209 | caption = caption.upper() 210 | print("loading image") 211 | current = Image.open(img) 212 | ch = current.height 213 | difference = current.height 214 | cw = current.width 215 | ch *= 1.2 216 | ch = int(ch) 217 | difference = ch - difference 218 | print(Fore.RED + Style.BRIGHT + "making new image 💄" + Style.RESET_ALL) 219 | top = Image.new('RGBA', (cw,ch), 'white') 220 | top.paste(current, (0,difference)) 221 | 222 | print("captioning") 223 | font_size = int(cw*0.085) 224 | font = ImageFont.truetype('static/fonts/impact.ttf', font_size) 225 | image_editable = ImageDraw.Draw(top) 226 | w,h = image_editable.textsize(caption, font=font) 227 | 228 | temp = cw / w 229 | temp *= 0.85 230 | font_size *= temp 231 | font_size = int(font_size) 232 | font = ImageFont.truetype('static/fonts/impact.ttf', font_size) 233 | w,h = image_editable.textsize(caption, font=font) 234 | 235 | if h > difference: 236 | hedit = h 237 | ch -= difference 238 | hedit += int(difference * 0.25) 239 | ch += hedit 240 | top = Image.new('RGBA', (cw,ch), 'white') 241 | font = ImageFont.truetype('static/fonts/impact.ttf', font_size) 242 | w,h = image_editable.textsize(caption, font=font) 243 | image_editable = ImageDraw.Draw(top) 244 | top.paste(current, (0,hedit)) 245 | difference = current.height 246 | difference = ch - difference 247 | 248 | image_editable.text(((cw - w)/2,(difference-h)/2), caption, (0,0,0), font=font) 249 | top.save(img, optimize=True) 250 | print("image created") 251 | 252 | async def downloadM_(referenced, filename): 253 | try: 254 | await get_attach(referenced).save(f"static/created/{filename}") 255 | print("attachment received") 256 | except: 257 | print(referenced.content) 258 | download_link(referenced, f"{filename}") 259 | print("Downloaded") 260 | return f"static/created/{filename}" 261 | 262 | 263 | # ------------------- DEEP FRY ------------------ 264 | 265 | def deepfryi(img): 266 | current = Image.open(img) 267 | current = current.filter(ImageFilter.UnsharpMask(radius=randint(5,20),percent=randint(105,550),threshold=randint(1,5))) 268 | layer = Image.new(current.mode, current.size, 'red') # "hue" selection is done by choosing a color... 269 | current = Image.blend(current, layer, 0.20) 270 | for i in range(2): 271 | current = current.filter(ImageFilter.UnsharpMask(radius=randint(5,25),percent=randint(105,550),threshold=randint(1,5))) 272 | current.save(img) 273 | 274 | class Images(commands.Cog): 275 | def __init__(self, bot): 276 | self.bot = bot 277 | self.upvote = self.bot.get_emoji(776161705960931399) 278 | self.downvote = self.bot.get_emoji(776162465842200617) 279 | 280 | @commands.Cog.listener() 281 | async def on_ready(self): 282 | print(Fore.MAGENTA + Style.BRIGHT + 'images.py is active' + Style.RESET_ALL) 283 | 284 | @commands.Cog.listener() 285 | async def on_message(self, message): 286 | downvote = self.bot.get_emoji(776162465842200617) 287 | upvote = self.bot.get_emoji(776161705960931399) 288 | 289 | # ----------- MIRROR MIRROR -------------------------- 290 | 291 | if "mirror mirror on the wall whos the upvotedest of them all" in message.content.lower(): 292 | basedCount = all_data.child('upvotecount').get() 293 | basedest = 0 294 | basedestp = "" 295 | for based_users in basedCount.items(): 296 | #await message.channel.send(based_users) 297 | user, count = based_users 298 | thePerson = self.bot.get_user(int(user)) 299 | if thePerson in message.guild.members: 300 | if count > basedest: 301 | basedest = count 302 | basedestp = thePerson 303 | #await message.channel.send(f"{basedest}, {basedestp}") 304 | user = str(basedestp.name) + '#' + str(basedestp.discriminator) 305 | mirror(user) 306 | ud = await message.reply(file=discord.File(f"static/created/{user}.jpg")) 307 | await ud.add_reaction(upvote) 308 | await ud.add_reaction(downvote) 309 | os.remove(f"static/created/{user}.jpg") 310 | return 311 | 312 | if "mirror mirror on the wall whos the basedest of them all" in message.content.lower(): 313 | basedCount = all_data.child('basedcount').get() 314 | basedest = 0 315 | basedestp = "" 316 | for based_users in basedCount.items(): 317 | #await message.channel.send(based_users) 318 | user, count = based_users 319 | thePerson = self.bot.get_user(int(user)) 320 | if thePerson in message.guild.members: 321 | if count > basedest: 322 | basedest = count 323 | basedestp = thePerson 324 | #await message.channel.send(f"{basedest}, {basedestp}") 325 | user = str(basedestp.name) + '#' + str(basedestp.discriminator) 326 | mirror(user) 327 | ud = await message.reply(file=discord.File(f"static/created/{user}.jpg")) 328 | await ud.add_reaction(upvote) 329 | await ud.add_reaction(downvote) 330 | os.remove(f"static/created/{user}.jpg") 331 | return 332 | 333 | if "mirror mirror on the wall who" in message.content.lower(): 334 | server = message.guild 335 | all_members = server.members 336 | member = random.choice(all_members) 337 | user = str(member.name) + '#' + str(member.discriminator) 338 | mirror(user) 339 | ud = await message.reply(file=discord.File(f"static/created/{user}.jpg")) 340 | await ud.add_reaction(upvote) 341 | await ud.add_reaction(downvote) 342 | os.remove(f"static/created/{user}.jpg") 343 | 344 | 345 | # ----------------------------------------------------------------- 346 | 347 | if message.reference != None: # if message has reference 348 | messageid = message.reference.message_id 349 | referenced = await message.channel.fetch_message(messageid) 350 | 351 | # --------------- ALWAYS HAS BEEN --------------------------- 352 | 353 | if "always has been" in message.content.lower(): 354 | content = referenced.content 355 | alwaysHasBeen(content) 356 | ud = await message.reply(file=discord.File(f"static/created/{content}.png")) 357 | await ud.add_reaction(upvote) 358 | await ud.add_reaction(downvote) 359 | os.remove(f"static/created/{content}.jpg") 360 | 361 | 362 | 363 | @commands.command() 364 | async def av(self,ctx, member: Member=None): 365 | await ctx.message.add_reaction("✅") 366 | if member == None: 367 | member = ctx.author 368 | await ctx.channel.send(member.avatar_url) 369 | 370 | @commands.command() 371 | async def deepfry(self, ctx, repeat=1): 372 | await ctx.message.add_reaction("✅") 373 | df_ID = gen_ID(4) # deepfry ID 374 | df_ID = str(df_ID) + '-' 375 | try: 376 | repeat = int(repeat) 377 | except: 378 | await ctx.reply("Command paramaters used incorrectly.") 379 | referenced = await imgVidRefs(ctx.message) 380 | print(Fore.RED + Style.BRIGHT+"\n---------------\n"+Style.RESET_ALL) 381 | print(Style.BRIGHT+f"Call me McDonalds cuz be be deep fryin this mf {repeat} times"+Style.RESET_ALL) 382 | # check -- is this an image? can I download it? 383 | if is_image(referenced): 384 | if repeat > 20: repeat = 20 # set 20 as the deepfry limit 385 | await downloadM_(referenced, f"deepfry{df_ID}.png") 386 | for i in range(repeat): 387 | deepfryi(f"static/created/deepfry{df_ID}.png") 388 | print(Style.DIM+ f"deepfried it {i+1} times bestie" + Style.RESET_ALL) 389 | print(Fore.YELLOW + Style.BRIGHT + "sending image ⏳"+ Style.RESET_ALL) 390 | ud = await ctx.reply(file=discord.File(f"static/created/deepfry{df_ID}.png")) 391 | print(Fore.GREEN + Style.BRIGHT + "complete ✔︎ " + Style.RESET_ALL) 392 | elif is_video(referenced): 393 | if repeat > 4: repeat = 4 # set 4 as the deepfry limit 394 | await downloadM_(referenced, f"deepfried{df_ID}0.mp4") # downloads video 395 | try: 396 | checkLength(f"deepfried{df_ID}0.mp4",60) # throws exception if video is too long 397 | except Exception as e: 398 | print(e) 399 | await ctx.send(e) 400 | return 401 | for i in range(repeat): 402 | deepfryv(f"static/created/deepfried{df_ID}{i}.mp4", i, df_ID) 403 | print(Style.DIM+ f"deepfried it {i+1} times bestie" + Style.RESET_ALL) 404 | print(Fore.YELLOW + Style.BRIGHT + "sending video ⏳"+ Style.RESET_ALL) 405 | ud = await ctx.reply(file=discord.File(f"static/created/deepfried{df_ID}{repeat}.mp4")) 406 | print(Fore.GREEN + Style.BRIGHT + "complete ✔︎ " + Style.RESET_ALL) 407 | await upvDownv(self.bot,ud,ctx.message) 408 | 409 | 410 | @commands.command(aliases=["caption:"]) 411 | async def caption(self, ctx, *, caption): 412 | await ctx.message.add_reaction("✅") 413 | # if message has reference -- no reference no caption 414 | caption = caption.upper() 415 | referenced = await imgVidRefs(ctx.message) 416 | print(Fore.RED + Style.BRIGHT+"\n---------------\n"+Style.RESET_ALL) 417 | print(Fore.YELLOW + Style.BRIGHT + "downloading attachment ⏳" + Style.RESET_ALL) 418 | 419 | # is this an image? can I download it? 420 | if is_image(referenced): 421 | await downloadM_(referenced, f"{caption[:2]}.png") 422 | # ok, caption this image lol 423 | add_top(f"static/created/{caption[:2]}.png",caption) 424 | print(Fore.YELLOW + Style.BRIGHT + "sending image ⏳"+ Style.RESET_ALL) 425 | ud = await ctx.reply(file=discord.File(f"static/created/{caption[:2]}.png")) 426 | print(Fore.GREEN + Style.BRIGHT + "complete ✔︎ " + Style.RESET_ALL) 427 | 428 | # is this a video? can I download it? 429 | elif is_video(referenced): 430 | await downloadM_(referenced, f"{caption[:2]}.mp4") 431 | captionClip = checkLength(f"{caption[:2]}.mp4",60) # throws exception if video is too long 432 | add_topv(f"static/created/{caption[:2]}.mp4",caption,captionClip.w,captionClip.h) 433 | print(Fore.YELLOW + Style.BRIGHT + "sending video ⏳"+ Style.RESET_ALL) 434 | ud = await ctx.reply(file=discord.File(f"static/created/captioned.mp4")) 435 | print(Fore.GREEN + Style.BRIGHT + "complete ✔︎ " + Style.RESET_ALL) 436 | await upvDownv(self.bot, ud, ctx.message) 437 | 438 | @commands.command(name="convert") 439 | async def convert(self, ctx, link=None, *, theRest=" "): 440 | await ctx.message.add_reaction("✅") 441 | clutter() 442 | # logging 443 | print(Fore.RED + Style.BRIGHT+"\n---------------\n"+Style.RESET_ALL) 444 | print(Fore.YELLOW + Style.BRIGHT + "downloading attachment ⏳" + Style.RESET_ALL) 445 | # download 446 | await video_crefs(ctx.message, f"convert.mp4") 447 | converting_ffmpy("static/created/convert.mp4", "static/created/converted.mp4") 448 | # send vid 449 | print(Fore.YELLOW + Style.BRIGHT + "sending video ⏳"+ Style.RESET_ALL) 450 | ud = await ctx.reply(f"{theRest} ", file=discord.File(f"static/created/converted.mp4")) 451 | print(Fore.GREEN + Style.BRIGHT + "complete ✔︎ " + Style.RESET_ALL) 452 | await upvDownv(self.bot, ud, ctx.message) 453 | 454 | @commands.command(name="speed") 455 | async def speed(self,ctx, spd, link=None): 456 | await ctx.message.add_reaction("✅") 457 | id_ = gen_ID(4) 458 | spd = float(spd) 459 | clutter() 460 | # logging 461 | print(Fore.RED + Style.BRIGHT+"\n---------------\n"+Style.RESET_ALL) 462 | print(Fore.YELLOW + Style.BRIGHT + "downloading attachment ⏳" + Style.RESET_ALL) 463 | # download 464 | try: 465 | await video_crefs(ctx.message, f"spd{id_}.mp4") 466 | except Exception as e: 467 | print(e) 468 | await ctx.reply("sorry bestie, but that video is over 210 seconds. I won't do it") 469 | return 470 | fast_forward(f"static/created/spd{id_}.mp4",f"static/created/newSpeed{id_}.mp4",spd) 471 | print(Fore.YELLOW + Style.BRIGHT + "sending video ⏳"+ Style.RESET_ALL) 472 | ud = await ctx.reply(file=discord.File(f"static/created/newSpeed{id_}.mp4")) 473 | print(Fore.GREEN + Style.BRIGHT + "complete ✔︎ " + Style.RESET_ALL) 474 | await upvDownv(self.bot,ud,ctx.message) 475 | 476 | @commands.command(name="layered") 477 | async def layered(self,ctx, commands, link=None): 478 | await ctx.message.add_reaction("✅") 479 | pass 480 | 481 | 482 | def setup(bot): 483 | bot.add_cog(Images(bot)) 484 | -------------------------------------------------------------------------------- /cogs/loadcogs.py: -------------------------------------------------------------------------------- 1 | # loadcogs.py 2 | import discord, random, os 3 | from discord.ext import commands 4 | 5 | import colorama 6 | from colorama import Fore 7 | from colorama import Style 8 | 9 | class LoadCogs(commands.Cog): 10 | def __init__(self, bot): 11 | self.bot = bot 12 | 13 | @commands.Cog.listener() 14 | async def on_ready(self): 15 | print(Fore.WHITE + Style.BRIGHT +'loadcogs.py is active' + Style.RESET_ALL) 16 | 17 | @commands.Cog.listener() 18 | async def load(self, ctx): 19 | for filename in os.listdir('./cogs'): 20 | if filename.endswith('.py'): 21 | self.bot.load_extension(f'cogs.{filename[:-3]}') 22 | 23 | @commands.Cog.listener() 24 | async def unload(self, ctx): 25 | for filename in os.listdir('./cogs'): 26 | if filename.endswith('.py'): 27 | self.bot.unload_extension(f'cogs.{filename[:-3]}') 28 | 29 | @commands.Cog.listener() 30 | async def reload(self,ctx): 31 | for filename in os.listdir('./cogs'): 32 | if filename.endswith('.py'): 33 | self.bot.unload_extension(f'cogs.{filename[:-3]}') 34 | self.bot.load_extension(f'cogs.{filename[:-3]}') 35 | 36 | 37 | def setup(bot): 38 | bot.add_cog(LoadCogs(bot)) 39 | -------------------------------------------------------------------------------- /insults.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/insults.txt -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.6.2 2 | async-timeout==3.0.1 3 | attrs==19.3.0 4 | blis==0.4.1 5 | boto==2.49.0 6 | CacheControl==0.12.6 7 | cached-property==1.5.1 8 | cachetools==4.1.0 9 | catalogue==1.0.0 10 | certifi==2020.4.5.1 11 | cffi==1.14.0 12 | chardet==3.0.4 13 | colorama==0.4.4 14 | cymem==2.0.3 15 | decorator==4.4.2 16 | dill==0.2.9 17 | discord.py==1.6.0 18 | dnspython==1.16.0 19 | ffmpy==0.3.0 20 | future==0.16.0 21 | google-api-core==2.2.2 22 | google-auth==1.35.0 23 | google-auth-httplib2==0.1.0 24 | google-cloud-core==0.27.1 25 | google-cloud-firestore==0.27.0 26 | google-cloud-storage==1.5.0 27 | google-crc32c==1.3.0 28 | google-gax==0.15.16 29 | google-resumable-media==2.1.0 30 | googleapis-common-protos==1.53.0 31 | grpcio==1.28.1 32 | httplib2==0.17.1 33 | idna==2.9 34 | imageio==2.9.0 35 | imageio-ffmpeg==0.4.3 36 | importlib-metadata==1.6.1 37 | inflection==0.5.0 38 | more-itertools==8.4.0 39 | moviepy==1.0.3 40 | msgpack==1.0.0 41 | multidict==4.7.5 42 | murmurhash==1.0.2 43 | numpy==1.19.0 44 | ordered-set==3.1.1 45 | ordered-set-stubs==0.1.3 46 | Pillow==8.2.0 47 | plac==1.1.3 48 | ply==3.8 49 | poetry-version==0.1.5 50 | preshed==3.0.2 51 | profanityfilter==2.0.6 52 | proglog==0.1.9 53 | protobuf==3.19.1 54 | pyasn1==0.4.8 55 | pyasn1-modules==0.2.8 56 | pycparser==2.20 57 | pydantic==1.5.1 58 | PyNaCl==1.3.0 59 | python-dotenv==0.12.0 60 | python-firebase==1.2 61 | pytz==2019.3 62 | redis==3.5.3 63 | redvid==1.1.3 64 | requests==2.23.0 65 | rsa==4.0 66 | six==1.14.0 67 | tinytag==1.7.0 68 | tomlkit==0.5.11 69 | tqdm==4.46.1 70 | urllib3==1.25.8 71 | yarl==1.4.2 72 | youtube-dl==2021.12.17 73 | zipp==3.1.0 74 | -------------------------------------------------------------------------------- /savescript: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "$0")" 4 | 5 | read -p 'commit name: ' commit 6 | 7 | if [ -z "$commit" ] 8 | then 9 | commit="autosave" 10 | fi 11 | git commit -am $commit 12 | 13 | output=$(git remote) 14 | pusharray=($output) 15 | 16 | for i in ${pusharray[@]}; do 17 | git push $i master 18 | done 19 | -------------------------------------------------------------------------------- /static/ahb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/ahb.png -------------------------------------------------------------------------------- /static/created/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/created/.gitkeep -------------------------------------------------------------------------------- /static/download/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/download/.gitkeep -------------------------------------------------------------------------------- /static/fonts/Impacted.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/fonts/Impacted.ttf -------------------------------------------------------------------------------- /static/fonts/arial-black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/fonts/arial-black.ttf -------------------------------------------------------------------------------- /static/fonts/impact.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/fonts/impact.ttf -------------------------------------------------------------------------------- /static/fonts/unicode.impact.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/fonts/unicode.impact.ttf -------------------------------------------------------------------------------- /static/mirror.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daminals/mee7/d6c67534696710d126bb40fed689398f5096b6f1/static/mirror.jpg --------------------------------------------------------------------------------