· 6 years ago · Feb 06, 2020, 11:54 PM
1import asyncio, aiohttp, discord
2import aalib
3import os, sys, linecache, traceback, glob
4import re, json, random, math, html
5import wand, wand.color, wand.drawing
6import PIL, PIL.Image, PIL.ImageFont, PIL.ImageOps, PIL.ImageDraw
7import numpy as np
8import cairosvg, jpglitch, urbandict
9import pixelsort.sorter, pixelsort.sorting, pixelsort.util, pixelsort.interval
10import hashlib, base64
11from vw import macintoshplus
12from urllib.parse import parse_qs
13from lxml import etree
14from imgurpython import ImgurClient
15from io import BytesIO, StringIO
16from discord.ext import commands
17from utils import checks
18from pyfiglet import figlet_format
19from string import ascii_lowercase as alphabet
20from urllib.parse import quote
21from mods.cog import Cog
22from concurrent.futures._base import CancelledError
23
24code = "```py\n{0}\n```"
25
26#http://stackoverflow.com/a/34084933
27#for google_scrap
28def get_deep_text(element):
29 try:
30 text = element.text or ''
31 for subelement in element:
32 text += get_deep_text(subelement)
33 text += element.tail or ''
34 return text
35 except:
36 return ''
37
38def posnum(num):
39 if num < 0 :
40 return - (num)
41 else:
42 return num
43
44def find_coeffs(pa, pb):
45 matrix = []
46 for p1, p2 in zip(pa, pb):
47 matrix.append([p1[0], p1[1], 1, 0, 0, 0, -p2[0]*p1[0], -p2[0]*p1[1]])
48 matrix.append([0, 0, 0, p1[0], p1[1], 1, -p2[1]*p1[0], -p2[1]*p1[1]])
49 A = np.matrix(matrix, dtype=np.float)
50 B = np.array(pb).reshape(8)
51 res = np.dot(np.linalg.inv(A.T*A)*A.T, B)
52 return np.array(res).reshape(8)
53
54class Fun(Cog):
55 def __init__(self, bot):
56 super().__init__(bot)
57 self.discord_path = bot.path.discord
58 self.files_path = bot.path.files
59 self.download = bot.download
60 self.bytes_download = bot.bytes_download
61 self.isimage = bot.isimage
62 self.isgif = bot.isgif
63 self.get_json = bot.get_json
64 self.truncate = bot.truncate
65 self.get_images = bot.get_images
66 self.escape = bot.escape
67 self.cursor = bot.mysql.cursor
68 self.get_text = bot.get_text
69 self.is_nsfw = bot.funcs.is_nsfw
70 try:
71 self.imgur_client = ImgurClient("", "")
72 except:
73 bot.remove_command('imgur')
74 self.image_cache = {}
75 self.search_cache = {}
76 self.youtube_cache = {}
77 self.twitch_cache = []
78 self.api_count = 0
79 self.emojis = {"soccer": "⚽", "basketball": "?", "football": "?", "baseball": "⚾", "tennis": "?", "volleyball": "?", "rugby_football": "?", "8ball": "?", "golf": "⛳", "golfer": "?", "ping_pong": "?", "badminton": "?", "hockey": "?", "field_hockey": "?", "cricket": "?", "ski": "?", "skier": "⛷", "snowboarder": "?", "ice_skate": "⛸", "bow_and_arrow": "?", "fishing_pole_and_fish": "?", "rowboat": "?", "swimmer": "?", "surfer": "?", "bath": "?", "basketball_player": "⛹", "lifter": "?", "bicyclist": "?", "mountain_bicyclist": "?", "horse_racing": "?", "levitate": "?", "trophy": "?", "running_shirt_with_sash": "?", "medal": "?", "military_medal": "?", "reminder_ribbon": "?", "rosette": "?", "ticket": "?", "tickets": "?", "performing_arts": "?", "art": "?", "circus_tent": "?", "microphone": "?", "headphones": "?", "musical_score": "?", "musical_keyboard": "?", "saxophone": "?", "trumpet": "?", "guitar": "?", "violin": "?", "clapper": "?", "video_game": "?", "space_invader": "?", "dart": "?", "game_die": "?", "slot_machine": "?", "bowling": "?", "♡": "heart", "green_apple": "?", "apple": "?", "pear": "?", "tangerine": "?", "lemon": "?", "banana": "?", "watermelon": "?", "grapes": "?", "strawberry": "?", "melon": "?", "cherries": "?", "peach": "?", "pineapple": "?", "tomato": "?", "eggplant": "?", "hot_pepper": "?", "corn": "?", "sweet_potato": "?", "honey_pot": "?", "bread": "?", "cheese": "?", "poultry_leg": "?", "meat_on_bone": "?", "fried_shrimp": "?", "egg": "?", "cooking": "?", "hamburger": "?", "fries": "?", "hotdog": "?", "pizza": "?", "spaghetti": "?", "taco": "?", "burrito": "?", "ramen": "?", "stew": "?", "fish_cake": "?", "sushi": "?", "bento": "?", "curry": "?", "rice_ball": "?", "rice": "?", "rice_cracker": "?", "oden": "?", "dango": "?", "shaved_ice": "?", "ice_cream": "?", "icecream": "?", "cake": "?", "birthday": "?", "custard": "?", "candy": "?", "lollipop": "?", "chocolate_bar": "?", "popcorn": "?", "doughnut": "?", "cookie": "?", "beer": "?", "beers": "?", "wine_glass": "?", "cocktail": "?", "tropical_drink": "?", "champagne": "?", "sake": "?", "tea": "?", "coffee": "☕", "baby_bottle": "?", "fork_and_knife": "?", "fork_knife_plate": "?", "dog": "?", "cat": "?", "mouse": "?", "hamster": "?", "rabbit": "?", "bear": "?", "panda_face": "?", "koala": "?", "tiger": "?", "lion_face": "?", "cow": "?", "pig": "?", "pig_nose": "?", "frog": "?", "octopus": "?", "monkey_face": "?", "see_no_evil": "?", "hear_no_evil": "?", "speak_no_evil": "?", "monkey": "?", "chicken": "?", "penguin": "?", "bird": "?", "baby_chick": "?", "hatching_chick": "?", "hatched_chick": "?", "wolf": "?", "boar": "?", "horse": "?", "unicorn": "?", "bee": "?", "honeybee": "?", "bug": "?", "snail": "?", "beetle": "?", "ant": "?", "spider": "?", "scorpion": "?", "crab": "?", "snake": "?", "turtle": "?", "tropical_fish": "?", "fish": "?", "blowfish": "?", "dolphin": "?", "flipper": "?", "whale": "?", "whale2": "?", "crocodile": "?", "leopard": "?", "tiger2": "?", "water_buffalo": "?", "ox": "?", "cow2": "?", "dromedary_camel": "?", "camel": "?", "elephant": "?", "goat": "?", "ram": "?", "sheep": "?", "racehorse": "?", "pig2": "?", "rat": "?", "mouse2": "?", "rooster": "?", "turkey": "?", "dove": "?", "dog2": "?", "poodle": "?", "cat2": "?", "rabbit2": "?", "chipmunk": "?", "feet": "?", "paw_prints": "?", "dragon": "?", "dragon_face": "?", "cactus": "?", "christmas_tree": "?", "evergreen_tree": "?", "deciduous_tree": "?", "palm_tree": "?", "seedling": "?", "herb": "?", "shamrock": "☘", "four_leaf_clover": "?", "bamboo": "?", "tanabata_tree": "?", "leaves": "?", "fallen_leaf": "?", "maple_leaf": "?", "ear_of_rice": "?", "hibiscus": "?", "sunflower": "?", "rose": "?", "tulip": "?", "blossom": "?", "cherry_blossom": "?", "bouquet": "?", "mushroom": "?", "chestnut": "?", "jack_o_lantern": "?", "shell": "?", "spider_web": "?", "earth_americas": "?", "earth_africa": "?", "earth_asia": "?", "full_moon": "?", "waning_gibbous_moon": "?", "last_quarter_moon": "?", "waning_crescent_moon": "?", "new_moon": "?", "waxing_crescent_moon": "?", "first_quarter_moon": "?", "waxing_gibbous_moon": "?", "moon": "?", "new_moon_with_face": "?", "full_moon_with_face": "?", "first_quarter_moon_with_face": "?", "last_quarter_moon_with_face": "?", "sun_with_face": "?", "crescent_moon": "?", "star": "⭐", "star2": "?", "dizzy": "?", "sparkles": "✨", "comet": "☄", "sunny": "☀", "white_sun_small_cloud": "?", "partly_sunny": "⛅", "white_sun_cloud": "?", "white_sun_rain_cloud": "?", "cloud": "☁", "cloud_rain": "?", "thunder_cloud_rain": "⛈", "cloud_lightning": "?", "zap": "⚡", "fire": "?", "boom": "?", "collision": "?", "snowflake": "❄", "cloud_snow": "?", "snowman2": "☃", "snowman": "⛄", "wind_blowing_face": "?", "dash": "?", "cloud_tornado": "?", "fog": "?", "umbrella2": "☂", "umbrella": "☔", "droplet": "?", "sweat_drops": "?", "ocean": "?", "watch": "⌚", "iphone": "?", "calling": "?", "computer": "?", "keyboard": "⌨", "desktop": "?", "printer": "?", "mouse_three_button": "?", "trackball": "?", "joystick": "?", "compression": "?", "minidisc": "?", "floppy_disk": "?", "cd": "?", "dvd": "?", "vhs": "?", "camera": "?", "camera_with_flash": "?", "video_camera": "?", "movie_camera": "?", "projector": "?", "film_frames": "?", "telephone_receiver": "?", "telephone": "☎", "phone": "☎", "pager": "?", "fax": "?", "tv": "?", "radio": "?", "microphone2": "?", "level_slider": "?", "control_knobs": "?", "stopwatch": "⏱", "timer": "⏲", "alarm_clock": "⏰", "clock": "?", "hourglass_flowing_sand": "⏳", "hourglass": "⌛", "satellite": "?", "battery": "?", "electric_plug": "?", "bulb": "?", "flashlight": "?", "candle": "?", "wastebasket": "?", "oil": "?", "money_with_wings": "?", "dollar": "?", "yen": "?", "euro": "?", "pound": "?", "moneybag": "?", "credit_card": "?", "gem": "?", "scales": "⚖", "wrench": "?", "hammer": "?", "hammer_pick": "⚒", "tools": "?", "pick": "⛏", "nut_and_bolt": "?", "gear": "⚙", "chains": "⛓", "gun": "?", "bomb": "?", "knife": "?", "hocho": "?", "dagger": "?", "crossed_swords": "⚔", "shield": "?", "smoking": "?", "skull_crossbones": "☠", "coffin": "⚰", "urn": "⚱", "amphora": "?", "crystal_ball": "?", "prayer_beads": "?", "barber": "?", "alembic": "⚗", "telescope": "?", "microscope": "?", "hole": "?", "pill": "?", "syringe": "?", "thermometer": "?", "label": "?", "bookmark": "?", "toilet": "?", "shower": "?", "bathtub": "?", "key": "?", "key2": "?", "couch": "?", "sleeping_accommodation": "?", "bed": "?", "door": "?", "bellhop": "?", "frame_photo": "?", "map": "?", "beach_umbrella": "⛱", "moyai": "?", "shopping_bags": "?", "balloon": "?", "flags": "?", "ribbon": "?", "gift": "?", "confetti_ball": "?", "tada": "?", "dolls": "?", "wind_chime": "?", "crossed_flags": "?", "izakaya_lantern": "?", "lantern": "?", "envelope": "✉", "email": "?", "envelope_with_arrow": "?", "incoming_envelope": "?", "love_letter": "?", "postbox": "?", "mailbox_closed": "?", "mailbox": "?", "mailbox_with_mail": "?", "mailbox_with_no_mail": "?", "package": "?", "postal_horn": "?", "inbox_tray": "?", "outbox_tray": "?", "scroll": "?", "page_with_curl": "?", "bookmark_tabs": "?", "bar_chart": "?", "chart_with_upwards_trend": "?", "chart_with_downwards_trend": "?", "page_facing_up": "?", "date": "?", "calendar": "?", "calendar_spiral": "?", "card_index": "?", "card_box": "?", "ballot_box": "?", "file_cabinet": "?", "clipboard": "?", "notepad_spiral": "?", "file_folder": "?", "open_file_folder": "?", "dividers": "?", "newspaper2": "?", "newspaper": "?", "notebook": "?", "closed_book": "?", "green_book": "?", "blue_book": "?", "orange_book": "?", "notebook_with_decorative_cover": "?", "ledger": "?", "books": "?", "book": "?", "open_book": "?", "link": "?", "paperclip": "?", "paperclips": "?", "scissors": "✂", "triangular_ruler": "?", "straight_ruler": "?", "pushpin": "?", "round_pushpin": "?", "triangular_flag_on_post": "?", "flag_white": "?", "flag_black": "?", "closed_lock_with_key": "?", "lock": "?", "unlock": "?", "lock_with_ink_pen": "?", "pen_ballpoint": "?", "pen_fountain": "?", "black_nib": "✒", "pencil": "?", "memo": "?", "pencil2": "✏", "crayon": "?", "paintbrush": "?", "mag": "?", "mag_right": "?", "grinning": "?", "grimacing": "?", "grin": "?", "joy": "?", "smiley": "?", "smile": "?", "sweat_smile": "?", "laughing": "?", "satisfied": "?", "innocent": "?", "wink": "?", "blush": "?", "slight_smile": "?", "upside_down": "?", "relaxed": "☺", "yum": "?", "relieved": "?", "heart_eyes": "?", "kissing_heart": "?", "kissing": "?", "kissing_smiling_eyes": "?", "kissing_closed_eyes": "?", "stuck_out_tongue_winking_eye": "?", "stuck_out_tongue_closed_eyes": "?", "stuck_out_tongue": "?", "money_mouth": "?", "nerd": "?", "sunglasses": "?", "hugging": "?", "smirk": "?", "no_mouth": "?", "neutral_face": "?", "expressionless": "?", "unamused": "?", "rolling_eyes": "?", "thinking": "?", "flushed": "?", "disappointed": "?", "worried": "?", "angry": "?", "rage": "?", "pensive": "?", "confused": "?", "slight_frown": "?", "frowning2": "☹", "persevere": "?", "confounded": "?", "tired_face": "?", "weary": "?", "triumph": "?", "open_mouth": "?", "scream": "?", "fearful": "?", "cold_sweat": "?", "hushed": "?", "frowning": "?", "anguished": "?", "cry": "?", "disappointed_relieved": "?", "sleepy": "?", "sweat": "?", "sob": "?", "dizzy_face": "?", "astonished": "?", "zipper_mouth": "?", "mask": "?", "thermometer_face": "?", "head_bandage": "?", "sleeping": "?", "zzz": "?", "poop": "?", "shit": "?", "smiling_imp": "?", "imp": "?", "japanese_ogre": "?", "japanese_goblin": "?", "skull": "?", "ghost": "?", "alien": "?", "robot": "?", "smiley_cat": "?", "smile_cat": "?", "joy_cat": "?", "heart_eyes_cat": "?", "smirk_cat": "?", "kissing_cat": "?", "scream_cat": "?", "crying_cat_face": "?", "pouting_cat": "?", "raised_hands": "?", "clap": "?", "wave": "?", "thumbsup": "?", "+1": "?", "thumbsdown": "?", "-1": "?", "punch": "?", "facepunch": "?", "fist": "✊", "v": "✌", "ok_hand": "?", "raised_hand": "✋", "hand": "✋", "open_hands": "?", "muscle": "?", "pray": "?", "point_up": "☝", "point_up_2": "?", "point_down": "?", "point_left": "?", "point_right": "?", "middle_finger": "?", "hand_splayed": "?", "metal": "?", "vulcan": "?", "writing_hand": "✍", "nail_care": "?", "lips": "?", "tongue": "?", "ear": "?", "nose": "?", "eye": "?", "eyes": "?", "bust_in_silhouette": "?", "busts_in_silhouette": "?", "speaking_head": "?", "baby": "?", "boy": "?", "girl": "?", "man": "?", "woman": "?", "person_with_blond_hair": "?", "older_man": "?", "older_woman": "?", "man_with_gua_pi_mao": "?", "man_with_turban": "?", "cop": "?", "construction_worker": "?", "guardsman": "?", "spy": "?", "santa": "?", "angel": "?", "princess": "?", "bride_with_veil": "?", "walking": "?", "runner": "?", "running": "?", "dancer": "?", "dancers": "?", "couple": "?", "two_men_holding_hands": "?", "two_women_holding_hands": "?", "bow": "?", "information_desk_person": "?", "no_good": "?", "ok_woman": "?", "raising_hand": "?", "person_with_pouting_face": "?", "person_frowning": "?", "haircut": "?", "massage": "?", "couple_with_heart": "?", "couple_ww": "?❤️?", "couple_mm": "?❤️?", "couplekiss": "?", "kiss_ww": "?❤️??", "kiss_mm": "?❤️??", "family": "?", "family_mwg": "???", "family_mwgb": "????", "family_mwbb": "????", "family_mwgg": "????", "family_wwb": "???", "family_wwg": "???", "family_wwgb": "????", "family_wwbb": "????", "family_wwgg": "????", "family_mmb": "???", "family_mmg": "???", "family_mmgb": "????", "family_mmbb": "????", "family_mmgg": "????", "womans_clothes": "?", "shirt": "?", "tshirt": "?", "jeans": "?", "necktie": "?", "dress": "?", "bikini": "?", "kimono": "?", "lipstick": "?", "kiss": "?", "footprints": "?", "high_heel": "?", "sandal": "?", "boot": "?", "mans_shoe": "?", "shoe": "?", "athletic_shoe": "?", "womans_hat": "?", "tophat": "?", "helmet_with_cross": "⛑", "mortar_board": "?", "crown": "?", "school_satchel": "?", "pouch": "?", "purse": "?", "handbag": "?", "briefcase": "?", "eyeglasses": "?", "dark_sunglasses": "?", "ring": "?", "closed_umbrella": "?", "100": "?", "1234": "?", "heart": "❤", "yellow_heart": "?", "green_heart": "?", "blue_heart": "?", "purple_heart": "?", "broken_heart": "?", "heart_exclamation": "❣", "two_hearts": "?", "revolving_hearts": "?", "heartbeat": "?", "heartpulse": "?", "sparkling_heart": "?", "cupid": "?", "gift_heart": "?", "heart_decoration": "?", "peace": "☮", "cross": "✝", "star_and_crescent": "☪", "om_symbol": "?", "wheel_of_dharma": "☸", "star_of_david": "✡", "six_pointed_star": "?", "menorah": "?", "yin_yang": "☯", "orthodox_cross": "☦", "place_of_worship": "?", "ophiuchus": "⛎", "aries": "♈", "taurus": "♉", "gemini": "♊", "cancer": "♋", "leo": "♌", "virgo": "♍", "libra": "♎", "scorpius": "♏", "sagittarius": "♐", "capricorn": "♑", "aquarius": "♒", "pisces": "♓", "id": "?", "atom": "⚛", "u7a7a": "?", "u5272": "?", "radioactive": "☢", "biohazard": "☣", "mobile_phone_off": "?", "vibration_mode": "?", "u6709": "?", "u7121": "?", "u7533": "?", "u55b6": "?", "u6708": "?", "eight_pointed_black_star": "✴", "vs": "?", "accept": "?", "white_flower": "?", "ideograph_advantage": "?", "secret": "㊙", "congratulations": "㊗", "u5408": "?", "u6e80": "?", "u7981": "?", "a": "?", "b": "?", "ab": "?", "cl": "?", "o2": "?", "sos": "?", "no_entry": "⛔", "name_badge": "?", "no_entry_sign": "?", "x": "❌", "o": "⭕", "anger": "?", "hotsprings": "♨", "no_pedestrians": "?", "do_not_litter": "?", "no_bicycles": "?", "non_potable_water": "?", "underage": "?", "no_mobile_phones": "?", "exclamation": "❗", "heavy_exclamation_mark": "❗", "grey_exclamation": "❕", "question": "❓", "grey_question": "❔", "bangbang": "‼", "interrobang": "⁉", "low_brightness": "?", "high_brightness": "?", "trident": "?", "fleur_de_lis": "⚜", "part_alternation_mark": "〽", "warning": "⚠", "children_crossing": "?", "beginner": "?", "recycle": "♻", "u6307": "?", "chart": "?", "sparkle": "❇", "eight_spoked_asterisk": "✳", "negative_squared_cross_mark": "❎", "white_check_mark": "✅", "diamond_shape_with_a_dot_inside": "?", "cyclone": "?", "loop": "➿", "globe_with_meridians": "?", "m": "Ⓜ", "atm": "?", "sa": "?", "passport_control": "?", "customs": "?", "baggage_claim": "?", "left_luggage": "?", "wheelchair": "♿", "no_smoking": "?", "wc": "?", "parking": "?", "potable_water": "?", "mens": "?", "womens": "?", "baby_symbol": "?", "restroom": "?", "put_litter_in_its_place": "?", "cinema": "?", "signal_strength": "?", "koko": "?", "ng": "?", "ok": "?", "up": "?", "cool": "?", "new": "?", "free": "?", "zero": "0⃣", "one": "1⃣", "two": "2⃣", "three": "3⃣", "four": "4⃣", "five": "5⃣", "six": "6⃣", "seven": "7⃣", "eight": "8⃣", "nine": "9⃣", "ten": "?","zero": "0⃣", "1": "1⃣", "2": "2⃣", "3": "3⃣", "4": "4⃣", "5": "5⃣", "6": "6⃣", "7": "7⃣", "8": "8⃣", "9": "9⃣", "10": "?", "keycap_ten": "?", "arrow_forward": "▶", "pause_button": "⏸", "play_pause": "⏯", "stop_button": "⏹", "record_button": "⏺", "track_next": "⏭", "track_previous": "⏮", "fast_forward": "⏩", "rewind": "⏪", "twisted_rightwards_arrows": "?", "repeat": "?", "repeat_one": "?", "arrow_backward": "◀", "arrow_up_small": "?", "arrow_down_small": "?", "arrow_double_up": "⏫", "arrow_double_down": "⏬", "arrow_right": "➡", "arrow_left": "⬅", "arrow_up": "⬆", "arrow_down": "⬇", "arrow_upper_right": "↗", "arrow_lower_right": "↘", "arrow_lower_left": "↙", "arrow_upper_left": "↖", "arrow_up_down": "↕", "left_right_arrow": "↔", "arrows_counterclockwise": "?", "arrow_right_hook": "↪", "leftwards_arrow_with_hook": "↩", "arrow_heading_up": "⤴", "arrow_heading_down": "⤵", "hash": "#⃣", "asterisk": "*⃣", "information_source": "ℹ", "abc": "?", "abcd": "?", "capital_abcd": "?", "symbols": "?", "musical_note": "?", "notes": "?", "wavy_dash": "〰", "curly_loop": "➰", "heavy_check_mark": "✔", "arrows_clockwise": "?", "heavy_plus_sign": "➕", "heavy_minus_sign": "➖", "heavy_division_sign": "➗", "heavy_multiplication_x": "✖", "heavy_dollar_sign": "?", "currency_exchange": "?", "copyright": "©", "registered": "®", "tm": "™", "end": "?", "back": "?", "on": "?", "top": "?", "soon": "?", "ballot_box_with_check": "☑", "radio_button": "?", "white_circle": "⚪", "black_circle": "⚫", "red_circle": "?", "large_blue_circle": "?", "small_orange_diamond": "?", "small_blue_diamond": "?", "large_orange_diamond": "?", "large_blue_diamond": "?", "small_red_triangle": "?", "black_small_square": "▪", "white_small_square": "▫", "black_large_square": "⬛", "white_large_square": "⬜", "small_red_triangle_down": "?", "black_medium_square": "◼", "white_medium_square": "◻", "black_medium_small_square": "◾", "white_medium_small_square": "◽", "black_square_button": "?", "white_square_button": "?", "speaker": "?", "sound": "?", "loud_sound": "?", "mute": "?", "mega": "?", "loudspeaker": "?", "bell": "?", "no_bell": "?", "black_joker": "?", "mahjong": "?", "spades": "♠", "clubs": "♣", "hearts": "♥", "diamonds": "♦", "flower_playing_cards": "?", "thought_balloon": "?", "anger_right": "?", "speech_balloon": "?", "clock1": "?", "clock2": "?", "clock3": "?", "clock4": "?", "clock5": "?", "clock6": "?", "clock7": "?", "clock8": "?", "clock9": "?", "clock10": "?", "clock11": "?", "clock12": "?", "clock130": "?", "clock230": "?", "clock330": "?", "clock430": "?", "clock530": "?", "clock630": "?", "clock730": "?", "clock830": "?", "clock930": "?", "clock1030": "?", "clock1130": "?", "clock1230": "?", "eye_in_speech_bubble": "??", "speech_left": "?", "eject": "⏏", "red_car": "?", "car": "?", "taxi": "?", "blue_car": "?", "bus": "?", "trolleybus": "?", "race_car": "?", "police_car": "?", "ambulance": "?", "fire_engine": "?", "minibus": "?", "truck": "?", "articulated_lorry": "?", "tractor": "?", "motorcycle": "?", "bike": "?", "rotating_light": "?", "oncoming_police_car": "?", "oncoming_bus": "?", "oncoming_automobile": "?", "oncoming_taxi": "?", "aerial_tramway": "?", "mountain_cableway": "?", "suspension_railway": "?", "railway_car": "?", "train": "?", "monorail": "?", "bullettrain_side": "?", "bullettrain_front": "?", "light_rail": "?", "mountain_railway": "?", "steam_locomotive": "?", "train2": "?", "metro": "?", "tram": "?", "station": "?", "helicopter": "?", "airplane_small": "?", "airplane": "✈", "airplane_departure": "?", "airplane_arriving": "?", "sailboat": "⛵", "boat": "⛵", "motorboat": "?", "speedboat": "?", "ferry": "⛴", "cruise_ship": "?", "rocket": "?", "satellite_orbital": "?", "seat": "?", "anchor": "⚓", "construction": "?", "fuelpump": "⛽", "busstop": "?", "vertical_traffic_light": "?", "traffic_light": "?", "checkered_flag": "?", "ship": "?", "ferris_wheel": "?", "roller_coaster": "?", "carousel_horse": "?", "construction_site": "?", "foggy": "?", "tokyo_tower": "?", "factory": "?", "fountain": "⛲", "rice_scene": "?", "mountain": "⛰", "mountain_snow": "?", "mount_fuji": "?", "volcano": "?", "japan": "?", "camping": "?", "tent": "⛺", "park": "?", "motorway": "?", "railway_track": "?", "sunrise": "?", "sunrise_over_mountains": "?", "desert": "?", "beach": "?", "island": "?", "city_sunset": "?", "city_sunrise": "?", "city_dusk": "?", "cityscape": "?", "night_with_stars": "?", "bridge_at_night": "?", "milky_way": "?", "stars": "?", "sparkler": "?", "fireworks": "?", "rainbow": "?", "homes": "?", "european_castle": "?", "japanese_castle": "?", "stadium": "?", "statue_of_liberty": "?", "house": "?", "house_with_garden": "?", "house_abandoned": "?", "office": "?", "department_store": "?", "post_office": "?", "european_post_office": "?", "hospital": "?", "bank": "?", "hotel": "?", "convenience_store": "?", "school": "?", "love_hotel": "?", "wedding": "?", "classical_building": "?", "church": "⛪", "mosque": "?", "synagogue": "?", "kaaba": "?", "shinto_shrine": "⛩"}
80 self.emoji_map = {"a": "", "b": "", "c": "©", "d": "↩", "e": "", "f": "", "g": "⛽", "h": "♓", "i": "ℹ", "j": "" or "", "k": "", "l": "", "m": "Ⓜ", "n": "♑", "o": "⭕" or "", "p": "", "q": "", "r": "®", "s": "" or "⚡", "t": "", "u": "⛎", "v": "" or "♈", "w": "〰" or "", "x": "❌" or "⚔", "y": "✌", "z": "Ⓩ", "1": "1⃣", "2": "2⃣", "3": "3⃣", "4": "4⃣", "5": "5⃣", "6": "6⃣", "7": "7⃣", "8": "8⃣", "9": "9⃣", "0": "0⃣", "$": "", "!": "❗", "?": "❓", " ": " "}
81 self.regional_map = {"z": "?", "y": "?", "x": "?", "w": "?", "v": "?", "u": "?", "t": "?", "s": "?", "r": "?", "q": "?", "p": "?", "o": "?", "n": "?", "m": "?", "l": "?", "k": "?", "j": "?", "i": "?", "h": "?", "g": "?", "f": "?", "e": "?", "d": "?", "c": "?", "b": "?", "a": "?"}
82 self.emote_regex = re.compile(r'<:.*:(?P<id>\d*)>')
83 self.retro_regex = re.compile(r"((https)(\:\/\/|)?u3\.photofunia\.com\/.\/results\/.\/.\/.*(\.jpg\?download))")
84 self.voice_list = ['`Allison - English/US (Expressive)`', '`Michael - English/US`', '`Lisa - English/US`', '`Kate - English/UK`', '`Renee - French/FR`', '`Birgit - German/DE`', '`Dieter - German/DE`', '`Francesca - Italian/IT`', '`Emi - Japanese/JP`', '`Isabela - Portuguese/BR`', '`Enrique - Spanish`', '`Laura - Spanish`', '`Sofia - Spanish/NA`']
85 self.scrap_regex = re.compile(",\"ou\":\"([^`]*?)\"")
86 self.google_keys = bot.google_keys
87 self.interval_functions = {"random": pixelsort.interval.random, "threshold": pixelsort.interval.threshold, "edges": pixelsort.interval.edge, "waves": pixelsort.interval.waves, "file": pixelsort.interval.file_mask, "file-edges": pixelsort.interval.file_edges, "none": pixelsort.interval.none}
88 self.s_functions = {"lightness": pixelsort.sorting.lightness, "intensity": pixelsort.sorting.intensity, "maximum": pixelsort.sorting.maximum, "minimum": pixelsort.sorting.minimum}
89 self.webmd_responses = ['redacted']
90 self.webmd_count = random.randint(0, len(self.webmd_responses)-1)
91 self.color_combinations = [[150, 50, -25], [135, 30, -10], [100, 50, -15], [75, 25, -15], [35, 20, -25], [0, 20, 0], [-25, 45, 35], [-25, 45, 65], [-45, 70, 75], [-65, 100, 135], [-45, 90, 100], [-10, 40, 70], [25, 25, 50], [65, 10, 10], [100, 25, 0], [135, 35, -10]]
92 self.fp_dir = os.listdir(self.files_path('fp/'))
93 self.more_cache = {}
94
95 async def gist(self, ctx, idk, content:str):
96 payload = {
97 'name': 'NotSoBot - By: {0}.'.format(ctx.message.author),
98 'title': 'ASCII for text: "{0}"'.format(idk),
99 'text': content,
100 'private': '1',
101 'lang': 'python',
102 'expire': '0'
103 }
104 with aiohttp.ClientSession() as session:
105 async with session.post('https://spit.mixtape.moe/api/create', data=payload) as r:
106 url = await r.text()
107 await self.bot.say('Uploaded to paste, URL: <{0}>'.format(url))
108
109 @commands.command(pass_context=True)
110 @commands.cooldown(1, 3)
111 async def badmeme(self, ctx, direct=None):
112 """returns bad meme (shit api)"""
113 load = await self.get_json("https://api.imgflip.com/get_memes")
114 url = random.choice(load['data']['memes'])
115 url = url['url']
116 if direct:
117 await self.bot.say(url)
118 else:
119 b = await self.bytes_download(url)
120 await self.bot.upload(b, filename='badmeme.png')
121
122 def do_magik(self, scale, *imgs):
123 try:
124 list_imgs = []
125 exif = {}
126 exif_msg = ''
127 count = 0
128 for img in imgs:
129 i = wand.image.Image(file=img)
130 i.format = 'jpg'
131 i.alpha_channel = True
132 if i.size >= (3000, 3000):
133 return ':warning: `Image exceeds maximum resolution >= (3000, 3000).`', None
134 exif.update({count:(k[5:], v) for k, v in i.metadata.items() if k.startswith('exif:')})
135 count += 1
136 i.transform(resize='800x800>')
137 i.liquid_rescale(width=int(i.width * 0.5), height=int(i.height * 0.5), delta_x=int(0.5 * scale) if scale else 1, rigidity=0)
138 i.liquid_rescale(width=int(i.width * 1.5), height=int(i.height * 1.5), delta_x=scale if scale else 2, rigidity=0)
139 magikd = BytesIO()
140 i.save(file=magikd)
141 magikd.seek(0)
142 list_imgs.append(magikd)
143 if len(list_imgs) > 1:
144 imgs = [PIL.Image.open(i).convert('RGBA') for i in list_imgs]
145 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
146 imgs_comb = np.hstack((np.asarray(i.resize(min_shape)) for i in imgs))
147 imgs_comb = PIL.Image.fromarray(imgs_comb)
148 ya = BytesIO()
149 imgs_comb.save(ya, 'png')
150 ya.seek(0)
151 elif not len(list_imgs):
152 return ':warning: **Command download function failed...**', None
153 else:
154 ya = list_imgs[0]
155 for x in exif:
156 if len(exif[x]) >= 2000:
157 continue
158 exif_msg += '**Exif data for image #{0}**\n'.format(str(x+1))+code.format(exif[x])
159 else:
160 if len(exif_msg) == 0:
161 exif_msg = None
162 return ya, exif_msg
163 except Exception as e:
164 return str(e), None
165
166 @commands.command(pass_context=True, aliases=['imagemagic', 'imagemagick', 'magic', 'magick', 'cas', 'liquid'])
167 @commands.cooldown(2, 5, commands.BucketType.user)
168 async def magik(self, ctx, *urls:str):
169 """Apply magik to Image(s)\n .magik image_url or .magik image_url image_url_2"""
170 try:
171 get_images = await self.get_images(ctx, urls=urls, limit=6, scale=5)
172 if not get_images:
173 return
174 img_urls = get_images[0]
175 scale = get_images[1]
176 scale_msg = get_images[2]
177 if scale_msg is None:
178 scale_msg = ''
179 msg = await self.bot.send_message(ctx.message.channel, "ok, processing")
180 list_imgs = []
181 for url in img_urls:
182 b = await self.bytes_download(url)
183 if b is False:
184 if len(img_urls) > 1:
185 await self.bot.say(':warning: **Command download function failed...**')
186 return
187 continue
188 list_imgs.append(b)
189 final, content_msg = await self.bot.loop.run_in_executor(None, self.do_magik, scale, *list_imgs)
190 if type(final) == str:
191 await self.bot.say(final)
192 return
193 if content_msg is None:
194 content_msg = scale_msg
195 else:
196 content_msg = scale_msg+content_msg
197 await self.bot.delete_message(msg)
198 await self.bot.upload(final, filename='magik.png', content=content_msg)
199 except discord.errors.Forbidden:
200 await self.bot.say(":warning: **I do not have permission to send files!**")
201 except Exception as e:
202 await self.bot.say(e)
203
204 def do_gmagik(self, ctx, gif, gif_dir, rand):
205 try:
206 try:
207 frame = PIL.Image.open(gif)
208 except:
209 return ':warning: Invalid Gif.'
210 if frame.size >= (3000, 3000):
211 os.remove(gif)
212 return ':warning: `GIF resolution exceeds maximum >= (3000, 3000).`'
213 nframes = 0
214 while frame:
215 frame.save('{0}/{1}_{2}.png'.format(gif_dir, nframes, rand), 'GIF')
216 nframes += 1
217 try:
218 frame.seek(nframes)
219 except EOFError:
220 break
221 imgs = glob.glob(gif_dir+"*_{0}.png".format(rand))
222 if len(imgs) > 150 and ctx.message.author.id != self.bot.owner.id:
223 for image in imgs:
224 os.remove(image)
225 os.remove(gif)
226 return ":warning: `GIF has too many frames (>= 150 Frames).`"
227 for image in imgs:
228 try:
229 im = wand.image.Image(filename=image)
230 except:
231 continue
232 i = im.clone()
233 i.transform(resize='800x800>')
234 i.liquid_rescale(width=int(i.width*0.5), height=int(i.height*0.5), delta_x=1, rigidity=0)
235 i.liquid_rescale(width=int(i.width*1.5), height=int(i.height*1.5), delta_x=2, rigidity=0)
236 i.resize(i.width, i.height)
237 i.save(filename=image)
238 return True
239 except Exception as e:
240 exc_type, exc_obj, tb = sys.exc_info()
241 f = tb.tb_frame
242 lineno = tb.tb_lineno
243 filename = f.f_code.co_filename
244 linecache.checkcache(filename)
245 line = linecache.getline(filename, lineno, f.f_globals)
246 print('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj))
247
248 @commands.command(pass_context=True)
249 @commands.cooldown(1, 20, commands.BucketType.server)
250 async def gmagik(self, ctx, url:str=None, framerate:str=None):
251 try:
252 url = await self.get_images(ctx, urls=url, gif=True, limit=2)
253 if url:
254 url = url[0]
255 else:
256 return
257 gif_dir = self.files_path('gif/')
258 check = await self.isgif(url)
259 if check is False:
260 await self.bot.say("Invalid or Non-GIF!")
261 ctx.command.reset_cooldown(ctx)
262 return
263 x = await self.bot.send_message(ctx.message.channel, "ok, processing (this might take a while for big gifs)")
264 rand = self.bot.random()
265 gifin = gif_dir+'1_{0}.gif'.format(rand)
266 gifout = gif_dir+'2_{0}.gif'.format(rand)
267 await self.download(url, gifin)
268 if os.path.getsize(gifin) > 5000000 and ctx.message.author.id != self.bot.owner.id:
269 await self.bot.say(":no_entry: `GIF Too Large (>= 5 mb).`")
270 os.remove(gifin)
271 return
272 try:
273 result = await self.bot.loop.run_in_executor(None, self.do_gmagik, ctx, gifin, gif_dir, rand)
274 except CancelledError:
275 await self.bot.say(':warning: Gmagik failed...')
276 return
277 if type(result) == str:
278 await self.bot.say(result)
279 return
280 if framerate != None:
281 args = ['ffmpeg', '-y', '-nostats', '-loglevel', '0', '-i', gif_dir+'%d_{0}.png'.format(rand), '-r', framerate, gifout]
282 else:
283 args = ['ffmpeg', '-y', '-nostats', '-loglevel', '0', '-i', gif_dir+'%d_{0}.png'.format(rand), gifout]
284 await self.bot.run_process(args)
285 await self.bot.upload(gifout, filename='gmagik.gif')
286 for image in glob.glob(gif_dir+"*_{0}.png".format(rand)):
287 os.remove(image)
288 os.remove(gifin)
289 os.remove(gifout)
290 await self.bot.delete_message(x)
291 except Exception as e:
292 print(e)
293
294 #redacted
295 @commands.command(pass_context=True)
296 async def aa(self, ctx, *, user:str):
297 """rope"""
298 user = user.strip("`")
299 if len(ctx.message.mentions):
300 user = ctx.message.mentions[0].name
301 msg = "``` _________ \n| | \n| 0 <-- {0} \n| /|\\ \n| / \\ \n| \n| \n```\n".format(user)
302 msg += "**kronk your splinter** `{0}`\nropstor.org?u={1}".format(user, quote(user))
303 await self.bot.say(msg)
304
305 @commands.command(pass_context=True)
306 async def a(self, ctx, *, user:str, direct=None):
307 """make dank meme"""
308 if len(user) > 25:
309 await self.bot.say("ur names 2 long asshole")
310 return
311 if len(ctx.message.mentions) and len(ctx.message.mentions) == 1:
312 user = ctx.message.mentions[0].name
313 payload = {'template_id': '57570410', 'username': '', 'password' : '', 'text0' : '', 'text1' : '{0} you'.format(user)}
314 with aiohttp.ClientSession() as session:
315 async with session.post("https://api.imgflip.com/caption_image", data=payload) as r:
316 load = await r.json()
317 url = load['data']['url']
318 if direct:
319 await self.bot.say(url)
320 else:
321 b = await self.bytes_download(url)
322 await self.bot.upload(b, filename='a.png')
323
324 @commands.command(pass_context=True)
325 async def caption(self, ctx, url:str=None, text:str=None, color=None, size=None, x:int=None, y:int=None):
326 """Add caption to an image\n .caption text image_url"""
327 try:
328 if url is None:
329 await self.bot.say("Error: Invalid Syntax\n`.caption <image_url> <text>** <color>* <size>* <x>* <y>*`\n`* = Optional`\n`** = Wrap text in quotes`")
330 return
331 check = await self.isimage(url)
332 if check == False:
333 await self.bot.say("Invalid or Non-Image!")
334 return
335 xx = await self.bot.send_message(ctx.message.channel, "ok, processing")
336 b = await self.bytes_download(url)
337 img = wand.image.Image(file=b)
338 i = img.clone()
339 font_path = self.files_path('impact.ttf')
340 if size != None:
341 color = wand.color.Color('{0}'.format(color))
342 font = wand.font.Font(path=font_path, size=int(size), color=color)
343 elif color != None:
344 color = wand.color.Color('{0}'.format(color))
345 font = wand.font.Font(path=font_path, size=40, color=color)
346 else:
347 color = wand.color.Color('red')
348 font = wand.font.Font(path=font_path, size=40, color=color)
349 if x is None:
350 x = None
351 y = int(i.height/10)
352 if x != None and x > 250:
353 x = x/2
354 if y != None and y > 250:
355 y = y/2
356 if x != None and x > 500:
357 x = x/4
358 if y != None and y > 500:
359 y = y/4
360 if x != None:
361 i.caption(str(text), left=x, top=y, font=font, gravity='center')
362 else:
363 i.caption(str(text), top=y, font=font, gravity='center')
364 final = BytesIO()
365 i.save(file=final)
366 final.seek(0)
367 await self.bot.delete_message(xx)
368 await self.bot.upload(final, filename='caption.png')
369 except Exception as e:
370 await self.bot.say("Error: Invalid Syntax\n `.caption <image_url> <text>** <color>* <size>* <x>* <y>*`\n`* = Optional`\n`** = Wrap text in quotes`")
371 print(e)
372
373 @commands.command(pass_context=True)
374 @commands.cooldown(1, 5)
375 async def triggered(self, ctx, user:str=None):
376 """Generate a Triggered Gif for a User or Image"""
377 try:
378 url = None
379 if user is None:
380 user = ctx.message.author
381 elif len(ctx.message.mentions):
382 user = ctx.message.mentions[0]
383 else:
384 url = user
385 if type(user) == discord.User or type(user) == discord.Member:
386 if user.avatar:
387 avatar = 'https://discordapp.com/api/users/{0.id}/avatars/{0.avatar}.jpg'.format(user)
388 else:
389 avatar = user.default_avatar_url
390 if url:
391 get_images = await self.get_images(ctx, urls=url, limit=1)
392 if not get_images:
393 return
394 avatar = get_images[0]
395 path = self.files_path(self.bot.random(True))
396 path2 = path[:-3]+'gif'
397 await self.download(avatar, path)
398 t_path = self.files_path('triggered.jpg')
399 await self.bot.run_process(['convert',
400 'canvas:none',
401 '-size', '512x680!',
402 '-resize', '512x680!',
403 '-draw', 'image over -60,-60 640,640 "{0}"'.format(path),
404 '-draw', 'image over 0,512 0,0 "{0}"'.format(t_path),
405 '(',
406 'canvas:none',
407 '-size', '512x680!',
408 '-draw', 'image over -45,-50 640,640 "{0}"'.format(path),
409 '-draw', 'image over 0,512 0,0 "{0}"'.format(t_path),
410 ')',
411 '(',
412 'canvas:none',
413 '-size', '512x680!',
414 '-draw', 'image over -50,-45 640,640 "{0}"'.format(path),
415 '-draw', 'image over 0,512 0,0 "{0}"'.format(t_path),
416 ')',
417 '(',
418 'canvas:none',
419 '-size', '512x680!',
420 '-draw', 'image over -45,-65 640,640 "{0}"'.format(path),
421 '-draw', 'image over 0,512 0,0 "{0}"'.format(t_path),
422 ')',
423 '-layers', 'Optimize',
424 '-set', 'delay', '2',
425 path2])
426 await self.bot.upload(path2, filename='triggered.gif')
427 os.remove(path)
428 os.remove(path2)
429 except Exception as e:
430 await self.bot.say(e)
431 try:
432 os.remove(path)
433 os.remove(path2)
434 except:
435 pass
436
437 async def do_triggered(self, ctx, user, url, t_path):
438 try:
439 if user is None:
440 user = ctx.message.author
441 elif len(ctx.message.mentions):
442 user = ctx.message.mentions[0]
443 else:
444 url = user
445 if type(user) == discord.User or type(user) == discord.Member:
446 if user.avatar:
447 avatar = 'https://discordapp.com/api/users/{0.id}/avatars/{0.avatar}.jpg'.format(user)
448 else:
449 avatar = user.default_avatar_url
450 if url:
451 get_images = await self.get_images(ctx, urls=url, limit=1)
452 if not get_images:
453 return
454 avatar = get_images[0]
455 path = self.files_path(self.bot.random(True))
456 await self.download(avatar, path)
457 await self.bot.run_process(['convert',
458 '(',
459 path,
460 '-resize', '256',
461 ')',
462 t_path,
463 '-append', path
464 ])
465 return path
466 except Exception as e:
467 print(e)
468 return False
469
470 @commands.command(pass_context=True)
471 @commands.cooldown(1, 5)
472 async def triggered2(self, ctx, user:str=None, url:str=None):
473 """Generate a Triggered Image for a User or Image"""
474 t_path = self.files_path('triggered.png')
475 path = await self.do_triggered(ctx, user, url, t_path)
476 if path is False:
477 await self.bot.say(':warning: **Command Failed.**')
478 try:
479 os.remove(path)
480 except:
481 pass
482 return
483 await self.bot.upload(path, filename='triggered3.png')
484 os.remove(path)
485
486 @commands.command(pass_context=True)
487 @commands.cooldown(1, 5)
488 async def triggered3(self, ctx, user:str=None, url:str=None):
489 """Generate a Triggered2 Image for a User or Image"""
490 t_path = self.files_path('triggered2.png')
491 path = await self.do_triggered(ctx, user, url, t_path)
492 if path is False:
493 await self.bot.say(':warning: **Command Failed.**')
494 try:
495 os.remove(path)
496 except:
497 pass
498 return
499 await self.bot.upload(path, filename='triggered3.png')
500 os.remove(path)
501
502 @commands.command(pass_context=True, aliases=['aes'])
503 async def aesthetics(self, ctx, *, text:str):
504 """Returns inputed text in aesthetics"""
505 final = ""
506 pre = ' '.join(text)
507 for char in pre:
508 if not ord(char) in range(33, 127):
509 final += char
510 continue
511 final += chr(ord(char) + 65248)
512 await self.truncate(ctx.message.channel, final)
513
514 def do_ascii(self, text):
515 try:
516 i = PIL.Image.new('RGB', (2000, 1000))
517 img = PIL.ImageDraw.Draw(i)
518 txt = figlet_format(text, font='starwars')
519 img.text((20, 20), figlet_format(text, font='starwars'), fill=(0, 255, 0))
520 text_width, text_height = img.textsize(figlet_format(text, font='starwars'))
521 imgs = PIL.Image.new('RGB', (text_width + 30, text_height))
522 ii = PIL.ImageDraw.Draw(imgs)
523 ii.text((20, 20), figlet_format(text, font='starwars'), fill=(0, 255, 0))
524 text_width, text_height = ii.textsize(figlet_format(text, font='starwars'))
525 final = BytesIO()
526 imgs.save(final, 'png')
527 final.seek(0)
528 return final, txt
529 except:
530 return False, False
531
532 @commands.command(pass_context=True, aliases=['expand'])
533 @commands.cooldown(1, 5)
534 async def ascii(self, ctx, *, text:str):
535 """Convert text into ASCII"""
536 if len(text) > 1000:
537 await self.bot.say("2 long asshole")
538 return
539 if text == 'donger' or text == 'dong':
540 text = "8====D"
541 final, txt = await self.bot.loop.run_in_executor(None, self.do_ascii, text)
542 if final is False:
543 await self.bot.say(':no_entry: go away with your invalid characters.')
544 return
545 if len(txt) >= 1999:
546 await self.gist(ctx, text, txt)
547 msg = None
548 elif len(txt) <= 600:
549 msg = "```fix\n{0}```".format(txt)
550 else:
551 msg = None
552 await self.bot.upload(final, filename='ascii.png', content=msg)
553
554 def generate_ascii(self, image):
555 font = PIL.ImageFont.truetype(self.files_path('FreeMonoBold.ttf'), 15, encoding="unic")
556 image_width, image_height = image.size
557 aalib_screen_width= int(image_width/24.9)*10
558 aalib_screen_height= int(image_height/41.39)*10
559 screen = aalib.AsciiScreen(width=aalib_screen_width, height=aalib_screen_height)
560 im = image.convert("L").resize(screen.virtual_size)
561 screen.put_image((0,0), im)
562 y = 0
563 how_many_rows = len(screen.render().splitlines())
564 new_img_width, font_size = font.getsize(screen.render().splitlines()[0])
565 img = PIL.Image.new("RGBA", (new_img_width, how_many_rows*15), (255,255,255))
566 draw = PIL.ImageDraw.Draw(img)
567 for lines in screen.render().splitlines():
568 draw.text((0,y), lines, (0,0,0), font=font)
569 y = y + 15
570 imagefit = PIL.ImageOps.fit(img, (image_width, image_height), PIL.Image.ANTIALIAS)
571 return imagefit
572
573 @commands.command(pass_context=True)
574 @commands.cooldown(1, 5, commands.BucketType.user)
575 async def iascii(self, ctx, url:str=None):
576 try:
577 get_images = await self.get_images(ctx, urls=url, limit=5)
578 if not get_images:
579 return
580 for url in get_images:
581 x = await self.bot.say("ok, processing")
582 b = await self.bytes_download(url)
583 if b is False:
584 if len(get_images) == 1:
585 await self.bot.say(':warning: **Command download function failed...**')
586 return
587 continue
588 im = PIL.Image.open(b)
589 img = await self.bot.loop.run_in_executor(None, self.generate_ascii, im)
590 final = BytesIO()
591 img.save(final, 'png')
592 final.seek(0)
593 await self.bot.delete_message(x)
594 await self.bot.upload(final, filename='iascii.png')
595 except Exception as e:
596 await self.bot.say(e)
597
598 def do_gascii(self, b, rand, gif_dir):
599 try:
600 try:
601 im = PIL.Image.open(b)
602 except IOError:
603 return ':warning: Cannot load gif.'
604 count = 0
605 mypalette = im.getpalette()
606 try:
607 while True:
608 im.putpalette(mypalette)
609 new_im = PIL.Image.new("RGBA", im.size)
610 new_im.paste(im)
611 new_im = self.generate_ascii(new_im)
612 new_im.save('{0}/{1}_{2}.png'.format(gif_dir, count, rand))
613 count += 1
614 im.seek(im.tell() + 1)
615 return True
616 except EOFError:
617 pass
618 except Exception as e:
619 print(e)
620
621 @commands.command(pass_context=True)
622 @commands.cooldown(1, 10, commands.BucketType.server)
623 async def gascii(self, ctx, url:str=None):
624 """Gif to ASCII"""
625 try:
626 get_images = await self.get_images(ctx, urls=url, gif=True, limit=2)
627 if not get_images:
628 await self.bot.say("Error: Invalid Syntax\n`.gascii <gif_url> <liquid_rescale>*`\n`* = Optional`")
629 return
630 for url in get_images:
631 rand = self.bot.random()
632 gif_dir = self.files_path('gascii/')
633 location = gif_dir+'1_{0}.gif'.format(rand)
634 location2 = gif_dir+'2_{0}.gif'.format(rand)
635 x = await self.bot.send_message(ctx.message.channel, "ok, processing")
636 await self.download(url, location)
637 if os.path.getsize(location) > 3000000 and ctx.message.author.id != self.bot.owner.id:
638 await self.bot.say("Sorry, GIF Too Large!")
639 os.remove(location)
640 return
641 result = await self.bot.loop.run_in_executor(None, self.do_gascii, location, rand, gif_dir)
642 if type(result) == str:
643 await self.bot.say(result)
644 return
645 list_imgs = glob.glob(gif_dir+"*_{0}.png".format(rand))
646 if len(list_imgs) > 120 and ctx.message.author.id != "130070621034905600":
647 await self.bot.say("Sorry, GIF has too many frames!")
648 for image in list_imgs:
649 os.remove(image)
650 os.remove(location)
651 return
652 await self.bot.run_process(['ffmpeg', '-y', '-nostats', '-loglevel', '0', '-i', self.files_path('gascii/')+'%d_{0}.png'.format(rand), location2])
653 await self.bot.delete_message(x)
654 await self.bot.upload(location2, filename='gascii.gif')
655 for image in list_imgs:
656 os.remove(image)
657 os.remove(location)
658 os.remove(location2)
659 except Exception as e:
660 await self.bot.say(e)
661
662 @commands.command(pass_context=True)
663 async def rip(self, ctx, name:str=None, *, text:str=None):
664 if name is None:
665 name = ctx.message.author.name
666 if len(ctx.message.mentions) >= 1:
667 name = ctx.message.mentions[0].name
668 if text != None:
669 if len(text) > 22:
670 one = text[:22]
671 two = text[22:]
672 url = "http://www.tombstonebuilder.com/generate.php?top1=R.I.P&top3={0}&top4={1}&top5={2}".format(name, one, two).replace(" ", "%20")
673 else:
674 url = "http://www.tombstonebuilder.com/generate.php?top1=R.I.P&top3={0}&top4={1}".format(name, text).replace(" ", "%20")
675 else:
676 if name[-1].lower() != 's':
677 name += "'s"
678 url = "http://www.tombstonebuilder.com/generate.php?top1=R.I.P&top3={0}&top4=Hopes and Dreams".format(name).replace(" ", "%20")
679 b = await self.bytes_download(url)
680 await self.bot.upload(b, filename='rip.png')
681
682 @commands.command(pass_context=True)
683 async def urban(self, ctx, *, word:str):
684 urb = urbandict.define(word)
685 if "There aren't any definitions" in urb[0]['def']:
686 await self.bot.say(":no_mouth: `No definition found.`")
687 return
688 msg = "**{0}**\n".format(word)
689 msg += "`Definition:` {0}\n".format(urb[0]['def'].replace("\n", ""))
690 msg += "`Example:` {0}".format(urb[0]['example'].replace("\n", ""))
691 await self.truncate(ctx.message.channel, msg)
692
693 async def add_cache(self, search, result, t=0, level=1):
694 try:
695 try:
696 if result['error']:
697 return
698 except KeyError:
699 pass
700 if t == 0:
701 self.image_cache[search] = [result, level]
702 elif t == 1:
703 self.search_cache[search] = [result, level]
704 elif t == 2:
705 self.youtube_cache[search] = [result, level]
706 except Exception as e:
707 print(e)
708
709 async def google_scrap(self, search:str, safe=True, image=False):
710 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:43.0) Gecko/20100101 Firefox/43.0'}
711 search = quote(search)
712 try:
713 if image:
714 api = 'https://www.google.com/search?tbm=isch&gs_l=img&safe={0}&q={1}'.format('on' if safe else 'off', search)
715 with aiohttp.ClientSession() as session:
716 with aiohttp.Timeout(5):
717 async with session.get(api, headers=headers) as r:
718 assert r.status == 200
719 txt = await r.text()
720 match = self.scrap_regex.findall(txt)
721 assert match
722 image = random.choice(match[:10])
723 check = await self.isimage(image)
724 i = 0
725 if not check:
726 while not check and i != 10:
727 image = match[:10][i]
728 check = await self.isimage(image)
729 i += 1
730 assert check
731 return image
732 else:
733 api = 'https://www.google.com/search?safe={0}&q={1}'.format('on' if safe else 'off', search)
734 #why are you so good danny, my old method was using regex so, not so good.....
735 entries = {}
736 with aiohttp.ClientSession() as session:
737 with aiohttp.Timeout(5):
738 async with session.get(api, headers=headers) as r:
739 assert r.status == 200
740 txt = await r.text()
741 root = etree.fromstring(txt, etree.HTMLParser())
742 search_nodes = root.findall(".//div[@class='g']")
743 result = False
744 for node in search_nodes:
745 if result != False:
746 break
747 try:
748 url_node = node.find('.//h3/a')
749 if url_node is None:
750 continue
751 desc = get_deep_text(node.find(".//div[@class='s']/div/span[@class='st']"))
752 title = get_deep_text(node.find(".//h3[@class='r']"))
753 url = url_node.attrib['href']
754 if url.startswith('/url?'):
755 url = parse_qs(url[5:])['q'][0]
756 result = [title, desc, url]
757 except:
758 continue
759 return result
760 except AssertionError:
761 return False
762 except Exception as e:
763 print(e)
764 return False
765
766 async def google_safety(self, message, s=False):
767 check = await self.is_nsfw(message)
768 if check:
769 if s:
770 return 'off'
771 return 1, False
772 sql = 'SELECT * FROM `google_nsfw` WHERE server={0}'
773 sql = sql.format(message.server.id)
774 result = self.cursor.execute(sql).fetchall()
775 if len(result) == 0:
776 if s:
777 return 'medium'
778 return 2, False
779 else:
780 level = int(result[0]['level'])
781 if s:
782 if level == 1:
783 return 'off'
784 elif level == 2:
785 return 'medium'
786 elif level == 3:
787 return 'high'
788 return level
789
790 @commands.command(pass_context=True, aliases=['googlesafety', 'safetylevel', 'googlensfw', 'saftey'])
791 @checks.mod_or_perm(manage_server=True)
792 async def safety(self, ctx, level:str=None):
793 s = await self.google_safety(ctx.message)
794 current_level = s[0] if type(s) != str and type(s) != int else s
795 check = s[1] if type(s) != str and type(s) != int else True
796 levels = [0, 1, 2, 3]
797 if current_level == 1:
798 msg = 'OFF'
799 elif current_level == 2:
800 msg = 'MEDIUM'
801 elif current_level == 3:
802 msg = 'HIGH'
803 if level is None:
804 await self.bot.say(':information_source: Current google safety level: `{0}` *{1}*'.format(current_level, msg))
805 return
806 else:
807 level = level.lower()
808 if level.isdigit() and int(level) in levels:
809 level = int(level)
810 elif level == 'off' or level == 'disable':
811 level = 1
812 elif level == 'low' or level == 'medium':
813 level = 2
814 elif level == 'high':
815 level = 3
816 if level not in levels:
817 await self.bot.say(':no_entry: `Invalid level.`')
818 return
819 if level == 0 or level == 1:
820 level = 1
821 smsg = 'OFF'
822 elif level == 2:
823 smsg = 'MEDIUM'
824 elif level == 3:
825 smsg = 'HIGH'
826 if current_level == level:
827 await self.bot.say(':no_entry: Google Saftey is already at that level!')
828 return
829 if check is False:
830 sql = 'INSERT INTO `google_nsfw` (`server`, `level`) VALUES (%s, %s)'
831 self.cursor.execute(sql, (ctx.message.server.id, level))
832 await self.bot.say(':white_check_mark: Set google safety level to **{1}**'.format(level, smsg))
833 else:
834 sql = 'UPDATE `google_nsfw` SET level={0} WHERE server={1}'
835 sql = sql.format(level, ctx.message.server.id)
836 self.cursor.execute(sql)
837 await self.bot.say(':white_check_mark: Updated google safety level from **{0}** *to* **{1}**'.format(msg, smsg))
838 self.cursor.commit()
839
840 @commands.command(pass_context=True, aliases=['im', 'photo', 'img'])
841 @commands.cooldown(3, 5)
842 async def image(self, ctx, *, search:str):
843 level = await self.google_safety(ctx.message, True)
844 in_cache = False
845 if search in self.image_cache.keys():
846 load_level = self.image_cache[search][1]
847 if load_level == level:
848 load = self.image_cache[search][0]
849 in_cache = True
850 try:
851 if in_cache is False:
852 key = await self.google_keys()
853 api = "https://www.googleapis.com/customsearch/v1?key={0}&cx=015418243597773804934:it6asz9vcss&searchType=image&safe={1}&q={2}".format(key, level, quote(search))
854 load = await self.get_json(api)
855 assert 'error' not in load.keys() and 'items' in load.keys()
856 assert len(load)
857 rand = random.choice(load['items'])
858 image = rand['link']
859 await self.bot.say(image)
860 await self.add_cache(search, load, 0, level)
861 except discord.errors.Forbidden:
862 await self.bot.say("no send_file permission asshole")
863 return
864 except AssertionError:
865 scrap = await self.google_scrap(search, True if level != 'off' else False, True)
866 if scrap:
867 await self.bot.say(scrap)
868 else:
869 await self.bot.say(":warning: `API Quota Reached or Invalid Search`")
870 except:
871 raise
872
873 @commands.command(pass_context=True, aliases=['go', 'googl', 'gogle', 'g'])
874 @commands.cooldown(3, 5)
875 async def google(self, ctx, *, search:str=None):
876 if search is None:
877 await self.bot.say("Error: Invalid Syntax\n`.google <text>`")
878 return
879 in_cache = False
880 level = await self.google_safety(ctx.message, True)
881 in_cache = False
882 if search in self.search_cache.keys():
883 load_level = self.search_cache[search][1]
884 if load_level == level:
885 load = self.search_cache[search][0]
886 in_cache = True
887 try:
888 if in_cache is False:
889 key = await self.google_keys()
890 api = "https://www.googleapis.com/customsearch/v1?key={0}&cx=015418243597773804934:it6asz9vcss&safe={1}&q={2}".format(key, level, quote(search))
891 load = await self.get_json(api)
892 assert 'error' not in load.keys() and 'items' in load.keys()
893 assert len(load)
894 rand = load['items'][0]
895 result = rand['link']
896 title = rand['title']
897 snippet = rand['snippet']
898 await self.bot.say("**{0}**\n`{1}`\n{2}".format(title, snippet, result))
899 await self.add_cache(search, load, 1, level)
900 except AssertionError:
901 scrap = await self.google_scrap(search, True if level != 'off' else False, False)
902 if scrap:
903 title = scrap[0]
904 snippet = scrap[1]
905 result = scrap[2]
906 await self.bot.say("**{0}**\n`{1}`\n{2}".format(title, snippet, result))
907 else:
908 await self.bot.say(":warning: `API Quota Reached or Invalid Search`")
909 except:
910 raise
911
912 async def youtube_scrap(self, search:str, safety=False):
913 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:43.0) Gecko/20100101 Firefox/43.0'}
914 search = quote(search)
915 api = 'https://www.youtube.com/results?search_query={0}'.format(search)
916 entries = {}
917 cookies = {'PREF': 'cvdm=grid&al=en&f4=4000000&f5=30&f1=50000000&f2=8000000'} if safety else None
918 with aiohttp.ClientSession(cookies=cookies) as session:
919 with aiohttp.Timeout(5):
920 async with session.get(api, headers=headers) as r:
921 assert r.status == 200
922 txt = await r.text()
923 root = etree.fromstring(txt, etree.HTMLParser())
924 search_nodes = root.findall(".//ol[@class='section-list']/li/ol[@class='item-section']/li")
925 if len(search_nodes) == 0:
926 return False
927 search_nodes.pop(0)
928 result = False
929 for node in search_nodes:
930 if result != False:
931 break
932 try:
933 url_node = node.find('div/div/div/h3/a')
934 if url_node is None:
935 continue
936 title = get_deep_text(url_node)
937 url = 'https://www.youtube.com/{0}'.format(url_node.attrib['href'])
938 result = [title, url]
939 except:
940 continue
941 return result
942
943 @commands.command(pass_context=True, aliases=['yt', 'video'])
944 @commands.cooldown(3, 5)
945 async def youtube(self, ctx, *, search:str=None):
946 if search is None:
947 await self.bot.say("Error: Invalid Syntax\n`.yt/youtube <text>`")
948 return
949 level = await self.google_safety(ctx.message, True)
950 in_cache = False
951 if search in self.youtube_cache.keys():
952 load_level = self.youtube_cache[search][1]
953 if load_level == level:
954 load = self.youtube_cache[search][0]
955 in_cache = True
956 try:
957 if in_cache is False:
958 key = await self.google_keys()
959 api = "https://www.googleapis.com/customsearch/v1?key={0}&cx=015418243597773804934:cdlwut5fxsk&q={1}".format(key, quote(search))
960 load = await self.get_json(api)
961 assert 'error' not in load.keys() and 'items' in load.keys()
962 assert len(load)
963 rand = load['items'][0]
964 link = rand['link']
965 title = rand['title']
966 snippet = rand['snippet']
967 await self.bot.say('**{0}**\n`{1}`\n{2}'.format(title, snippet, link))
968 await self.add_cache(search, load, 2, level)
969 except AssertionError:
970 scrap = await self.youtube_scrap(search, True if level != 'off' else False)
971 if scrap:
972 title = scrap[0]
973 url = scrap[1]
974 await self.bot.say("**{0}**\n{1}".format(title, url))
975 else:
976 await self.bot.say(":warning: `API Quota Reached or Invalid Search`")
977
978 @commands.command()
979 @commands.cooldown(2, 5)
980 async def imgur(self, *, text:str=None):
981 try:
982 if text is None:
983 load = self.imgur_client.gallery_random(page=0)
984 else:
985 load = self.imgur_client.gallery_search(text, advanced=None, sort='viral', window='all', page=0)
986 rand = random.choice(load)
987 try:
988 if 'image/' in rand.type:
989 await self.bot.say('{0}'.format(rand.link))
990 except AttributeError:
991 if rand.title:
992 title = '**'+rand.title+'**\n'
993 else:
994 title = ''
995 if rand.description != None:
996 desc = '`'+rand.description+'`\n'
997 else:
998 desc = ''
999 await self.bot.say('{0}{1}{2}'.format(title, desc, rand.link))
1000 except Exception as e:
1001 await self.bot.say(e)
1002
1003 @commands.command(aliases=['gif'])
1004 @commands.cooldown(2, 5)
1005 async def giphy(self, *, text:str=None):
1006 if text is None:
1007 api = 'http://api.giphy.com/v1/gifs/random?&api_key=dc6zaTOxFJmzC'
1008 else:
1009 api = 'http://api.giphy.com/v1/gifs/search?q={0}&api_key=dc6zaTOxFJmzC'.format(quote(text))
1010 load = await self.get_json(api)
1011 if len(load['data']) == 0:
1012 await self.bot.say(':warning: `No results found on` <https://giphy.com>')
1013 else:
1014 rand = False
1015 try:
1016 gif = random.choice(load['data'])
1017 except:
1018 gif = load['data']
1019 rand = True
1020 url = gif['url']
1021 if rand:
1022 gif_url = gif['image_url']
1023 else:
1024 gif_url = gif['images']['fixed_height']['url']
1025 await self.bot.say('{0}'.format(url))
1026
1027 @commands.command(pass_context=True, aliases=['w2x', 'waifu2x', 'enlarge', 'upscale'])
1028 @commands.cooldown(1, 15)
1029 async def resize(self, ctx, *urls):
1030 try:
1031 get_images = await self.get_images(ctx, urls=urls, scale=10, limit=1)
1032 if not get_images:
1033 return
1034 url = get_images[0][0]
1035 size = get_images[1]
1036 if size is None:
1037 size = 3
1038 scale_msg = get_images[2]
1039 if scale_msg is None:
1040 scale_msg = ''
1041 else:
1042 scale_msg = '\n'+scale_msg
1043 do_2 = False
1044 rand = self.bot.random()
1045 x = await self.bot.send_message(ctx.message.channel, "ok, resizing `{0}` by `{1}`".format(url, str(size)))
1046 b = await self.bytes_download(url)
1047 if sys.getsizeof(b) > 3000000:
1048 await self.bot.say("Sorry, image too large for waifu2x servers!")
1049 return
1050 await self.bot.edit_message(x, "25%, resizing")
1051 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:43.0) Gecko/20100101 Firefox/43.0'}
1052 payload = aiohttp.FormData()
1053 payload.add_field('url', url)
1054 payload.add_field('scale', str(size))
1055 payload.add_field('style', 'art')
1056 payload.add_field('noise', '3')
1057 payload.add_field('comp', '10')
1058 await self.bot.edit_message(x, "50%, w2x")
1059 try:
1060 with aiohttp.ClientSession() as session:
1061 with aiohttp.Timeout(30):
1062 async with session.post('http://waifu2x.me/convert', data=payload, headers=headers) as r:
1063 txt = await r.text()
1064 download_url = 'http://waifu2x.me/{0}'.format(txt)
1065 final = None
1066 except asyncio.TimeoutError:
1067 do_2 = True
1068 if do_2:
1069 idk = []
1070 if size == 1:
1071 idk.append(2)
1072 if size == 2:
1073 idk.append(2)
1074 if size == 3:
1075 idk.append(1.6)
1076 idk.append(2)
1077 if size == 4:
1078 idk.append(2)
1079 idk.append(2)
1080 if size == 5:
1081 idk.append(1.6)
1082 idk.append(2)
1083 idk.append(2)
1084 if size == 6:
1085 for i in range(3):
1086 idk.append(2)
1087 if size == 7:
1088 for i in range(3):
1089 idk.append(2)
1090 idk.append(1.6)
1091 if size == 8:
1092 for i in range(4):
1093 idk.append(2)
1094 if size == 9:
1095 for i in range(4):
1096 idk.append(2)
1097 idk.append(1.6)
1098 if size == 10:
1099 for i in range(5):
1100 idk.append(2)
1101 for s in idk:
1102 if final:
1103 b = final
1104 if s == 2:
1105 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:43.0) Gecko/20100101 Firefox/43.0'}
1106 payload = aiohttp.FormData()
1107 payload.add_field('scale', '2')
1108 payload.add_field('style', 'art')
1109 payload.add_field('noise', '1')
1110 payload.add_field('url', url)
1111 with aiohttp.ClientSession() as session:
1112 with aiohttp.Timeout(30):
1113 async with session.post('http://waifu2x.udp.jp/api', data=payload, headers=headers) as r:
1114 raw = await r.read()
1115 elif s == 1.6:
1116 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:43.0) Gecko/20100101 Firefox/43.0'}
1117 payload = aiohttp.FormData()
1118 payload.add_field('scale', '1.6')
1119 payload.add_field('style', 'art')
1120 payload.add_field('noise', '1')
1121 payload.add_field('url', url)
1122 with aiohttp.ClientSession() as session:
1123 with aiohttp.Timeout(30):
1124 async with session.post('http://waifu2x.udp.jp/api', data=payload, headers=headers) as r:
1125 raw = await r.read()
1126 final = BytesIO(raw)
1127 final.seek(0)
1128 if final is None:
1129 final = await self.bytes_download(download_url)
1130 if sys.getsizeof(final) > 8388608:
1131 await self.bot.say("Sorry, image too large for discord!")
1132 return
1133 await self.bot.edit_message(x, "100%, uploading")
1134 i = 0
1135 while sys.getsizeof(final) == 88 and i < 5:
1136 final = await self.bytes_download(download_url)
1137 await asyncio.sleep(0.3)
1138 if sys.getsizeof(final) != 0:
1139 i = 5
1140 else:
1141 i += 1
1142 await self.bot.upload(final, filename='enlarge.png', content='Visit image link for accurate resize visual.'+scale_msg if size > 3 else scale_msg if scale_msg != '' else None)
1143 await asyncio.sleep(3)
1144 await self.bot.delete_message(x)
1145 except Exception as e:
1146 await self.bot.say(code.format(e))
1147 await self.bot.say("Error: Failed\n `Discord Failed To Upload or Waifu2x Servers Failed`")
1148
1149 @commands.group(pass_context=True, invoke_without_command=True)
1150 async def meme(self, ctx, meme:str=None, *, line=None):
1151 """Generates a meme."""
1152 if meme is None:
1153 await self.bot.say("Error: Invalid Syntax\n`meme` has 4 commands\n`meme` **+** `<mention> or <custom_image> or <template>` **+** `<line1> <line2>*` *=optional")
1154 return
1155 if line is None:
1156 await self.bot.say("Error: Invalid Syntax\n`meme` has 4 parameters\n`.meme <template> <line_one> <line_two> <style>*`\n* = Optional")
1157 return
1158 line2 = None
1159 if '|' in line:
1160 split = line.split('|')
1161 line1 = split[0]
1162 line2 = split[1]
1163 else:
1164 split = line.split()
1165 if len(split) > 2:
1166 line1 = ' '.join(split[:2])
1167 line2 = ' '.join(split[2:])
1168 else:
1169 line1 = split[0]
1170 if len(split) > 1:
1171 line2 = ' '.join(split[1:])
1172 if line2 is None:
1173 line2 = ''
1174 rep = [["-","--"],["_","__"],["?","~q"],["%","~p"],[" ","%20"],["''","\""]]
1175 for s in rep:
1176 line1 = line1.replace(s[0],s[1])
1177 line2 = line2.replace(s[0],s[1])
1178 if len(ctx.message.mentions):
1179 link = "http://memegen.link/custom/{0}/{1}.jpg?alt={2}".format(line1, line2, 'https://discordapp.com/api/users/{0.id}/avatars/{0.avatar}.jpg'.format(ctx.message.mentions[0]))
1180 b = await self.bytes_download(link)
1181 elif meme.startswith("http"):
1182 link = "http://memegen.link/custom/{0}/{1}.jpg?alt={2}".format(line1, line2, meme)
1183 b = await self.bytes_download(link)
1184 else:
1185 link = "http://memegen.link/{0}/{1}/{2}.jpg".format(meme, line1, line2)
1186 b = await self.bytes_download(link)
1187 if b is False:
1188 await self.bot.say(':warning: **Command download function failed...**')
1189 return
1190 await self.bot.upload(b, filename='meme.png')
1191
1192 @meme.group(name="templates", pass_context=True, invoke_without_command=True)
1193 async def _templates(self, ctx):
1194 """Gives users a list of meme templates."""
1195 await self.bot.say("Templates to choose from: <{}>".format("http://memegen.link/templates/"))
1196
1197 @commands.command(aliases=['r'])
1198 async def reverse(self, *, text:str):
1199 """Reverse Text\n.revese <text>"""
1200 text = text.replace('\u202E', '')
1201 s = text.split('\n')
1202 kek = ''
1203 for x in s:
1204 kek += u"\u202E " + x + '\n'
1205 kek = kek
1206 await self.bot.say(kek, replace_mentions=True)
1207
1208 async def get_emote_image(self, em, one=False, apple=False):
1209 em = em.replace('⠀', '').replace(' ', '')
1210 emote = em.lower()
1211 emote = emote.encode("unicode_escape").decode()
1212 if "\\U000" in emote and emote.count("\\U000") == 1:
1213 emote = emote.replace("\\U000", '')
1214 elif emote.count("\\U000") == 2:
1215 emote = emote.split("\\U000")
1216 emote = '{0}-{1}'.format(emote[1], emote[2])
1217 else:
1218 emote = emote.replace("\\u", '')
1219 if em == '?️?':
1220 emote = '1f308'
1221 if one:
1222 path = self.files_path('emojione/{0}.svg'.format(emote))
1223 elif apple:
1224 path = self.files_path('apple_emoji/{0}.png'.format(emote))
1225 else:
1226 path = self.files_path('twemoji/{0}.svg'.format(emote))
1227 return path
1228
1229 async def png_svg(self, path, size):
1230 with open(path, 'rb') as f:
1231 path = f.read()
1232 s = bytes(str(size), encoding="utf-8")
1233 b = path.replace(b"<svg ", b"<svg width=\"" + s + b"px\" height=\"" + s + b"px\" ")
1234 path = BytesIO(cairosvg.svg2png(b))
1235 return path
1236
1237 fp_emotes = {
1238 #redacted spam
1239 }
1240 @commands.command(pass_context=True, aliases=['emoji', 'hugemoji', 'hugeemoji'])
1241 @commands.cooldown(1, 3, commands.BucketType.user)
1242 async def e(self, ctx, *ems:str):
1243 """Returns a large emoji image"""
1244 try:
1245 if len(ems) == 0:
1246 await self.bot.say(':no_entry: Please input emotes to enlargen.')
1247 return
1248 if len(ems) > 50:
1249 await self.bot.say(':no_entry: `Max emoji limit (<= 50)`')
1250 return
1251 size = 1024
1252 for s in ems:
1253 if s.isdigit():
1254 size = int(s)
1255 if size > 2048:
1256 size = 2048
1257 one = False
1258 apple_emote = False
1259 steam = False
1260 for em in ems:
1261 if em == 'emojione' or em == 'one':
1262 one = True
1263 elif em == 'apple' or em == 'ios':
1264 apple_emote = True
1265 elif em == 'steam':
1266 steam = True
1267 if len(self.twitch_cache) == 0:
1268 twitch_images_load = await self.get_json('https://twitchemotes.com/api_cache/v2/images.json')
1269 twitch_sub_load = await self.get_json('https://twitchemotes.com/api_cache/v2/subscriber.json')
1270 self.twitch_cache.append(twitch_images_load)
1271 self.twitch_cache.append(twitch_sub_load)
1272 else:
1273 twitch_images_load = self.twitch_cache[0]
1274 twitch_sub_load = self.twitch_cache[1]
1275 list_imgs = []
1276 count = -1
1277 for em in ems:
1278 if em == 'emojione' or em == 'one' or em == 'apple' or em == 'ios' or em == 'steam':
1279 continue
1280 if str(em).isdigit():
1281 continue
1282 if em == ' ' or em == '':
1283 continue
1284 found = False
1285 gif = False
1286 count += 1
1287 path = await self.get_emote_image(em, one, apple_emote)
1288 if os.path.isfile(path) is False:
1289 match = self.emote_regex.match(ems[count])
1290 if match != None:
1291 emote = 'https://cdn.discordapp.com/emojis/{0}.png'.format(str(match.group('id')))
1292 path = await self.bytes_download(emote)
1293 if sys.getsizeof(path) == 88:
1294 continue
1295 else:
1296 found = True
1297 else:
1298 found = True
1299 if not apple_emote:
1300 path = await self.png_svg(path, size)
1301 if not found:
1302 match = em.strip(':')
1303 if match in self.fp_emotes:
1304 found = True
1305 url = self.fp_emotes[match]
1306 path = await self.bytes_download(url)
1307 if not found:
1308 match = em.strip(':')
1309 if match in [x[:-4] for x in self.fp_dir]:
1310 try:
1311 f = self.fp_dir[self.fp_dir.index(match+'.png')]
1312 except:
1313 f = self.fp_dir[self.fp_dir.index(match+'.gif')]
1314 gif = True
1315 found = True
1316 path = self.files_path('fp/{0}'.format(f))
1317 if not found:
1318 frankerz_path = self.files_path('frankerz_emotes.txt')
1319 frankerz_emotes = []
1320 with open(frankerz_path) as f:
1321 for line in f:
1322 frankerz_emotes.append(json.loads(line))
1323 f.close()
1324 for page in frankerz_emotes:
1325 for emote in page['emoticons']:
1326 if emote['name'] == em:
1327 found = True
1328 try:
1329 url = 'https:'+emote['urls']['4']
1330 except:
1331 try:
1332 url = 'https:'+emote['urls']['3']
1333 except:
1334 try:
1335 url = 'https:'+emote['urls']['2']
1336 except:
1337 url = 'https:'+emote['urls']['1']
1338 path = await self.bytes_download(url)
1339 break
1340 if not found:
1341 load = twitch_images_load
1342 for emote in load['images']:
1343 if load['images'][emote]['code'] == em:
1344 found = True
1345 url = 'https://static-cdn.jtvnw.net/emoticons/v1/{0}/3.0'.format(emote)
1346 path = await self.bytes_download(url)
1347 break
1348 if not found:
1349 load = twitch_sub_load
1350 for channel in load['channels']:
1351 for emote in load['channels'][channel]['emotes']:
1352 if emote['code'] == em:
1353 found = True
1354 url = 'https://static-cdn.jtvnw.net/emoticons/v1/{0}/3.0'.format(emote)
1355 path = await self.bytes_download(url)
1356 break
1357 if not found:
1358 if em in self.emojis.keys():
1359 path = await self.png_svg(await self.get_emote_image(self.emojis[em]), size)
1360 found = True
1361 if not found and steam:
1362 steam_url = "https://steamcommunity-a.akamaihd.net/economy/emoticon/{0}".format(em.lower())
1363 s_e = await self.bytes_download(steam_url)
1364 if sys.getsizeof(s_e) != 88:
1365 path = s_e
1366 found = True
1367 if found:
1368 list_imgs.append(path)
1369 if len(list_imgs) == 0:
1370 if ems:
1371 for s in ems:
1372 for w in s:
1373 if w in alphabet:
1374 list_imgs.append(await self.png_svg(await self.get_emote_image(self.regional_map[w]), size))
1375 if not list_imgs:
1376 em = [e for e in em]
1377 path = await self.get_emote_image(em[0])
1378 if os.path.isfile(path):
1379 for e in em:
1380 path = await self.get_emote_image(e)
1381 if os.path.isfile(path):
1382 list_imgs.append(await self.png_svg(path, size))
1383 if not list_imgs:
1384 await self.bot.say(":warning: `Emoji Invalid/Not Found`")
1385 return
1386 if len(list_imgs) > 1:
1387 imgs = [PIL.Image.open(i).convert('RGBA') for i in list_imgs]
1388 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
1389 imgs_comb = np.hstack((np.asarray(i.resize(min_shape)) for i in imgs))
1390 imgs_comb = PIL.Image.fromarray(imgs_comb)
1391 b = BytesIO()
1392 imgs_comb.save(b, 'png')
1393 b.seek(0)
1394 else:
1395 b = list_imgs[0]
1396 try:
1397 await self.bot.upload(b, filename='emote.gif' if gif and len(list_imgs) == 1 else 'emote.png')
1398 except:
1399 await self.bot.say('sorry, file 2 big (> 8 mb)')
1400 await asyncio.sleep(5)
1401 try:
1402 self.bot.pruned_messages.append(ctx.message)
1403 await self.bot.delete_message(ctx.message)
1404 except:
1405 pass
1406 except Exception as e:
1407 exc_type, exc_obj, tb = sys.exc_info()
1408 f = tb.tb_frame
1409 lineno = tb.tb_lineno
1410 filename = f.f_code.co_filename
1411 linecache.checkcache(filename)
1412 line = linecache.getline(filename, lineno, f.f_globals)
1413 await self.bot.say(code.format('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)))
1414
1415 @commands.command(pass_context=True, aliases=['steamemoji', 'steame', 'semoji'])
1416 async def se(self, ctx, em:str):
1417 """Returns a steam emoji image"""
1418 em = em.lower()
1419 desc = None
1420 if em == ':b1:' or em == 'b1':
1421 b = self.files_path('b1.png')
1422 else:
1423 url = "https://steamcommunity-a.akamaihd.net/economy/emoticonhover/{0}".format(em)
1424 txt = await self.get_text(url)
1425 if not txt:
1426 await self.bot.say(":warning: `Emoticon Not Found/Invalid`\nRemember to do :steam_emoticon: (optional ':').")
1427 return
1428 root = etree.fromstring(txt, etree.HTMLParser())
1429 base = root.find('.//img[@class="emoticon_large"]')
1430 b = BytesIO(base64.b64decode(base.attrib['src'][22:]))
1431 desc = '**{0}**'.format(root.find('.//div[@class="emoticon_hover_desc"]').text)
1432 await self.bot.upload(b, filename='steam.png', content=desc)
1433
1434 @commands.command(pass_context=True)
1435 @commands.cooldown(3, 5)
1436 async def b1(self, ctx):
1437 """cool"""
1438 await self.bot.upload(self.files_path('b1.png'))
1439
1440 @commands.group(pass_context=True, invoke_without_command=True)
1441 @commands.cooldown(1, 5)
1442 async def merge(self, ctx, *urls:str):
1443 """Merge/Combine Two Photos"""
1444 try:
1445 if urls and 'vertical' in urls:
1446 vertical = True
1447 else:
1448 vertical = False
1449 get_images = await self.get_images(ctx, urls=urls, limit=20)
1450 if get_images and len(get_images) == 1:
1451 await self.bot.say('You gonna merge one image?')
1452 return
1453 elif not get_images:
1454 return
1455 xx = await self.bot.send_message(ctx.message.channel, "ok, processing")
1456 count = 0
1457 list_im = []
1458 for url in get_images:
1459 count += 1
1460 b = await self.bytes_download(url)
1461 if sys.getsizeof(b) == 215:
1462 await self.bot.say(":no_entry: Image `{0}` is invalid!".format(str(count)))
1463 continue
1464 list_im.append(b)
1465 imgs = [PIL.Image.open(i).convert('RGBA') for i in list_im]
1466 if vertical:
1467 max_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[1][1]
1468 imgs_comb = np.vstack((np.asarray(i.resize(max_shape)) for i in imgs))
1469 else:
1470 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
1471 imgs_comb = np.hstack((np.asarray(i.resize(min_shape)) for i in imgs))
1472 imgs_comb = PIL.Image.fromarray(imgs_comb)
1473 final = BytesIO()
1474 imgs_comb.save(final, 'png')
1475 final.seek(0)
1476 await self.bot.delete_message(xx)
1477 await self.bot.upload(final, filename='merge.png')
1478 except Exception as e:
1479 await self.bot.say(code.format(e))
1480
1481 @commands.command(pass_context=True, aliases=['cancerify', 'em'])
1482 async def emojify(self, ctx, *, txt:str):
1483 txt = txt.lower()
1484 msg = ""
1485 for s in txt:
1486 if s in self.emoji_map:
1487 msg += "{0}".format(self.emoji_map[s])
1488 else:
1489 msg += s
1490 await self.bot.say(msg)
1491
1492 @commands.command(pass_context=True, aliases=['toe', 'analyze'])
1493 async def tone(self, ctx, *, text:str):
1494 """Analyze Tone in Text"""
1495 payload = {'text':text}
1496 headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0.2 Waterfox/46.0.2'}
1497 with aiohttp.ClientSession() as session:
1498 async with session.post('https://tone-analyzer-demo.mybluemix.net/api/tone', data=payload, headers=headers) as r:
1499 load = await r.json()
1500 anger = load['document_tone']['tone_categories'][0]['tones'][0]['score']
1501 disgust = load['document_tone']['tone_categories'][0]['tones'][1]['score']
1502 fear = load['document_tone']['tone_categories'][0]['tones'][2]['score']
1503 joy = load['document_tone']['tone_categories'][0]['tones'][3]['score']
1504 sadness = load['document_tone']['tone_categories'][0]['tones'][4]['score']
1505 emotions_msg = "Anger: {0}\nDisgust: {1}\nFear: {2}\nJoy: {3}\nSadness: {4}".format(anger, disgust, fear, joy, sadness)
1506 analytical = load['document_tone']['tone_categories'][1]['tones'][0]['score']
1507 confident = load['document_tone']['tone_categories'][1]['tones'][1]['score']
1508 tentative = load['document_tone']['tone_categories'][1]['tones'][2]['score']
1509 language_msg = "Analytical: {0}\nConfidence: {1}\nTentitive: {2}".format(analytical, confident, tentative)
1510 openness = load['document_tone']['tone_categories'][2]['tones'][0]['score']
1511 conscientiousness = load['document_tone']['tone_categories'][2]['tones'][1]['score']
1512 extraversion = load['document_tone']['tone_categories'][2]['tones'][2]['score']
1513 agreeableness = load['document_tone']['tone_categories'][2]['tones'][3]['score']
1514 emotional_range = load['document_tone']['tone_categories'][2]['tones'][4]['score']
1515 social_msg = "Openness: {0}\nConscientiousness: {1}\nExtraversion (Stimulation): {2}\nAgreeableness: {3}\nEmotional Range: {4}".format(openness, conscientiousness, extraversion, agreeableness, emotional_range)
1516 await self.bot.say("\n**Emotions**"+code.format(emotions_msg)+"**Language Style**"+code.format(language_msg)+"**Social Tendencies**"+code.format(social_msg))
1517
1518 @commands.command(pass_context=True, aliases=['text2img', 'texttoimage', 'text2image'])
1519 async def tti(self, ctx, *, txt:str):
1520 api = 'http://api.img4me.com/?font=arial&fcolor=FFFFFF&size=35&type=png&text={0}'.format(quote(txt))
1521 r = await self.get_text(api)
1522 b = await self.bytes_download(r)
1523 await self.bot.upload(b, filename='tti.png')
1524
1525 @commands.command(pass_context=True, aliases=['comicsans'])
1526 async def sans(self, ctx, *, txt:str):
1527 api = 'http://api.img4me.com/?font=sans&fcolor=000000&size=35&type=png&text={0}'.format(quote(txt))
1528 r = await self.get_text(api)
1529 b = await self.bytes_download(r)
1530 await self.bot.upload(b, filename='tti.png')
1531
1532 @commands.command(pass_context=True, aliases=['needsmorejpeg', 'jpegify', 'magik2'])
1533 @commands.cooldown(2, 5, commands.BucketType.user)
1534 async def jpeg(self, ctx, url:str=None, quality:int=1):
1535 """Add more JPEG to an Image\nNeeds More JPEG!"""
1536 if quality > 10:
1537 quality = 10
1538 elif quality < 1:
1539 quality = 1
1540 get_images = await self.get_images(ctx, urls=url)
1541 if not get_images:
1542 return
1543 for url in get_images:
1544 b = await self.bytes_download(url)
1545 if b is False:
1546 if len(get_images) == 1:
1547 await self.bot.say(':warning: **Command download function failed...**')
1548 return
1549 continue
1550 img = PIL.Image.open(b).convert('RGB')
1551 final = BytesIO()
1552 img.save(final, 'JPEG', quality=quality)
1553 final.seek(0)
1554 await self.bot.upload(final, filename='needsmorejpeg.jpg')
1555
1556 # @commands.command(pass_context=True, aliases=['needsmorejpeg', 'nmj', 'jpegify'])
1557 # async def jpeg(self, ctx, url:str, amount:int=5):
1558 # """Add more JPEG to an Image\nNeeds More JPEG!"""
1559 # if url.startswith('<@') and len(ctx.message.mentions) != 0:
1560 # url = ctx.message.mentions[0].avatar_url
1561 # api = 'http://api.jpeg.li/v1/existing'
1562 # for x in amount:
1563 # payload = {
1564 # 'url': url
1565 # }
1566 # r = requests.post(api, data=payload)
1567 # url = r.json()['url']
1568 # b = await self.bytes_download(url)
1569 # await self.bot.upload(b, filename='needsmorejpeg.jpg')
1570
1571 def do_vw(self, b, txt):
1572 im = PIL.Image.open(b)
1573 k = random.randint(0, 100)
1574 im = macintoshplus.draw_method1(k, txt, im)
1575 final = BytesIO()
1576 im.save(final, 'png')
1577 final.seek(0)
1578 return final
1579
1580 @commands.command(pass_context=True, aliases=['vaporwave', 'vape', 'vapewave'])
1581 @commands.cooldown(2, 5)
1582 async def vw(self, ctx, url:str, *, txt:str=None):
1583 """Vaporwave an image!"""
1584 get_images = await self.get_images(ctx, urls=url, limit=1)
1585 if not get_images:
1586 return
1587 for url in get_images:
1588 if txt is None:
1589 txt = "vapor wave"
1590 b = await self.bytes_download(url)
1591 final = await self.bot.loop.run_in_executor(None, self.do_vw, b, txt)
1592 await self.bot.send_file(ctx.message.channel, final, filename='vapewave.png')
1593
1594 @commands.command(pass_context=True)
1595 async def jagroshisgay(self, ctx, *, txt:str):
1596 x = await self.bot.send_message(ctx.message.channel, txt, replace_mentions=True)
1597 txt = u"\u202E " + txt
1598 await self.bot.edit_message(x, txt)
1599
1600 @commands.command(pass_context=True, aliases=['achievement', 'ach'])
1601 async def mc(self, ctx, *, txt:str):
1602 """Generate a Minecraft Achievement"""
1603 api = "https://mcgen.herokuapp.com/a.php?i=1&h=Achievement-{0}&t={1}".format(ctx.message.author.name, txt)
1604 b = await self.bytes_download(api)
1605 i = 0
1606 while sys.getsizeof(b) == 88 and i != 10:
1607 b = await self.bytes_download(api)
1608 if sys.getsizeof(b) != 0:
1609 i = 10
1610 else:
1611 i += 1
1612 if i == 10 and sys.getsizeof(b) == 88:
1613 await self.bot.say("Minecraft Achievement Generator API is bad, pls try again")
1614 return
1615 await self.bot.upload(b, filename='achievement.png')
1616
1617 @commands.command(aliases=['cow'])
1618 async def cowsay(self, *, txt:str):
1619 try:
1620 msg = await self.bot.run_process(["cowsay", txt], True)
1621 msg = msg
1622 await self.bot.say("```\n"+msg+"```")
1623 except Exception as e:
1624 print(e)
1625
1626 @commands.command(aliases=['dragon'])
1627 async def dragonsay(self, *, txt:str):
1628 msg = await self.bot.run_process(["cowsay", '-f', 'dragon', txt], True)
1629 msg = msg
1630 await self.bot.say("```\n"+msg+"```")
1631
1632 @commands.command(aliases=['sheep'])
1633 async def sheepsay(self, *, txt:str):
1634 msg = await self.bot.run_process(["cowsay", '-f', 'sheep', txt], True)
1635 msg = msg
1636 await self.bot.say("```\n"+msg+"```")
1637
1638 @commands.command(aliases=['dino'])
1639 async def dinosay(self, *, txt:str):
1640 msg = await self.bot.run_process(["cowsay", '-f', 'stegosaurus', txt], True)
1641 msg = msg
1642 await self.bot.say("```\n"+msg+"```")
1643
1644 @commands.command(aliases=['pony'])
1645 async def ponysay(self, *, txt:str):
1646 msg = await self.bot.run_process(["cowsay", '-f', 'unipony-smaller', txt], True)
1647 msg = msg
1648 await self.bot.say("```\n"+msg+"```")
1649
1650 @commands.command(aliases=['mech'])
1651 async def mechsay(self, *, txt:str):
1652 msg = await self.bot.run_process(["cowsay", '-f', 'mech-and-cow', txt], True)
1653 msg = msg
1654 await self.bot.say("```\n"+msg+"```")
1655
1656 @commands.command(aliases=['dragoncow', 'dragonandcow'])
1657 async def dragoncowsay(self, *, txt:str):
1658 msg = await self.bot.run_process(["cowsay", '-f', 'dragon-and-cow', txt], True)
1659 msg = msg
1660 await self.bot.say("```\n"+msg+"```")
1661
1662 # thanks RoadCrosser#3657
1663 @commands.group(pass_context=True, aliases=['eye'], invoke_without_command=True)
1664 @commands.cooldown(2, 5)
1665 async def eyes(self, ctx, url:str=None, eye:str=None, resize:str=None):
1666 get_images = await self.get_images(ctx, urls=url, limit=5)
1667 if not get_images:
1668 return
1669 for url in get_images:
1670 resize_amount = None
1671 monocle = False
1672 flipped = False
1673 flipped_count = 1
1674 if eye != None:
1675 eye = eye.lower()
1676 if eye is None or eye == 'default' or eye == '0':
1677 eye_location = self.files_path('eye.png')
1678 elif eye == 'spongebob' or eye == 'blue' or eye == '1':
1679 eye_location = self.files_path('spongebob_eye.png')
1680 elif eye == 'big' or eye == '2':
1681 eye_location = self.files_path('big_eye.png')
1682 resize_amount = 110
1683 elif eye == 'small' or eye == '3':
1684 eye_location = self.files_path('small_eye.png')
1685 resize_amount = 110
1686 elif eye == 'money' or eye == '4':
1687 eye_location = self.files_path('money_eye.png')
1688 elif eye == 'blood' or eye == 'bloodshot' or eye == '5':
1689 eye_location = self.files_path('bloodshot_eye.png')
1690 resize_amount = 200
1691 elif eye == 'red' or eye == '6':
1692 eye_location = self.files_path('red_eye.png')
1693 resize_amount = 200
1694 elif eye == 'meme' or eye == 'illuminati' or eye == 'triangle' or eye == '7':
1695 eye_location = self.files_path('illuminati_eye.png')
1696 resize_amount = 150
1697 elif eye == 'googly' or eye == 'googlyeye' or eye == 'plastic' or eye == '8':
1698 eye_location = self.files_path('googly_eye.png')
1699 resize_amount = 200
1700 elif eye == 'monocle' or eye == 'fancy' or eye == '9':
1701 eye_location = self.files_path('monocle_eye.png')
1702 resize_amount = 80
1703 monocle = True
1704 elif eye == 'flip' or eye == 'flipped' or eye == 'reverse' or eye == 'reversed' or eye == '10':
1705 eye_location = self.files_path('eye.png')
1706 eye_flipped_location = self.files_path('eye_flipped.png')
1707 flipped = True
1708 elif 'eyesCenter' in eye or eye == 'one' or eye == 'center' or eye == '11':
1709 eye_location = self.files_path('one_eye_center.png')
1710 else:
1711 eye_location = self.files_path('eye.png')
1712 if resize_amount is None:
1713 resize_amount = 130
1714 try:
1715 if resize != None:
1716 sigh = str(resize).split('.')
1717 if len(sigh) == 1:
1718 resize = int(resize)
1719 else:
1720 resize = float(resize)
1721 if resize == 0:
1722 resize_amount = 120
1723 else:
1724 resize_amount = resize*100
1725 except ValueError:
1726 resize_amount = 120
1727 x = await self.bot.send_message(ctx.message.channel, "ok, processing")
1728 b = await self.bytes_download(url)
1729 if b is False:
1730 if len(get_images) == 1:
1731 await self.bot.say(':warning: **Command download function failed...**')
1732 return
1733 continue
1734 img = PIL.Image.open(b).convert("RGBA")
1735 eyes = PIL.Image.open(eye_location).convert("RGBA")
1736 data = {"url": url}
1737 headers = {"Content-Type":"application/json","Ocp-Apim-Subscription-Key": '3bb232c5dcba448c8b1e95da94b286cd'}
1738 async with aiohttp.ClientSession() as session:
1739 async with session.post('https://api.projectoxford.ai/face/v1.0/detect?returnFaceId=false&returnFaceLandmarks=true&returnFaceAttributes=headPose', headers=headers, data=json.dumps(data)) as r:
1740 faces = await r.json()
1741 if "error" in faces:
1742 await self.bot.say(":warning: `Error occured in the API, could not process image url`")
1743 await self.bot.delete_message(x)
1744 return
1745 if len(faces) == 0:
1746 await self.bot.say(":no_entry: `Face not detected`")
1747 await self.bot.delete_message(x)
1748 return
1749 eye_list = []
1750 for f in faces:
1751 if monocle == True:
1752 eye_list += ([((f['faceLandmarks']['pupilRight']['x'],f['faceLandmarks']['pupilRight']['y']),f['faceRectangle']['height'],(f['faceAttributes']['headPose']))])
1753 else:
1754 eye_list += (((f['faceLandmarks']['pupilLeft']['x'],f['faceLandmarks']['pupilLeft']['y']),f['faceRectangle']['height'],(f['faceAttributes']['headPose'])),((f['faceLandmarks']['pupilRight']['x'],f['faceLandmarks']['pupilRight']['y']),f['faceRectangle']['height'],(f['faceAttributes']['headPose'])))
1755 for e in eye_list:
1756 width, height = eyes.size
1757 h = e[1]/resize_amount*50
1758 width = h/height*width
1759 if flipped:
1760 if (flipped_count % 2 == 0):
1761 s_image = wand.image.Image(filename=eye_flipped_location)
1762 else:
1763 s_image = wand.image.Image(filename=eye_location)
1764 flipped_count += 1
1765 else:
1766 s_image = wand.image.Image(filename=eye_location)
1767 i = s_image.clone()
1768 i.resize(int(width), int(h))
1769 s_image = BytesIO()
1770 i.save(file=s_image)
1771 s_image.seek(0)
1772 inst = PIL.Image.open(s_image)
1773 yaw = e[2]['yaw']
1774 pitch = e[2]['pitch']
1775 width, height = inst.size
1776 pyaw = int(yaw/180*height)
1777 ppitch = int(pitch/180*width)
1778 new = PIL.Image.new('RGBA', (width+posnum(ppitch)*2, height+posnum(pyaw)*2), (255, 255, 255, 0))
1779 new.paste(inst, (posnum(ppitch), posnum(pyaw)))
1780 width, height = new.size
1781 coeffs = find_coeffs([(0, 0), (width, 0), (width, height), (0, height)], [(ppitch, pyaw), (width-ppitch, -pyaw), (width+ppitch, height+pyaw), (-ppitch, height-pyaw)])
1782 inst = new.transform((width, height), PIL.Image.PERSPECTIVE, coeffs, PIL.Image.BICUBIC).rotate(-e[2]['roll'], expand=1, resample=PIL.Image.BILINEAR)
1783 eyel = PIL.Image.new('RGBA', img.size, (255, 255, 255, 0))
1784 width, height = inst.size
1785 if monocle:
1786 eyel.paste(inst, (int(e[0][0]-width/2), int(e[0][1]-height/3.7)))
1787 else:
1788 eyel.paste(inst, (int(e[0][0]-width/2), int(e[0][1]-height/2)))
1789 img = PIL.Image.alpha_composite(img, eyel)
1790 final = BytesIO()
1791 img.save(final, "png")
1792 final.seek(0)
1793 await self.bot.upload(final, filename="eyes.png")
1794 await self.bot.delete_message(x)
1795 # except Exception as e:
1796 # exc_type, exc_obj, tb = sys.exc_info()
1797 # f = tb.tb_frame
1798 # lineno = tb.tb_lineno
1799 # filename = f.f_code.co_filename
1800 # linecache.checkcache(filename)
1801 # line = linecache.getline(filename, lineno, f.f_globals)
1802 # await self.bot.say(code.format('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)))
1803 # os.remove(location)
1804 # os.remove(final_location)
1805 # os.remove(s_image_loc)
1806
1807 @eyes.command(name='list', pass_context=True, invoke_without_command=True)
1808 @commands.cooldown(1, 20)
1809 async def eyes_list(self, ctx):
1810 eyes = ['Default - 0', 'Spongebob - 1', 'Big - 2', 'Small - 3', 'Money - 4', 'Bloodshot - 5', 'Red - 6', 'Illuminati - 7', 'Googly - 8', 'Monocle - 9', 'Flipped - 10', 'Center - 11']
1811 thing = []
1812 for s in eyes:
1813 thing.append('`'+s+'`')
1814 await self.bot.say("In order to use, you must do `eyes image_url eye_type (name or number)`\n**Eye types**\n"+', '.join(thing))
1815
1816 @commands.command(pass_context=True, aliases=['identify', 'captcha', 'whatis'])
1817 async def i(self, ctx, *, url:str):
1818 """Identify an image/gif using Microsofts Captionbot API"""
1819 with aiohttp.ClientSession() as session:
1820 async with session.post("https://www.captionbot.ai/api/message", data={"conversationId": "FPrBPK2gAJj","waterMark": "","userMessage": url}) as r:
1821 pass
1822 load = await self.get_json("https://www.captionbot.ai/api/message?waterMark=&conversationId=FPrBPK2gAJj")
1823 msg = '`{0}`'.format(json.loads(load)['BotMessages'][-1])
1824 await self.bot.say(msg)
1825
1826 @commands.command(pass_context=True, aliases=['mentionspam'])
1827 @commands.cooldown(1, 30)
1828 @checks.admin_or_perm(manage_server=True)
1829 async def ms(self, ctx, amount:int, id:str, channel:discord.Channel=None):
1830 if amount > 100:
1831 await self.bot.say("2 many mentions asshole")
1832 return
1833 try:
1834 await self.bot.delete_message(ctx.message)
1835 except:
1836 pass
1837 user = discord.Server.get_member(ctx.message.server, id)
1838 if user is None:
1839 await self.bot.say("invalid user id")
1840 return
1841 channels_readable = []
1842 for s in ctx.message.server.channels:
1843 if s.type == discord.ChannelType.voice:
1844 continue
1845 if user.permissions_in(s).read_messages and user.permissions_in(s).send_messages:
1846 channels_readable.append(s)
1847 count = 0
1848 for i in range(amount):
1849 if channel is None:
1850 for s in channels_readable:
1851 if count == amount:
1852 break
1853 x = await self.bot.send_message(s, '{0}'.format(user.mention))
1854 await self.bot.delete_message(x)
1855 count += 1
1856 await asyncio.sleep(0.21)
1857 else:
1858 x = await self.bot.send_message(channel, '{0}'.format(user.mention))
1859 await self.bot.delete_message(x)
1860 await asyncio.sleep(0.21)
1861 x = await self.bot.say('done')
1862 await asyncio.sleep(5)
1863 await self.bot.delete_message(x)
1864
1865 # yeah, hardcoded paths for life on this one
1866 @commands.group(pass_context=True, invoke_without_command=True, aliases=['texttospeech', 'text2speech'])
1867 async def tts(self, ctx, *, txt:str):
1868 """Text to speech"""
1869 rand = self.bot.random()
1870 ogg_name = '{0}.ogg'.format(rand)
1871 path = '/var/www/vhosts/mods.nyc/bot.mods.nyc/ogg_files/{0}'.format(ogg_name)
1872 html = '<audio controls autoplay><source src="https://bot.facepunch.org/ogg_files/{0}" type="audio/ogg"></audio>'.format(ogg_name)
1873 html_file_name = '{0}.html'.format(rand)
1874 html_file = '/var/www/vhosts/mods.nyc/bot.mods.nyc/tts/{0}'.format(html_file_name)
1875 with open(html_file, 'wb') as f:
1876 f.write(html.encode())
1877 f.close()
1878 url_msg = 'https://bot.facepunch.org/tts/{0}'.format(html_file_name)
1879 url = 'https://text-to-speech-demo.mybluemix.net/api/synthesize?voice=en-US_AllisonVoice&X-WDC-PL-OPT-OUT=1&self.download=true&text={0}'.format(quote(txt))
1880 await self.download(url, path)
1881 await self.bot.say(url_msg)
1882
1883 @tts.command(name='custom', pass_context=True, invoke_without_command=True, aliases=['texttospeech', 'text2speech'])
1884 async def tts_custom(self, ctx, voice:str, *, txt:str):
1885 """Text to speech"""
1886 voice = voice.lower()
1887 vv = None
1888 if voice == 'allison':
1889 vv = 'en-US_AllisonVoice'
1890 elif voice == 'michael':
1891 vv = 'en-US_MichaelVoice'
1892 elif voice == 'lisa':
1893 vv = 'en-US_LisaVoice'
1894 elif voice == 'kate':
1895 vv = 'en-GB_KateVoice'
1896 elif voice == 'renee':
1897 vv = 'fr-FR_ReneeVoice'
1898 elif voice == 'birgit':
1899 vv = 'de-DE_BirgitVoice'
1900 elif voice == 'dieter':
1901 vv = 'de-DE_DieterVoice'
1902 elif voice == 'francesca':
1903 vv = 'it-IT_FrancescaVoice'
1904 elif voice == 'emi':
1905 vv = 'ja-JP_EmiVoice'
1906 elif voice == 'isabela':
1907 vv = 'pt-BR_IsabelaVoice'
1908 elif voice == 'enrique':
1909 vv = 'es-ES_EnriqueVoice'
1910 elif voice == 'laura':
1911 vv = 'es-ES_LauraVoice'
1912 elif voice == 'sofia':
1913 vv = 'es-US_SofiaVoice'
1914 if vv is None:
1915 await self.bot.say("**Invalid Voice**\nHere's a list of voices you can use `format: tts custom <voice (without location)> <text>`\n"+', '.join(self.voice_list))
1916 return
1917 rand = self.bot.random()
1918 ogg_name = 'tts_{0}.ogg'.format(rand)
1919 path = '/var/www/vhosts/mods.nyc/bot.mods.nyc/ogg_files/{0}'.format(ogg_name)
1920 html = '<audio controls autoplay><source src="https://bot.facepunch.org/ogg_files/{0}" type="audio/ogg"></audio>'.format(ogg_name)
1921 html_file_name = '{0}.html'.format(rand)
1922 html_file = '/var/www/vhosts/mods.nyc/bot.mods.nyc/tts/{0}'.format(html_file_name)
1923 with open(html_file, 'wb') as f:
1924 f.write(html.encode())
1925 f.close()
1926 url_msg = 'https://bot.facepunch.org/tts/{0}'.format(html_file_name)
1927 url = 'https://text-to-speech-demo.mybluemix.net/api/synthesize?voice={1}&text={0}&X-WDC-PL-OPT-OUT=1&self.download=true'.format(txt.replace(' ', '%20'), vv)
1928 await self.download(url, path)
1929 await self.bot.say(url_msg)
1930
1931 @tts.command(name='list', invoke_without_command=True)
1932 async def tts_list(self):
1933 await self.bot.say("**List of custom voices**\nFormat: `tts custom <voice (without location)> <text>`\n"+', '.join(self.voice_list))
1934
1935 @commands.command(pass_context=True, aliases=['wm'])
1936 async def watermark(self, ctx, url:str, mark:str=None):
1937 try:
1938 check = await self.isimage(url)
1939 if check == False:
1940 await self.bot.say("Invalid or Non-Image!")
1941 return
1942 b = await self.bytes_download(url)
1943 if mark == 'brazzers' or mark is None:
1944 wmm = self.files_path('brazzers.png')
1945 else:
1946 check = await self.isimage(mark)
1947 if check == False:
1948 await self.bot.say("Invalid or Non-Image for Watermark!")
1949 return
1950 wmm = await self.bytes_download(mark)
1951 final = BytesIO()
1952 with wand.image.Image(file=b) as img:
1953 if mark:
1954 with wand.image.Image(file=wmm) as wm:
1955 img.watermark(image=wm, left=int(img.width/15), top=int(img.height/10))
1956 else:
1957 with wand.image.Image(filename=wmm) as wm:
1958 img.watermark(image=wm, left=int(img.width/15), top=int(img.height/10))
1959 img.save(file=final)
1960 final.seek(0)
1961 await self.bot.upload(final, filename='watermark.png')
1962 except Exception as e:
1963 exc_type, exc_obj, tb = sys.exc_info()
1964 f = tb.tb_frame
1965 lineno = tb.tb_lineno
1966 filename = f.f_code.co_filename
1967 linecache.checkcache(filename)
1968 line = linecache.getline(filename, lineno, f.f_globals)
1969 await self.bot.say(code.format('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)))
1970
1971 def do_glitch(self, b, amount, seed, iterations):
1972 b.seek(0)
1973 img = jpglitch.Jpeg(bytearray(b.getvalue()), amount, seed, iterations)
1974 final = BytesIO()
1975 img.save_image(final)
1976 final.seek(0)
1977 return final
1978
1979 def do_gglitch(self, b):
1980 b = bytearray(b.getvalue())
1981 for x in range(0, sys.getsizeof(b)):
1982 if b[x] == 33:
1983 if b[x + 1] == 255:
1984 end = x
1985 break
1986 elif b[x + 1] == 249:
1987 end = x
1988 break
1989 for x in range(13, end):
1990 b[x] = random.randint(0, 255)
1991 return BytesIO(b)
1992
1993 @commands.command(aliases=['jpglitch'], pass_context=True)
1994 @commands.cooldown(2, 5)
1995 async def glitch(self, ctx, url:str=None, iterations:int=None, amount:int=None, seed:int=None):
1996 try:
1997 if iterations is None:
1998 iterations = random.randint(1, 30)
1999 if amount is None:
2000 amount = random.randint(1, 20)
2001 elif amount > 99:
2002 amount = 99
2003 if seed is None:
2004 seed = random.randint(1, 20)
2005 get_images = await self.get_images(ctx, urls=url, msg=False)
2006 gif = False
2007 if not get_images:
2008 get_images = await self.get_images(ctx, urls=url, gif=True)
2009 if get_images:
2010 gif = True
2011 else:
2012 return
2013 for url in get_images:
2014 b = await self.bytes_download(url)
2015 if not gif:
2016 img = PIL.Image.open(b)
2017 b = BytesIO()
2018 img.save(b, format='JPEG')
2019 final = await self.bot.loop.run_in_executor(None, self.do_glitch, b, amount, seed, iterations)
2020 await self.bot.upload(final, filename='glitch.jpeg', content='Iterations: `{0}` | Amount: `{1}` | Seed: `{2}`'.format(iterations, amount, seed))
2021 else:
2022 final = await self.bot.loop.run_in_executor(None, self.do_gglitch, b)
2023 await self.bot.upload(final, filename='glitch.gif')
2024 except:
2025 await self.bot.say("sorry, can't reglitch an image.")
2026 raise
2027
2028 @commands.command(pass_context=True)
2029 async def glitch2(self, ctx, *urls:str):
2030 try:
2031 get_images = await self.get_images(ctx, urls=urls)
2032 if not get_images:
2033 return
2034 for url in get_images:
2035 path = self.files_path(self.bot.random(True))
2036 await self.download(url, path)
2037 args = ['convert', '(', path, '-resize', '1024x1024>', ')', '-alpha', 'on', '(', '-clone', '0', '-channel', 'RGB', '-separate', '-channel', 'A', '-fx', '0', '-compose', 'CopyOpacity', '-composite', ')', '(', '-clone', '0', '-roll', '+5', '-channel', 'R', '-fx', '0', '-channel', 'A', '-evaluate', 'multiply', '.3', ')', '(', '-clone', '0', '-roll', '-5', '-channel', 'G', '-fx', '0', '-channel', 'A', '-evaluate', 'multiply', '.3', ')', '(', '-clone', '0', '-roll', '+0+5', '-channel', 'B', '-fx', '0', '-channel', 'A', '-evaluate', 'multiply', '.3', ')', '(', '-clone', '0', '-channel', 'A', '-fx', '0', ')', '-delete', '0', '-background', 'none', '-compose', 'SrcOver', '-layers', 'merge', '-rotate', '90', '-wave', '1x5', '-rotate', '-90', path]
2038 await self.bot.run_process(args)
2039 await self.bot.upload(path, filename='glitch2.png')
2040 os.remove(path)
2041 except:
2042 try:
2043 os.remove(path)
2044 except:
2045 pass
2046 raise
2047
2048 def do_sort(self, image, interval, angle, randomness, s_func):
2049 input_img = PIL.Image.open(image)
2050 input_img.convert('RGBA')
2051 input_img.rotate(angle, expand=True)
2052 data = input_img.load()
2053 pixels = []
2054 for y in range(input_img.size[1]):
2055 pixels.append([])
2056 for x in range(input_img.size[0]):
2057 pixels[y].append(data[x, y])
2058 intervals = self.interval_functions[interval](pixels, image, angle)
2059 s_func = self.s_functions[s_func]
2060 sorted_pixels = pixelsort.sorter.sort_image(pixels, intervals, randomness, s_func)
2061 output_img = PIL.Image.new('RGBA', input_img.size)
2062 for y in range(output_img.size[1]):
2063 for x in range(output_img.size[0]):
2064 output_img.putpixel((x, y), sorted_pixels[y][x])
2065 if angle != 0:
2066 output_img.rotate(-angle, expand=True)
2067 output_img = pixelsort.util.crop_to(output_img, PIL.Image.open(image))
2068 b = BytesIO()
2069 output_img.save(b, 'png')
2070 b.seek(0)
2071 return b
2072
2073 @commands.command(aliases=['pixelsort'], pass_context=True)
2074 @commands.cooldown(2, 5, commands.BucketType.user)
2075 async def sort(self, ctx, url:str=None, *args):
2076 try:
2077 angle = 0
2078 randomness = 0
2079 interval = 'edges'
2080 s_func = 'lightness'
2081 for arg in args:
2082 if arg.isdigit() and arg != '0' and angle is 0:
2083 angle = int(arg)
2084 elif randomness is 0 and arg.isdigit():
2085 randomness = int(arg)
2086 elif interval == 'edges':
2087 interval = str(arg)
2088 else:
2089 s_func = str(arg)
2090 if interval not in self.interval_functions.keys():
2091 await self.bot.say(':warning: Invalid Interval Function.\nInterval Functions: `{0}`'.format(', '.join(list(self.interval_functions.keys()))))
2092 return
2093 elif s_func not in self.s_functions.keys():
2094 await self.bot.say(':warning: Invalid Sorting Function.\nSorting Functions: `{0}`'.format(', '.join(list(self.s_functions.keys()))))
2095 return
2096 if angle >= 360:
2097 await self.bot.say(':warning: Angle must be less then `360`.')
2098 angle = 0
2099 get_images = await self.get_images(ctx, urls=url)
2100 if not get_images:
2101 return
2102 for url in get_images:
2103 b = await self.bytes_download(url)
2104 if b is False:
2105 if len(get_images) == 1:
2106 await self.bot.say(':warning: **Command download function failed...**')
2107 return
2108 continue
2109 img = await self.bot.loop.run_in_executor(None, self.do_sort, b, interval, angle, randomness, s_func)
2110 await self.bot.upload(img, filename='pixelsort.png', content='Interval: `{0}` | Sorting: `{1}`{2}{3}'.format(interval, s_func, ' | Angle: **{0}**'.format(angle) if angle != 0 else '', ' | Randomness: **{0}**'.format(randomness) if randomness != 0 else ''))
2111 except Exception as e:
2112 exc_type, exc_obj, tb = sys.exc_info()
2113 f = tb.tb_frame
2114 lineno = tb.tb_lineno
2115 filename = f.f_code.co_filename
2116 linecache.checkcache(filename)
2117 line = linecache.getline(filename, lineno, f.f_globals)
2118 await self.bot.say(code.format('EXCEPTION IN ({}, LINE {} "{}"): {}'.format(filename, lineno, line.strip(), exc_obj)))
2119
2120 @commands.command()
2121 async def bean(self, url:str):
2122 """You got BEANED"""
2123 try:
2124 check = await self.isimage(url)
2125 if check is False:
2126 await self.bot.say('Invalid or Non-Image!')
2127 return
2128 b = await self.bytes_download(url)
2129 bean_path = self.files_path('bean.png')
2130 bean = PIL.Image.open(bean_path)
2131 img = PIL.Image.open(b)
2132 width, height = bean.size
2133 bean.resize((int(width/50), int(height/50)))
2134 img.paste(bean, (math.floor(width/2), math.floor(height/2)))
2135 final = BytesIO()
2136 img.save(final, 'png')
2137 final.seek(0)
2138 await self.bot.upload(final, filename='beaned.png')
2139 except Exception as e:
2140 await self.bot.say(e)
2141
2142 @commands.command(aliases=['pixel'], pass_context=True)
2143 async def pixelate(self, ctx, *urls):
2144 try:
2145 get_images = await self.get_images(ctx, urls=urls, limit=6, scale=3000)
2146 if not get_images:
2147 return
2148 img_urls = get_images[0]
2149 pixels = get_images[1]
2150 if pixels is None:
2151 pixels = 9
2152 scale_msg = get_images[2]
2153 if scale_msg is None:
2154 scale_msg = ''
2155 for url in img_urls:
2156 b = await self.bytes_download(url)
2157 if b is False:
2158 if len(img_urls) > 1:
2159 await self.bot.say(':warning: **Command download function failed...**')
2160 return
2161 continue
2162 bg = (0, 0, 0)
2163 img = PIL.Image.open(b)
2164 img = img.resize((int(img.size[0]/pixels), int(img.size[1]/pixels)), PIL.Image.NEAREST)
2165 img = img.resize((int(img.size[0]*pixels), int(img.size[1]*pixels)), PIL.Image.NEAREST)
2166 load = img.load()
2167 for i in range(0, img.size[0], pixels):
2168 for j in range(0, img.size[1], pixels):
2169 for r in range(pixels):
2170 load[i+r, j] = bg
2171 load[i, j+r] = bg
2172 final = BytesIO()
2173 img.save(final, 'png')
2174 final.seek(0)
2175 await self.bot.upload(final, filename='pixelated.png', content=scale_msg)
2176 await asyncio.sleep(0.21)
2177 except:
2178 await self.bot.say(':warning: `Too many pixels.`')
2179
2180 async def do_retro(self, text, bcg):
2181 if '|' not in text:
2182 if len(text) >= 15:
2183 text = [text[i:i + 15] for i in range(0, len(text), 15)]
2184 else:
2185 split = text.split()
2186 if len(split) == 1:
2187 text = [x for x in text]
2188 if len(text) == 4:
2189 text[2] = text[2]+text[-1]
2190 del text[3]
2191 else:
2192 text = split
2193 else:
2194 text = text.split('|')
2195 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:43.0) Gecko/20100101 Firefox/43.0'}
2196 payload = aiohttp.FormData()
2197 payload.add_field('current-category', 'all_effects')
2198 payload.add_field('bcg', bcg)
2199 payload.add_field('txt', '4')
2200 count = 1
2201 for s in text:
2202 if count > 3:
2203 break
2204 payload.add_field('text'+str(count), s.replace("'", "\'"))
2205 count += 1
2206 try:
2207 with aiohttp.ClientSession() as session:
2208 with aiohttp.Timeout(5):
2209 async with session.post('https://photofunia.com/effects/retro-wave?server=3', data=payload, headers=headers) as r:
2210 txt = await r.text()
2211 except asyncio.TimeoutError:
2212 return
2213 match = self.retro_regex.findall(txt)
2214 if match:
2215 download_url = match[0][0]
2216 b = await self.bytes_download(download_url)
2217 return b
2218 return False
2219
2220 @commands.command()
2221 async def retro(self, *, text:str):
2222 retro_result = await self.do_retro(text, '5')
2223 if retro_result is False:
2224 await self.bot.say(':warning: This text contains unsupported characters')
2225 else:
2226 await self.bot.upload(retro_result, filename='retro.png')
2227
2228 @commands.command()
2229 async def retro2(self, *, text:str):
2230 retro_result = await self.do_retro(text, '2')
2231 if retro_result is False:
2232 await self.bot.say(':warning: This text contains unsupported characters')
2233 else:
2234 await self.bot.upload(retro_result, filename='retro.png')
2235
2236 @commands.command()
2237 async def retro3(self, *, text:str):
2238 retro_result = await self.do_retro(text, '4')
2239 if retro_result is False:
2240 await self.bot.say(':warning: This text contains unsupported characters')
2241 else:
2242 await self.bot.upload(retro_result, filename='retro.png')
2243
2244 def do_waaw(self, b):
2245 f = BytesIO()
2246 f2 = BytesIO()
2247 with wand.image.Image(file=b, format='png') as img:
2248 h1 = img.clone()
2249 width = int(img.width/2) if int(img.width/2) > 0 else 1
2250 h1.crop(width=width, height=int(img.height), gravity='east')
2251 h2 = h1.clone()
2252 h1.rotate(degree=180)
2253 h1.flip()
2254 h1.save(file=f)
2255 h2.save(file=f2)
2256 f.seek(0)
2257 f2.seek(0)
2258 list_im = [f2, f]
2259 imgs = [PIL.ImageOps.mirror(PIL.Image.open(i).convert('RGBA')) for i in list_im]
2260 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
2261 imgs_comb = np.hstack((np.asarray(i.resize(min_shape)) for i in imgs))
2262 imgs_comb = PIL.Image.fromarray(imgs_comb)
2263 final = BytesIO()
2264 imgs_comb.save(final, 'png')
2265 final.seek(0)
2266 return final
2267
2268 #Thanks to Iguniisu#9746 for the idea
2269 @commands.command(pass_context=True, aliases=['magik3', 'mirror'])
2270 @commands.cooldown(2, 5, commands.BucketType.user)
2271 async def waaw(self, ctx, *urls:str):
2272 get_images = await self.get_images(ctx, urls=urls, limit=5)
2273 if not get_images:
2274 return
2275 for url in get_images:
2276 b = await self.bytes_download(url)
2277 if b is False:
2278 if len(get_images) == 1:
2279 await self.bot.say(':warning: **Command download function failed...**')
2280 return
2281 continue
2282 final = await self.bot.loop.run_in_executor(None, self.do_waaw, b)
2283 await self.bot.upload(final, filename='waaw.png')
2284
2285 def do_haah(self, b):
2286 f = BytesIO()
2287 f2 = BytesIO()
2288 with wand.image.Image(file=b, format='png') as img:
2289 h1 = img.clone()
2290 h1.transform('50%x100%')
2291 h2 = h1.clone()
2292 h2.rotate(degree=180)
2293 h2.flip()
2294 h1.save(file=f)
2295 h2.save(file=f2)
2296 f.seek(0)
2297 f2.seek(0)
2298 list_im = [f2, f]
2299 imgs = [PIL.ImageOps.mirror(PIL.Image.open(i).convert('RGBA')) for i in list_im]
2300 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
2301 imgs_comb = np.hstack((np.asarray(i.resize(min_shape)) for i in imgs))
2302 imgs_comb = PIL.Image.fromarray(imgs_comb)
2303 final = BytesIO()
2304 imgs_comb.save(final, 'png')
2305 final.seek(0)
2306 return final
2307
2308 @commands.command(pass_context=True, aliases=['magik4', 'mirror2'])
2309 @commands.cooldown(2, 5, commands.BucketType.user)
2310 async def haah(self, ctx, *urls:str):
2311 get_images = await self.get_images(ctx, urls=urls, limit=5)
2312 if not get_images:
2313 return
2314 for url in get_images:
2315 b = await self.bytes_download(url)
2316 if b is False:
2317 if len(get_images) == 1:
2318 await self.bot.say(':warning: **Command download function failed...**')
2319 return
2320 continue
2321 final = await self.bot.loop.run_in_executor(None, self.do_haah, b)
2322 await self.bot.upload(final, filename='haah.png')
2323
2324 def do_woow(self, b):
2325 f = BytesIO()
2326 f2 = BytesIO()
2327 with wand.image.Image(file=b, format='png') as img:
2328 h1 = img.clone()
2329 width = int(img.width) if int(img.width) > 0 else 1
2330 h1.crop(width=width, height=int(img.height/2), gravity='north')
2331 h2 = h1.clone()
2332 h2.rotate(degree=180)
2333 h2.flop()
2334 h1.save(file=f)
2335 h2.save(file=f2)
2336 f.seek(0)
2337 f2.seek(0)
2338 list_im = [f, f2]
2339 imgs = [PIL.Image.open(i).convert('RGBA') for i in list_im]
2340 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
2341 imgs_comb = np.vstack((np.asarray(i.resize(min_shape)) for i in imgs))
2342 imgs_comb = PIL.Image.fromarray(imgs_comb)
2343 final = BytesIO()
2344 imgs_comb.save(final, 'png')
2345 final.seek(0)
2346 return final
2347
2348 @commands.command(pass_context=True, aliases=['magik5', 'mirror3'])
2349 @commands.cooldown(2, 5, commands.BucketType.user)
2350 async def woow(self, ctx, *urls:str):
2351 get_images = await self.get_images(ctx, urls=urls, limit=5)
2352 if not get_images:
2353 return
2354 for url in get_images:
2355 b = await self.bytes_download(url)
2356 if b is False:
2357 if len(get_images) == 1:
2358 await self.bot.say(':warning: **Command download function failed...**')
2359 return
2360 continue
2361 final = await self.bot.loop.run_in_executor(None, self.do_woow, b)
2362 await self.bot.upload(final, filename='woow.png')
2363
2364 def do_hooh(self, b):
2365 f = BytesIO()
2366 f2 = BytesIO()
2367 with wand.image.Image(file=b, format='png') as img:
2368 h1 = img.clone()
2369 width = int(img.width) if int(img.width) > 0 else 1
2370 h1.crop(width=width, height=int(img.height/2), gravity='south')
2371 h2 = h1.clone()
2372 h1.rotate(degree=180)
2373 h2.flop()
2374 h1.save(file=f)
2375 h2.save(file=f2)
2376 f.seek(0)
2377 f2.seek(0)
2378 list_im = [f, f2]
2379 imgs = [PIL.Image.open(i).convert('RGBA') for i in list_im]
2380 min_shape = sorted([(np.sum(i.size), i.size) for i in imgs])[0][1]
2381 imgs_comb = np.vstack((np.asarray(i.resize(min_shape)) for i in imgs))
2382 imgs_comb = PIL.Image.fromarray(imgs_comb)
2383 final = BytesIO()
2384 imgs_comb.save(final, 'png')
2385 final.seek(0)
2386 return final
2387
2388 @commands.command(pass_context=True, aliases=['magik6', 'mirror4'])
2389 @commands.cooldown(2, 5, commands.BucketType.user)
2390 async def hooh(self, ctx, *urls:str):
2391 get_images = await self.get_images(ctx, urls=urls, limit=5)
2392 if not get_images:
2393 return
2394 for url in get_images:
2395 b = await self.bytes_download(url)
2396 if b is False:
2397 if len(get_images) == 1:
2398 await self.bot.say(':warning: **Command download function failed...**')
2399 return
2400 continue
2401 final = await self.bot.loop.run_in_executor(None, self.do_hooh, b)
2402 await self.bot.upload(final, filename='hooh.png')
2403
2404 @commands.command(pass_context=True)
2405 async def flip(self, ctx, *urls:str):
2406 get_images = await self.get_images(ctx, urls=urls, limit=5)
2407 if not get_images:
2408 return
2409 for url in get_images:
2410 b = await self.bytes_download(url)
2411 img = PIL.Image.open(b)
2412 img = PIL.ImageOps.flip(img)
2413 final = BytesIO()
2414 img.save(final, 'png')
2415 final.seek(0)
2416 await self.bot.upload(final, filename='flip.png')
2417
2418 @commands.command(pass_context=True)
2419 async def flop(self, ctx, *urls:str):
2420 get_images = await self.get_images(ctx, urls=urls, limit=5)
2421 if not get_images:
2422 return
2423 for url in get_images:
2424 b = await self.bytes_download(url)
2425 img = PIL.Image.open(b)
2426 img = PIL.ImageOps.mirror(img)
2427 final = BytesIO()
2428 img.save(final, 'png')
2429 final.seek(0)
2430 await self.bot.upload(final, filename='flop.png')
2431
2432 @commands.command(pass_context=True, aliases=['inverse', 'negate'])
2433 async def invert(self, ctx, url:str=None, *, txt:str=None):
2434 if not url.startswith('http'):
2435 if txt:
2436 txt = url + txt
2437 else:
2438 txt = url
2439 get_images = await self.get_images(ctx, urls=url, limit=1)
2440 else:
2441 get_images = await self.get_images(ctx, urls=url, limit=1)
2442 if not get_images:
2443 return
2444 for url in get_images:
2445 b = await self.bytes_download(url)
2446 img = PIL.Image.open(b).convert('RGBA')
2447 img = PIL.ImageOps.invert(img)
2448 final = BytesIO()
2449 img.save(final, 'png')
2450 final.seek(0)
2451 await self.bot.upload(final, filename='flop.png')
2452
2453 @commands.command(aliases=['indicator'])
2454 async def regional(self, *, txt:str):
2455 msg = ''
2456 for s in txt.lower():
2457 if s in self.regional_map:
2458 msg += u''+self.regional_map[s]
2459 else:
2460 msg += s
2461 await self.bot.say(msg)
2462
2463 @commands.command(pass_context=True)
2464 @commands.cooldown(2, 5)
2465 async def react(self, ctx, *, txt:str):
2466 msg = None
2467 channel = ctx.message.channel
2468 for c in ctx.message.channel_mentions:
2469 channel = c
2470 txt = txt.replace(c.mention, '')
2471 if not channel.is_private:
2472 perms = channel.permissions_for(ctx.message.server.me)
2473 if perms.add_reactions is False:
2474 await self.bot.say(':no_entry: `Sorry, I do not have add_rections permission.`')
2475 return
2476 for s in txt.split():
2477 if s.isdigit():
2478 if len(s) > 10:
2479 msg = await self.bot.get_message(channel, s)
2480 txt = txt.replace(s, '')
2481 break
2482 if msg is None:
2483 msg = ctx.message
2484 count = 0
2485 icount = 0
2486 continue_count = 0
2487 added = []
2488 indexs = {}
2489 _x = False
2490 word_emotes = ['cool', 'ok', 'ng', 'up', 'new', 'ab', 'cl', 'sos', 'id']
2491 for split in txt.lower().split():
2492 if split in word_emotes and split not in added:
2493 indexs[txt.lower().rindex(split)] = [len(split), self.emojis[split]]
2494 match = self.emote_regex.match(split)
2495 if match:
2496 em = None
2497 for e in self.bot.get_all_emojis():
2498 if e.id == str(match.group('id')):
2499 em = e
2500 break
2501 if em:
2502 indexs[txt.lower().rindex(split)] = [len(split), em]
2503 for s in txt.lower():
2504 if len(added) > 20:
2505 break
2506 if s == ' ':
2507 continue
2508 if icount in indexs:
2509 i = indexs[icount]
2510 if i[1] in added:
2511 continue
2512 continue_count += i[0]
2513 await self.bot.add_reaction(msg, i[1])
2514 added.append(i[1])
2515 count += 1
2516 else:
2517 if icount == 0:
2518 icount += 1
2519 if continue_count != 0:
2520 icount += 1
2521 continue_count -= 1
2522 continue
2523 em = None
2524 if s not in added:
2525 if s in self.regional_map:
2526 em = self.regional_map[s]
2527 elif s in self.emojis:
2528 em = self.emojis[s]
2529 else:
2530 for e in self.emojis:
2531 if self.emojis[e] == s:
2532 em = self.emojis[e]
2533 break
2534 if em is None:
2535 if s == '?':
2536 em = self.emojis['question']
2537 elif s == '!':
2538 em = self.emojis['exclamation']
2539 elif s == '#':
2540 em = self.emojis['hash']
2541 else:
2542 if s == 'a' or s == 'b' or s == 'm':
2543 em = self.emojis[s]
2544 elif s == 'c':
2545 em = self.emojis['copyright']
2546 elif s == 'r':
2547 em = self.emojis['registered']
2548 elif s == 'o':
2549 em = self.emojis['o2']
2550 elif s == 'p':
2551 em = self.emojis['parking']
2552 elif s == 'i':
2553 em = self.emojis['information_source']
2554 elif s == 'l':
2555 if txt.lower().count('i') <= 1:
2556 em = self.regional_map['i']
2557 elif s == 'e':
2558 em = self.emojis['email']
2559 elif s == 'm':
2560 em = self.emojis['scorpius']
2561 elif s == 'o':
2562 em = self.emojis['zero']
2563 elif s == 'x':
2564 if _x:
2565 em = self.emojis['heavy_multiplication_x']
2566 else:
2567 em = self.emojis[s]
2568 _x = True
2569 if em:
2570 await self.bot.add_reaction(msg, em)
2571 added.append(s)
2572 count += 1
2573 await asyncio.sleep(0.21)
2574 icount += 1
2575 if count == 0:
2576 await self.bot.say(':no_entry: Invalid Text.')
2577 else:
2578 x = await self.bot.send_message(ctx.message.channel, ':white_check_mark: Added `{0}` reactions.'.format(count))
2579 await asyncio.sleep(5)
2580 try:
2581 if msg != ctx.message:
2582 await self.bot.delete_messages([x, ctx.message])
2583 else:
2584 await self.bot.delete_message(x)
2585 except:
2586 pass
2587
2588 @commands.command()
2589 async def webmd(self):
2590 """Your personal online medical question assistant!"""
2591 if self.webmd_count >= len(self.webmd_responses):
2592 self.webmd_count = 0
2593 kek = self.webmd_responses[self.webmd_count]
2594 self.webmd_count += 1
2595 await self.bot.say(':information_source: *According to WebMD*\n**{0}**...'.format(kek))
2596
2597 @commands.command(pass_context=True)
2598 @commands.cooldown(1, 5)
2599 async def wasted(self, ctx, *urls:str):
2600 """GTA5 Wasted Generator"""
2601 try:
2602 get_images = await self.get_images(ctx, urls=urls, limit=3)
2603 if not get_images:
2604 return
2605 for url in get_images:
2606 path = self.files_path(self.bot.random(True))
2607 await self.download(url, path)
2608 args = ['convert', path]
2609 img = PIL.Image.open(path)
2610 aspectRatio = img.height / img.width
2611 aspectRatio2 = img.width / img.height
2612 height = img.height
2613 width = img.width
2614 if img.width < 512:
2615 args.append('-resize')
2616 width = 512
2617 height = math.floor(aspectRatio * 512)
2618 args.append('512x{0}'.format(height))
2619 if img.height < 512:
2620 args.append('-resize')
2621 height = 512
2622 width = math.floor(aspectRatio2 * 512)
2623 args.append(str(width))
2624 if img.width > 1500:
2625 args.append('-resize')
2626 width = 1500
2627 height = math.floor(aspectRatio * 1500)
2628 args.append('1500x{0}'.format(height))
2629 if img.height > 1500:
2630 args.append('-resize')
2631 height = 1500
2632 width = math.floor(aspectRatio2 * 1500)
2633 args.append(str(width))
2634 args.extend(['-recolor', '.3 .1 .3 .3 .1 .3 .3 .1 .3', '-fill', 'rgba(0,0,0,0.5)'])
2635 signHeight = height * 0.2
2636 args.extend(['-draw', 'rectangle 0, {0}, {1}, {2}'.format(height / 2 - signHeight / 2, width, height / 2 + signHeight / 2)])
2637 args.extend([
2638 '-gravity', 'South',
2639 '-font', self.files_path('pricedown.ttf'),
2640 '-fill', 'rgb(200,30,30)',
2641 '-stroke', 'black',
2642 '-strokewidth', '3',
2643 '-weight', '300'
2644 ])
2645 args.extend([
2646 '-pointsize', str(math.floor(signHeight * 0.8)),
2647 '-draw', 'text 0,{0} "wasted"'.format(math.floor(height / 2 - signHeight * 0.45)),
2648 path])
2649 await self.bot.run_process(args)
2650 await self.bot.upload(path, filename='wasted.png')
2651 del img
2652 os.remove(path)
2653 except:
2654 try:
2655 os.remove(path)
2656 except:
2657 pass
2658 raise
2659
2660 @commands.command(pass_context=True, aliases=['greentext', '>'])
2661 async def green(self, ctx, *, txt:str):
2662 try:
2663 self.bot.pruned_messages.append(ctx.message)
2664 await self.bot.delete_message(ctx.message)
2665 except:
2666 pass
2667 await self.bot.say('```css\n>{0}\n```'.format(txt), replace_mentions=True)
2668
2669 @commands.command(pass_context=True, aliases=['lsd', 'drugs', 'wew'])
2670 @commands.cooldown(1, 5)
2671 async def rainbow(self, ctx, *urls:str):
2672 """Change images color matrix multiple times into a gif"""
2673 try:
2674 get_images = await self.get_images(ctx, urls=urls, limit=3)
2675 if not get_images:
2676 return
2677 for url in get_images:
2678 path = self.files_path(self.bot.random(True))
2679 path2 = path[:-3]+'gif'
2680 await self.download(url, path)
2681 args = ['convert']
2682 for c in self.color_combinations:
2683 args.extend([
2684 '(',
2685 path,
2686 '-resize', '256x256>',
2687 '-colorize', '{0},{1},{2}'.format(c[0], c[1], c[2]),
2688 ')'
2689 ])
2690 args.extend([
2691 '-delay', '2',
2692 '-set', 'delay', '2',
2693 '-loop', '0',
2694 path2])
2695 await self.bot.run_process(args)
2696 await self.bot.upload(path2, filename='rainbow.gif')
2697 os.remove(path)
2698 os.remove(path2)
2699 except:
2700 try:
2701 os.remove(path)
2702 os.remove(path2)
2703 except:
2704 pass
2705 raise
2706
2707 @commands.command(pass_context=True, aliases=['waves'])
2708 @commands.cooldown(1, 5)
2709 async def wave(self, ctx, *urls:str):
2710 """Wave image multiple times into a gif"""
2711 try:
2712 get_images = await self.get_images(ctx, urls=urls, limit=3)
2713 if not get_images:
2714 return
2715 for url in get_images:
2716 path = self.files_path(self.bot.random(True))
2717 path2 = path[:-3]+'gif'
2718 await self.download(url, path)
2719 args = ['convert', '(', path, '-resize', '256x256>', ')', '-alpha', 'on', 'canvas:none', '-background', 'none']
2720 amp = 5
2721 while amp < 20:
2722 args.extend([
2723 '(',
2724 '-clone', '0',
2725 '-wave', '-' + str(amp) + 'x15',
2726 ')'
2727 ])
2728 amp += 5
2729 amp = 20
2730 while amp >= 5:
2731 args.extend([
2732 '(',
2733 '-clone', '0',
2734 '-wave', '-' + str(amp) + 'x15',
2735 ')'
2736 ])
2737 amp -= 5
2738 args.extend([
2739 '-delay', '4',
2740 '-set', 'delay', '4',
2741 '-loop', '0',
2742 path2])
2743 await self.bot.run_process(args)
2744 await self.bot.upload(path2, filename='wave.gif')
2745 os.remove(path)
2746 os.remove(path2)
2747 except:
2748 try:
2749 os.remove(path)
2750 os.remove(path2)
2751 except:
2752 pass
2753 raise
2754
2755 @commands.command(pass_context=True)
2756 @commands.cooldown(1, 5)
2757 async def wall(self, ctx, *urls:str):
2758 """Image multiplied with curved perspective"""
2759 try:
2760 get_images = await self.get_images(ctx, urls=urls, limit=3)
2761 if not get_images:
2762 return
2763 for url in get_images:
2764 path = self.files_path(self.bot.random(True))
2765 await self.download(url, path)
2766 await self.bot.run_process(['convert', '(', path, '-resize', '128', ')', '-virtual-pixel', 'tile', '-mattecolor', 'none', '-background', 'none', '-resize', '512x512!', '-distort', 'Perspective', '0,0,57,42 0,128,63,130 128,0,140,60 128,128,140,140', path])
2767 await self.bot.upload(path, filename='wall.png')
2768 os.remove(path)
2769 except:
2770 try:
2771 os.remove(path)
2772 except:
2773 pass
2774 raise
2775
2776 @commands.command(pass_context=True, aliases=['cappend', 'layers'])
2777 @commands.cooldown(1, 5)
2778 async def layer(self, ctx, *urls:str):
2779 """Layers an image with its self"""
2780 try:
2781 get_images = await self.get_images(ctx, urls=urls, limit=3)
2782 if not get_images:
2783 return
2784 for url in get_images:
2785 path = self.files_path(self.bot.random(True))
2786 await self.download(url, path)
2787 args = ['convert', path]
2788 args.extend([
2789 '(',
2790 path,
2791 '-flop',
2792 ')',
2793 '+append',
2794 '(',
2795 '(',
2796 path,
2797 '-flip',
2798 ')',
2799 '(',
2800 path,
2801 '-flop',
2802 '-flip',
2803 ')',
2804 '+append',
2805 ')',
2806 '-append',
2807 path])
2808 await self.bot.run_process(args)
2809 await self.bot.upload(path, filename='layer.png')
2810 os.remove(path)
2811 except:
2812 try:
2813 os.remove(path)
2814 except:
2815 pass
2816 raise
2817
2818 @commands.command(pass_context=True)
2819 async def rotate(self, ctx, *urls:str):
2820 """Rotate image X degrees"""
2821 get_images = await self.get_images(ctx, urls=urls, limit=3, scale=360)
2822 if not get_images:
2823 return
2824 img_urls = get_images[0]
2825 scale = get_images[1] if get_images[1] else random.choice([90, 180, 50, 45, 270, 120, 80])
2826 for url in img_urls:
2827 b = await self.bytes_download(url)
2828 img = PIL.Image.open(b).convert('RGBA')
2829 img = img.rotate(int(scale))
2830 final = BytesIO()
2831 img.save(final, 'png')
2832 final.seek(0)
2833 await self.bot.upload(final, filename='rotate.png', content='Rotated: `{0}°`'.format(scale))
2834
2835 @commands.command(pass_context=True)
2836 @commands.cooldown(1, 5)
2837 async def dice(self, ctx, *urls:str):
2838 """Dice up an image"""
2839 try:
2840 get_images = await self.get_images(ctx, urls=urls, limit=3)
2841 if not get_images:
2842 return
2843 for url in get_images:
2844 path = self.files_path(self.bot.random(True))
2845 path2 = path[:-3]+'miff'
2846 await self.download(url, path)
2847 img = PIL.Image.open(path)
2848 width, height = img.size
2849 size = min(math.ceil(width * .1), math.ceil(height * .1))
2850 fragmentsW = math.ceil(width / size)
2851 fragmentsH = math.ceil(height / size)
2852 total = fragmentsW * fragmentsH
2853 args = ['convert', '-quiet', path, '-crop', '{0}x{0}'.format(size), path2]
2854 await self.bot.run_process(args)
2855 args = ['montage', '-background', 'none', '-tile', '{0}x{1}'.format(fragmentsW, fragmentsH), '-geometry', '+0+0']
2856 i = 0
2857 while i < total:
2858 rand = random.randint(-2, 2)
2859 args.extend([
2860 '(',
2861 '{0}[{1}]'.format(path2, i), '-rotate', str(rand * 90),
2862 ')'
2863 ])
2864 i += 1
2865 args.append(path)
2866 await self.bot.run_process(args)
2867 await self.bot.upload(path, filename='dice.png')
2868 os.remove(path)
2869 os.remove(path2)
2870 del img
2871 except:
2872 try:
2873 os.remove(path)
2874 os.remove(path2)
2875 except:
2876 pass
2877 raise
2878
2879 @commands.command(pass_context=True)
2880 @commands.cooldown(1, 5)
2881 async def scramble(self, ctx, *urls:str):
2882 """Scramble image"""
2883 try:
2884 get_images = await self.get_images(ctx, urls=urls, limit=3)
2885 if not get_images:
2886 return
2887 for url in get_images:
2888 path = self.files_path(self.bot.random(True))
2889 path2 = path[:-3]+'miff'
2890 await self.download(url, path)
2891 img = PIL.Image.open(path)
2892 width, height = img.size
2893 size = min(math.ceil(width * .1), math.ceil(height * .1))
2894 fragmentsW = math.ceil(width / size)
2895 fragmentsH = math.ceil(height / size)
2896 total = fragmentsW * fragmentsH
2897 left = []
2898 i = 0
2899 while i < total:
2900 left.append(i)
2901 i += 1
2902 args = ['convert', '-quiet', path, '-crop', '{0}x{0}'.format(size), path2]
2903 await self.bot.run_process(args)
2904 args = ['montage', '-background', 'none', '-tile', '{0}x{1}'.format(fragmentsW, fragmentsH), '-geometry', '+0+0']
2905 i = 0
2906 while i < total:
2907 r = random.randint(0, len(left)-1)
2908 sli = left[r]
2909 left.pop(r)
2910 rand = random.randint(-2, 2)
2911 args.extend(['(', '{0}[{1}]'.format(path2, sli), '-rotate', str(rand * 90), ')'])
2912 i += 1
2913 args.append(path)
2914 await self.bot.run_process(args)
2915 await self.bot.upload(path, filename='scramble.png')
2916 os.remove(path)
2917 os.remove(path2)
2918 del img
2919 except:
2920 try:
2921 os.remove(path)
2922 os.remove(path2)
2923 except:
2924 pass
2925 raise
2926
2927 @commands.command(pass_context=True)
2928 @commands.cooldown(1, 5)
2929 async def scramble2(self, ctx, *urls:str):
2930 """Scramble image without rotation"""
2931 try:
2932 get_images = await self.get_images(ctx, urls=urls, limit=3)
2933 if not get_images:
2934 return
2935 for url in get_images:
2936 path = self.files_path(self.bot.random(True))
2937 path2 = path[:-3]+'miff'
2938 await self.download(url, path)
2939 img = PIL.Image.open(path)
2940 width, height = img.size
2941 size = min(math.ceil(width * .1), math.ceil(height * .1))
2942 fragmentsW = math.ceil(width / size)
2943 fragmentsH = math.ceil(height / size)
2944 total = fragmentsW * fragmentsH
2945 left = []
2946 i = 0
2947 while i < total:
2948 left.append(i)
2949 i += 1
2950 args = ['convert', '-quiet', path, '-crop', '{0}x{0}'.format(size), path2]
2951 await self.bot.run_process(args)
2952 args = ['montage', '-background', 'none', '-tile', '{0}x{1}'.format(fragmentsW, fragmentsH), '-geometry', '+0+0']
2953 i = 0
2954 while i < total:
2955 r = random.randint(0, len(left)-1)
2956 sli = left[r]
2957 left.pop(r)
2958 args.extend(['{0}[{1}]'.format(path2, sli)])
2959 i += 1
2960 args.append(path)
2961 await self.bot.run_process(args)
2962 await self.bot.upload(path, filename='scramble2.png')
2963 os.remove(path)
2964 os.remove(path2)
2965 del img
2966 except:
2967 try:
2968 os.remove(path)
2969 os.remove(path2)
2970 except:
2971 pass
2972 raise
2973
2974 @commands.command(pass_context=True, aliases=['multi'])
2975 @commands.cooldown(1, 10)
2976 async def multiply(self, ctx, *urls:str):
2977 """Rotate and shrink image multiple times on a large canvas"""
2978 try:
2979 get_images = await self.get_images(ctx, urls=urls, limit=3)
2980 if not get_images:
2981 return
2982 for url in get_images:
2983 path = self.files_path(self.bot.random(True))
2984 await self.download(url, path)
2985 img = PIL.Image.open(path)
2986 width, height = img.size
2987 size = min(math.ceil(width * .1), math.ceil(height * .1))
2988 fragmentsW = math.ceil(width / size)
2989 fragmentsH = math.ceil(height / size)
2990 total = fragmentsW * fragmentsH
2991 args = ['convert', '-quiet', path, '-crop', '{0}x{0}'.format(size), path]
2992 await self.bot.run_process(args)
2993 args = ['montage', '-background', 'none', '-tile', '{0}x{1}'.format(fragmentsW, fragmentsH), '-geometry', '+0+0']
2994 i = 0
2995 while i < total:
2996 rand = random.randint(-2, 2)
2997 args.extend([
2998 '(',
2999 '{0}[{1}]'.format(path, i), '-rotate', str(rand * 90),
3000 ')'
3001 ])
3002 i += 1
3003 args.append(path)
3004 await self.bot.run_process(args)
3005 await self.bot.upload(path, filename='wtf.png')
3006 os.remove(path)
3007 del img
3008 except:
3009 try:
3010 os.remove(path)
3011 except:
3012 pass
3013 raise
3014
3015 @commands.command(pass_context=True)
3016 @commands.cooldown(1, 5)
3017 async def shake(self, ctx, *urls:str):
3018 """Generate a Triggered Gif for a User or Image"""
3019 try:
3020 get_images = await self.get_images(ctx, urls=urls, limit=3)
3021 if not get_images:
3022 return
3023 for url in get_images:
3024 path = self.files_path(self.bot.random(True))
3025 path2 = path[:-3]+'gif'
3026 await self.download(url, path)
3027 await self.bot.run_process(['convert',
3028 'canvas:none',
3029 '-size', '512x512!',
3030 '-resize', '512x512!',
3031 '-draw', 'image over -60,-60 640,640 "{0}"'.format(path),
3032 '(',
3033 'canvas:none',
3034 '-size', '512x512!',
3035 '-draw', 'image over -45,-50 640,640 "{0}"'.format(path),
3036 ')',
3037 '(',
3038 'canvas:none',
3039 '-size', '512x512!',
3040 '-draw', 'image over -50,-45 640,640 "{0}"'.format(path),
3041 ')',
3042 '(',
3043 'canvas:none',
3044 '-size', '512x512!',
3045 '-draw', 'image over -45,-65 640,640 "{0}"'.format(path),
3046 ')',
3047 '-layers', 'Optimize',
3048 '-set', 'delay', '2',
3049 path2])
3050 await self.bot.upload(path2, filename='shake.gif')
3051 os.remove(path)
3052 os.remove(path2)
3053 except Exception as e:
3054 await self.bot.say(e)
3055 try:
3056 os.remove(path)
3057 os.remove(path2)
3058 except:
3059 pass
3060
3061 @commands.command(pass_context=True, aliases=['360', 'grotate'])
3062 @commands.cooldown(1, 5)
3063 async def spin(self, ctx, *urls:str):
3064 """Make image into circular form and rotate it 360 into a gif"""
3065 try:
3066 get_images = await self.get_images(ctx, urls=urls, limit=3)
3067 if not get_images:
3068 return
3069 for url in get_images:
3070 path = self.files_path(self.bot.random(True))
3071 path2 = path[:3]+'gif'
3072 await self.download(url, path)
3073 args = ['convert', '-alpha', 'on', '(', path, '-scale', '256x256>', '-scale', '256x256<', ')', '(', '-size', '256x256', 'xc:none', '-fill', 'white', '-draw', 'circle 128,128 128,0', ')', '-compose', 'copyopacity', '-background', 'white']
3074 i = 0
3075 while i <= 340:
3076 args.extend(['(', '-clone', '0', '-rotate', str(i), '-crop', '256x256+0+0!', '-clone', '1', '-composite', ')'])
3077 i += 20
3078 args.extend(['-compose', 'srcover', '-delete', '0', '-delete', '0', '-delay', '5', '-set', 'delay', '5', '-set', 'dispose', 'None', path2])
3079 await self.bot.run_process(args)
3080 await self.bot.upload(path, filename='spin.gif')
3081 os.remove(path)
3082 os.remove(path2)
3083 except:
3084 try:
3085 os.remove(path)
3086 os.remove(path2)
3087 except:
3088 pass
3089 raise
3090
3091def setup(bot):
3092 bot.add_cog(Fun(bot))