diff --git a/ASCII/README.md b/ASCII/README.md
index 37a00e9..47cf595 100644
--- a/ASCII/README.md
+++ b/ASCII/README.md
@@ -1,6 +1,9 @@
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=T8E56M6SP9JH2)
+Try the plugin out in #ircart on EFnet. irc://irc.efnet.org/#ircart
+
+
ASCII Art Plugin
Convert text to ASCII art or image URLs to ASCII/ANSI art. Covert ASCII art to PNG. Get ASCII weather, moon phase, and cryptocurrecy rates.
@@ -103,14 +106,15 @@ img --bg <0-99> (set a background color)
img --fg <0-99> (set a foreground color)
img --fast (use Euclidean color difference.)
img --slow (use cie2000 color difference. best quality, default)
-img --dither (dither source image to 256 colors. trades off quality for speed)
+img --quantize (quantize source image to 256 colors. trades off quality for speed)
+img --no-quantize (don't quantize source to 256 colors)
```
Here are some images using 99 color default output:
-
+
^ output of img https://i.imgur.com/aF9wihd.jpg (image command with default settings)
-
+
^ output of img --block https://i.imgur.com/aF9wihd.jpg (image command with colored space blocks)
-
+
^ output of img --ascii https://i.imgur.com/aF9wihd.jpg (image command with colored space blocks)
```
***************+*++++++++++++++++++++++++++++++++++++++=++=++========================---------------
diff --git a/ASCII/__init__.py b/ASCII/__init__.py
index 8b77afe..00f39a1 100644
--- a/ASCII/__init__.py
+++ b/ASCII/__init__.py
@@ -1,43 +1,44 @@
-###
-# Copyright (c) 2019 oddluck
-# All rights reserved.
-#
-#
-###
-
-"""
-ASCII: Uses API to retrieve information
-"""
-
-import supybot
-import supybot.world as world
-
-# Use this for the version of this plugin. You may wish to put a CVS keyword
-# in here if you're keeping the plugin in CVS or some similar system.
-__version__ = ""
-
-# XXX Replace this with an appropriate author or supybot.Author instance.
-__author__ = supybot.authors.unknown
-
-# This is a dictionary mapping supybot.Author instances to lists of
-# contributions.
-__contributors__ = {}
-
-# This is a url where the most recent plugin package can be downloaded.
-__url__ = ''
-
-from . import config
-from . import plugin
-from imp import reload
-# In case we're being reloaded.
-reload(config)
-reload(plugin)
-# Add more reloads here if you add third-party modules and want them to be
-# reloaded when this plugin is reloaded. Don't forget to import them as well!
-
-if world.testing:
- from . import test
-
-Class = plugin.Class
-configure = config.configure
-
+###
+# Copyright (c) 2019 oddluck
+# All rights reserved.
+#
+#
+###
+
+"""
+ASCII: Uses API to retrieve information
+"""
+
+import supybot
+import supybot.world as world
+
+# Use this for the version of this plugin. You may wish to put a CVS keyword
+# in here if you're keeping the plugin in CVS or some similar system.
+__version__ = ""
+
+# XXX Replace this with an appropriate author or supybot.Author instance.
+__author__ = supybot.Author('oddluck', 'oddluck',
+ 'oddluck@riseup.net')
+
+# This is a dictionary mapping supybot.Author instances to lists of
+# contributions.
+__contributors__ = {}
+
+# This is a url where the most recent plugin package can be downloaded.
+__url__ = 'https://github.com/oddluck/limnoria-plugins/'
+
+from . import config
+from . import plugin
+from imp import reload
+# In case we're being reloaded.
+reload(config)
+reload(plugin)
+# Add more reloads here if you add third-party modules and want them to be
+# reloaded when this plugin is reloaded. Don't forget to import them as well!
+
+if world.testing:
+ from . import test
+
+Class = plugin.Class
+configure = config.configure
+
diff --git a/ASCII/config.py b/ASCII/config.py
index 18893b1..6b6f68d 100644
--- a/ASCII/config.py
+++ b/ASCII/config.py
@@ -1,57 +1,66 @@
-###
-# Copyright (c) 2019, oddluck
-# All rights reserved.
-#
-#
-###
-
-import supybot.conf as conf
-import supybot.registry as registry
-try:
- from supybot.i18n import PluginInternationalization
- _ = PluginInternationalization('ASCII')
-except:
- # Placeholder that allows to run the plugin on a bot
- # without the i18n module
- _ = lambda x: x
-
-
-def configure(advanced):
- # This will be called by supybot to configure this module. advanced is
- # a bool that specifies whether the user identified themself as an advanced
- # user or not. You should effect your configuration by manipulating the
- # registry as appropriate.
- from supybot.questions import expect, anything, something, yn
- conf.registerPlugin('ASCII', True)
-
-ASCII = conf.registerPlugin('ASCII')
-
-conf.registerGlobalValue(ASCII, 'pasteAPI',
-registry.String('', _("""Paste.ee API Key""")))
-
-conf.registerGlobalValue(ASCII, 'imgurAPI',
-registry.String('', _("""Imgur Client ID""")))
-
-conf.registerChannelValue(ASCII, 'pasteEnable',
-registry.Boolean(False, _("""Turns on and off paste.ee support""")))
-
-conf.registerChannelValue(ASCII, 'delay',
-registry.Float(1.0, _("""Set the time delay betwen lines. Not currently implemented.""")))
-
-conf.registerChannelValue(ASCII, 'dither',
-registry.Boolean(True, _("""Enable dithering. Results in much faster rendering at a slight decrease in quality. Default: True""")))
-
-conf.registerChannelValue(ASCII, 'speed',
-registry.String('Slow', _("""Set the speed of the color rendering. 'Slow' (default) to use CIEDE2000 color difference. 'Fast' to use Euclidean color difference.""")))
-
-conf.registerChannelValue(ASCII, 'imgDefault',
-registry.String('1/2', _("""Set the default art type for the img command. Options are 'ascii', '1/2' (default), '1/4', 'block', and 'no-color'""")))
-
-conf.registerChannelValue(ASCII, 'asciiWidth',
-registry.Integer(100, _("""Set the default column width for ascii art images""")))
-
-conf.registerChannelValue(ASCII, 'blockWidth',
-registry.Integer(70, _("""Set the default column width for 1/2 and 1/4 block art images""")))
-
-conf.registerChannelValue(ASCII, 'colors',
-registry.Integer(99, _("""Set the default number of colors to use. Options are 16 for colors 0-15 only, 83 for colors 16-98 only, and 99 (default) to use all available colors""")))
+###
+# Copyright (c) 2019, oddluck
+# All rights reserved.
+#
+#
+###
+
+import supybot.conf as conf
+import supybot.registry as registry
+try:
+ from supybot.i18n import PluginInternationalization
+ _ = PluginInternationalization('ASCII')
+except:
+ # Placeholder that allows to run the plugin on a bot
+ # without the i18n module
+ _ = lambda x: x
+
+
+def configure(advanced):
+ # This will be called by supybot to configure this module. advanced is
+ # a bool that specifies whether the user identified themself as an advanced
+ # user or not. You should effect your configuration by manipulating the
+ # registry as appropriate.
+ from supybot.questions import expect, anything, something, yn
+ conf.registerPlugin('ASCII', True)
+
+ASCII = conf.registerPlugin('ASCII')
+
+conf.registerGlobalValue(ASCII, 'pasteAPI',
+registry.String('', _("""Paste.ee API Key""")))
+
+conf.registerGlobalValue(ASCII, 'imgurAPI',
+registry.String('', _("""Imgur Client ID""")))
+
+conf.registerChannelValue(ASCII, 'pasteEnable',
+registry.Boolean(False, _("""Turns on and off paste.ee support""")))
+
+conf.registerChannelValue(ASCII, 'delay',
+registry.Float(1.0, _("""Set the time delay betwen lines. Not currently implemented.""")))
+
+conf.registerChannelValue(ASCII, 'quantize',
+registry.Boolean(False, _("""Enable quantizing to 256 colors before rendering. Results in much faster rendering at a slight decrease in quality. Default: False""")))
+
+conf.registerChannelValue(ASCII, 'resize',
+registry.Integer(3, _("""Set the resize algorithm. 0 = nearest, 1 = lanczos, 2 = bilinear, 3 = bicubic, 4 = box, 5 = hamming""")))
+
+conf.registerChannelValue(ASCII, 'speed',
+registry.String('Slow', _("""Set the speed of the color rendering. 'Slow' (default) to use CIEDE2000 color difference. 'Fast' to use Euclidean color difference.""")))
+
+conf.registerChannelValue(ASCII, 'imgDefault',
+registry.String('1/2', _("""Set the default art type for the img command. Options are 'ascii', '1/2' (default), '1/4', 'block', and 'no-color'""")))
+
+conf.registerChannelValue(ASCII, 'asciiWidth',
+registry.Integer(100, _("""Set the default column width for ascii art images""")))
+
+conf.registerChannelValue(ASCII, 'blockWidth',
+registry.Integer(80, _("""Set the default column width for 1/2 and 1/4 block art images""")))
+
+conf.registerChannelValue(ASCII, 'colors',
+registry.Integer(99, _("""Set the default number of colors to use. Options are 16 for colors 0-15 only, 83 for colors 16-98 only, and 99 (default) to use all available colors""")))
+
+conf.registerChannelValue(ASCII, 'fg',
+registry.Integer(99, _("""Set the default foreground color for ascii art images. 0-98. 99 is disabled (default)""")))
+
+conf.registerChannelValue(ASCII, 'bg',
+registry.Integer(99, _("""Set the default background color for ascii art images. 0-98. 99 is disabled (default)""")))
diff --git a/ASCII/plugin.py b/ASCII/plugin.py
index 8f90237..2dfb8b0 100644
--- a/ASCII/plugin.py
+++ b/ASCII/plugin.py
@@ -1,1713 +1,1664 @@
-###
-# Copyright (c) 2019 oddluck
-# All rights reserved.
-#
-#
-###
-
-import supybot.ansi as ansi
-import supybot.utils as utils
-from supybot.commands import *
-import supybot.plugins as plugins
-import supybot.ircutils as ircutils
-import supybot.callbacks as callbacks
-import supybot.ircmsgs as ircmsgs
-import os
-import requests
-from PIL import Image, ImageOps, ImageFont, ImageDraw, ImageEnhance
-import numpy as np
-import sys, math
-from fake_useragent import UserAgent
-import re
-import pexpect
-import time
-import random as random
-import pyimgur
-from bs4 import BeautifulSoup
-
-try:
- from supybot.i18n import PluginInternationalization
- _ = PluginInternationalization('Weed')
-except ImportError:
- # Placeholder that allows to run the plugin on a bot
- # without the i18n module
- _ = lambda x: x
-
-class ASCII(callbacks.Plugin):
- """Uses API to retrieve information"""
- threaded = True
-
- def __init__(self, irc):
- self.__parent = super(ASCII, self)
- self.__parent.__init__(irc)
- self.colors = 99
- self.stopped = {}
- self.old_color = None
- self.rgbColors = [
- (255,255,255),
- (0,0,0),
- (0,0,127),
- (0,147,0),
- (255,0,0),
- (127,0,0),
- (156,0,156),
- (252,127,0),
- (255,255,0),
- (0,252,0),
- (0,147,147),
- (0,255,255),
- (0,0,252),
- (255,0,255),
- (127,127,127),
- (210,210,210),
- (71,0,0),
- (71,33,0),
- (71,71,0),
- (50,71,0),
- (0,71,0),
- (0,71,44),
- (0,71,71),
- (0,39,71),
- (0,0,71),
- (46,0,71),
- (71,0,71),
- (71,0,42),
- (116,0,0),
- (116,58,0),
- (116,116,0),
- (81,116,0),
- (0,116,0),
- (0,116,73),
- (0,116,116),
- (0,64,116),
- (0,0,116),
- (75,0,116),
- (116,0,116),
- (116,0,69),
- (181,0,0),
- (181,99,0),
- (181,181,0),
- (125,181,0),
- (0,181,0),
- (0,181,113),
- (0,181,181),
- (0,99,181),
- (0,0,181),
- (117,0,181),
- (181,0,181),
- (181,0,107),
- (255,0,0),
- (255,140,0),
- (255,255,0),
- (178,255,0),
- (0,255,0),
- (0,255,160),
- (0,255,255),
- (0,140,255),
- (0,0,255),
- (165,0,255),
- (255,0,255),
- (255,0,152),
- (255,89,89),
- (255,180,89),
- (255,255,113),
- (207,255,96),
- (111,255,111),
- (101,255,201),
- (109,255,255),
- (89,180,255),
- (89,89,255),
- (196,89,255),
- (255,102,255),
- (255,89,188),
- (255,156,156),
- (255,211,156),
- (255,255,156),
- (226,255,156),
- (156,255,156),
- (156,255,219),
- (156,255,255),
- (156,211,255),
- (156,156,255),
- (220,156,255),
- (255,156,255),
- (255,148,211),
- (0,0,0),
- (19,19,19),
- (40,40,40),
- (54,54,54),
- (77,77,77),
- (101,101,101),
- (129,129,129),
- (159,159,159),
- (188,188,188),
- (226,226,226),
- (255,255,255)]
- self.colors83= {
- (11.5497, 31.8768, 18.1739):16,
- (17.5866, 15.7066, 25.9892):17,
- (29.0208, -8.5776, 37.5533):18,
- (27.2543, -19.015, 35.3673):19,
- (25.2798, -34.2963, 32.8426):20,
- (25.8276, -27.5812, 10.7515):21,
- (26.6245, -19.1316, -5.6261):22,
- (14.986, 1.2467, -23.6473):23,
- (4.1091, 27.6851, -41.3905):24,
- (9.2862, 34.8709, -32.6869):25,
- (14.3696, 39.0991, -24.2113):26,
- (12.6512, 34.8073, -6.066):27,
- (22.699, 44.779, 34.3145):28,
- (31.2054, 21.9979, 41.7676):29,
- (47.2407, -12.0488, 52.8125):30,
- (44.5753, -27.9355, 49.6338):31,
- (41.9858, -48.1745, 46.4957):32,
- (42.7207, -39.1444, 16.0528):33,
- (43.8747, -26.8746, -7.9028):34,
- (26.5278, 3.8603, -34.8152):35,
- (11.0, 44.2673, -60.2918):36,
- (19.0423, 48.637, -46.7161):37,
- (26.6606, 54.9202, -34.0091):38,
- (24.1377, 48.6121, -6.8774):39,
- (37.5243, 61.9327, 51.9413):40,
- (50.3904, 27.7338, 58.553):41,
- (71.4677, -16.6651, 73.0447):42,
- (67.5818, -39.987, 68.408):43,
- (64.1995, -66.6294, 64.3075):44,
- (65.1526, -54.8772, 23.9922):45,
- (66.8122, -37.1703, -10.9303):46,
- (41.6262, 7.9137, -50.0682):47,
- (21.343, 61.2273, -83.3898):48,
- (32.0743, 66.9878, -65.2716):49,
- (43.0033, 75.9603, -47.0378):50,
- (39.3866, 66.9043, -7.4929):51,
- (53.2329, 80.1093, 67.2201):52,
- (69.4811, 36.8308, 75.4949):53,
- (97.1382, -21.5559, 94.4825):54,
- (92.125, -51.6335, 88.501):55,
- (87.737, -86.1846, 83.1812):56,
- (88.9499, -71.2147, 31.6061):57,
- (91.1165, -48.0796, -14.1381):58,
- (58.0145, 11.3842, -65.6058):59,
- (32.3026, 79.1967, -107.8637):60,
- (45.9331, 86.4699, -84.8483):61,
- (60.3199, 98.2542, -60.843):62,
- (55.6111, 86.4597, -9.1916):63,
- (60.8927, 62.8729, 35.0702):64,
- (78.8241, 18.6736, 56.0796):65,
- (97.6208, -17.6977, 66.4162):66,
- (94.1539, -37.4631, 68.7023):67,
- (89.8813, -66.1541, 56.3842):68,
- (91.0093, -53.1765, 13.8066):69,
- (92.571, -38.7824, -11.8131):70,
- (70.8615, -4.4808, -45.0866):71,
- (47.6091, 49.3215, -82.3961):72,
- (58.1323, 68.3853, -64.8302):73,
- (68.0079, 76.2368, -48.6298):74,
- (63.3723, 71.7112, -18.3923):75,
- (74.4686, 36.8822, 15.7988):76,
- (87.1187, 8.2035, 33.0227):77,
- (98.1056, -13.9188, 47.2642):78,
- (96.0337, -24.7493, 44.2003):79,
- (92.1264, -48.2196, 38.3812):80,
- (93.3211, -36.9827, 8.0947):81,
- (94.2302, -28.9926, -9.1665):82,
- (82.3123, -6.9657, -27.1167):83,
- (68.0684, 23.3938, -49.2364):84,
- (73.6833, 41.0464, -40.0349):85,
- (77.4342, 51.3197, -33.9217):86,
- (74.2811, 48.1595, -14.7725):87,
- (0.0, 0.0, 0.0):88,
- (5.8822, 0.0022, -0.0022):89,
- (16.1144, 0.0022, -0.0033):90,
- (22.6151, 0.0018, -0.004):91,
- (32.7476, 0.0018, -0.0044):92,
- (42.7837, 0.0032, -0.0055):93,
- (53.9767, 0.0034, -0.0063):94,
- (65.4912, 0.0036, -0.0074):95,
- (76.2461, 0.0044, -0.0083):96,
- (89.8837, 0.0048, -0.0094):97,
- (100.0, 0.0053, -0.0104):98}
- self.colors16 = {
- (100.0, 0.0053, -0.0104):0,
- (0.0, 0.0, 0.0):1,
- (12.8119, 47.2407, -64.3396):2,
- (52.8041, -57.1624, 55.1703):3,
- (53.2329, 80.1093, 67.2201):4,
- (25.2966, 47.7847, 37.7562):5,
- (36.8705, 68.0659, -42.1489):6,
- (66.4237, 42.1616, 73.4335):7,
- (97.1382, -21.5559, 94.4825):8,
- (86.8105, -85.4149, 82.4382):9,
- (55.0455, -31.8888, -9.3772):10,
- (91.1165, -48.0796, -14.1381):11,
- (31.8712, 78.4892, -106.9003):12,
- (60.3199, 98.2542, -60.843):13,
- (53.1928, 0.0029, -0.0061):14,
- (84.1985, 0.0045, -0.0089):15}
- self.colors99= {
- (100.0, 0.0053, -0.0104):0,
- (0.0, 0.0, 0.0):1,
- (12.8119, 47.2407, -64.3396):2,
- (52.8041, -57.1624, 55.1703):3,
- (53.2329, 80.1093, 67.2201):4,
- (25.2966, 47.7847, 37.7562):5,
- (36.8705, 68.0659, -42.1489):6,
- (66.4237, 42.1616, 73.4335):7,
- (97.1382, -21.5559, 94.4825):8,
- (86.8105, -85.4149, 82.4382):9,
- (55.0455, -31.8888, -9.3772):10,
- (91.1165, -48.0796, -14.1381):11,
- (31.8712, 78.4892, -106.9003):12,
- (60.3199, 98.2542, -60.843):13,
- (53.1928, 0.0029, -0.0061):14,
- (84.1985, 0.0045, -0.0089):15,
- (11.5497, 31.8768, 18.1739):16,
- (17.5866, 15.7066, 25.9892):17,
- (29.0208, -8.5776, 37.5533):18,
- (27.2543, -19.015, 35.3673):19,
- (25.2798, -34.2963, 32.8426):20,
- (25.8276, -27.5812, 10.7515):21,
- (26.6245, -19.1316, -5.6261):22,
- (14.986, 1.2467, -23.6473):23,
- (4.1091, 27.6851, -41.3905):24,
- (9.2862, 34.8709, -32.6869):25,
- (14.3696, 39.0991, -24.2113):26,
- (12.6512, 34.8073, -6.066):27,
- (22.699, 44.779, 34.3145):28,
- (31.2054, 21.9979, 41.7676):29,
- (47.2407, -12.0488, 52.8125):30,
- (44.5753, -27.9355, 49.6338):31,
- (41.9858, -48.1745, 46.4957):32,
- (42.7207, -39.1444, 16.0528):33,
- (43.8747, -26.8746, -7.9028):34,
- (26.5278, 3.8603, -34.8152):35,
- (11.0, 44.2673, -60.2918):36,
- (19.0423, 48.637, -46.7161):37,
- (26.6606, 54.9202, -34.0091):38,
- (24.1377, 48.6121, -6.8774):39,
- (37.5243, 61.9327, 51.9413):40,
- (50.3904, 27.7338, 58.553):41,
- (71.4677, -16.6651, 73.0447):42,
- (67.5818, -39.987, 68.408):43,
- (64.1995, -66.6294, 64.3075):44,
- (65.1526, -54.8772, 23.9922):45,
- (66.8122, -37.1703, -10.9303):46,
- (41.6262, 7.9137, -50.0682):47,
- (21.343, 61.2273, -83.3898):48,
- (32.0743, 66.9878, -65.2716):49,
- (43.0033, 75.9603, -47.0378):50,
- (39.3866, 66.9043, -7.4929):51,
- (69.4811, 36.8308, 75.4949):53,
- (92.125, -51.6335, 88.501):55,
- (87.737, -86.1846, 83.1812):56,
- (88.9499, -71.2147, 31.6061):57,
- (58.0145, 11.3842, -65.6058):59,
- (32.3026, 79.1967, -107.8637):60,
- (45.9331, 86.4699, -84.8483):61,
- (55.6111, 86.4597, -9.1916):63,
- (60.8927, 62.8729, 35.0702):64,
- (78.8241, 18.6736, 56.0796):65,
- (97.6208, -17.6977, 66.4162):66,
- (94.1539, -37.4631, 68.7023):67,
- (89.8813, -66.1541, 56.3842):68,
- (91.0093, -53.1765, 13.8066):69,
- (92.571, -38.7824, -11.8131):70,
- (70.8615, -4.4808, -45.0866):71,
- (47.6091, 49.3215, -82.3961):72,
- (58.1323, 68.3853, -64.8302):73,
- (68.0079, 76.2368, -48.6298):74,
- (63.3723, 71.7112, -18.3923):75,
- (74.4686, 36.8822, 15.7988):76,
- (87.1187, 8.2035, 33.0227):77,
- (98.1056, -13.9188, 47.2642):78,
- (96.0337, -24.7493, 44.2003):79,
- (92.1264, -48.2196, 38.3812):80,
- (93.3211, -36.9827, 8.0947):81,
- (94.2302, -28.9926, -9.1665):82,
- (82.3123, -6.9657, -27.1167):83,
- (68.0684, 23.3938, -49.2364):84,
- (73.6833, 41.0464, -40.0349):85,
- (77.4342, 51.3197, -33.9217):86,
- (74.2811, 48.1595, -14.7725):87,
- (5.8822, 0.0022, -0.0022):89,
- (16.1144, 0.0022, -0.0033):90,
- (22.6151, 0.0018, -0.004):91,
- (32.7476, 0.0018, -0.0044):92,
- (42.7837, 0.0032, -0.0055):93,
- (53.9767, 0.0034, -0.0063):94,
- (65.4912, 0.0036, -0.0074):95,
- (76.2461, 0.0044, -0.0083):96,
- (89.8837, 0.0048, -0.0094):97}
- self.x256colors99 = [1,5,32,30,2,38,34,96,94,4,56,8,60,13,11,0,1,36,2,48,48,60,32,34,47,47,47,72,3,33,10,59,59,59,44,45,45,46,71,71,9,68,45,69,46,83,56,68,57,57,69,11,28,38,37,49,49,60,30,93,47,72,72,72,31,33,10,59,59,59,43,45,45,46,71,71,9,68,57,69,70,83,56,68,68,57,69,70,5,39,38,49,49,61,41,93,50,50,72,72,30,30,94,84,84,84,43,43,45,46,71,71,43,68,80,81,82,83,55,68,68,80,81,70,40,51,6,50,50,61,41,64,63,50,73,73,30,41,76,87,85,84,42,42,95,96,84,84,55,67,79,81,82,83,55,67,80,80,81,82,40,51,51,50,50,73,41,64,63,75,13,73,53,7,76,87,85,85,42,65,77,76,87,85,42,66,78,78,15,97,55,67,79,79,81,82,4,64,63,63,13,13,7,64,63,75,75,74,53,64,76,87,87,86,65,65,65,76,87,86,8,77,77,77,97,86,8,66,66,78,78,0,1,89,89,90,91,91,92,92,92,93,93,14,94,94,95,95,95,96,96,96,15,97,97,97]
- self.x256colors16 = [1,5,3,3,2,6,10,15,14,4,9,8,12,13,11,0,1,2,2,2,12,12,3,10,12,12,12,12,3,10,10,10,14,14,3,3,10,10,10,10,9,9,9,11,11,11,9,9,9,9,11,11,5,6,2,12,12,12,3,14,14,12,12,12,3,3,10,14,14,14,3,3,10,10,10,15,9,9,9,11,11,11,9,9,9,9,11,11,5,6,6,6,6,12,14,14,6,6,6,13,3,14,14,14,14,13,3,3,3,11,11,11,9,9,9,11,11,11,9,9,9,9,11,11,5,6,6,6,6,6,7,4,6,13,13,13,7,7,14,14,13,13,8,8,15,15,15,15,8,9,9,15,15,15,9,9,9,9,11,11,4,6,6,6,13,13,7,4,13,13,13,13,7,7,4,13,13,13,8,7,7,15,15,13,8,8,8,15,15,15,8,8,8,9,0,0,4,4,13,13,13,13,7,4,13,13,13,13,7,7,4,13,13,13,7,7,7,15,15,13,8,8,8,15,15,15,8,8,8,8,0,0,1,1,1,1,1,1,1,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,0]
- self.x256colors83 = [88,28,32,30,36,38,34,96,94,52,56,54,60,62,58,98,88,36,36,48,48,60,32,34,47,47,47,72,32,33,34,59,59,59,44,45,45,46,71,71,44,68,45,69,46,83,56,68,57,57,69,58,28,38,37,49,49,60,30,93,47,72,72,72,31,33,34,59,59,59,43,45,45,46,71,71,56,68,57,69,70,83,56,68,68,57,69,70,28,39,38,49,49,61,41,93,50,50,72,72,30,30,94,84,84,84,43,43,45,46,71,71,43,68,80,81,82,83,55,68,68,80,81,70,40,51,51,50,50,61,41,64,63,50,73,73,30,41,76,87,85,84,42,42,95,96,84,84,55,67,79,81,82,83,55,67,80,80,81,82,40,51,51,50,50,73,41,64,63,75,62,73,53,53,76,87,85,85,42,65,77,76,87,85,42,66,78,78,97,97,55,67,79,79,81,82,52,64,63,63,62,62,52,64,63,75,75,74,53,64,76,87,87,86,65,65,65,76,87,86,54,77,77,77,97,86,54,66,66,78,78,98,88,89,89,90,91,91,92,92,92,93,93,94,94,94,95,95,95,96,96,96,97,97,97,97]
- self.x16colors = {
- '30':'01',
- '31':'04',
- '32':'03',
- '33':'08',
- '34':'02',
- '35':'06',
- '36':'10',
- '37':'15',
- '30;1':'14',
- '31;1':'07',
- '32;1':'09',
- '33;1':'08',
- '34;1':'12',
- '35;1':'13',
- '36;1':'11',
- '37;1':'00',
- '40':'01',
- '41':'04',
- '42':'03',
- '43':'08',
- '44':'02',
- '45':'06',
- '46':'10',
- '47':'15',
- '40;1':'14',
- '41;1':'07',
- '42;1':'09',
- '43;1':'08',
- '44;1':'12',
- '45;1':'13',
- '46;1':'11',
- '47;1':'00'}
-
- def doPrivmsg(self, irc, msg):
- channel = msg.args[0]
- self.stopped.setdefault(channel, None)
- if msg.args[1].lower().strip()[1:] == 'cq':
- self.stopped[channel] = True
-
- def doPaste(self, description, paste):
- try:
- apikey = self.registryValue('pasteAPI')
- payload = {'description':description,'sections':[{'contents':paste}]}
- headers = {'X-Auth-Token':apikey}
- post_response = requests.post(url='https://api.paste.ee/v1/pastes', json=payload, headers=headers)
- response = post_response.json()
- return response['link'].replace('/p/', '/r/')
- except:
- return "Error. Did you set a valid Paste.ee API Key? https://paste.ee/account/api"
-
- def renderImage(self, text, size=18, defaultBg = 1, defaultFg = 0):
- try:
- if utf8 and not isinstance(text, unicode):
- text = text.decode('utf-8')
- except:
- pass
- text = text.replace('\t', ' ')
- self.strip_colors_regex = re.compile('(\x03([0-9]{1,2})(,[0-9]{1,2})?)|[\x0f\x02\x1f\x03\x16]').sub
- path = os.path.dirname(os.path.abspath(__file__))
- defaultFont = "{0}/DejaVu.ttf".format(path)
- def strip_colors(string):
- return self.strip_colors_regex('', string)
- _colorRegex = re.compile('(([0-9]{1,2})(,([0-9]{1,2}))?)')
- IGNORE_CHRS = ('\x16','\x1f','\x02', '\x03', '\x0f')
- lineLens = [len(line) for line in strip_colors(text).splitlines()]
- maxWidth, height = max(lineLens), len(lineLens)
- font = ImageFont.truetype(defaultFont, size)
- fontX = 10
- fontY = 20
- imageX, imageY = maxWidth * fontX, height * fontY
- image = Image.new('RGB', (imageX, imageY), self.rgbColors[defaultBg])
- draw = ImageDraw.Draw(image)
- dtext, drect, match, x, y, fg, bg = draw.text, draw.rectangle, _colorRegex.match, 0, 0, defaultFg, defaultBg
- start = time.time()
- for text in text.split('\n'):
- ll, i = len(text), 0
- while i < ll:
- chr = text[i]
- if chr == "\x03":
- m = match(text[i+1:i+6])
- if m:
- i+= len(m.group(1))
- fg = int(m.group(2))
- if m.group(4) is not None:
- bg = int(m.group(4))
- else:
- bg, fg = defaultBg, defaultFg
- elif chr == "\x0f":
- fg, bg = defaultFg, defaultBg
- elif chr not in IGNORE_CHRS:
- if bg != defaultBg: # bg is not white, render it
- drect((x, y, x+fontX, y+fontY), fill=self.rgbColors[bg])
- if bg != fg: # text will show, render it. this saves a lot of time!
- dtext((x, y), chr, font=font, fill=self.rgbColors[fg])
- x += fontX
- i += 1
- y += fontY
- fg, bg, x = defaultFg, defaultBg, 0
- return image, imageX, imageY
-
- def getColor(self, pixel, speed):
- pixel = tuple(pixel)
- if self.colors == 16:
- colors = list(self.colors16.keys())
- elif self.colors == 99:
- colors = list(self.colors99.keys())
- else:
- colors = list(self.colors83.keys())
- try:
- return self.matches[pixel]
- except KeyError:
- closest_colors = sorted(colors, key=lambda color: self.distance(color, self.rgb2lab(pixel), speed))
- closest_color = closest_colors[0]
- if self.colors == 16:
- self.matches[pixel] = self.colors16[closest_color]
- elif self.colors == 99:
- self.matches[pixel] = self.colors99[closest_color]
- else:
- self.matches[pixel] = self.colors83[closest_color]
- return self.matches[pixel]
-
- def rgb2lab (self, inputColor) :
- num = 0
- RGB = [0, 0, 0]
- for value in inputColor :
- value = float(value) / 255
- if value > 0.04045 :
- value = ( ( value + 0.055 ) / 1.055 ) ** 2.4
- else :
- value = value / 12.92
- RGB[num] = value * 100
- num = num + 1
- XYZ = [0, 0, 0,]
- X = RGB [0] * 0.4124 + RGB [1] * 0.3576 + RGB [2] * 0.1805
- Y = RGB [0] * 0.2126 + RGB [1] * 0.7152 + RGB [2] * 0.0722
- Z = RGB [0] * 0.0193 + RGB [1] * 0.1192 + RGB [2] * 0.9505
- XYZ[ 0 ] = round( X, 4 )
- XYZ[ 1 ] = round( Y, 4 )
- XYZ[ 2 ] = round( Z, 4 )
- XYZ[ 0 ] = float( XYZ[ 0 ] ) / 95.047 # ref_X = 95.047 Observer= 2°, Illuminant= D65
- XYZ[ 1 ] = float( XYZ[ 1 ] ) / 100.0 # ref_Y = 100.000
- XYZ[ 2 ] = float( XYZ[ 2 ] ) / 108.883 # ref_Z = 108.883
- num = 0
- for value in XYZ :
- if value > 0.008856 :
- value = value ** ( 0.3333333333333333 )
- else :
- value = ( 7.787 * value ) + ( 16 / 116 )
- XYZ[num] = value
- num = num + 1
- Lab = [0, 0, 0]
- L = ( 116 * XYZ[ 1 ] ) - 16
- a = 500 * ( XYZ[ 0 ] - XYZ[ 1 ] )
- b = 200 * ( XYZ[ 1 ] - XYZ[ 2 ] )
- Lab [ 0 ] = round( L, 4 )
- Lab [ 1 ] = round( a, 4 )
- Lab [ 2 ] = round( b, 4 )
- return Lab
-
- def ciede2000(self, color1, color2):
- """
- Calculates color difference according to the `CIEDE 2000`_ formula. This is
- the most accurate algorithm currently implemented but also the most complex
- and slowest. Like CIE1994 it is largely based in CIE L*C*h* space, but with
- several modifications to account for perceptual uniformity flaws.
- .. _CIEDE 2000: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000
- """
- # See WP article and Sharma 2005 for important implementation notes:
- # http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
- #
- # Yes, there's lots of locals; but this is easiest to understand as it's a
- # near straight translation of the math
- # pylint: disable=too-many-locals
- C_ = (
- math.sqrt(color1[1] ** 2 + color1[2] ** 2) +
- math.sqrt(color2[1] ** 2 + color2[2] ** 2)
- ) / 2
-
- G = (1 - math.sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7))) / 2
- a1_prime = (1 + G) * color1[1]
- a2_prime = (1 + G) * color2[1]
- C1_prime = math.sqrt(a1_prime ** 2 + color1[2] ** 2)
- C2_prime = math.sqrt(a2_prime ** 2 + color2[2] ** 2)
- L_ = (color1[0] + color2[0]) / 2
- C_ = (C1_prime + C2_prime) / 2
- h1 = (
- 0.0 if color1[2] == a1_prime == 0 else
- math.degrees(math.atan2(color1[2], a1_prime)) % 360
- )
- h2 = (
- 0.0 if color2[2] == a2_prime == 0 else
- math.degrees(math.atan2(color2[2], a2_prime)) % 360
- )
- if C1_prime * C2_prime == 0.0:
- dh = 0.0
- h_ = h1 + h2
- elif abs(h1 - h2) <= 180:
- dh = h2 - h1
- h_ = (h1 + h2) / 2
- else:
- if h2 > h1:
- dh = h2 - h1 - 360
- else:
- dh = h2 - h1 + 360
- if h1 + h2 >= 360:
- h_ = (h1 + h2 - 360) / 2
- else:
- h_ = (h1 + h2 + 360) / 2
-
- dL = color2[0] - color1[0]
- dC = C2_prime - C1_prime
- dH = 2 * math.sqrt(C1_prime * C2_prime) * math.sin(math.radians(dh / 2))
- T = (
- 1 -
- 0.17 * math.cos(math.radians(h_ - 30)) +
- 0.24 * math.cos(math.radians(2 * h_)) +
- 0.32 * math.cos(math.radians(3 * h_ + 6)) -
- 0.20 * math.cos(math.radians(4 * h_ - 63))
- )
- SL = 1 + (0.015 * (L_ - 50) ** 2) / math.sqrt(20 + (L_ - 50) ** 2)
- SC = 1 + 0.045 * C_
- SH = 1 + 0.015 * C_ * T
- RT = (
- -2 * math.sqrt(C_ ** 7 / (C_ ** 7 + 25 ** 7)) *
- math.sin(math.radians(60 * math.exp(-(((h_ - 275) / 25) ** 2))))
- )
- delta_e = math.sqrt(
- (dL / SL) ** 2 +
- (dC / SC) ** 2 +
- (dH / SH) ** 2 +
- RT * (dC / SC) * (dH / SH)
- )
- return delta_e
-
- def distance(self, c1, c2, speed):
- if speed == 'fast':
- delta_e = math.sqrt((c1[0] - c2[0]) **2 + (c1[1] - c2[1]) ** 2 + (c1[2] - c2[2]) **2)
- elif speed == 'slow':
- delta_e = self.ciede2000(c1, c2)
- return delta_e
-
- def process_ansi(self, ansi):
- if self.colors == 16:
- colors = self.x256colors16
- elif self.colors == 99:
- colors = self.x256colors99
- else:
- colors = self.x256colors83
- x16color1 = None
- x16color2 = None
- x256color1 = None
- x256color2 = None
- effect = None
- ansi = ansi.lower().strip('\x1b[').strip('m').split(';')
- if len(ansi) > 1:
- i = 0
- while i < len(ansi):
- if i >= len(ansi):
- break
- elif ansi[i]== '0':
- effect = 0
- i += 1
- continue
- elif ansi[i] == '1':
- effect = 1
- i += 1
- continue
- elif ansi[i] == '4':
- effect = 4
- i += 1
- continue
- elif ansi[i] == '2':
- effect = 2
- i += 1
- continue
- elif int(ansi[i]) > 29 and int(ansi[i]) < 38:
- if effect == 1 or ansi[-1] == '1':
- x16color2 = self.x16colors['{0};1'.format(ansi[i])]
- effect = None
- i += 1
- continue
- else:
- x16color2 = self.x16colors[ansi[i]]
- i += 1
- continue
- elif int(ansi[i]) > 39 and int(ansi[i]) < 48:
- if effect == 1 or ansi[-1] == '1':
- x16color2 = self.x16colors['{0};1'.format(ansi[i])]
- effect = None
- i += 1
- continue
- else:
- x16color2 = self.x16colors[ansi[i]]
- i += 1
- continue
- elif ansi[i] == '38':
- x256color1 = colors[int(ansi[i+2])]
- i += 3
- continue
- elif ansi[i] == '48':
- x256color2 = colors[int(ansi[i+2])]
- i += 3
- continue
- else:
- i += 1
- continue
- if x16color1 and x16color2:
- color = '\x03{0},{1}'.format(x16color1, x16color2)
- elif x256color1 and x256color2:
- color = '\x03{0},{1}'.format('%02d' % x256color1, '%02d' % x256color2)
- elif x16color1:
- color = '\x03{0}'.format(x16color1)
- elif x16color2:
- color = '\x0399,{0}'.format(x16color2)
- elif x256color1:
- color = '\x03{0}'.format('%02d' % x256color1)
- elif x256color2:
- color = '\x0399,{0}'.format('%02d' % x256color2)
- else:
- color = ''
- if effect == 1:
- color += '\x02'
- if effect == 4:
- color += '\x1F'
- elif len(ansi[0]) > 0:
- if ansi[0] == '0':
- color = '\x0F'
- elif ansi[0] == '1' or ansi[0] == '2':
- color = '\x02'
- elif ansi[0] == '4':
- color = '\x1F'
- elif int(ansi[0]) > 29 and int(ansi[0]) < 38:
- color = '\x03{0}'.format(self.x16colors[ansi[0]])
- elif int(ansi[0]) > 39 and int(ansi[0]) < 48:
- color = '\x0399,{0}'.format(self.x16colors[ansi[0]])
- elif ansi[0][-1] == 'c':
- color = ' ' * int(ansi[0][:-1])
- else:
- color = ''
- else:
- color = ''
- if color != self.old_color:
- self.old_color = color
- return color
- else:
- return ''
-
- def ansi2irc(self, output):
- output = output.replace('\x1b[0m\x1b', '\x1b')
- output = re.sub(r'\x1B\[[0-?]*[ -/]*[@-~]', lambda m: self.process_ansi(m.group(0)), output)
- output = re.sub('\x0399,(\d\d)\x03(\d\d)', '\x03\g<2>,\g<1>', output)
- return output
-
- def png(self, irc, msg, args, optlist, url):
- """[--bg] [--fg]
- Generate PNG from text file
- """
- optlist = dict(optlist)
- if 'bg' in optlist:
- bg = optlist.get('bg')
- else:
- bg = 1
- if 'fg' in optlist:
- fg = optlist.get('fg')
- else:
- fg = 0
- if url.startswith("https://paste.ee/p/"):
- url = re.sub("https://paste.ee/p/", "https://paste.ee/r/", url)
- ua = UserAgent()
- header = {'User-Agent':str(ua.random)}
- r = requests.head(url, headers=header)
- if "text/plain" in r.headers["content-type"]:
- file = requests.get(url, headers=header)
- else:
- irc.reply("Invalid file type.", private=False, notice=False)
- return
- file = file.content.decode()
- im, x, y = self.renderImage(file, 18, bg, fg)
- path = os.path.dirname(os.path.abspath(__file__))
- filepath = "{0}/tmp/tldr.png".format(path)
- im.save(filepath, "PNG")
- CLIENT_ID = self.registryValue('imgurAPI')
- imgur = pyimgur.Imgur(CLIENT_ID)
- uploaded_image = imgur.upload_image(filepath, title=url)
- irc.reply(uploaded_image.link, noLengthCheck=True, private=False, notice=False)
- png = wrap(png, [getopts({'bg':'int', 'fg':'int'}), ('text')])
-
- def ascii(self, irc, msg, args, channel, optlist, text):
- """[] [--font ] [--color ] []
- Text to ASCII art
- """
- if not channel:
- channel = msg.args[0]
- channel = msg.args[0]
- optlist = dict(optlist)
- font = None
- words = []
- if text:
- text = text.strip()
- if '|' in text:
- words = text.split('|')
- if 'color' in optlist:
- color = optlist.get('color')
- if "," in color:
- color = color.split(",")
- color1 = color[0].strip()
- color2 = color[1].strip()
- else:
- color1 = color
- color2 = None
- else:
- color1 = None
- color2 = None
- if 'font' in optlist:
- font = optlist.get('font')
- if words:
- for word in words:
- if word.strip():
- data = requests.get("https://artii.herokuapp.com/make?text={0}&font={1}".format(word.strip(), font))
- for line in data.text.splitlines():
- if line.strip():
- irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False)
- else:
- data = requests.get("https://artii.herokuapp.com/make?text={0}&font={1}".format(text, font))
- for line in data.text.splitlines():
- if line.strip():
- irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False, to=channel)
- elif 'font' not in optlist:
- if words:
- for word in words:
- if word.strip():
- data = requests.get("https://artii.herokuapp.com/make?text={0}&font=univers".format(word.strip()))
- for line in data.text.splitlines():
- if line.strip():
- irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False, to=channel)
- else:
- data = requests.get("https://artii.herokuapp.com/make?text={0}&font=univers".format(text))
- for line in data.text.splitlines():
- if line.strip():
- irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False, to=channel)
-
- ascii = wrap(ascii, [optional('channel'), getopts({'font':'text', 'color':'text'}), ('text')])
-
- def fontlist(self, irc, msg, args):
- """
- get list of fonts for text-to-ascii-art
- """
- fontlist = requests.get("https://artii.herokuapp.com/fonts_list")
- response = sorted(fontlist.text.split('\n'))
- irc.reply(str(response).replace('\'', '').replace('[', '').replace(']', ''))
- fontlist = wrap(fontlist)
-
- def img(self, irc, msg, args, channel, optlist, url):
- """[<#channel>] [--delay #.#] [--w <###>] [--s <#.#] [--16] [--99] [--83] [--ascii] [--block] [--1/2] [--1/4] [--chars ] [--ramp ] [--bg <0-98>] [--fg <0-98>] [--no-color] [--invert] [--dither] [--no-dither]
- Image to ASCII Art.
- --w columns.
- --s saturation (1.0).
- --16 colors 0-15.
- --99 colors 0-98.
- --83 colors 16-98.
- --ascii color ascii.
- --block space block.
- --1/4 for 1/4 block.
- --1/2 for 1/2 block
- --chars color text.
- --ramp set ramp (".:-=+*#%@").
- --bg <0-98> set bg.
- --fg <0-99> set fg.
- --no-color greyscale ascii.
- --invert inverts ramp.
- --dither to reduce source colors.
- --no-dither for no color reduction.
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- gscale = "\xa0"
- if '16' in optlist:
- self.colors = 16
- elif '83' in optlist:
- self.colors = 83
- elif '99' in optlist:
- self.colors = 99
- else:
- self.colors = self.registryValue('colors', msg.args[0])
- if 'fast' in optlist:
- speed = 'fast'
- elif 'slow' in optlist:
- speed = 'slow'
- else:
- speed = self.registryValue('speed', msg.args[0]).lower()
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- if 'dither' in optlist:
- dither = True
- elif 'no-dither' in optlist:
- dither = False
- else:
- dither = self.registryValue('dither', msg.args[0])
- if 'bg' in optlist:
- bg = optlist.get('bg')
- else:
- bg = 1
- if 'fg' in optlist:
- fg = optlist.get('fg')
- else:
- fg = 99
- if 'chars' in optlist:
- type = 'ascii'
- gscale = optlist.get('chars')
- elif 'ramp' in optlist:
- type = 'ascii'
- gscale = optlist.get('ramp')
- elif 'ascii' in optlist and bg == 0 or bg == 98:
- type = 'ascii'
- gscale = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:\"^`'."
- elif 'ascii' in optlist:
- type = 'ascii'
- gscale = ".'`^\":;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"
- elif '1/4' in optlist:
- type = '1/4'
- elif '1/2' in optlist:
- type = '1/2'
- elif 'block' in optlist:
- type = 'ascii'
- gscale = '\xa0'
- else:
- type = self.registryValue('imgDefault', msg.args[0]).lower()
- if 'no-color' in optlist and 'ramp' not in optlist and bg == 0 or bg == 98:
- type = 'no-color'
- gscale = "@%#*+=-:. "
- elif 'no-color' in optlist and 'ramp' not in optlist:
- type = 'no-color'
- gscale = " .:-=+*#%@"
- elif 'no-color' in optlist and 'chars' not in optlist:
- type = 'no-color'
- if not gscale.strip():
- gscale = '\xa0'
- if 'invert' in optlist and 'chars' not in optlist and gscale != '\xa0':
- gscale = gscale[::-1]
- if 'w' in optlist:
- cols = optlist.get('w')
- elif type == 'ascii' or type == 'no-color' or type == 'block':
- cols = self.registryValue('asciiWidth', msg.args[0])
- else:
- cols = self.registryValue('blockWidth', msg.args[0])
- if type == '1/4':
- cols = cols * 2
- if 's' in optlist:
- s = float(optlist.get('s'))
- path = os.path.dirname(os.path.abspath(__file__))
- filepath = "{0}/tmp".format(path)
- filename = "{0}/{1}".format(filepath, url.split('/')[-1])
- ua = UserAgent()
- header = {'User-Agent':str(ua.random)}
- image_formats = ("image/png", "image/jpeg", "image/jpg", "image/gif")
- r = requests.head(url, headers=header)
- if r.headers["content-type"] in image_formats:
- response = requests.get(url, headers=header)
- else:
- irc.reply("Invalid file type.", private=False, notice=False)
- return
- if response.status_code == 200:
- with open("{0}".format(filename), 'wb') as f:
- f.write(response.content)
- # open image and convert to grayscale
- image = Image.open(filename)
- if image.mode == 'RGBA':
- image = Image.alpha_composite(Image.new("RGBA", image.size, self.rgbColors[bg] + (255,)), image)
- if image.mode != 'RGB':
- image = image.convert('RGB')
- try:
- os.remove(filename)
- except:
- pass
- # store dimensions
- W, H = image.size[0], image.size[1]
- # compute width of tile
- w = W/cols
- # compute tile height based on aspect ratio and scale
- if type == '1/2':
- scale = 1.0
- else:
- scale = 0.5
- h = w/scale
- # compute number of rows
- rows = int(H/h)
- image = ImageOps.autocontrast(image)
- if type != 'no-color':
- image2 = image.resize((cols, rows), Image.LANCZOS)
- if 's' in optlist:
- image2 = ImageEnhance.Color(image2).enhance(s)
- if dither:
- image2 = image2.convert('P', palette=Image.ADAPTIVE)
- image2 = image2.convert('RGB')
- colormap = np.array(image2)
- self.matches = {}
- # ascii image is a list of character strings
- aimg = []
- if type == '1/2':
- k = 0
- for j in range(0, rows - 1, 2):
- # append an empty string
- aimg.append("")
- old_color = "99,99"
- for i in range(cols):
- color1 = '%02d' % self.getColor(colormap[j][i].tolist(), speed)
- color2 = '%02d' % self.getColor(colormap[j+1][i].tolist(), speed)
- color = "{0},{1}".format(color1, color2)
- if color != old_color:
- if color1 == color2:
- gsval = " "
- color = "0,{0}".format(color1)
- else:
- gsval = "▀"
- alt_gsval = "▄"
- if gsval != " " and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]) and 'tops' not in optlist:
- aimg[k] += alt_gsval
- elif gsval == " " and "{0}".format(color1) == "{0}".format(old_color.split(',')[1]):
- aimg[k] += " "
- else:
- aimg[k] += "\x03{0}{1}".format(color, gsval)
- old_color = color
- else:
- if color1 == color2:
- aimg[k] += " "
- else:
- aimg[k] += "▀"
- for i in range(0,98):
- i = '%02d' % i
- aimg[k] = re.sub("\x030,{0}(\s+)\x03(\d\d),{0}".format(i), "\x03\g<2>,{0}\g<1>".format(i), aimg[k])
- for i in range(0,98):
- i = '%02d' % i
- aimg[k] = aimg[k].replace("{0}".format(i), "{0}".format(int(i)))
- k += 1
- elif type == '1/4':
- k = 0
- for j in range(0, rows - 1, 2):
- # append an empty string
- aimg.append("")
- old_color = "99,99"
- for i in range(0, cols - 1, 2):
- color1 = '%02d' % self.getColor(colormap[j][i].tolist(), speed)
- color2 = '%02d' % self.getColor(colormap[j+1][i].tolist(), speed)
- color3 = '%02d' % self.getColor(colormap[j][i+1].tolist(), speed)
- color4 = '%02d' % self.getColor(colormap[j+1][i+1].tolist(), speed)
- if color1 == color2 and color1 == color3 and color1 == color4:
- gsval = " "
- color = "0,{0}".format(color1)
- elif color1 == color4 and color2 == color3:
- gsval = "▚"
- color = "{0},{1}".format(color1, color2)
- elif color1 == color2 and color1 == color3 and color1 != color4:
- gsval = "▛"
- color = "{0},{1}".format(color1, color4)
- elif color3 == color4 and color2 == color4 and color3 != color1:
- gsval = "▟"
- color = "{0},{1}".format(color2, color1)
- elif color1 == color2 and color1 == color4 and color1 != color3:
- gsval = "▙"
- color = "{0},{1}".format(color1, color3)
- elif color1 == color3 and color1 == color4 and color1 != color2:
- gsval = "▜"
- color = "{0},{1}".format(color1, color2)
- elif color1 == color3 and color2 == color4 and color1 != color2 and color3 != color4:
- gsval = "▀"
- color = "{0},{1}".format(color1, color4)
- elif color1 == color2 and color3 == color4 and color1 != color3 and color2 != color4:
- gsval = "▌"
- color = "{0},{1}".format(color1, color4)
- else:
- row1 = '%02d' % self.getColor(np.average([tuple(colormap[j][i].tolist()), tuple(colormap[j][i+1].tolist())], axis=0).tolist(), speed)
- row2 = '%02d' % self.getColor(np.average([tuple(colormap[j+1][i+1].tolist()), tuple(colormap[j][i+1].tolist())], axis=0).tolist(), speed)
- if row2 == color1 and row2 != color3:
- gsval = "▙"
- color = "{0},{1}".format(row2, color3)
- elif row1 == color2 and row1 != color4:
- gsval = "▛"
- color = "{0},{1}".format(row1, color4)
- elif row2 == color3 and row2 != color1:
- gsval = "▟"
- color = "{0},{1}".format(row2, color1)
- elif row1 == color4 and row1 != color2:
- gsval = "▜"
- color = "{0},{1}".format(row1, color2)
- else:
- col1 = '%02d' % self.getColor(np.average([tuple(colormap[j][i].tolist()), tuple(colormap[j+1][i].tolist())], axis=0).tolist(), speed)
- col2 = '%02d' % self.getColor(np.average([tuple(colormap[j][i+1].tolist()), tuple(colormap[j+1][i+1].tolist())], axis=0).tolist(), speed)
- if col1 == color4 and col1 != color3:
- gsval = "▙"
- color = "{0},{1}".format(col1, color3)
- elif col1 == color3 and col1 != color4:
- gsval = "▛"
- color = "{0},{1}".format(col1, color4)
- elif col2 == color2 and col2 != color1:
- gsval = "▟"
- color = "{0},{1}".format(col2, color1)
- elif col2 == color1 and col2 != color2:
- gsval = "▜"
- color = "{0},{1}".format(col2, color2)
- elif row1 != row2:
- gsval = "▀"
- color = "{0},{1}".format(row1, row2)
- elif col1 != col2:
- gsval = "▌"
- color = "{0},{1}".format(col1, col2)
- elif row1 == row2:
- gsval = " "
- color = "0,{0}".format(row1)
- elif col1 == col2:
- gsval = " "
- color = "0,{0}".format(col1)
- if color != old_color:
- if gsval == " " and "{0}".format(color.split(',')[1]) == "{0}".format(old_color.split(',')[1]):
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▚" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▞"
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▀" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▄"
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▌" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▐"
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▛" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▟"
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▟" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▛"
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▜" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▙"
- aimg[k] += "{0}".format(gsval)
- elif gsval == "▙" and color == "{0},{1}".format(old_color.split(',')[1], old_color.split(',')[0]):
- gsval = "▜"
- aimg[k] += "{0}".format(gsval)
- else:
- old_color = color
- # append char to string
- aimg[k] += "\x03{0}{1}".format(color, gsval)
- else:
- aimg[k] += "{0}".format(gsval)
- for i in range(0,98):
- i = '%02d' % i
- aimg[k] = re.sub("\x030,{0}(\s+)\x03(\d\d),{0}".format(i), "\x03\g<2>,{0}\g<1>".format(i), aimg[k])
- for i in range(0,98):
- i = '%02d' % i
- aimg[k] = aimg[k].replace("{0}".format(i), "{0}".format(int(i)))
- k += 1
- else:
- if 'chars' not in optlist and gscale != '\xa0':
- image = image.resize((cols, rows), Image.LANCZOS)
- image = image.convert('L')
- lumamap = np.array(image)
- # generate list of dimensions
- char = 0
- for j in range(rows):
- # append an empty string
- aimg.append("")
- old_color = None
- for i in range(cols):
- if 'chars' not in optlist and gscale != '\xa0':
- # get average luminance
- avg = int(np.average(lumamap[j][i]))
- # look up ascii char
- gsval = gscale[int((avg * (len(gscale) - 1))/255)]
- elif 'chars' in optlist and gscale != '\xa0':
- if char < len(gscale):
- gsval = gscale[char]
- char += 1
- else:
- char = 0
- gsval = gscale[char]
- char += 1
- else:
- gsval = '\xa0'
- # get color value
- if type != 'no-color' and i == 0:
- color = self.getColor(colormap[j][i].tolist(), speed)
- old_color = color
- if 'bg' not in optlist:
- if gsval != '\xa0':
- if gsval.isdigit():
- color = "{:02d}".format(int(color))
- aimg[j] += "\x03{0}{1}".format(color, gsval)
- else:
- aimg[j] += "\x03{0}{1}".format(int(color), gsval)
- else:
- aimg[j] += "\x030,{0} ".format(int(color))
- else:
- if gsval != '\xa0':
- if gsval.isdigit():
- newbg = "{:02d}".format(int(bg))
- aimg[j] += "\x03{0},{1}{2}".format(int(color), newbg, gsval)
- else:
- aimg[j] += "\x03{0},{1}{2}".format(int(color), int(bg), gsval)
- else:
- aimg[j] += "\x030,{0} ".format(int(color))
- elif type != 'no-color' and gsval != ' ':
- color = self.getColor(colormap[j][i].tolist(), speed)
- if color != old_color:
- old_color = color
- # append ascii char to string
- if 'bg' not in optlist:
- if gsval != '\xa0':
- if gsval.isdigit():
- color = "{:02d}".format(int(color))
- aimg[j] += "\x03{0}{1}".format(color, gsval)
- else:
- aimg[j] += "\x03{0}{1}".format(int(color), gsval)
- else:
- aimg[j] += "\x030,{0} ".format(int(color))
- else:
- if gsval != '\xa0':
- if gsval.isdigit():
- newbg = "{:02d}".format(int(bg))
- aimg[j] += "\x03{0},{1}{2}".format(int(color), newbg, gsval)
- else:
- aimg[j] += "\x03{0},{1}{2}".format(int(color), int(bg), gsval)
- else:
- aimg[j] += "\x030,{0} ".format(int(color))
- else:
- aimg[j] += "{0}".format(gsval)
- else:
- aimg[j] += "{0}".format(gsval)
- # return txt image
- output = aimg
- paste = ""
- self.stopped[msg.args[0]] = False
- for line in output:
- if type == 'no-color' and 'fg' in optlist and 'bg' in optlist:
- newbg = "{:02d}".format(int(bg))
- line = "\x03{0},{1}{2}".format(int(fg), newbg, line)
- elif type == 'no-color' and 'fg' in optlist:
- newfg = "{:02d}".format(int(fg))
- line = "\x03{0}{1}".format(newfg, line)
- elif type == 'no-color' and 'bg' in optlist:
- newbg = "{:02d}".format(int(bg))
- line = "\x0399,{0}{1}".format(newbg, line)
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- if not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply(line, prefixNick=False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
- img = wrap(img,[optional('channel'), getopts({'w':'int', 'invert':'', 'fast':'', 'slow':'', '16':'', '99':'', '83':'', 'delay':'float', 'dither':'', 'no-dither':'', 'chars':'text', 'bg':'int', 'fg':'int', 'ramp':'text', 'no-color':'', 'block':'', 'ascii':'', '1/4':'', '1/2':'', 's':'float', 'tops':''}), ('text')])
-
- def scroll(self, irc, msg, args, channel, optlist, url):
- """[] [--delay]
- Play ASCII/ANSI art text files from web links.
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- self.stopped[msg.args[0]] = False
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- if url.startswith("https://paste.ee/p/"):
- url = re.sub("https://paste.ee/p/", "https://paste.ee/r/", url)
- ua = UserAgent()
- header = {'User-Agent':str(ua.random)}
- r = requests.head(url, headers=header)
- if "text/plain" in r.headers["content-type"]:
- file = requests.get(url, headers=header)
- else:
- irc.reply("Invalid file type.", private=False, notice=False)
- return
- file = file.content.decode()
- for line in file.splitlines():
- if line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- scroll = wrap(scroll, [optional('channel'), getopts({'delay':'float'}), ('text')])
-
- def a2m(self, irc, msg, args, channel, optlist, url):
- """[] [--delay] [--l] [--r] [--n] [--p] [--t] [--w]
- Convert ANSI files to IRC formatted text. https://github.com/tat3r/a2m
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- opts = ''
- if 'l' in optlist:
- l = optlist.get('l')
- opts += '-l {0} '.format(l)
- if 'r' in optlist:
- r = optlist.get('r')
- opts += '-r {0} '.format(r)
- if 'n' in optlist:
- opts += '-n '.format(n)
- if 'p' in optlist:
- opts += '-p '.format(p)
- if 't' in optlist:
- t = optlist.get('t')
- opts += '-t {0} '.format(t)
- if 'w' in optlist:
- w = optlist.get('w')
- opts += '-w {0} '.format(w)
- else:
- opts += '-w 80 '
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- ua = UserAgent()
- header = {'User-Agent':str(ua.random)}
- r = requests.head(url, headers=header)
- try:
- if "text/plain" in r.headers["content-type"] or "application/octet-stream" in r.headers["content-type"] and int(r.headers["content-length"]) < 1000000:
- path = os.path.dirname(os.path.abspath(__file__))
- filepath = "{0}/tmp".format(path)
- filename = "{0}/{1}".format(filepath, url.split('/')[-1])
- r = requests.get(url, headers=header)
- open(filename, 'wb').write(r.content)
- try:
- output = pexpect.run('a2m {0} {1}'.format(opts.strip(), str(filename)))
- try:
- os.remove(filename)
- except:
- pass
- except:
- irc.reply("Error. Have you installed A2M? https://github.com/tat3r/a2m", private=False, notice=False)
- return
- else:
- irc.reply("Invalid file type.")
- return
- except:
- irc.reply("Invalid file type.")
- return
- paste = ""
- self.stopped[msg.args[0]] = False
- for line in output.splitlines():
- line = line.decode()
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- if line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
- a2m = wrap(a2m, [optional('channel'), getopts({'l':'int', 'r':'int', 't':'int', 'w':'int', 'delay':'float'}), ('text')])
-
- def p2u(self, irc, msg, args, channel, optlist, url):
- """[] [--b] [--f] [--p] [--s] [--t] [--w] [--delay]
- Picture to Unicode. https://git.trollforge.org/p2u/about/
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- opts = ''
- if 'b' in optlist:
- b = optlist.get('b')
- opts += '-b {0} '.format(b)
- if 'f' in optlist:
- f = optlist.get('f')
- opts += '-f {0} '.format(f)
- else:
- opts += '-f m '
- if 'p' in optlist:
- p = optlist.get('p')
- opts += '-p {0} '.format(p)
- else:
- opts += '-p x '
- if 's' in optlist:
- s = optlist.get('s')
- opts += '-s {0} '.format(s)
- if 't' in optlist:
- t = optlist.get('t')
- opts += '-t {0} '.format(t)
- if 'w' in optlist:
- w = optlist.get('w')
- opts += '-w {0} '.format(w)
- else:
- w = self.registryValue('blockWidth', msg.args[0])
- opts += '-w {0} '.format(w)
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- path = os.path.dirname(os.path.abspath(__file__))
- filepath = "{0}/tmp".format(path)
- filename = "{0}/{1}".format(filepath, url.split('/')[-1])
- ua = UserAgent()
- header = {'User-Agent':str(ua.random)}
- image_formats = ("image/png", "image/jpeg", "image/jpg", "image/gif")
- r = requests.head(url, headers=header)
- if r.headers["content-type"] in image_formats:
- response = requests.get(url, headers=header)
- else:
- irc.reply("Invalid file type.", private=False, notice=False)
- return
- if response.status_code == 200:
- with open("{0}".format(filename), 'wb') as f:
- f.write(response.content)
- try:
- output = pexpect.run('p2u -f m {0} {1}'.format(opts.strip(), str(filename)))
- try:
- os.remove(filename)
- except:
- pass
- except:
- irc.reply("Error. Have you installed p2u? https://git.trollforge.org/p2u", private=False, notice=False)
- return
- paste = ""
- self.stopped[msg.args[0]] = False
- for line in output.splitlines():
- line = line.decode()
- line = re.sub('^\x03 ', ' ', line)
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- if line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
- else:
- irc.reply("Unexpected file type or link format", private=False, notice=False)
- p2u = wrap(p2u, [optional('channel'), getopts({'b':'int', 'f':'text', 'p':'text', 's':'int', 't':'int', 'w':'int', 'delay':'float'}), ('text')])
-
- def tdf(self, irc, msg, args, channel, optlist, text):
- """[] [--f] [--j] [--w] [--e] [--r] [--i][--delay]
- Text to TheDraw ANSI Fonts. http://www.roysac.com/thedrawfonts-tdf.html
- --f [font] Specify font file used.
- --j l|r|c Justify left, right, or center. Default is left.
- --w n Set screen width. Default is 80.
- --c a|m Color format ANSI or mirc. Default is ANSI.
- --i Print font details.
- --r Use random font.
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- opts = ''
- if 'f' in optlist:
- f = optlist.get('f')
- opts += '-f {0} '.format(f.lower())
- else:
- opts += '-r '
- if 'j' in optlist:
- j = optlist.get('j')
- opts += '-j {0} '.format(j)
- if 'w' in optlist:
- w = optlist.get('w')
- opts += '-w {0} '.format(w)
- else:
- opts += '-w 80 '
- if 'e' in optlist:
- e = optlist.get('e')
- opts += '-e {0} '.format(e)
- if 'r' in optlist:
- opts += '-r '
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- if 'i' in optlist:
- opts += '-i '
- try:
- output = pexpect.run('tdfiglet -c m {0} {1}'.format(opts.strip(), r'{}'.format(text)))
- except:
- irc.reply("Error. Have you installed tdfiglet? https://github.com/tat3r/tdfiglet", private=False, notice=False)
- return
- paste = ""
- self.stopped[msg.args[0]] = False
- output = output.decode().replace('\r\r\n', '\r\n')
- for line in output.splitlines():
- line = re.sub('\x03\x03\s*', '\x0F ', line)
- line = re.sub('\x0F\s*\x03$', '', line)
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- if not line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(text, paste), private=False, notice=False, to=channel)
- tdf = wrap(tdf, [optional('channel'), getopts({'f':'text', 'j':'text', 'w':'int', 'e':'text', 'r':'', 'i':'', 'delay':'float'}), ('text')])
-
- def toilet(self, irc, msg, args, channel, optlist, text):
- """[] [--f fontname] [--F filter1,filter2,etc.] [--w] [--delay]
- Toilet. -f to select font. -F to select filters. Separate multiple filters with a comma.
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- opts = ''
- if 'f' in optlist:
- f = optlist.get('f')
- opts += '-f {0} '.format(f)
- if 'F' in optlist:
- filter = optlist.get('F')
- if ',' in filter:
- filter = filter.split(',')
- for i in range(len(filter)):
- opts += '-F {0} '.format(filter[i])
- else:
- opts += '-F {0} '.format(filter)
- if 'w' in optlist:
- w = optlist.get('w')
- opts += '-w {0} '.format(w)
- elif 'W' in optlist:
- opts += '-W '
- else:
- opts += '-w 100 '
- if 's' in optlist:
- opts += '-s '
- elif 'k' in optlist:
- opts += '-k '
- elif 'o' in optlist:
- opts += '-o '
- elif 'S' in optlist:
- opts += '-S '
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- try:
- output = pexpect.run('toilet --irc {0} {1}'.format(opts.strip(), text))
- except:
- irc.reply("Error. Have you installed toilet?", private=False, notice=False)
- return
- paste = ""
- self.stopped[msg.args[0]] = False
- output = output.decode().replace('\r\r\n', '\r\n')
- for line in output.splitlines():
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- if not line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(text, paste), private=False, notice=False, to=channel)
- toilet = wrap(toilet, [optional('channel'), getopts({'f':'text', 'F':'text', 's':'', 'S':'', 'k':'', 'w':'int', 'W':'', 'o':'', 'delay':'float'}), ('text')])
-
- def fonts(self, irc, msg, args, optlist):
- """[--toilet]
- List figlets. Default list are tdf fonts. --toilet for toilet fonts
- """
- optlist = dict(optlist)
- if 'toilet' in optlist:
- try:
- reply = ", ".join(sorted(os.listdir("/usr/share/figlet")))
- irc.reply(reply, prefixNick=False)
- except:
- irc.reply("Sorry, unable to access font directory /usr/share/figlet")
- else:
- try:
- reply = ", ".join(sorted(os.listdir("/usr/local/share/tdfiglet/fonts/")))
- irc.reply("http://www.roysac.com/thedrawfonts-tdf.html", prefixNick=False)
- irc.reply(reply, prefixNick=False)
- except FileNotFoundError:
- reply = ", ".join(sorted(os.listdir("/usr/share/figlet")))
- irc.reply(reply, prefixNick=False)
- except:
- irc.reply("Sorry, unable to access font directories /usr/local/share/tdfiglet/fonts/ or /usr/share/figlet")
- fonts = wrap(fonts, [getopts({'toilet':''})])
-
- def wttr(self, irc, msg, args, channel, optlist, location):
- """[] [--16] [--99]
- ASCII weather report from wttr.in for .
- --16 for 16 colors (default).
- --99 for 99 colors.
- Get moon phase with 'wttr moon'.
- ?u (use imperial units).
- ?m (metric).
- ?<1-3> (number of days)
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- if '16' in optlist:
- self.colors = 16
- elif '99' in optlist:
- self.colors = 99
- else:
- self.colors = self.registryValue('colors', msg.args[0])
- if 'fast' in optlist:
- speed = 'fast'
- elif 'slow' in optlist:
- speed = 'slow'
- else:
- speed = 'fast'
- file = requests.get("http://wttr.in/{0}".format(location))
- output = file.content.decode()
- self.matches = {}
- output = self.ansi2irc(output)
- output = re.sub('⚡', '☇ ', output)
- output = re.sub('‘‘', '‘ ', output)
- paste = ""
- self.stopped[msg.args[0]] = False
- for line in output.splitlines():
- line = line.strip('\x0F')
- if not line.strip() and not self.stopped[msg.args[0]]:
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif line.strip() and not self.stopped[msg.args[0]] and not line.startswith("Follow"):
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(location, paste), private=False, notice=False, to=channel)
- wttr = wrap(wttr, [optional('channel'), getopts({'delay':'float', '16':'', '99':'', 'fast':'', 'slow':''}), ('text')])
-
- def rate(self, irc, msg, args, channel, optlist, coin):
- """[] [--16] [--99] [--sub ] [coin]
- Crypto exchange rate info from rate.sx. http://rate.sx/:help. Use --sub to set subdomain e.g. eur, btc, etc.
- Get a graph with [coin] e.g. 'rate btc'.
- --16 for 16 colors (default).
- --99 for 99 colors.
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- if '16' in optlist:
- self.colors = 16
- elif '99' in optlist:
- self.colors = 99
- else:
- self.colors = self.registryValue('colors', msg.args[0])
- if 'fast' in optlist:
- speed = 'fast'
- elif 'slow' in optlist:
- speed = 'slow'
- else:
- speed = 'fast'
- if 'sub' in optlist:
- sub = optlist.get('sub')
- else:
- sub = 'usd'
- if not coin:
- coin = ''
- self.matches= {}
- file = requests.get("http://{0}.rate.sx/{1}".format(sub, coin))
- output = file.content.decode()
- output = self.ansi2irc(output)
- output = output.replace('\x1b(B', '')
- paste = ""
- self.stopped[msg.args[0]] = False
- for line in output.splitlines():
- line = line.strip('\x0F')
- if not line.strip() and not self.stopped[msg.args[0]]:
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(coin, paste), private=False, notice=False, to=channel)
- rate = wrap(rate, [optional('channel'), getopts({'delay':'float', '16':'', '99':'', 'sub':'text', 'fast':'', 'slow':''}), optional('text')])
-
- def cow(self, irc, msg, args, channel, optlist, text):
- """[] [--delay] [--type ]
- Cowsay
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- if 'type' in optlist:
- type = optlist.get('type')
- else:
- type = 'default'
- data = requests.get("https://easyapis.soue.tk/api/cowsay?text={0}&type={1}".format(text, type))
- self.stopped[msg.args[0]] = False
- paste = ''
- for line in data.text.splitlines():
- if self.registryValue('pasteEnable', msg.args[0]):
- paste += line + "\n"
- if not line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- if self.registryValue('pasteEnable', msg.args[0]):
- irc.reply(self.doPaste(text, paste), private=False, notice=False, to=channel)
- cow = wrap(cow, [optional('channel'), getopts({'delay':'float', 'type':'text'}), ('text')])
-
- def fortune(self, irc, msg, args, channel, optlist):
- """[]
- Returns a random ASCII from http://www.asciiartfarts.com/fortune.txt
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- self.stopped[msg.args[0]] = False
- data = requests.get("http://www.asciiartfarts.com/fortune.txt")
- fortunes = data.text.split('%\n')
- fortune = random.randrange(0, len(fortunes))
- for line in fortunes[fortune].splitlines():
- if not line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- fortune = wrap(fortune, [optional('channel'), getopts({'delay':'float'})])
-
- def mircart(self, irc, msg, args, channel, optlist, search):
- """[] (search text)
- Search https://mircart.org/ and scroll first result
- """
- if not channel:
- channel = msg.args[0]
- optlist = dict(optlist)
- if 'delay' in optlist:
- delay = optlist.get('delay')
- else:
- delay = self.registryValue('delay', msg.args[0])
- self.stopped[msg.args[0]] = False
- ua = UserAgent()
- header = {'User-Agent':str(ua.random)}
- data = requests.get("https://mircart.org/?s={0}".format(search), headers=header)
- soup = BeautifulSoup(data.text)
- url = soup.find(href=re.compile(".txt"))
- data = requests.get(url.get('href'), headers=header)
- output = data.content.decode()
- for line in output.splitlines():
- if not line.strip() and not self.stopped[msg.args[0]]:
- time.sleep(delay)
- irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
- time.sleep(delay)
- irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
- irc.reply(url.get('href'))
- mircart = wrap(mircart, [optional('channel'), getopts({'delay':'float'}), ('text')])
-
- def cq(self, irc, msg, args):
- """
- Stop the scroll.
- """
- if not self.stopped[msg.args[0]]:
- self.stopped[msg.args[0]] = True
- irc.reply("Stopping.")
- cq = wrap(cq)
-
-Class = ASCII
+###
+# Copyright (c) 2019 oddluck
+# All rights reserved.
+#
+#
+###
+
+import supybot.ansi as ansi
+import supybot.utils as utils
+from supybot.commands import *
+import supybot.plugins as plugins
+import supybot.ircutils as ircutils
+import supybot.ircdb as ircdb
+import supybot.callbacks as callbacks
+import supybot.ircmsgs as ircmsgs
+import os
+import requests
+from PIL import Image, ImageOps, ImageFont, ImageDraw, ImageEnhance
+import numpy as np
+import sys, math
+from fake_useragent import UserAgent
+import re
+import pexpect
+import time
+import random as random
+import pyimgur
+from bs4 import BeautifulSoup
+
+try:
+ from supybot.i18n import PluginInternationalization
+ _ = PluginInternationalization('Weed')
+except ImportError:
+ # Placeholder that allows to run the plugin on a bot
+ # without the i18n module
+ _ = lambda x: x
+
+class ASCII(callbacks.Plugin):
+ """Uses API to retrieve information"""
+ threaded = True
+
+ def __init__(self, irc):
+ self.__parent = super(ASCII, self)
+ self.__parent.__init__(irc)
+ self.colors = 99
+ self.stopped = {}
+ self.old_color = None
+ self.rgbColors = [
+ (255,255,255),
+ (0,0,0),
+ (0,0,127),
+ (0,147,0),
+ (255,0,0),
+ (127,0,0),
+ (156,0,156),
+ (252,127,0),
+ (255,255,0),
+ (0,252,0),
+ (0,147,147),
+ (0,255,255),
+ (0,0,252),
+ (255,0,255),
+ (127,127,127),
+ (210,210,210),
+ (71,0,0),
+ (71,33,0),
+ (71,71,0),
+ (50,71,0),
+ (0,71,0),
+ (0,71,44),
+ (0,71,71),
+ (0,39,71),
+ (0,0,71),
+ (46,0,71),
+ (71,0,71),
+ (71,0,42),
+ (116,0,0),
+ (116,58,0),
+ (116,116,0),
+ (81,116,0),
+ (0,116,0),
+ (0,116,73),
+ (0,116,116),
+ (0,64,116),
+ (0,0,116),
+ (75,0,116),
+ (116,0,116),
+ (116,0,69),
+ (181,0,0),
+ (181,99,0),
+ (181,181,0),
+ (125,181,0),
+ (0,181,0),
+ (0,181,113),
+ (0,181,181),
+ (0,99,181),
+ (0,0,181),
+ (117,0,181),
+ (181,0,181),
+ (181,0,107),
+ (255,0,0),
+ (255,140,0),
+ (255,255,0),
+ (178,255,0),
+ (0,255,0),
+ (0,255,160),
+ (0,255,255),
+ (0,140,255),
+ (0,0,255),
+ (165,0,255),
+ (255,0,255),
+ (255,0,152),
+ (255,89,89),
+ (255,180,89),
+ (255,255,113),
+ (207,255,96),
+ (111,255,111),
+ (101,255,201),
+ (109,255,255),
+ (89,180,255),
+ (89,89,255),
+ (196,89,255),
+ (255,102,255),
+ (255,89,188),
+ (255,156,156),
+ (255,211,156),
+ (255,255,156),
+ (226,255,156),
+ (156,255,156),
+ (156,255,219),
+ (156,255,255),
+ (156,211,255),
+ (156,156,255),
+ (220,156,255),
+ (255,156,255),
+ (255,148,211),
+ (0,0,0),
+ (19,19,19),
+ (40,40,40),
+ (54,54,54),
+ (77,77,77),
+ (101,101,101),
+ (129,129,129),
+ (159,159,159),
+ (188,188,188),
+ (226,226,226),
+ (255,255,255)]
+ self.colors83= {
+ (11.5497, 31.8768, 18.1739):16,
+ (17.5866, 15.7066, 25.9892):17,
+ (29.0208, -8.5776, 37.5533):18,
+ (27.2543, -19.015, 35.3673):19,
+ (25.2798, -34.2963, 32.8426):20,
+ (25.8276, -27.5812, 10.7515):21,
+ (26.6245, -19.1316, -5.6261):22,
+ (14.986, 1.2467, -23.6473):23,
+ (4.1091, 27.6851, -41.3905):24,
+ (9.2862, 34.8709, -32.6869):25,
+ (14.3696, 39.0991, -24.2113):26,
+ (12.6512, 34.8073, -6.066):27,
+ (22.699, 44.779, 34.3145):28,
+ (31.2054, 21.9979, 41.7676):29,
+ (47.2407, -12.0488, 52.8125):30,
+ (44.5753, -27.9355, 49.6338):31,
+ (41.9858, -48.1745, 46.4957):32,
+ (42.7207, -39.1444, 16.0528):33,
+ (43.8747, -26.8746, -7.9028):34,
+ (26.5278, 3.8603, -34.8152):35,
+ (11.0, 44.2673, -60.2918):36,
+ (19.0423, 48.637, -46.7161):37,
+ (26.6606, 54.9202, -34.0091):38,
+ (24.1377, 48.6121, -6.8774):39,
+ (37.5243, 61.9327, 51.9413):40,
+ (50.3904, 27.7338, 58.553):41,
+ (71.4677, -16.6651, 73.0447):42,
+ (67.5818, -39.987, 68.408):43,
+ (64.1995, -66.6294, 64.3075):44,
+ (65.1526, -54.8772, 23.9922):45,
+ (66.8122, -37.1703, -10.9303):46,
+ (41.6262, 7.9137, -50.0682):47,
+ (21.343, 61.2273, -83.3898):48,
+ (32.0743, 66.9878, -65.2716):49,
+ (43.0033, 75.9603, -47.0378):50,
+ (39.3866, 66.9043, -7.4929):51,
+ (53.2329, 80.1093, 67.2201):52,
+ (69.4811, 36.8308, 75.4949):53,
+ (97.1382, -21.5559, 94.4825):54,
+ (92.125, -51.6335, 88.501):55,
+ (87.737, -86.1846, 83.1812):56,
+ (88.9499, -71.2147, 31.6061):57,
+ (91.1165, -48.0796, -14.1381):58,
+ (58.0145, 11.3842, -65.6058):59,
+ (32.3026, 79.1967, -107.8637):60,
+ (45.9331, 86.4699, -84.8483):61,
+ (60.3199, 98.2542, -60.843):62,
+ (55.6111, 86.4597, -9.1916):63,
+ (60.8927, 62.8729, 35.0702):64,
+ (78.8241, 18.6736, 56.0796):65,
+ (97.6208, -17.6977, 66.4162):66,
+ (94.1539, -37.4631, 68.7023):67,
+ (89.8813, -66.1541, 56.3842):68,
+ (91.0093, -53.1765, 13.8066):69,
+ (92.571, -38.7824, -11.8131):70,
+ (70.8615, -4.4808, -45.0866):71,
+ (47.6091, 49.3215, -82.3961):72,
+ (58.1323, 68.3853, -64.8302):73,
+ (68.0079, 76.2368, -48.6298):74,
+ (63.3723, 71.7112, -18.3923):75,
+ (74.4686, 36.8822, 15.7988):76,
+ (87.1187, 8.2035, 33.0227):77,
+ (98.1056, -13.9188, 47.2642):78,
+ (96.0337, -24.7493, 44.2003):79,
+ (92.1264, -48.2196, 38.3812):80,
+ (93.3211, -36.9827, 8.0947):81,
+ (94.2302, -28.9926, -9.1665):82,
+ (82.3123, -6.9657, -27.1167):83,
+ (68.0684, 23.3938, -49.2364):84,
+ (73.6833, 41.0464, -40.0349):85,
+ (77.4342, 51.3197, -33.9217):86,
+ (74.2811, 48.1595, -14.7725):87,
+ (0.0, 0.0, 0.0):88,
+ (5.8822, 0.0022, -0.0022):89,
+ (16.1144, 0.0022, -0.0033):90,
+ (22.6151, 0.0018, -0.004):91,
+ (32.7476, 0.0018, -0.0044):92,
+ (42.7837, 0.0032, -0.0055):93,
+ (53.9767, 0.0034, -0.0063):94,
+ (65.4912, 0.0036, -0.0074):95,
+ (76.2461, 0.0044, -0.0083):96,
+ (89.8837, 0.0048, -0.0094):97,
+ (100.0, 0.0053, -0.0104):98}
+ self.colors16 = {
+ (100.0, 0.0053, -0.0104):0,
+ (0.0, 0.0, 0.0):1,
+ (12.8119, 47.2407, -64.3396):2,
+ (52.8041, -57.1624, 55.1703):3,
+ (53.2329, 80.1093, 67.2201):4,
+ (25.2966, 47.7847, 37.7562):5,
+ (36.8705, 68.0659, -42.1489):6,
+ (66.4237, 42.1616, 73.4335):7,
+ (97.1382, -21.5559, 94.4825):8,
+ (86.8105, -85.4149, 82.4382):9,
+ (55.0455, -31.8888, -9.3772):10,
+ (91.1165, -48.0796, -14.1381):11,
+ (31.8712, 78.4892, -106.9003):12,
+ (60.3199, 98.2542, -60.843):13,
+ (53.1928, 0.0029, -0.0061):14,
+ (84.1985, 0.0045, -0.0089):15}
+ self.colors99= {
+ (100.0, 0.0053, -0.0104):0,
+ (0.0, 0.0, 0.0):1,
+ (12.8119, 47.2407, -64.3396):2,
+ (52.8041, -57.1624, 55.1703):3,
+ (53.2329, 80.1093, 67.2201):4,
+ (25.2966, 47.7847, 37.7562):5,
+ (36.8705, 68.0659, -42.1489):6,
+ (66.4237, 42.1616, 73.4335):7,
+ (97.1382, -21.5559, 94.4825):8,
+ (86.8105, -85.4149, 82.4382):9,
+ (55.0455, -31.8888, -9.3772):10,
+ (91.1165, -48.0796, -14.1381):11,
+ (31.8712, 78.4892, -106.9003):12,
+ (60.3199, 98.2542, -60.843):13,
+ (53.1928, 0.0029, -0.0061):14,
+ (84.1985, 0.0045, -0.0089):15,
+ (11.5497, 31.8768, 18.1739):16,
+ (17.5866, 15.7066, 25.9892):17,
+ (29.0208, -8.5776, 37.5533):18,
+ (27.2543, -19.015, 35.3673):19,
+ (25.2798, -34.2963, 32.8426):20,
+ (25.8276, -27.5812, 10.7515):21,
+ (26.6245, -19.1316, -5.6261):22,
+ (14.986, 1.2467, -23.6473):23,
+ (4.1091, 27.6851, -41.3905):24,
+ (9.2862, 34.8709, -32.6869):25,
+ (14.3696, 39.0991, -24.2113):26,
+ (12.6512, 34.8073, -6.066):27,
+ (22.699, 44.779, 34.3145):28,
+ (31.2054, 21.9979, 41.7676):29,
+ (47.2407, -12.0488, 52.8125):30,
+ (44.5753, -27.9355, 49.6338):31,
+ (41.9858, -48.1745, 46.4957):32,
+ (42.7207, -39.1444, 16.0528):33,
+ (43.8747, -26.8746, -7.9028):34,
+ (26.5278, 3.8603, -34.8152):35,
+ (11.0, 44.2673, -60.2918):36,
+ (19.0423, 48.637, -46.7161):37,
+ (26.6606, 54.9202, -34.0091):38,
+ (24.1377, 48.6121, -6.8774):39,
+ (37.5243, 61.9327, 51.9413):40,
+ (50.3904, 27.7338, 58.553):41,
+ (71.4677, -16.6651, 73.0447):42,
+ (67.5818, -39.987, 68.408):43,
+ (64.1995, -66.6294, 64.3075):44,
+ (65.1526, -54.8772, 23.9922):45,
+ (66.8122, -37.1703, -10.9303):46,
+ (41.6262, 7.9137, -50.0682):47,
+ (21.343, 61.2273, -83.3898):48,
+ (32.0743, 66.9878, -65.2716):49,
+ (43.0033, 75.9603, -47.0378):50,
+ (39.3866, 66.9043, -7.4929):51,
+ (69.4811, 36.8308, 75.4949):53,
+ (92.125, -51.6335, 88.501):55,
+ (87.737, -86.1846, 83.1812):56,
+ (88.9499, -71.2147, 31.6061):57,
+ (58.0145, 11.3842, -65.6058):59,
+ (32.3026, 79.1967, -107.8637):60,
+ (45.9331, 86.4699, -84.8483):61,
+ (55.6111, 86.4597, -9.1916):63,
+ (60.8927, 62.8729, 35.0702):64,
+ (78.8241, 18.6736, 56.0796):65,
+ (97.6208, -17.6977, 66.4162):66,
+ (94.1539, -37.4631, 68.7023):67,
+ (89.8813, -66.1541, 56.3842):68,
+ (91.0093, -53.1765, 13.8066):69,
+ (92.571, -38.7824, -11.8131):70,
+ (70.8615, -4.4808, -45.0866):71,
+ (47.6091, 49.3215, -82.3961):72,
+ (58.1323, 68.3853, -64.8302):73,
+ (68.0079, 76.2368, -48.6298):74,
+ (63.3723, 71.7112, -18.3923):75,
+ (74.4686, 36.8822, 15.7988):76,
+ (87.1187, 8.2035, 33.0227):77,
+ (98.1056, -13.9188, 47.2642):78,
+ (96.0337, -24.7493, 44.2003):79,
+ (92.1264, -48.2196, 38.3812):80,
+ (93.3211, -36.9827, 8.0947):81,
+ (94.2302, -28.9926, -9.1665):82,
+ (82.3123, -6.9657, -27.1167):83,
+ (68.0684, 23.3938, -49.2364):84,
+ (73.6833, 41.0464, -40.0349):85,
+ (77.4342, 51.3197, -33.9217):86,
+ (74.2811, 48.1595, -14.7725):87,
+ (5.8822, 0.0022, -0.0022):89,
+ (16.1144, 0.0022, -0.0033):90,
+ (22.6151, 0.0018, -0.004):91,
+ (32.7476, 0.0018, -0.0044):92,
+ (42.7837, 0.0032, -0.0055):93,
+ (53.9767, 0.0034, -0.0063):94,
+ (65.4912, 0.0036, -0.0074):95,
+ (76.2461, 0.0044, -0.0083):96,
+ (89.8837, 0.0048, -0.0094):97}
+ self.x256colors99 = [1,5,32,30,2,38,34,96,94,4,56,8,60,13,11,0,1,36,2,48,48,60,32,34,47,47,47,72,3,33,10,59,59,59,44,45,45,46,71,71,9,68,45,69,46,83,56,68,57,57,69,11,28,38,37,49,49,60,30,93,47,72,72,72,31,33,10,59,59,59,43,45,45,46,71,71,9,68,57,69,70,83,56,68,68,57,69,70,5,39,38,49,49,61,41,93,50,50,72,72,30,30,94,84,84,84,43,43,45,46,71,71,43,68,80,81,82,83,55,68,68,80,81,70,40,51,6,50,50,61,41,64,63,50,73,73,30,41,76,87,85,84,42,42,95,96,84,84,55,67,79,81,82,83,55,67,80,80,81,82,40,51,51,50,50,73,41,64,63,75,13,73,53,7,76,87,85,85,42,65,77,76,87,85,42,66,78,78,15,97,55,67,79,79,81,82,4,64,63,63,13,13,7,64,63,75,75,74,53,64,76,87,87,86,65,65,65,76,87,86,8,77,77,77,97,86,8,66,66,78,78,0,1,89,89,90,91,91,92,92,92,93,93,14,94,94,95,95,95,96,96,96,15,97,97,97]
+ self.x256colors16 = [1,5,3,3,2,6,10,15,14,4,9,8,12,13,11,0,1,2,2,2,12,12,3,10,12,12,12,12,3,10,10,10,14,14,3,3,10,10,10,10,9,9,9,11,11,11,9,9,9,9,11,11,5,6,2,12,12,12,3,14,14,12,12,12,3,3,10,14,14,14,3,3,10,10,10,15,9,9,9,11,11,11,9,9,9,9,11,11,5,6,6,6,6,12,14,14,6,6,6,13,3,14,14,14,14,13,3,3,3,11,11,11,9,9,9,11,11,11,9,9,9,9,11,11,5,6,6,6,6,6,7,4,6,13,13,13,7,7,14,14,13,13,8,8,15,15,15,15,8,9,9,15,15,15,9,9,9,9,11,11,4,6,6,6,13,13,7,4,13,13,13,13,7,7,4,13,13,13,8,7,7,15,15,13,8,8,8,15,15,15,8,8,8,9,0,0,4,4,13,13,13,13,7,4,13,13,13,13,7,7,4,13,13,13,7,7,7,15,15,13,8,8,8,15,15,15,8,8,8,8,0,0,1,1,1,1,1,1,1,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,0]
+ self.x256colors83 = [88,28,32,30,36,38,34,96,94,52,56,54,60,62,58,98,88,36,36,48,48,60,32,34,47,47,47,72,32,33,34,59,59,59,44,45,45,46,71,71,44,68,45,69,46,83,56,68,57,57,69,58,28,38,37,49,49,60,30,93,47,72,72,72,31,33,34,59,59,59,43,45,45,46,71,71,56,68,57,69,70,83,56,68,68,57,69,70,28,39,38,49,49,61,41,93,50,50,72,72,30,30,94,84,84,84,43,43,45,46,71,71,43,68,80,81,82,83,55,68,68,80,81,70,40,51,51,50,50,61,41,64,63,50,73,73,30,41,76,87,85,84,42,42,95,96,84,84,55,67,79,81,82,83,55,67,80,80,81,82,40,51,51,50,50,73,41,64,63,75,62,73,53,53,76,87,85,85,42,65,77,76,87,85,42,66,78,78,97,97,55,67,79,79,81,82,52,64,63,63,62,62,52,64,63,75,75,74,53,64,76,87,87,86,65,65,65,76,87,86,54,77,77,77,97,86,54,66,66,78,78,98,88,89,89,90,91,91,92,92,92,93,93,94,94,94,95,95,95,96,96,96,97,97,97,97]
+ self.x16colors = {
+ '30':'01',
+ '31':'05',
+ '32':'03',
+ '33':'07',
+ '34':'02',
+ '35':'06',
+ '36':'10',
+ '37':'15',
+ '30;1':'14',
+ '31;1':'04',
+ '32;1':'09',
+ '33;1':'08',
+ '34;1':'12',
+ '35;1':'13',
+ '36;1':'11',
+ '37;1':'00',
+ '40':'01',
+ '41':'05',
+ '42':'03',
+ '43':'07',
+ '44':'02',
+ '45':'06',
+ '46':'10',
+ '47':'15',
+ '40;1':'14',
+ '41;1':'04',
+ '42;1':'09',
+ '43;1':'08',
+ '44;1':'12',
+ '45;1':'13',
+ '46;1':'11',
+ '47;1':'00'}
+
+ def doPrivmsg(self, irc, msg):
+ channel = msg.args[0]
+ self.stopped.setdefault(channel, None)
+ if msg.args[1].lower().strip()[1:] == 'cq':
+ self.stopped[channel] = True
+
+ def doPaste(self, description, paste):
+ try:
+ apikey = self.registryValue('pasteAPI')
+ payload = {'description':description,'sections':[{'contents':paste}]}
+ headers = {'X-Auth-Token':apikey}
+ post_response = requests.post(url='https://api.paste.ee/v1/pastes', json=payload, headers=headers)
+ response = post_response.json()
+ return response['link'].replace('/p/', '/r/')
+ except:
+ return "Error. Did you set a valid Paste.ee API Key? https://paste.ee/account/api"
+
+ def renderImage(self, text, size=18, defaultBg = 1, defaultFg = 0):
+ try:
+ if utf8 and not isinstance(text, unicode):
+ text = text.decode('utf-8')
+ except:
+ pass
+ text = text.replace('\t', ' ')
+ self.strip_colors_regex = re.compile('(\x03([0-9]{1,2})(,[0-9]{1,2})?)|[\x0f\x02\x1f\x03\x16]').sub
+ path = os.path.dirname(os.path.abspath(__file__))
+ defaultFont = "{0}/DejaVu.ttf".format(path)
+ def strip_colors(string):
+ return self.strip_colors_regex('', string)
+ _colorRegex = re.compile('(([0-9]{1,2})(,([0-9]{1,2}))?)')
+ IGNORE_CHRS = ('\x16','\x1f','\x02', '\x03', '\x0f')
+ lineLens = [len(line) for line in strip_colors(text).splitlines()]
+ maxWidth, height = max(lineLens), len(lineLens)
+ font = ImageFont.truetype(defaultFont, size)
+ fontX = 10
+ fontY = 20
+ imageX, imageY = maxWidth * fontX, height * fontY
+ image = Image.new('RGB', (imageX, imageY), self.rgbColors[defaultBg])
+ draw = ImageDraw.Draw(image)
+ dtext, drect, match, x, y, fg, bg = draw.text, draw.rectangle, _colorRegex.match, 0, 0, defaultFg, defaultBg
+ start = time.time()
+ for text in text.split('\n'):
+ ll, i = len(text), 0
+ while i < ll:
+ chr = text[i]
+ if chr == "\x03":
+ m = match(text[i+1:i+6])
+ if m:
+ i+= len(m.group(1))
+ fg = int(m.group(2))
+ if m.group(4) is not None:
+ bg = int(m.group(4))
+ else:
+ bg, fg = defaultBg, defaultFg
+ elif chr == "\x0f":
+ fg, bg = defaultFg, defaultBg
+ elif chr not in IGNORE_CHRS:
+ if bg != defaultBg: # bg is not white, render it
+ drect((x, y, x+fontX, y+fontY), fill=self.rgbColors[bg])
+ if bg != fg: # text will show, render it. this saves a lot of time!
+ dtext((x, y), chr, font=font, fill=self.rgbColors[fg])
+ x += fontX
+ i += 1
+ y += fontY
+ fg, bg, x = defaultFg, defaultBg, 0
+ return image, imageX, imageY
+
+ def getColor(self, pixel, speed):
+ pixel = tuple(pixel)
+ if self.colors == 16:
+ colors = list(self.colors16.keys())
+ elif self.colors == 99:
+ colors = list(self.colors99.keys())
+ else:
+ colors = list(self.colors83.keys())
+ try:
+ return self.matches[pixel]
+ except KeyError:
+ closest_colors = sorted(colors, key=lambda color: self.distance(color, self.rgb2lab(pixel), speed))
+ closest_color = closest_colors[0]
+ if self.colors == 16:
+ self.matches[pixel] = self.colors16[closest_color]
+ elif self.colors == 99:
+ self.matches[pixel] = self.colors99[closest_color]
+ else:
+ self.matches[pixel] = self.colors83[closest_color]
+ return self.matches[pixel]
+
+ def rgb2lab (self, inputColor) :
+ try:
+ return self.labmatches[inputColor]
+ except:
+ num = 0
+ RGB = [0, 0, 0]
+ for value in inputColor :
+ value = float(value) / 255
+ if value > 0.04045 :
+ value = ( ( value + 0.055 ) / 1.055 ) ** 2.4
+ else :
+ value = value / 12.92
+ RGB[num] = value * 100
+ num = num + 1
+ XYZ = [0, 0, 0,]
+ X = RGB [0] * 0.4124 + RGB [1] * 0.3576 + RGB [2] * 0.1805
+ Y = RGB [0] * 0.2126 + RGB [1] * 0.7152 + RGB [2] * 0.0722
+ Z = RGB [0] * 0.0193 + RGB [1] * 0.1192 + RGB [2] * 0.9505
+ XYZ[ 0 ] = round( X, 4 )
+ XYZ[ 1 ] = round( Y, 4 )
+ XYZ[ 2 ] = round( Z, 4 )
+ XYZ[ 0 ] = float( XYZ[ 0 ] ) / 95.047 # ref_X = 95.047 Observer= 2°, Illuminant= D65
+ XYZ[ 1 ] = float( XYZ[ 1 ] ) / 100.0 # ref_Y = 100.000
+ XYZ[ 2 ] = float( XYZ[ 2 ] ) / 108.883 # ref_Z = 108.883
+ num = 0
+ for value in XYZ :
+ if value > 0.008856 :
+ value = value ** ( 0.3333333333333333 )
+ else :
+ value = ( 7.787 * value ) + ( 16 / 116 )
+ XYZ[num] = value
+ num = num + 1
+ Lab = [0, 0, 0]
+ L = ( 116 * XYZ[ 1 ] ) - 16
+ a = 500 * ( XYZ[ 0 ] - XYZ[ 1 ] )
+ b = 200 * ( XYZ[ 1 ] - XYZ[ 2 ] )
+ Lab [ 0 ] = round( L, 4 )
+ Lab [ 1 ] = round( a, 4 )
+ Lab [ 2 ] = round( b, 4 )
+ self.labmatches[inputColor] = Lab
+ return self.labmatches[inputColor]
+
+ def ciede2000(self, lab1, lab2):
+ """ CIEDE2000 color difference formula. https://peteroupc.github.io/colorgen.html"""
+ dl=lab2[0]-lab1[0]
+ hl=lab1[0]+dl*0.5
+ sqb1=lab1[2]*lab1[2]
+ sqb2=lab2[2]*lab2[2]
+ c1=math.sqrt(lab1[1]*lab1[1]+sqb1)
+ c2=math.sqrt(lab2[1]*lab2[1]+sqb2)
+ hc7=math.pow((c1+c2)*0.5,7)
+ trc=math.sqrt(hc7/(hc7+6103515625))
+ t2=1.5-trc*0.5
+ ap1=lab1[1]*t2
+ ap2=lab2[1]*t2
+ c1=math.sqrt(ap1*ap1+sqb1)
+ c2=math.sqrt(ap2*ap2+sqb2)
+ dc=c2-c1
+ hc=c1+dc*0.5
+ hc7=math.pow(hc,7)
+ trc=math.sqrt(hc7/(hc7+6103515625))
+ h1=math.atan2(lab1[2],ap1)
+ if h1<0:
+ h1=h1+math.pi*2
+ h2=math.atan2(lab2[2],ap2)
+ if h2<0:
+ h2=h2+math.pi*2
+ hdiff=h2-h1
+ hh=h1+h2
+ if abs(hdiff)>math.pi:
+ hh=hh+math.pi*2
+ if h2<=h1:
+ hdiff=hdiff+math.pi*2
+ else:
+ hdiff=hdiff-math.pi*2
+ hh=hh*0.5
+ t2=1-0.17*math.cos(hh-math.pi/6)+0.24*math.cos(hh*2)
+ t2=t2+0.32*math.cos(hh*3+math.pi/30)
+ t2=t2-0.2*math.cos(hh*4-math.pi*63/180)
+ dh=2*math.sqrt(c1*c2)*math.sin(hdiff*0.5)
+ sqhl=(hl-50)*(hl-50)
+ fl=dl/(1+(0.015*sqhl/math.sqrt(20+sqhl)))
+ fc=dc/(hc*0.045+1)
+ fh=dh/(t2*hc*0.015+1)
+ dt=30*math.exp(-math.pow(36*hh-55*math.pi,2)/(25*math.pi*math.pi))
+ r=-2*trc*math.sin(2*dt*math.pi/180)
+ return math.sqrt(fl*fl+fc*fc+fh*fh+r*fc*fh)
+
+ def distance(self, c1, c2, speed):
+ if speed == 'fast':
+ delta_e = math.sqrt((c1[0] - c2[0]) **2 + (c1[1] - c2[1]) ** 2 + (c1[2] - c2[2]) **2)
+ elif speed == 'slow':
+ delta_e = self.ciede2000(c1, c2)
+ return delta_e
+
+ def process_ansi(self, ansi):
+ if self.colors == 16:
+ colors = self.x256colors16
+ elif self.colors == 99:
+ colors = self.x256colors99
+ else:
+ colors = self.x256colors83
+ x16color1 = None
+ x16color2 = None
+ x256color1 = None
+ x256color2 = None
+ effect = None
+ ansi = ansi.lower().strip('\x1b[').strip('m').split(';')
+ if len(ansi) > 1:
+ i = 0
+ while i < len(ansi):
+ if i >= len(ansi):
+ break
+ elif ansi[i]== '0':
+ effect = 0
+ i += 1
+ continue
+ elif ansi[i] == '1':
+ effect = 1
+ i += 1
+ continue
+ elif ansi[i] == '4':
+ effect = 4
+ i += 1
+ continue
+ elif ansi[i] == '2':
+ effect = 2
+ i += 1
+ continue
+ elif int(ansi[i]) > 29 and int(ansi[i]) < 38:
+ if effect == 1 or ansi[-1] == '1':
+ x16color1 = self.x16colors['{0};1'.format(ansi[i])]
+ effect = None
+ i += 1
+ continue
+ else:
+ x16color1 = self.x16colors[ansi[i]]
+ i += 1
+ continue
+ elif int(ansi[i]) > 39 and int(ansi[i]) < 48:
+ if effect == 1 or ansi[-1] == '1':
+ x16color2 = self.x16colors['{0};1'.format(ansi[i])]
+ effect = None
+ i += 1
+ continue
+ else:
+ x16color2 = self.x16colors[ansi[i]]
+ i += 1
+ continue
+ elif ansi[i] == '38':
+ x256color1 = colors[int(ansi[i+2])]
+ i += 3
+ continue
+ elif ansi[i] == '48':
+ x256color2 = colors[int(ansi[i+2])]
+ i += 3
+ continue
+ else:
+ i += 1
+ continue
+ if x16color1 and x16color2:
+ color = '\x03{0},{1}'.format(x16color1, x16color2)
+ elif x256color1 and x256color2:
+ color = '\x03{0},{1}'.format('%02d' % x256color1, '%02d' % x256color2)
+ elif x16color1:
+ color = '\x03{0}'.format(x16color1)
+ elif x16color2:
+ color = '\x0399,{0}'.format(x16color2)
+ elif x256color1:
+ color = '\x03{0}'.format('%02d' % x256color1)
+ elif x256color2:
+ color = '\x0399,{0}'.format('%02d' % x256color2)
+ else:
+ color = ''
+ if effect == 1:
+ color += '\x02'
+ if effect == 4:
+ color += '\x1F'
+ elif len(ansi[0]) > 0:
+ if ansi[0] == '0':
+ color = '\x0F'
+ elif ansi[0] == '1' or ansi[0] == '2':
+ color = '\x02'
+ elif ansi[0] == '4':
+ color = '\x1F'
+ elif int(ansi[0]) > 29 and int(ansi[0]) < 38:
+ color = '\x03{0}'.format(self.x16colors[ansi[0]])
+ elif int(ansi[0]) > 39 and int(ansi[0]) < 48:
+ color = '\x0399,{0}'.format(self.x16colors[ansi[0]])
+ elif ansi[0][-1] == 'c':
+ color = ' ' * int(ansi[0][:-1])
+ else:
+ color = ''
+ else:
+ color = ''
+ if color != self.old_color:
+ self.old_color = color
+ return color
+ else:
+ return ''
+
+ def ansi2irc(self, output):
+ output = output.replace('\x1b(B\x1b[m', '\x1b[0m')
+ output = output.replace('\x1b\x1b', '\x1b')
+ output = re.sub(r'\x1B\[[0-?]*[ -/]*[@-~]', lambda m: self.process_ansi(m.group(0)), output)
+ output = re.sub('\x0399,(\d\d)\x03(\d\d)', '\x03\g<2>,\g<1>', output)
+ output = output.replace('\x0F\x03', '\x03')
+ return output
+
+ def png(self, irc, msg, args, optlist, url):
+ """[--bg] [--fg]
+ Generate PNG from text file
+ """
+ optlist = dict(optlist)
+ if 'bg' in optlist:
+ bg = optlist.get('bg')
+ else:
+ bg = 1
+ if 'fg' in optlist:
+ fg = optlist.get('fg')
+ else:
+ fg = 0
+ if url.startswith("https://paste.ee/p/"):
+ url = re.sub("https://paste.ee/p/", "https://paste.ee/r/", url)
+ ua = UserAgent()
+ header = {'User-Agent':str(ua.random)}
+ r = requests.head(url, headers=header)
+ if "text/plain" in r.headers["content-type"]:
+ file = requests.get(url, headers=header)
+ else:
+ irc.reply("Invalid file type.", private=False, notice=False)
+ return
+ try:
+ file = file.content.decode()
+ except:
+ file = file.content.decode('cp437')
+ file = re.sub('(\x03(\d+).*)\x03,', '\g<1>\x03\g<2>,', file).replace('\r\n','\n')
+ im, x, y = self.renderImage(file, 18, bg, fg)
+ path = os.path.dirname(os.path.abspath(__file__))
+ filepath = "{0}/tmp/tldr.png".format(path)
+ im.save(filepath, "PNG")
+ CLIENT_ID = self.registryValue('imgurAPI')
+ imgur = pyimgur.Imgur(CLIENT_ID)
+ uploaded_image = imgur.upload_image(filepath, title=url)
+ irc.reply(uploaded_image.link, noLengthCheck=True, private=False, notice=False)
+ png = wrap(png, [getopts({'bg':'int', 'fg':'int'}), ('text')])
+
+ def ascii(self, irc, msg, args, channel, optlist, text):
+ """[] [--font ] [--color ] []
+ Text to ASCII art
+ """
+ if not channel:
+ channel = msg.args[0]
+ channel = msg.args[0]
+ optlist = dict(optlist)
+ font = None
+ words = []
+ if text:
+ text = text.strip()
+ if '|' in text:
+ words = text.split('|')
+ if 'color' in optlist:
+ color = optlist.get('color')
+ if "," in color:
+ color = color.split(",")
+ color1 = color[0].strip()
+ color2 = color[1].strip()
+ else:
+ color1 = color
+ color2 = None
+ else:
+ color1 = None
+ color2 = None
+ if 'font' in optlist:
+ font = optlist.get('font')
+ if words:
+ for word in words:
+ if word.strip():
+ data = requests.get("https://artii.herokuapp.com/make?text={0}&font={1}".format(word.strip(), font))
+ for line in data.text.splitlines():
+ if line.strip():
+ irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False)
+ else:
+ data = requests.get("https://artii.herokuapp.com/make?text={0}&font={1}".format(text, font))
+ for line in data.text.splitlines():
+ if line.strip():
+ irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False, to=channel)
+ elif 'font' not in optlist:
+ if words:
+ for word in words:
+ if word.strip():
+ data = requests.get("https://artii.herokuapp.com/make?text={0}&font=univers".format(word.strip()))
+ for line in data.text.splitlines():
+ if line.strip():
+ irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False, to=channel)
+ else:
+ data = requests.get("https://artii.herokuapp.com/make?text={0}&font=univers".format(text))
+ for line in data.text.splitlines():
+ if line.strip():
+ irc.reply(ircutils.mircColor(line, color1, color2), prefixNick=False, private=False, notice=False, to=channel)
+
+ ascii = wrap(ascii, [optional('channel'), getopts({'font':'text', 'color':'text'}), ('text')])
+
+ def fontlist(self, irc, msg, args):
+ """
+ get list of fonts for text-to-ascii-art
+ """
+ fontlist = requests.get("https://artii.herokuapp.com/fonts_list")
+ response = sorted(fontlist.text.split('\n'))
+ irc.reply(str(response).replace('\'', '').replace('[', '').replace(']', ''))
+ fontlist = wrap(fontlist)
+
+ def img(self, irc, msg, args, channel, optlist, url):
+ """[<#channel>] [--delay #.#] [--w <###>] [--s <#.#] [--16] [--99] [--83] [--ascii] [--block] [--1/2] [--chars ] [--ramp ] [--bg <0-98>] [--fg <0-98>] [--no-color] [--invert]
+ Image to ASCII Art.
+ --w columns.
+ --s saturation (1.0).
+ --16 colors 0-15.
+ --99 colors 0-98.
+ --83 colors 16-98.
+ --ascii color ascii.
+ --block space block.
+ --1/2 for 1/2 block
+ --chars color text.
+ --ramp set ramp (".:-=+*#%@").
+ --bg <0-98> set bg.
+ --fg <0-99> set fg.
+ --no-color greyscale ascii.
+ --invert inverts ramp.
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ gscale = "\xa0"
+ if '16' in optlist:
+ self.colors = 16
+ elif '83' in optlist:
+ self.colors = 83
+ elif '99' in optlist:
+ self.colors = 99
+ else:
+ self.colors = self.registryValue('colors', msg.args[0])
+ if 'fast' in optlist:
+ speed = 'fast'
+ elif 'slow' in optlist:
+ speed = 'slow'
+ else:
+ speed = self.registryValue('speed', msg.args[0]).lower()
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ if 'quantize' in optlist:
+ quantize = True
+ elif 'no-quantize' in optlist:
+ quantize = False
+ else:
+ quantize = self.registryValue('quantize', msg.args[0])
+ if 'bg' in optlist:
+ bg = optlist.get('bg')
+ else:
+ bg = self.registryValue('bg', msg.args[0])
+ if 'fg' in optlist:
+ fg = optlist.get('fg')
+ else:
+ fg = self.registryValue('fg', msg.args[0])
+ if 'chars' in optlist:
+ type = 'ascii'
+ gscale = optlist.get('chars')
+ elif 'ramp' in optlist:
+ type = 'ascii'
+ gscale = optlist.get('ramp')
+ elif 'ascii' in optlist and bg == 0 or bg == 98:
+ type = 'ascii'
+ gscale = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:\"^`'."
+ elif 'ascii' in optlist:
+ type = 'ascii'
+ gscale = ".'`^\":;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$"
+ elif '1/2' in optlist:
+ type = '1/2'
+ elif 'block' in optlist:
+ type = 'ascii'
+ gscale = '\xa0'
+ else:
+ type = self.registryValue('imgDefault', msg.args[0]).lower()
+ if 'no-color' in optlist and 'ramp' not in optlist and bg == 0 or bg == 98:
+ type = 'no-color'
+ gscale = "@%#*+=-:. "
+ elif 'no-color' in optlist and 'ramp' not in optlist:
+ type = 'no-color'
+ gscale = " .:-=+*#%@"
+ elif 'no-color' in optlist and 'chars' not in optlist:
+ type = 'no-color'
+ if not gscale.strip():
+ gscale = '\xa0'
+ if 'invert' in optlist and 'chars' not in optlist and gscale != '\xa0':
+ gscale = gscale[::-1]
+ if 'w' in optlist:
+ cols = optlist.get('w')
+ elif type == 'ascii' or type == 'no-color' or type == 'block':
+ cols = self.registryValue('asciiWidth', msg.args[0])
+ else:
+ cols = self.registryValue('blockWidth', msg.args[0])
+ if 's' in optlist:
+ s = float(optlist.get('s'))
+ path = os.path.dirname(os.path.abspath(__file__))
+ filepath = "{0}/tmp".format(path)
+ filename = "{0}/{1}".format(filepath, url.split('/')[-1])
+ ua = UserAgent()
+ header = {'User-Agent':str(ua.random)}
+ image_formats = ("image/png", "image/jpeg", "image/jpg", "image/gif")
+ r = requests.head(url, headers=header)
+ if r.headers["content-type"] in image_formats:
+ response = requests.get(url, headers=header)
+ else:
+ irc.reply("Invalid file type.", private=False, notice=False)
+ return
+ if response.status_code == 200:
+ with open("{0}".format(filename), 'wb') as f:
+ f.write(response.content)
+ # open image and convert to grayscale
+ image = Image.open(filename)
+ if image.mode == 'RGBA':
+ if bg == 99:
+ newbg = 1
+ else:
+ newbg = bg
+ image = Image.alpha_composite(Image.new("RGBA", image.size, self.rgbColors[newbg] + (255,)), image)
+ if image.mode != 'RGB':
+ image = image.convert('RGB')
+ try:
+ os.remove(filename)
+ except:
+ pass
+ # store dimensions
+ W, H = image.size[0], image.size[1]
+ # compute width of tile
+ w = W/cols
+ # compute tile height based on aspect ratio and scale
+ if type == '1/2':
+ scale = 1.0
+ else:
+ scale = 0.5
+ h = w/scale
+ # compute number of rows
+ rows = int(H/h)
+ if 'resize' in optlist:
+ resize = optlist.get('resize')
+ else:
+ resize = self.registryValue('resize', msg.args[0])
+ if type != 'no-color':
+ image2 = image.resize((cols, rows), resize)
+ if 's' in optlist:
+ image2 = ImageEnhance.Color(image2).enhance(s)
+ if quantize:
+ image2 = image2.quantize(dither=None)
+ image2 = image2.convert('RGB')
+ colormap = np.array(image2)
+ self.matches = {}
+ self.labmatches = {}
+ # ascii image is a list of character strings
+ aimg = []
+ if type == '1/2':
+ k = 0
+ for j in range(0, rows - 1, 2):
+ # append an empty string
+ aimg.append("")
+ old_color1 = "99"
+ old_color2 = "99"
+ old_char = None
+ for i in range(cols):
+ color1 = '%02d' % self.getColor(colormap[j][i].tolist(), speed)
+ color2 = '%02d' % self.getColor(colormap[j+1][i].tolist(), speed)
+ if color1 == color2:
+ gsval = " "
+ else:
+ gsval = "▀"
+ if color1 == old_color1 and color2 == old_color2:
+ aimg[k] += gsval
+ old_char = gsval
+ elif gsval == " " and color1 == old_color2:
+ aimg[k] += " "
+ old_char = gsval
+ elif gsval == " " and color1 == old_color1 and old_char == '█':
+ aimg[k] = aimg[k][:-1]
+ aimg[k] += "\x0301,{0} ".format(color1)
+ old_color1 = "01"
+ old_color2 = color1
+ old_char = gsval
+ elif gsval == " " and color1 == old_color1 and old_char == '^█':
+ aimg[k] = aimg[k][:-4]
+ aimg[k] += "\x0301,{0} ".format(color1)
+ old_color1 = "01"
+ old_color2 = color1
+ old_char = gsval
+ elif gsval == " " and color1 == old_color1 and old_char == "^^▀" and 'tops' not in optlist:
+ aimg[k] = aimg[k][:-7]
+ aimg[k] += "\x03{0},{1}▄ ".format(old_color2, color1)
+ old_color1 = old_color2
+ old_color2 = color1
+ old_char = gsval
+ elif gsval == " " and color1 == old_color1 and old_char != '█' and 'tops' not in optlist:
+ aimg[k] += "█"
+ old_char = '█'
+ elif gsval == " " and 'tops' not in optlist:
+ aimg[k] += "\x03{0}█".format(color1)
+ old_color1 = color1
+ old_char = '^█'
+ elif gsval != " " and color1 == old_color1 and old_char == '^█' and 'tops' not in optlist:
+ aimg[k] = aimg[k][:-4]
+ aimg[k] += "\x03{0},{1} ▄".format(color2, color1)
+ old_color1 = color2
+ old_color2 = color1
+ old_char = '▄'
+ elif gsval != " " and color2 == old_color1 and old_char == '^█':
+ aimg[k] = aimg[k][:-4]
+ aimg[k] += "\x03{0},{1} ▀".format(color1, color2)
+ old_color1 = color1
+ old_color2 = color2
+ old_char = gsval
+ elif gsval != " " and color1 == old_color2 and color2 == old_color1 and old_char == "^^▀" and 'tops' not in optlist:
+ aimg[k] = aimg[k][:-7]
+ aimg[k] += "\x03{0},{1}▄▀".format(color1, color2)
+ old_color1 = color1
+ old_color2 = color2
+ old_char = gsval
+ elif gsval != " " and color1 == old_color1 and color2 != old_color2 and old_char == "^^▀" and 'tops' not in optlist:
+ aimg[k] = aimg[k][:-7]
+ aimg[k] += "\x03{0},{1}▄\x03{2}▄".format(old_color2, color1, color2)
+ old_color1 = color2
+ old_color2 = color1
+ old_char = '▄'
+ elif gsval != " " and color1 == old_color1 and color2 != old_color2 and old_char == "^▀" and 'tops' not in optlist:
+ aimg[k] = aimg[k][:-4]
+ aimg[k] += "\x03{0},{1}▄\x03{2}▄".format(old_color2, color1, color2)
+ old_color1 = color2
+ old_color2 = color1
+ old_char = '▄'
+ elif gsval != " " and color1 == old_color2 and color2 == old_color1 and 'tops' not in optlist:
+ aimg[k] += "▄"
+ old_char = '▄'
+ elif gsval != " " and color1 == old_color2 and 'tops' not in optlist:
+ aimg[k] += "\x03{0}▄".format(color2)
+ old_color1 = color2
+ old_char = '▄'
+ elif color1 != old_color1 and color2 == old_color2:
+ aimg[k] += "\x03{0}{1}".format(color1, gsval)
+ old_color1 = color1
+ if gsval == ' ':
+ old_char = gsval
+ else:
+ old_char = '^▀'
+ else:
+ aimg[k] += "\x03{0},{1}{2}".format(color1, color2, gsval)
+ old_color1 = color1
+ old_color2 = color2
+ if gsval == ' ':
+ old_char = gsval
+ else:
+ old_char = '^^▀'
+ if 'tops' in optlist:
+ aimg[k] = re.sub("\x03\d\d,(\d\d\s+\x03)", "\x0301,\g<1>", aimg[k])
+ aimg[k] = re.sub("\x03\d\d,(\d\d\s+$)", "\x0301,\g<1>", aimg[k])
+ aimg[k] = re.sub("\x03\d\d,(\d\d\s\x03)", "\x0301,\g<1>", aimg[k])
+ aimg[k] = re.sub("\x0301,(\d\d)(\s+)\x03(\d\d)([^,])", "\x03\g<3>,\g<1>\g<2>\g<4>", aimg[k])
+ for i in range(0,98):
+ i = '%02d' % i
+ aimg[k] = aimg[k].replace("{0}".format(i), "{0}".format(int(i)))
+ k += 1
+ else:
+ if 'chars' not in optlist and gscale != '\xa0':
+ image = image.resize((cols, rows), resize)
+ image = image.convert('L')
+ lumamap = np.array(image)
+ # generate list of dimensions
+ char = 0
+ for j in range(rows):
+ # append an empty string
+ aimg.append("")
+ old_color = None
+ for i in range(cols):
+ if 'chars' not in optlist and gscale != '\xa0':
+ # get average luminance
+ avg = int(np.average(lumamap[j][i]))
+ # look up ascii char
+ gsval = gscale[int((avg * (len(gscale) - 1))/255)]
+ elif 'chars' in optlist and gscale != '\xa0':
+ if char < len(gscale):
+ gsval = gscale[char]
+ char += 1
+ else:
+ char = 0
+ gsval = gscale[char]
+ char += 1
+ else:
+ gsval = '\xa0'
+ # get color value
+ if type != 'no-color' and gscale != '\xa0' and i == 0:
+ color = self.getColor(colormap[j][i].tolist(), speed)
+ old_color = color
+ if bg != 99:
+ color = "{0},{1}".format(color, "{:02d}".format(int(bg)))
+ if gsval != '\xa0':
+ aimg[j] += "\x03{0}{1}".format(color, gsval)
+ else:
+ aimg[j] += "\x030,{0} ".format(int(color))
+ elif type == 'no-color' and i == 0:
+ if bg != 99 and fg != 99:
+ aimg[j] += "\x03{0},{1}{2}".format("{:02d}".format(int(fg)), "{:02d}".format(int(bg)), gsval)
+ elif fg != 99:
+ aimg[j] += "\x03{0}{1}".format("{:02d}".format(int(fg)), gsval)
+ elif bg != 99:
+ aimg[j] += "\x03{0},{1}{2}".format("{:02d}".format(int(fg)), "{:02d}".format(int(bg)), gsval)
+ elif type != 'no-color' and gsval != ' ':
+ color = self.getColor(colormap[j][i].tolist(), speed)
+ if color != old_color:
+ old_color = color
+ # append ascii char to string
+ if gsval != '\xa0':
+ if gsval.isdigit():
+ color = "{:02d}".format(int(color))
+ aimg[j] += "\x03{0}{1}".format(color, gsval)
+ else:
+ aimg[j] += "\x03{0}{1}".format(int(color), gsval)
+ else:
+ aimg[j] += "\x030,{0} ".format(int(color))
+ else:
+ aimg[j] += "{0}".format(gsval)
+ else:
+ aimg[j] += "{0}".format(gsval)
+ output = aimg
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ for line in output:
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ if not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply(line, prefixNick=False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
+ img = wrap(img,[optional('channel'), getopts({'w':'int', 'invert':'', 'fast':'', 'slow':'', '16':'', '99':'', '83':'', 'delay':'float', 'resize':'int', 'quantize':'', 'no-quantize':'', 'chars':'text', 'bg':'int', 'fg':'int', 'ramp':'text', 'no-color':'', 'block':'', 'ascii':'', '1/2':'', 's':'float', 'tops':''}), ('text')])
+
+ def scroll(self, irc, msg, args, channel, optlist, url):
+ """[] [--delay]
+ Play ASCII/ANSI art text files from web links.
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ self.stopped[msg.args[0]] = False
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ if url.startswith("https://paste.ee/p/"):
+ url = re.sub("https://paste.ee/p/", "https://paste.ee/r/", url)
+ ua = UserAgent()
+ header = {'User-Agent':str(ua.random)}
+ r = requests.head(url, headers=header)
+ if "text/plain" in r.headers["content-type"]:
+ file = requests.get(url, headers=header)
+ else:
+ irc.reply("Invalid file type.", private=False, notice=False)
+ return
+ file = file.content.decode().replace('\r\n','\n')
+ for line in file.split('\n'):
+ if line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ scroll = wrap(scroll, [optional('channel'), getopts({'delay':'float'}), ('text')])
+
+ def a2m(self, irc, msg, args, channel, optlist, url):
+ """[] [--delay] [--l] [--r] [--n] [--p] [--t] [--w]
+ Convert ANSI files to IRC formatted text. https://github.com/tat3r/a2m
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ opts = ''
+ if 'l' in optlist:
+ l = optlist.get('l')
+ opts += '-l {0} '.format(l)
+ if 'r' in optlist:
+ r = optlist.get('r')
+ opts += '-r {0} '.format(r)
+ if 'n' in optlist:
+ opts += '-n '.format(n)
+ if 'p' in optlist:
+ opts += '-p '
+ if 't' in optlist:
+ t = optlist.get('t')
+ opts += '-t {0} '.format(t)
+ if 'w' in optlist:
+ w = optlist.get('w')
+ opts += '-w {0} '.format(w)
+ else:
+ opts += '-w 80 '
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ ua = UserAgent()
+ header = {'User-Agent':str(ua.random)}
+ r = requests.head(url, headers=header)
+ try:
+ if "text/plain" in r.headers["content-type"] or "application/octet-stream" in r.headers["content-type"] and int(r.headers["content-length"]) < 1000000:
+ path = os.path.dirname(os.path.abspath(__file__))
+ filepath = "{0}/tmp".format(path)
+ filename = "{0}/{1}".format(filepath, url.split('/')[-1])
+ r = requests.get(url, headers=header)
+ open(filename, 'wb').write(r.content.replace(b';5;', b';'))
+ try:
+ output = pexpect.run('a2m {0} {1}'.format(opts.strip(), str(filename)))
+ try:
+ os.remove(filename)
+ except:
+ pass
+ except:
+ irc.reply("Error. Have you installed A2M? https://github.com/tat3r/a2m", private=False, notice=False)
+ return
+ else:
+ irc.reply("Invalid file type.")
+ return
+ except:
+ irc.reply("Invalid file type.")
+ return
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ output = re.sub('(\x03(\d+).*)\x03,', '\g<1>\x03\g<2>,', output.decode())
+ for line in output.splitlines():
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ if line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif not line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ else:
+ return
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
+ a2m = wrap(a2m, [optional('channel'), getopts({'l':'int', 'r':'int', 't':'int', 'w':'int', 'p':'', 'delay':'float'}), ('text')])
+
+ def p2u(self, irc, msg, args, channel, optlist, url):
+ """[] [--b] [--f] [--p] [--s] [--t] [--w] [--delay]
+ Picture to Unicode. https://git.trollforge.org/p2u/about/
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ opts = ''
+ if 'b' in optlist:
+ b = optlist.get('b')
+ opts += '-b {0} '.format(b)
+ if 'f' in optlist:
+ f = optlist.get('f')
+ opts += '-f {0} '.format(f)
+ else:
+ opts += '-f m '
+ if 'p' in optlist:
+ p = optlist.get('p')
+ opts += '-p {0} '.format(p)
+ else:
+ opts += '-p x '
+ if 's' in optlist:
+ s = optlist.get('s')
+ opts += '-s {0} '.format(s)
+ if 't' in optlist:
+ t = optlist.get('t')
+ opts += '-t {0} '.format(t)
+ if 'w' in optlist:
+ w = optlist.get('w')
+ opts += '-w {0} '.format(w)
+ else:
+ w = self.registryValue('blockWidth', msg.args[0])
+ opts += '-w {0} '.format(w)
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ path = os.path.dirname(os.path.abspath(__file__))
+ filepath = "{0}/tmp".format(path)
+ filename = "{0}/{1}".format(filepath, url.split('/')[-1])
+ ua = UserAgent()
+ header = {'User-Agent':str(ua.random)}
+ image_formats = ("image/png", "image/jpeg", "image/jpg", "image/gif")
+ r = requests.head(url, headers=header)
+ if r.headers["content-type"] in image_formats:
+ response = requests.get(url, headers=header)
+ else:
+ irc.reply("Invalid file type.", private=False, notice=False)
+ return
+ if response.status_code == 200:
+ with open("{0}".format(filename), 'wb') as f:
+ f.write(response.content)
+ try:
+ output = pexpect.run('p2u -f m {0} {1}'.format(opts.strip(), str(filename)))
+ try:
+ os.remove(filename)
+ except:
+ pass
+ except:
+ irc.reply("Error. Have you installed p2u? https://git.trollforge.org/p2u", private=False, notice=False)
+ return
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ for line in output.splitlines():
+ line = line.decode()
+ line = re.sub('^\x03 ', ' ', line)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ if line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(url, paste), private=False, notice=False, to=channel)
+ else:
+ irc.reply("Unexpected file type or link format", private=False, notice=False)
+ p2u = wrap(p2u, [optional('channel'), getopts({'b':'int', 'f':'text', 'p':'text', 's':'int', 't':'int', 'w':'int', 'delay':'float'}), ('text')])
+
+ def tdf(self, irc, msg, args, channel, optlist, text):
+ """[] [--f] [--j] [--w] [--e] [--r] [--i][--delay]
+ Text to TheDraw ANSI Fonts. http://www.roysac.com/thedrawfonts-tdf.html
+ --f [font] Specify font file used.
+ --j l|r|c Justify left, right, or center. Default is left.
+ --w n Set screen width. Default is 80.
+ --c a|m Color format ANSI or mirc. Default is ANSI.
+ --i Print font details.
+ --r Use random font.
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ opts = ''
+ if 'f' in optlist:
+ f = optlist.get('f')
+ opts += '-f {0} '.format(f.lower())
+ else:
+ opts += '-r '
+ if 'j' in optlist:
+ j = optlist.get('j')
+ opts += '-j {0} '.format(j)
+ if 'w' in optlist:
+ w = optlist.get('w')
+ opts += '-w {0} '.format(w)
+ else:
+ opts += '-w 80 '
+ if 'e' in optlist:
+ e = optlist.get('e')
+ opts += '-e {0} '.format(e)
+ if 'r' in optlist:
+ opts += '-r '
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ if 'i' in optlist:
+ opts += '-i '
+ try:
+ output = pexpect.run('tdfiglet -c m {0} {1}'.format(opts.strip(), r'{}'.format(text)))
+ except:
+ irc.reply("Error. Have you installed tdfiglet? https://github.com/tat3r/tdfiglet", private=False, notice=False)
+ return
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ output = output.decode().replace('\r\r\n', '\r\n')
+ for line in output.splitlines():
+ line = re.sub('\x03\x03\s*', '\x0F ', line)
+ line = re.sub('\x0F\s*\x03$', '', line)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(text, paste), private=False, notice=False, to=channel)
+ tdf = wrap(tdf, [optional('channel'), getopts({'f':'text', 'j':'text', 'w':'int', 'e':'text', 'r':'', 'i':'', 'delay':'float'}), ('text')])
+
+ def toilet(self, irc, msg, args, channel, optlist, text):
+ """[] [--f fontname] [--F filter1,filter2,etc.] [--w] [--delay]
+ Toilet. -f to select font. -F to select filters. Separate multiple filters with a comma.
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ opts = ''
+ if 'f' in optlist:
+ f = optlist.get('f')
+ opts += '-f {0} '.format(f)
+ if 'F' in optlist:
+ filter = optlist.get('F')
+ if ',' in filter:
+ filter = filter.split(',')
+ for i in range(len(filter)):
+ opts += '-F {0} '.format(filter[i])
+ else:
+ opts += '-F {0} '.format(filter)
+ if 'w' in optlist:
+ w = optlist.get('w')
+ opts += '-w {0} '.format(w)
+ elif 'W' in optlist:
+ opts += '-W '
+ else:
+ opts += '-w 100 '
+ if 's' in optlist:
+ opts += '-s '
+ elif 'k' in optlist:
+ opts += '-k '
+ elif 'o' in optlist:
+ opts += '-o '
+ elif 'S' in optlist:
+ opts += '-S '
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ try:
+ output = pexpect.run('toilet --irc {0} {1}'.format(opts.strip(), text))
+ except:
+ irc.reply("Error. Have you installed toilet?", private=False, notice=False)
+ return
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ output = output.decode().replace('\r\r\n', '\r\n')
+ for line in output.splitlines():
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(text, paste), private=False, notice=False, to=channel)
+ toilet = wrap(toilet, [optional('channel'), getopts({'f':'text', 'F':'text', 's':'', 'S':'', 'k':'', 'w':'int', 'W':'', 'o':'', 'delay':'float'}), ('text')])
+
+ def fonts(self, irc, msg, args, optlist):
+ """[--toilet]
+ List figlets. Default list are tdf fonts. --toilet for toilet fonts
+ """
+ optlist = dict(optlist)
+ if 'toilet' in optlist:
+ try:
+ reply = ", ".join(sorted(os.listdir("/usr/share/figlet")))
+ irc.reply(reply, prefixNick=False)
+ except:
+ irc.reply("Sorry, unable to access font directory /usr/share/figlet")
+ else:
+ try:
+ reply = ", ".join(sorted(os.listdir("/usr/local/share/tdfiglet/fonts/")))
+ irc.reply("http://www.roysac.com/thedrawfonts-tdf.html", prefixNick=False)
+ irc.reply(reply, prefixNick=False)
+ except FileNotFoundError:
+ reply = ", ".join(sorted(os.listdir("/usr/share/figlet")))
+ irc.reply(reply, prefixNick=False)
+ except:
+ irc.reply("Sorry, unable to access font directories /usr/local/share/tdfiglet/fonts/ or /usr/share/figlet")
+ fonts = wrap(fonts, [getopts({'toilet':''})])
+
+ def wttr(self, irc, msg, args, channel, optlist, location):
+ """[] [--16] [--99]
+ ASCII weather report from wttr.in for .
+ --16 for 16 colors (default).
+ --99 for 99 colors.
+ Get moon phase with 'wttr moon'.
+ ?u (use imperial units).
+ ?m (metric).
+ ?<1-3> (number of days)
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ if '16' in optlist:
+ self.colors = 16
+ elif '99' in optlist:
+ self.colors = 99
+ else:
+ self.colors = self.registryValue('colors', msg.args[0])
+ if 'fast' in optlist:
+ speed = 'fast'
+ elif 'slow' in optlist:
+ speed = 'slow'
+ else:
+ speed = 'fast'
+ file = requests.get("http://wttr.in/{0}".format(location))
+ output = file.content.decode()
+ output = self.ansi2irc(output)
+ output = re.sub('⚡', '☇ ', output)
+ output = re.sub('‘‘', '‘ ', output)
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ for line in output.splitlines():
+ line = line.strip('\x0F')
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif line.strip() and not self.stopped[msg.args[0]] and not line.startswith("Follow"):
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(location, paste), private=False, notice=False, to=channel)
+ wttr = wrap(wttr, [optional('channel'), getopts({'delay':'float', '16':'', '99':'', 'fast':'', 'slow':''}), ('text')])
+
+ def rate(self, irc, msg, args, channel, optlist, coin):
+ """[] [--16] [--99] [--sub ] [coin]
+ Crypto exchange rate info from rate.sx. http://rate.sx/:help. Use --sub to set subdomain e.g. eur, btc, etc.
+ Get a graph with [coin] e.g. 'rate btc'.
+ --16 for 16 colors (default).
+ --99 for 99 colors.
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ if '16' in optlist:
+ self.colors = 16
+ elif '99' in optlist:
+ self.colors = 99
+ else:
+ self.colors = self.registryValue('colors', msg.args[0])
+ if 'fast' in optlist:
+ speed = 'fast'
+ elif 'slow' in optlist:
+ speed = 'slow'
+ else:
+ speed = 'fast'
+ if 'sub' in optlist:
+ sub = optlist.get('sub')
+ else:
+ sub = 'usd'
+ if not coin:
+ coin = ''
+ file = requests.get("http://{0}.rate.sx/{1}".format(sub, coin))
+ output = file.content.decode()
+ output = self.ansi2irc(output)
+ output = output.replace('\x1b(B', '')
+ paste = ""
+ self.stopped[msg.args[0]] = False
+ for line in output.splitlines():
+ line = line.strip('\x0F')
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(coin, paste), private=False, notice=False, to=channel)
+ rate = wrap(rate, [optional('channel'), getopts({'delay':'float', '16':'', '99':'', 'sub':'text', 'fast':'', 'slow':''}), optional('text')])
+
+ def cow(self, irc, msg, args, channel, optlist, text):
+ """[] [--delay] [--type ]
+ Cowsay
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ if 'type' in optlist:
+ type = optlist.get('type')
+ else:
+ type = 'default'
+ data = requests.get("https://easyapis.soue.tk/api/cowsay?text={0}&type={1}".format(text, type))
+ self.stopped[msg.args[0]] = False
+ paste = ''
+ for line in data.text.splitlines():
+ if self.registryValue('pasteEnable', msg.args[0]):
+ paste += line + "\n"
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ if self.registryValue('pasteEnable', msg.args[0]):
+ irc.reply(self.doPaste(text, paste), private=False, notice=False, to=channel)
+ cow = wrap(cow, [optional('channel'), getopts({'delay':'float', 'type':'text'}), ('text')])
+
+ def fortune(self, irc, msg, args, channel, optlist):
+ """[]
+ Returns a random ASCII from http://www.asciiartfarts.com/fortune.txt
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ self.stopped[msg.args[0]] = False
+ data = requests.get("http://www.asciiartfarts.com/fortune.txt")
+ fortunes = data.text.split('%\n')
+ fortune = random.randrange(0, len(fortunes))
+ for line in fortunes[fortune].splitlines():
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ fortune = wrap(fortune, [optional('channel'), getopts({'delay':'float'})])
+
+ def mircart(self, irc, msg, args, channel, optlist, search):
+ """[] (search text)
+ Search https://mircart.org/ and scroll first result
+ """
+ if not channel:
+ channel = msg.args[0]
+ if channel != msg.args[0] and not ircdb.checkCapability(msg.prefix, 'admin'):
+ irc.errorNoCapability('admin')
+ return
+ optlist = dict(optlist)
+ if 'delay' in optlist:
+ delay = optlist.get('delay')
+ else:
+ delay = self.registryValue('delay', msg.args[0])
+ self.stopped[msg.args[0]] = False
+ ua = UserAgent()
+ header = {'User-Agent':str(ua.random)}
+ data = requests.get("https://mircart.org/?s={0}".format(search), headers=header)
+ soup = BeautifulSoup(data.text)
+ url = soup.find(href=re.compile(".txt"))
+ data = requests.get(url.get('href'), headers=header)
+ output = data.content.decode()
+ for line in output.splitlines():
+ if not line.strip() and not self.stopped[msg.args[0]]:
+ time.sleep(delay)
+ irc.reply('\xa0', prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ elif line.strip() and not self.stopped[msg.args[0]] and "Follow @igor_chubin" not in line:
+ time.sleep(delay)
+ irc.reply(line, prefixNick = False, noLengthCheck=True, private=False, notice=False, to=channel)
+ irc.reply(url.get('href'))
+ mircart = wrap(mircart, [optional('channel'), getopts({'delay':'float'}), ('text')])
+
+ def cq(self, irc, msg, args):
+ """
+ Stop the scroll.
+ """
+ if not self.stopped[msg.args[0]]:
+ self.stopped[msg.args[0]] = True
+ irc.reply("Stopping.")
+ cq = wrap(cq)
+
+Class = ASCII