This commit is contained in:
.[d]. 2022-02-01 22:44:42 -06:00
parent 58885932fb
commit 92efd55db5
27 changed files with 3719 additions and 0 deletions

44
README.md Normal file
View File

@ -0,0 +1,44 @@
# MAPLE+G1MP ML/Irc3 Hybrid
```
[ Hybrid of machine learning and irc3 framework ]
- Maple - [sourcecode](https://git.tcp.direct/decoded/Maple)
- g1mp - [sourcecode](https://git.tcp.direct/decoded/g1mp)
```
## Prerequisites
1. `apt install python3`
2. `apt install python3-pip`
3. `python3 -m pip install virtualenv`
## Instructions
1. `git clone --recursive https://git.tcp.direct/decoded/m4pl1mp.git`
2. `cd m4pl1mp`
3. `virtualenv env -p python3`
4. `source env/bin/activate`
### Append your api keys to env/bin/activate. Example below:
```
cat env/bin/activate
..
export DEVELOPER_KEY="1394823190182390182382383215382158321" # <- YOUTUBE API KEY
export CONSUMER_KEY="2151235132512351235123512351325231" # <- TWITTER API KEY
export CONSUMER_SECRET="514512521345234523452345234523452345234523452" # <- TWITTER API KEY
export ACCESS_TOKEN_KEY="24513429875209348502934850294898348034850293485203948592" # <- TWITTER API KEY
export ACCESS_TOKEN_SECRET="523490582034985203948520394804884820934850923485" # <- TWITTER API KEY
```
### If you don't have either 'twitter' or 'youtube' api keys set irc3 will crash
### on startup, comment out the youtube_plugin and twitter_plugin in maple.ini
### until you get some api keys.
5. `pip install -r requirements.txt`
6. `change the instance of #tcpdirect in plugins/maple_plugin.py to whatever channel she will communicate`
### you should lookover maple.ini and make changes, mostly the names/servers/etc and possibly autojoins.
### plugins/auth.py is used to identify to nameserver but you can also use sasl through maple.ini. things
### should run now simply running the command below.. if you need to background.. screen/tmux or & disown
7. `irc3 maple.ini`
## TODO:
1. update maple_plugin.py to use a queue stack
2. do callback exception handling
## DONE:
1. revise maple.py to run async inside irc3

426
databases/emote.db Normal file
View File

@ -0,0 +1,426 @@
¢‿¢
©¿© o
ª{•̃̾_•̃̾}ª
¬_¬
¯\(º_o)/¯
¯\(º o)/¯
¯\_(⊙︿⊙)_/¯
¯\_(ツ)_/¯
°ω°
°Д°
°‿‿°
°ﺑ°
´ ▽ ` )ノ
¿ⓧ_ⓧﮌ
Ò,ó
ó‿ó
ô⌐ô
ôヮô
ŎםŎ
ŏﺡó
ʕ•̫͡•ʔ
ʕ•ᴥ•ʔ
ʘ‿ʘ
˚•_•˚
˚⌇˚
˚▱˚
̿ ̿̿'̿'\̵͇̿̿\=(•̪●)=/̵͇̿̿/'̿̿ ̿ ̿ ̿
͡° ͜ʖ ͡°
Σ ◕ ◡ ◕
Σ (゚Д゚;
Σ(゚Д゚;≡;゚д゚)
Σ(゚Д゚ )
Σ(||゚Д゚)
Φ,Φ
δﺡό
σ_σ
д_д
ф_ф
щ(゚Д゚щ)
щ(ಠ益ಠщ)
щ(ಥДಥщ)
Ծ_Ծ
أ‿أ
ب_ب
ح˚௰˚づ
ح˚ᆺ˚ว
حᇂﮌᇂ)
٩๏̯͡๏۶
٩๏̯͡๏)۶
٩◔̯◔۶
٩(×̯×)۶
٩(̾●̮̮̃̾•̃̾)۶
٩(͡๏̯͡๏)۶
٩(͡๏̯ ͡๏)۶
٩(ಥ_ಥ)۶
٩(•̮̮̃•̃)۶
٩(●̮̮̃•̃)۶
٩(●̮̮̃●̃)۶
٩(。͡•‿•。)۶
٩(-̮̮̃•̃)۶
٩(-̮̮̃-̃)۶
۞_۞
۞_۟۞
۹ↁﮌↁ
۹⌤_⌤۹
॓_॔
१✌◡✌५
१|˚–˚|५
ਉ_ਉ
ଘ_ଘ
இ_இ
ఠ_ఠ
రృర
ಠ¿ಠi
ಠ‿ಠ
ಠ⌣ಠ
ಠ╭╮ಠ
ಠ▃ಠ
ಠ◡ಠ
ಠ益ಠ
ಠ益ಠ
ಠ︵ಠ凸
ಠ , ಥ
ಠ.ಠ
ಠoಠ
ಠ_ృ
ಠ_ಠ
ಠ_๏
ಠ~ಠ
ಡ_ಡ
ತಎತ
ತ_ತ
ಥдಥ
ಥ‿ಥ
ಥ⌣ಥ
ಥ◡ಥ
ಥ﹏ಥ
ಥ_ಥ
ಭ_ಭ
ರ_ರ
ಸ , ໖
ಸ_ಸ
ക_ക
อ้_อ้
อ_อ
โ๏௰๏ใ ื
๏̯͡๏﴿
๏̯͡๏
๏̯͡๏﴿
๏[-ิิ_•ิ]๏
๏_๏
໖_໖
ლ(´ڡ`ლ)
ლ(́◉◞౪◟◉‵ლ)
ლ(ಠ益ಠლ)
ლ(╹◡╹ლ)
ლ(◉◞౪◟◉‵ლ)
ლ,ᔑ•ﺪ͟͠•ᔐ.ლ
ᄽὁȍ ̪ őὀᄿ
ᕕ( ᐛ )ᕗ
ᕙ(⇀‸↼‶)ᕗ
ᕦ(ò_óˇ)ᕤ
ᶘ ᵒᴥᵒᶅ
‘︿’
•▱•
•✞_✞•
•ﺑ•
•(⌚_⌚)•
•_•)
‷̗ↂ凸ↂ‴̖
‹•.•›
(•¿•)
(ᵒᴥᵒ­­­­­)
(•¿•)
ↁ_ↁ
⇎_⇎
∩(︶▽︶)∩
∩( ・ω・)∩
≖‿≖
≧ヮ≦
⊂•⊃_⊂•⊃
⊂⌒~⊃。Д。)⊃
⊂(◉‿◉)つ
⊂(゚Д゚,,⊂⌒`つ
⊙ω⊙
⊙▂⊙
⊙▃⊙
⊙△⊙
⊙︿⊙
⊙﹏⊙
⊙0⊙
⊛ठ̯⊛
⋋ō_ō`
━━━ヽ(ヽ(゚ヽ(゚ヽ(゚゚ヽ(゚゚)ノ゚゚)ノ゚)ノ゚)ノ)ノ━━━
┌∩┐(◕_◕)┌∩┐
┌( ಠ_ಠ)┘
┌( ಥ_ಥ)┘
╚(•⌂•)╝
╭╮╭╮☜{•̃̾_•̃̾}☞╭╮╭╮
╭✬⌢✬╮
╮(▽)╭
╯‵Д′)╯彡┻━┻
╰☆╮
□_□
►_◄
◃┆◉◡◉┆▷
◉△◉
◉︵◉
◉_◉
○_○
●¿●\ ~
●_●
◔̯◔
◔ᴗ◔
◔ ⌣ ◔
◔_◔
◕ω◕
◕‿◕
◕◡◕
◕ ◡ ◕
◖♪_♪|◗
◖|◔◡◉|◗
◘_◘
◙‿◙
◜㍕◝
◪_◪
◮_◮
☁ ☝ˆ~ˆ☂
☆¸☆
☉‿⊙
☉_☉
☐_☐
☜ق❂Ⴢ❂ق☞
☜(⌒▽⌒)☞
☜(゚ヮ゚☜)
☜-(ΘLΘ)-☞
☝☞✌
☮▁▂▃▄☾ ♛ ◡ ♛ ☽▄▃▂▁☮
☹_☹
☻_☻
☼.☼
☾˙❀‿❀˙☽
♀ح♀ヾ
♥‿♥
♥╣[-_-]╠♥
♥╭╮♥
♥◡♥
✌♫♪˙❤‿❤˙♫♪✌
✌.ʕʘ‿ʘʔ.✌
✌.|•͡˘‿•͡˘|.✌
✖‿✖
✖_✖
❐‿❑
_
_Ꙩ
⨂_⨂
〆(・・@)
《〠_〠》
【•】_【•】
〠_〠
〴⋋_⋌〵
<EFBFBD> <20>
ニガー? ━━━━━━(゚゚)━━━━━━ ニガー?
ペ㍕˚\
ヽ(´ー` )ノ
ヽ(๏๏ )ノ
ヽ(`Д´)ノ
ヽ(`皿′o)ノ
ヽ(`Д´)ノ
ㅎ_ㅎ
乂◜◬◝乂
凸ಠ益ಠ)凸
句_句
Ꙩ⌵Ꙩ
Ꙩ_Ꙩ
ꙩ_ꙩ
Ꙫ_Ꙫ
ꙫ_ꙫ
ꙮ_ꙮ
흫_흫
句_句
﴾͡๏̯͡๏﴿ O'RLY?
¯\(ºдಠ)/¯
(·×·)
(⌒Д⌒)
(╹ェ╹)
(♯・・)⊃
( ´`)☆
 ´
(゜Д゜)
(・・)
(・A・)
(゚゚)
( ̄へ ̄)
´☣///_ゝ///☣`)
つ Д
_☆( ´_⊃_
。◕‿‿◕。
。◕ ‿ ◕。
!⑈ˆ~ˆ!⑈
!(`・ω・。)
(¬‿¬)
(¬▂¬)
(¬_¬)
(°ℇ °)
(°°)
(´ω`)
(´◉◞౪◟◉)
(´ヘ`;)
(´・ω・`)
(´ー`)
(ʘ‿ʘ)
(ʘ_ʘ)
(˚இ˚)
(͡๏̯͡๏)
(ΘεΘ;)
(ι´Д`)ノ
(Ծ‸ Ծ)
(॓_॔)
( ्०)
(ு८ு_ .:)
(ಠ‾ಠ)
(ಠ‿ʘ)
(ಠ‿ಠ)
(ಠ⌣ಠ)
(ಠ益ಠ ╬)
(ಠ益ಠ)
(ಠ_ృ)
(ಠ_ಠ)
(ಥ﹏ಥ)
(ಥ_ಥ)
(๏̯͡๏ )
(ღ˘⌣˘ღ) ♫・*:.。. .。.:*・
(ღ˘⌣˘ღ)
(ᵔᴥᵔ)
(•ω•)
(•‿•)
(•⊙ω⊙•)
(• ε •)
(∩▂∩)
(∩︵∩)
()
(≧ω≦)
(≧◡≦)
(≧ロ≦)
(⊙ヮ⊙)
(⊙_◎)
(⋋▂⋌)
(⌐■_■)
(‿‿)
(┛◉Д◉)┛┻━┻
(╥_╥)
(╬ಠ益ಠ)
(╬◣д◢)
(╬ ಠ益ಠ)
(╯°□°)╯︵ ┻━┻
(╯ಊ╰)
(╯◕_◕)╯
(╯︵╰,)
(╯3╰)
(╯_╰)
(╹◡╹)凸
(▰˘◡˘▰)
(●´ω`●)
(●´`●)
(◑‿◐)
(◑◡◑)
(◕‿◕✿)
(◕‿◕)
(◕‿-)
(◕︵◕)
(◕ ^ ◕)
(◕_◕)
(◜௰◝)
(◡‿◡✿)
(◣_◢)
(☞゚゚)☞
(☞゚ヮ゚)☞
(☞゚ ゚ )☞
(☼◡☼)
(☼_☼)
(✌゚゚)☞
(✖╭╮✖)
(✪㉨✪)
(✿◠‿◠)
(✿ ♥‿♥)
( ・・)
( ・ัω・ั)
( ゚゚)o彡゜えーりんえーりん!!
(。・_・。)
(つд`)
(づ。◕‿‿◕。)づ
(ノಠ益ಠ)ノ彡┻━┻
( ◑‿◑)
(_・。)
(・・ )
(屮゚Д゚)屮
(︶ω︶)
(︶︹︺)
(ﺧ益ﺨ)
(一_一)
(`・ω・´)”
(。◕‿‿◕。)
(。◕‿◕。)
(。◕ ‿ ◕。)
(。♥‿♥。)
(。・ω..・)っ
(・ェ-)
(ノ◕ヮ◕)ノ*:・゚✧
(゚Д゚)
(゚Д゚)y┛~~
(゚゚)
(゚ヮ゚)
( ̄□ ̄)
( ̄。 ̄)
( ̄ー ̄)
( ̄(エ) ̄)
( °٢° )
( ´_ゝ)
( ͡° ͜ʖ ͡°)
( ͡~ ͜ʖ ͡°)
( ಠ◡ಠ )
( •_•)>⌐■-■
(  ゚,_ゝ゚)
( ・ิз・ิ)
( ゚д゚)、
( ^▽^)σ)~O~)
((((゜д゜;))))
(*´д`*)
(*..Д`)
(*..д`*)
(*~▽~)
(-๏_๏-)
(-_- )
(/◔ ◡ ◔)/
(///_ಥ)
(;´Д`)
(=ω=;)
(=゜ω゜)
(>'o')> ♥ <('o'<)
(n˘v˘•)¬
(o´ωo)
(V)(°,,°)(V)
(\/) (°,,°) (\/)
(^▽^)
(`・ω・´)
(~ ̄▽ ̄)~
/╲/\╭ºoꍘoº╮/\\
<【☯】‿【☯】>
= (゚д゚)ウ
@_@
d(*⌒▽⌒*)b
o(≧≦)o
o(≧o≦)o
q(❂‿❂)p
y=ー( ゚д゚)・∵.
\˚ㄥ˚\
\ᇂ_ᇂ\
\(ಠ ὡ ಠ )/
\(◕ ◡ ◕\)
^̮^
^ㅂ^
_(͡๏̯͡๏)_
{´◕ ◡ ◕`}
{ಠ_ಠ}__,,|,
{◕ ◡ ◕}

73
maple.ini Normal file
View File

@ -0,0 +1,73 @@
[bot]
nick = not_maple
username = not_g1mp
realname = "[ not_g1mp'n ain't easy unless you're not_maple ]"
host = ircd.chat
port = 6697
version = 1
url = ircd.chat
ssl = true
ssl_verify = CERT_NONE
includes =
irc3.plugins.command
irc3.plugins.asynchronious
irc3.plugins.uptime
irc3.plugins.ctcp
irc3.plugins.cron
irc3.plugins.logger
irc3.plugins.userlist
plugins.storage_plugin
plugins.base_plugin
plugins.emote_plugin
plugins.youtube_plugin
plugins.crypto_plugin
plugins.auth_plugin
plugins.url_grabber_plugin
plugins.notes_plugin
plugins.quote_plugin
plugins.ratesex_plugin
plugins.remind_plugin
plugins.sed_plugin
plugins.seen_plugin
plugins.strain_plugin
plugins.tell_plugin
plugins.twitter_plugin
plugins.ud_plugin
plugins.figlet_plugin
plugins.soundcloud_plugin
plugins.isup_plugin
plugins.maple_plugin
autojoins =
${#}tcpdirect
flood_burst = 0
flood_rate = 1
flood_rate_delay = 1
storage = json://databases/maple_db.json
[irc3.plugins.command]
cmd = ?
guard = irc3.plugins.command.mask_based_policy
[irc3.plugins.command.masks]
d!*dr1p@* = all_permissions
* = view
ignore_list =
GitServ!*@*
GitServ_!*@*
g1mp!*@*
g1mp_!*@*
maple!*@*
maple_!*@*
[0]!*@*
[0]_!*@*
nav!*@*
nav_!*@*
van!*@*
van_!*@*
professorOak!*@*
professorOak_!*@*
*!van@*

30
plugins/auth_plugin.py Normal file
View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from irc3.plugins.cron import cron
import irc3
###########################################################################################
###########################################################################################
NICKSERV_USERNAME='not_maple'
NICKSERV_PASSWORD='CHANGEYOURPASSWORD'
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
def __init__(self,bot):
self.bot=bot
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.CONNECTED)
def connected(self, **kw):
MSG=f"identify {NICKSERV_USERNAME} {NICKSERV_PASSWORD}"
self.bot.privmsg('NICKSERV',MSG)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################
@cron('*/1 * * * *')
def cron_auth(bot):
if not bot.nick==bot.original_nick:
MSG=f"identify {NICKSERV_USERNAME} {NICKSERV_PASSWORD}"
bot.privmsg('NICKSERV',MSG)
###########################################################################################
###########################################################################################

239
plugins/base_plugin.py Normal file
View File

@ -0,0 +1,239 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
from irc3.utils import IrcString
import irc3
import os
import sys
import time
import re
import functools
###########################################################################################
###########################################################################################
USER_STRING_MATCH = re.compile('(.+)!(.+)@(.+)')
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
###########################################################################################
###########################################################################################
def __init__(self, bot):
staff_set = set()
self.bot = bot
self.bot.auto_kick_list = set(self.bot.db.getlist("auto_kick_list", []))
self.bot.ignore_list = set(self.bot.db.getlist("ignore_nicks_list", []))
self.bot.staff_list = set(self.bot.db.getlist("staff_list", []))
current_masks = self.bot.config.get('irc3.plugins.command.masks')
for k, v in current_masks.items():
if v in ["staff", "all_permissions"]:
staff_set.add(k)
if not self.bot.ignore_list:
self.bot.ignore_list = set(self.bot.config.get('irc3.plugins.command.masks', {}).get("ignore_list", []))
if not self.bot.staff_list:
self.bot.staff_list = set(staff_set)
self.bot.db.setlist("staff_list", self.bot.staff_list)
for hostname in self.bot.staff_list:
if not current_masks.get(hostname):
self.bot.config['irc3.plugins.command.masks'][hostname] = "staff"
###########################################################################################
###########################################################################################
@irc3.extend
def check_if_ignored(self, hostmask):
global_hostmask = hostmask.replace(hostmask.nick, ".+")
nick_mask = hostmask.replace(hostmask.host,".+@.+")
host_pattern = re.compile(global_hostmask)
nick_pattern = re.compile(nick_mask)
for mask in self.bot.ignore_list:
if host_pattern.match(mask):
return True
if nick_pattern.match(mask):
return True
return False
###########################################################################################
###########################################################################################
@irc3.event(irc3.rfc.CONNECTED)
def _add_hostmask(self, *args, **kwargs):
def handle_who(self, response):
result = response.result()
self.bot.hostmask = result.get('mask')
task = self.bot.who(self.bot.get_nick())
task.add_done_callback(functools.partial(handle_who, self))
opper_password = self.bot.config.get("opper_password")
opper_username = self.bot.config.get("opper_username")
self.bot.send_line("GOD {} {}".format(opper_username, opper_password))
self.bot.privmsg("nickserv", "IDENTIFY {} {}".format(self.bot.nick, opper_password))
###########################################################################################
###########################################################################################
@irc3.event(irc3.rfc.JOIN)
def auto_kick_handler(self, mask, channel, **kw):
msg = "g1mp'n ain't easy unless you're maple"
if mask.nick in self.bot.auto_kick_list:
cmd = "MODE {} +b {}!*@*".format(channel, mask.nick)
self.bot.send(cmd)
self.bot.kick(channel, mask.nick, msg)
###########################################################################################
###########################################################################################
@command(permission='view', public=True, show_in_help_list=False)
def v(self, mask, target, args):
channel = self.bot.channels[target]
has_voice_list = []
for _, nick in channel.modes.items():
has_voice_list.append(nick)
for nick in channel:
if nick not in has_voice_list:
cmd = "MODE {} +v {}".format(target, nick)
self.bot.send(cmd)
###########################################################################################
###########################################################################################
@command(permission='admin', public=True, show_in_help_list=False)
def op(self, mask, target, args):
if args['<nick>']:
nick = args['<nick>']
cmd = "MODE {} +o {}".format(target, nick)
self.bot.send(cmd)
###########################################################################################
###########################################################################################
@command(permission='admin', public=True, show_in_help_list=False)
def deop(self, mask, target, args):
if args['<nick>']:
nick = args['<nick>']
cmd = "MODE {} -o {}".format(target, nick)
self.bot.send(cmd)
###########################################################################################
###########################################################################################
@command(permission="admin", show_in_help_list=False)
def stats(self, mask, target, args):
###########################################################################################
###########################################################################################
if args['<channel>']:
channel = args['<channel>']
target = mask.nick
else:
channel = target
if channel in self.bot.channels:
channel = self.bot.channels[channel]
message = '{0} users'.format(len(channel))
for mode, nicknames in sorted(channel.modes.items()):
message += ' - {0}({1})'.format(mode, len(nicknames))
self.bot.privmsg(target, message)
###########################################################################################
###########################################################################################
@command(permission='admin', public=False, show_in_help_list=False)
def restart(self, mask, target, args):
self.bot.privmsg(target, 'BOT RESTARTING')
time.sleep(1)
os.execl(sys.executable, sys.executable, *sys.argv)
###########################################################################################
###########################################################################################
@command(permission='admin', public=False, show_in_help_list=False)
def uptime(self, mask, target, args):
pass
###########################################################################################
###########################################################################################
@command(permission='admin', public=False, show_in_help_list=False)
def ping(self, mask, target, args):
pass
###########################################################################################
###########################################################################################
@command(permission='staff', public=True, show_in_help_list=True)
def staff(self, mask, target, args):
###################################################################################
###################################################################################
def __staff_list(self, mask, target, args):
current_masks = self.bot.config.get("irc3.plugins.command.masks", "")
current_staff_list = [k for k,v in current_masks.items() if v in ["all_permissions", "staff"]]
self.bot.privmsg(target, "\x02༺Staff List༻\x0F\x02\x0303 ▶ \x0F\x0302{}".format(", ".join(current_staff_list)))
###################################################################################
###################################################################################
def __staff_del(self, mask, target, args):
###############################################################################
###############################################################################
def del_hostmask(self, host_string):
current_masks = self.bot.config.get("irc3.plugins.command.masks", "")
if host_string in current_masks.keys():
mask_list = current_masks.get(host_string, "").split(",")
if "all_permissions" in mask_list:
self.bot.privmsg(target, "Don't fuck with the admin")
return
elif "staff" in mask_list:
del(self.bot.config["irc3.plugins.command.masks"][host_string])
self.bot.staff_list.remove(host_string)
self.bot.db.setlist("staff_list", self.bot.staff_list)
self.bot.privmsg(target, '{} removed from staff'.format(host_string))
return
else:
pass # pass for brevarity
else:
self.bot.privmsg(target, '{} is not a staff member'.format(host_string))
###############################################################################
###############################################################################
def handle_who(self, response):
result = response.result()
nick = result.get("nick")
mask = result.get('mask')
host_string = mask.replace(nick,"*")
del_hostmask(self, host_string)
###############################################################################
###############################################################################
nick = args.get("<nick>")
match_list = USER_STRING_MATCH.findall(nick)
if match_list and len(match_list[0]) == 3:
del_hostmask(self, nick)
return
else:
task = self.bot.who(nick)
task.add_done_callback(functools.partial(handle_who, self))
return
###################################################################################
###################################################################################
def __staff_add(self, mask, target, args):
###############################################################################
###############################################################################
def add_hostmask(self, host_string):
current_masks = self.bot.config.get("irc3.plugins.command.masks", "")
if host_string in current_masks.keys():
mask_list = current_masks.get(host_string, "").split(",")
if "staff" or "all_permissions" in mask_list:
self.bot.privmsg(target, "{} is already a staff member".format(host_string))
return
else:
self.bot.config["irc3.plugins.command.masks"][host_string] = "staff"
self.bot.staff_list.add(host_string)
self.bot.db.setlist("staff_list", self.bot.staff_list)
self.bot.privmsg(target, '{} added to staff'.format(host_string))
###############################################################################
###############################################################################
def handle_who(self, response):
result = response.result()
nick = result.get("nick")
mask = result.get('mask')
host_string = mask.replace(nick,"*")
add_hostmask(self, host_string)
###############################################################################
###############################################################################
nick = args.get("<nick>")
match_list = USER_STRING_MATCH.findall(nick)
###############################################################################
###############################################################################
if match_list and len(match_list[0]) == 3:
add_hostmask(self, nick)
return
else:
task = self.bot.who(nick)
task.add_done_callback(functools.partial(handle_who, self))
return
###################################################################################
###################################################################################
cmd = args.get("<cmd>")
###################################################################################
###################################################################################
if not cmd:
self.bot.privmsg(target, "please specify add/del/list")
elif cmd in ["d","del","delete","remove"]:
__staff_del(self, mask, target, args)
elif cmd in ["l", "list"]:
__staff_list(self, mask, target, args)
elif cmd in ["w", "write","a", "add"]:
__staff_add(self, mask, target, args)
###################################################################################
###################################################################################

112
plugins/crypto_plugin.py Normal file
View File

@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import aiohttp
import asyncio
import async_timeout
headers = { 'authorization': 'Apikey 94e50805f19646893ee16424918998caad5ec6accff539a23ffee8e546eda4e3' }
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@command(permission='view')
def cc(self, mask, target, args):
"""Show Crypto Value
%%cc <coin>
"""
###################################################################################
###################################################################################
coin = args['<coin>'].upper()
async def fetch(session, url):
async with async_timeout.timeout(10):
async with session.get(url) as response:
return await response.json()
###################################################################################
###################################################################################
async def grab_url(url):
async with aiohttp.ClientSession(headers=headers) as session:
json_response = await fetch(session, url)
return json_response
###################################################################################
###################################################################################
def parse_coin(response):
try:
task_result, _ = response.result()
task1, task2, task3 = task_result
rlist = sorted([task1.result(), task2.result(), task3.result()], key=lambda item: len(item.keys()))
if rlist[1].get("USD"):
price = rlist[1].get("USD")
price_multi = rlist[2].get("DISPLAY")[coin].get("USD", {})
daily_avg = rlist[0].get("USD")
elif rlist[2].get("USD"):
price_multi = rlist[1].get("DISPLAY")[coin].get("USD", {})
price = rlist[2].get("USD")
daily_avg = rlist[0].get("USD")
data_dict = {}
for k, v in price_multi.items():
if isinstance(v, str):
v = v.replace("$","").replace(" ","").replace(",","")
data_dict[k] = v
price_multi = data_dict
X = float(daily_avg) # AVERAGE OF THE DAY
P = float(price_multi.get('PRICE')) # PRICE CURRENTLY
H = float(price_multi.get('HIGHDAY')) # HIGH OF THE DAY
L = float(price_multi.get('LOWDAY')) # LOW OF THE DAY
A = float(price) # AGGREGATED EXCHANGE
Y = float(price_multi.get('CHANGE24HOUR')) # PRICE PERCENT DIFFERENTIAL 24 HOURS AGO
C = float(price_multi.get('CHANGEPCT24HOUR'))
if C <= 0:
C = "\x0304{}\x0F".format(C)
else:
C = "\x0303{}\x0F".format(C)
if Y <= 0:
Y = "\x0304{}\x0F".format(Y)
else:
Y = "\x0303{}\x0F".format(Y)
symbol = price_multi.get('FROMSYMBOL')
msg = "\x02\x0302[ {coin:}/{symbol:} ]\x0F @\x0303${p:,}\x0F ::: H\x0303${h:,}\x0F L\x0303${l:,}\x0F ::: Y${y:} @ %{c:} ::: X\x0303${x:,}\x0F A\x0303${a:,}\x0F".format(coin=coin, symbol=symbol, p=P, h=H, l=L, y=Y,c=C, x=X, a=A)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
except Exception as e:
msg = self.bot.emo('their api is glitching: check back later')
self.bot.privmsg(target, msg)
###################################################################################
###################################################################################
def process_lookups(response):
try:
html = response.result()
except Exception as e:
msg = self.bot.emo('site error: {}'.format(e.message))
self.bot.privmsg(target, msg)
return
coin_result = html.get("Data",{}).get(coin, None)
if not coin_result:
msg = self.bot.emo('Invalid coin - see https://min-api.cryptocompare.com/data/all/coinlist data keys')
self.bot.privmsg(target, msg)
return
day_avg_url = "https://min-api.cryptocompare.com/data/dayAvg?fsym={}&tsym=USD&api_key=94e50805f19646893ee16424918998caad5ec6accff539a23ffee8e546eda4e3".format(coin)
price_multi_url = "https://min-api.cryptocompare.com/data/pricemultifull?fsyms={}&tsyms=USD&api_key=94e50805f19646893ee16424918998caad5ec6accff539a23ffee8e546eda4e3".format(coin)
price_url = "https://min-api.cryptocompare.com/data/price?fsym={}&tsyms=USD&api_key=94e50805f19646893ee16424918998caad5ec6accff539a23ffee8e546eda4e3".format(coin)
tasks = [asyncio.ensure_future(grab_url(day_avg_url)),
asyncio.ensure_future(grab_url(price_multi_url)),
asyncio.ensure_future(grab_url(price_url))]
task = self.bot.create_task(asyncio.wait(tasks))
task.add_done_callback(parse_coin)
###################################################################################
###################################################################################
url = "https://min-api.cryptocompare.com/data/all/coinlist"
asyncio.ensure_future(grab_url(url), loop=self.bot.loop).add_done_callback(process_lookups)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

41
plugins/emote_plugin.py Normal file
View File

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import random
import os
dir_path = os.path.dirname(os.path.realpath(__file__))
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@irc3.extend
def emo(self,s):
emote_db = '%s/../databases/emote.db' % dir_path
emoj = random.choice(list(open(emote_db)))
random.randint(0,1)
if random.randint(0,1) == 0:
emoj = "\x0304{}\x0F".format(emoj)
else:
emoj = "\x0303{}\x0F".format(emoj)
s = s + '\x0303 ▶ ' + emoj
return s
#######################################################################################
#######################################################################################
@command(permission='view')
def emote(self, mask, target, args):
"""Show Emotion
%%emote
"""
def __random_line():
emote_db = '%s/../databases/emote.db' % dir_path
return random.choice(list(open(emote_db)))
emoj = __random_line()
self.bot.privmsg(target, "%s" % emoj)
###########################################################################################
###########################################################################################

52
plugins/figlet_plugin.py Normal file
View File

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import pyfiglet
import random
fig = pyfiglet.Figlet(width=100)
@irc3.plugin
class Plugin:
def __init__(self, bot):
self.bot = bot
self.fig_fonts = set(self.bot.db.getlist("fig_font_list", []))
if not self.fig_fonts:
self.fig_fonts = fig.getFonts()
self.bot.db.setlist("fig_font_list", self.fig_fonts)
@irc3.extend
def fig(self, text, font=None):
if font in self.fig_fonts:
fig.setFont(font=font)
else:
font = random.choice(list(self.fig_fonts))
return fig.renderText(text)
@command(permission='view', name="fig", public=True, show_in_help_list=True)
def figcmd(self, mask, target, args):
"""Print figlet Text
%%fig <cmdmsg>...
"""
cmdmsg = ' '.join(args['<cmdmsg>'])
cmd = ' '.join(cmdmsg.split()[:1])
msg = ' '.join(cmdmsg.split()[1:])
font = cmd
text = msg
if font == "list":
font_list = self.bot.db.getlist("fig_font_list")
self.bot.privmsg(target, "Current Fig Fonts {}".format(",".join(font_list)))
return
if font == "ignore":
ignored_font = args.get("<text>")
self.fig_fonts.remove(ignored_font)
self.bot.db.setlist("fig_font_list", self.fig_fonts)
self.bot.privmsg(target, "Ignoring {}".format(ignored_font))
return
if text is not None and font in self.fig_fonts:
msg = self.bot.emo(font)
self.bot.privmsg(target, msg)
fig_text = self.fig(text=text, font=font)
else:
newfont = random.choice(list(self.fig_fonts))
msg = self.bot.emo(newfont)
self.bot.privmsg(target, msg)
fig_text = self.fig(text=font, font=newfont) # Cause weird command format
for line in fig_text.split("\n"):
self.bot.privmsg(target, line)

85
plugins/isup_plugin.py Normal file
View File

@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
def isup_check(self, domain_or_ip):
msg=''
try:
url=f'http://{domain_or_ip}'
try:
req = Request(
url,
data=None,
headers={
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
}
)
response=urlopen(req,timeout=10).read().decode('utf-8')
except HTTPError as e:
msg='maybe -> could not complete the request. error code: {}'.format(e.code)
except URLError as e:
msg='down -> failed to reach the server. reason: {}'.format(e.reason)
else:
msg=f'up -> http://{domain_or_ip} is communicating'
except:
url=f'https://{domain_or_ip}'
try:
req = Request(
url,
data=None,
headers={
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
}
)
response=urlopen(req,timeout=10).read().decode('utf-8')
except HTTPError as e:
msg='maybe -> could not complete the request. error code: {}'.format(e.code)
except URLError as e:
msg='down -> failed to reach the server. reason: {}'.format(e.reason)
else:
msg=f'up -> https://{domain_or_ip} is communicating'
finally:
return msg
#######################################################################################
#######################################################################################
@command(permission='view')
def isup(self, mask, target, args):
"""isup domain
%%isup <domain>
"""
domain=args.get('<domain>')
domain_noise=domain
try:
domain_noise=domain.split('://')[1]
except:
pass
try:
if not domain_noise:
domain_noise=domain[:domain.find('.')+domain[domain.find('.')+1:].find('/')+1].split('://')[1]
except:
if not domain_noise.find('/')==-1:
domain_noise=domain[:domain.find('.')+domain[domain.find('.')+1:].find('/')+1].split('://')[0]
if domain_noise[-1]=="/": domain_noise=domain_noise[:-1]
if domain_noise[:domain_noise.find(':')].replace('.','').isnumeric() and (len(domain_noise[:domain_noise.find(':')])-3)==len(domain_noise[:domain_noise.find(':')].replace('.','')):
domain=domain_noise
elif domain_noise.replace('.','').isnumeric() and (len(domain_noise)-3) == len(domain_noise.replace('.','')):
domain=domain_noise
elif domain_noise.find('/') == -1 and not domain_noise.find('.') == -1 and domain_noise.replace('.','').isalnum():
domain=domain_noise
else:
self.bot.privmsg(target,self.bot.emo("{}: doesn't sanitize towards a valid domain/ip".format(domain)))
return
self.bot.privmsg(target,self.bot.emo("{}".format(self.isup_check(domain))))
###########################################################################################
###########################################################################################

43
plugins/joke_plugin.py Normal file
View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
###############################################################################################
###############################################################################################
from irc3.plugins.command import command
import irc3
###############################################################################################
###############################################################################################
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
###############################################################################################
###############################################################################################
@irc3.plugin
class Plugin:
###########################################################################################
###########################################################################################
def __init__(self, bot):
self.bot=bot
self.site_url="https://icanhazdadjoke.com"
###########################################################################################
###########################################################################################
def urlget(self,url):
USER_AGENT_CURL="curl/7.78.0"
ACCEPT_MODES="text/plain"
STATUS_BAD_CODE=":( - error code: {}"
STATUS_BAD_REASON=":( - failed reason: {}"
STATUS_OK=":)"
r = Request(url,data=None,headers={ 'user-agent': USER_AGENT_CURL, 'accept': ACCEPT_MODES })
try: response = urlopen(r,timeout=15).read().decode('utf-8')
except HTTPError as e: return STATUS_BAD_CODE.format(e.code)
except URLError as e: return STATUS_BAD_REASON.format(e.reason)
else: return STATUS_OK + response
###########################################################################################
###########################################################################################
@irc3.extend
@command(permission='view')
def joke(self, mask, target, args):
"""joke
%%joke
"""
response=self.urlget(self.site_url)[2:]
for msg in response.splitlines():
if len(msg) > 1:
self.bot.privmsg(target, self.bot.emo(msg))

357
plugins/maple_plugin.py Normal file
View File

@ -0,0 +1,357 @@
# -*- coding: utf-8 -*-
import os
import io
import irc3
import requests
from tqdm import tqdm
from glob import glob
import torch
import torch.nn.functional as F
import numpy as np
import logging
import signal
import configparser
import logging
import random
from transformers import GPT2Config,GPT2LMHeadModel,GPT2Tokenizer
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
#import ipdb
###########################################################################################################
###########################################################################################################
@irc3.plugin
class Plugin:
#######################################################################################################
#######################################################################################################
PoolExecutor=ThreadPoolExecutor
#######################################################################################################
#######################################################################################################
terminate=False
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger=logging.getLogger(__name__)
#######################################################################################
#######################################################################################
CONFIG_FILE={
'small':'https://convaisharables.blob.core.windows.net/lsp/117M/config.json',
'medium':'https://convaisharables.blob.core.windows.net/lsp/345M/config.json'
}
VOCAB_FILE={
'small':'https://convaisharables.blob.core.windows.net/lsp/117M/vocab.json',
'medium':'https://convaisharables.blob.core.windows.net/lsp/345M/vocab.json'
}
MERGE_FILE={
'small':'https://convaisharables.blob.core.windows.net/lsp/117M/merges.txt',
'medium':'https://convaisharables.blob.core.windows.net/lsp/345M/merges.txt'
}
LSP_MODEL_URL={
'multiref':{
'medium_fs':'https://convaisharables.blob.core.windows.net/lsp/multiref/medium_fs.pkl',
'medium_ft':'https://convaisharables.blob.core.windows.net/lsp/multiref/medium_ft.pkl',
'small_fs':'https://convaisharables.blob.core.windows.net/lsp/multiref/small_fs.pkl',
'small_ft':'https://convaisharables.blob.core.windows.net/lsp/multiref/small_ft.pkl'
},
'dstc':{
'small_ft':'https://convaisharables.blob.core.windows.net/lsp/DSTC/medium_ft.pkl'
}
}
#######################################################################################
#######################################################################################
REVERSE_MODEL_URL='https://convaisharables.blob.core.windows.net/lsp/multiref/small_reverse.pkl'
#######################################################################################
#######################################################################################
PERSONALITY="""
[model]
data_folder=models
model_size=medium
dataset=multiref
from_scratch=False
no_cuda=False
use_mmi=False
[decoder]
seed=0
temperature=0.6474
top_k=40
top_p=0
max_length=128
num_samples=1
max_turns_history=1
[personality]
telegram_token=YOUR_TOKEN_HERE
giphy_token=YOUR_TOKEN_HERE
giphy_weirdness=5
"""
#######################################################################################
#######################################################################################
def __init__(self,bot):
self.maple_message=''
self.PERSONALITY=self.PERSONALITY.format(RND=datetime.now().microsecond)
self.bot=bot
self.delay=0.025
self.cycle=0
CONFIG=io.StringIO(self.PERSONALITY)
self.config=configparser.ConfigParser()
self.config.read_file(CONFIG)
self.target_folder_name=self.download_model_folder(self.config)
self.model,self.tokenizer=self.load_model(self.target_folder_name,self.config)
self.use_mmi=self.config.getboolean('model','use_mmi')
if self.use_mmi:
self.mmi_target_folder_name=self.download_reverse_model_folder(self.config)
self.mmi_model,mmi_tokenizer=self.load_model(self.mmi_target_folder_name,self.config)
else:
self.mmi_model=None
self.mmi_tokenizer=None
loop=self.bot.loop
loop.call_later(self.delay,self.main)
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_for_maple(self, mask=None, target=None, data=None, **kw):
##############################################
if mask.nick == 'maple':
data=data.lower().replace('maple','').strip()
# ##############################################
# if not data.lower().find('maple') > -1:
# return
#data=data.lower().replace('maple','').strip()
##############################################
self.maple_message=data
#######################################################################################
#######################################################################################
def signal_handling(self,signum,frame):
self.terminate=True
#######################################################################################
#######################################################################################
def http_get(self,url,temp_file):
req=requests.get(url,stream=True)
content_length=req.headers.get('Content-Length')
total=int(content_length) if content_length is not None else None
progress=tqdm(unit="B",total=total)
for chunk in req.iter_content(chunk_size=1024):
if chunk:
progress.update(len(chunk))
temp_file.write(chunk)
progress.close()
#######################################################################################
#######################################################################################
def download_file(self,url,folder):
if not os.path.exists(folder):
os.makedirs(folder,exist_ok=True)
file_name=os.path.basename(url)
if 'pytorch_model.bin' in file_name:
file_name='pytorch_model.bin'
if os.path.isfile(os.path.join(folder,file_name)):
return
with open(os.path.join(folder,file_name),'wb') as f:
self.http_get(url,f)
#######################################################################################
#######################################################################################
def download_model_folder(self,config):
data_folder=config.get('model','data_folder')
model_size=config.get('model','model_size')
dataset=config.get('model','dataset')
from_scratch=config.getboolean('model','from_scratch')
if not os.path.exists(data_folder):
os.makedirs(data_folder, exist_ok=True)
target_folder_name=model_size+"_"+dataset+("_fs" if from_scratch else "_ft")
target_folder=os.path.join(data_folder,target_folder_name)
self.logger.info(f"Downloading model files to {target_folder_name}...")
self.download_file(self.CONFIG_FILE[model_size],target_folder)
self.download_file(self.VOCAB_FILE[model_size],target_folder)
self.download_file(self.MERGE_FILE[model_size],target_folder)
model_train_type=model_size+('_fs' if from_scratch else '_ft')
if model_train_type not in self.LSP_MODEL_URL[dataset]:
k=','.join(list(self.LSP_MODEL_URL[dataset].keys()))
raise ValueError(f"'{model_train_type}' not exist for dataset '{dataset}', please choose from [{k}]")
self.download_file(self.LSP_MODEL_URL[dataset][model_train_type],target_folder)
return target_folder_name
#######################################################################################
#######################################################################################
def download_reverse_model_folder(self,config):
data_folder=config.get('model','data_folder')
model_size='medium'
if not os.path.exists(data_folder):
os.makedirs(data_folder,exist_ok=True)
target_folder_name=model_size+'_reverse'
target_folder=os.path.join(data_folder,target_folder_name)
self.logger.info(f"Downloading model files to {target_folder_name}...")
self.download_file(self.CONFIG_FILE[model_size],target_folder)
self.download_file(self.VOCAB_FILE[model_size],target_folder)
self.download_file(self.MERGE_FILE[model_size],target_folder)
self.download_file(self.REVERSE_MODEL_URL,target_folder)
return target_folder_name
#######################################################################################
#######################################################################################
def load_model(self,target_folder_name,config):
data_folder=config.get('model','data_folder')
model_size=config.get('model','model_size')
no_cuda=config.getboolean('model', 'no_cuda')
self.logger.info(f"Loading model from {target_folder_name}...")
device=torch.device("cuda" if torch.cuda.is_available() and not no_cuda else "cpu")
target_folder=os.path.join(data_folder,target_folder_name)
tokenizer=GPT2Tokenizer(os.path.join(target_folder, 'vocab.json'), os.path.join(target_folder, 'merges.txt'))
config=GPT2Config.from_json_file(os.path.join(target_folder, 'config.json'))
state_dict_path=glob(os.path.join(target_folder,f'*.pkl'))[0]
state_dict=torch.load(state_dict_path,map_location=device)
if model_size=='small':
for key in list(state_dict.keys()):
state_dict[key.replace('module.','')]=state_dict.pop(key)
state_dict['lm_head.weight']=state_dict['lm_head.decoder.weight']
state_dict.pop("lm_head.decoder.weight",None)
model=GPT2LMHeadModel(config)
model.load_state_dict(state_dict)
model.to(device)
model.eval()
return model,tokenizer
#######################################################################################
#######################################################################################
def set_seed(self,seed):
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
#######################################################################################
#######################################################################################
def top_k_top_p_filtering(self,logits,top_k=0,top_p=0.0,filter_value=-float('Inf')):
top_k=min(top_k,logits.size(-1))
if top_k>0:
indices_to_remove=logits<torch.topk(logits,top_k)[0][...,-1,None]
logits[indices_to_remove]=filter_value
if top_p>0.0:
sorted_logits,sorted_indices=torch.sort(logits,descending=True)
cumulative_probs=torch.cumsum(F.softmax(sorted_logits,dim=-1),dim=-1)
sorted_indices_to_remove=cumulative_probs>top_p
sorted_indices_to_remove[...,1:]=sorted_indices_to_remove[...,:-1].clone()
sorted_indices_to_remove[...,0]=0
indices_to_remove=sorted_indices_to_remove.scatter(dim=1,index=sorted_indices,src=sorted_indices_to_remove)
logits[indices_to_remove]=filter_value
return logits
#######################################################################################
#######################################################################################
def sample_sequence(self,model,tokenizer,context_ids,config):
no_cuda=config.getboolean('model','no_cuda')
num_samples=config.getint('decoder','num_samples')
max_length=config.getint('decoder','max_length')
temperature=config.getfloat('decoder','temperature')
top_k=config.getint('decoder','top_k')
top_p=config.getfloat('decoder','top_p')
device=torch.device("cuda" if torch.cuda.is_available() and not no_cuda else "cpu")
context_tensor=torch.tensor(context_ids,dtype=torch.long,device=device)
context_tensor=context_tensor.unsqueeze(0).repeat(num_samples,1)
generated=context_tensor
with torch.no_grad():
while True:
inputs={'input_ids':generated}
outputs=model(**inputs)
next_token_logits=outputs[0][:,-1,:]/(temperature if temperature>0 else 1.)
filtered_logits=self.top_k_top_p_filtering(next_token_logits,top_k=top_k,top_p=top_p)
if temperature==0.0:
next_token=torch.argmax(filtered_logits,dim=-1).unsqueeze(-1)
else:
next_token=torch.multinomial(F.softmax(filtered_logits,dim=-1),num_samples=1)
generated=torch.cat((generated,next_token),dim=1)
if (generated[:,len(context_ids):]==tokenizer.eos_token_id).any(dim=1).all():
break
if generated.shape[1]-len(context_ids)>=max_length:
break
return generated
#######################################################################################
#######################################################################################
def select_using_mmi(self,mmi_model,mmi_tokenizer,candidates,config):
no_cuda=config.getboolean('model','no_cuda')
device=torch.device("cuda" if torch.cuda.is_available() and not no_cuda else "cpu")
scores=[]
for i,candidate in enumerate(candidates):
context=[]
for response in reversed(candidate):
context.extend(response)
context.append(mmi_tokenizer.eos_token_id)
context_ids=mmi_tokenizer.encode(context)
context_tensor=torch.tensor(context_ids,dtype=torch.long,device=device)
loss,_,_=mmi_model(input_ids=context_tensor,labels=context_tensor)
scores.append(-loss.float())
scores=torch.stack(scores, dim=0)
winner=torch.multinomial(F.softmax(scores,dim=0),num_samples=1).item()
return winner
#######################################################################################
#######################################################################################
def generate_response(self,model,tokenizer,context,config,mmi_model=None,mmi_tokenizer=None):
use_mmi=config.getboolean('model','use_mmi')
num_samples=config.getint('decoder','num_samples')
max_length=config.getint('decoder','max_length')
seed=config.get('decoder','seed')
seed=int(seed) if seed is not None else None
if seed is not None:
self.set_seed(seed)
context_ids=tokenizer.encode(context)
samples=self.sample_sequence(model, tokenizer, context_ids, config)
samples=samples[:, len(context_ids):].tolist()
texts=[]
for sample in samples:
text=tokenizer.decode(sample,clean_up_tokenization_spaces=True)
text=text[: text.find(tokenizer.eos_token)]
texts.append(text)
if use_mmi:
assert(num_samples > 1)
candidates=[context+text for text in texts]
best_i=self.select_using_mmi(mmi_model,mmi_tokenizer,candidates,config)
return [texts[best_i]]
return texts
#######################################################################################
#######################################################################################
def run_chat(self,model,tokenizer,config,mmi_model=None,mmi_tokenizer=None):
num_samples=config.getint('decoder','num_samples')
max_turns_history=config.getint('decoder','max_turns_history')
turns=[]
signal.signal(signal.SIGINT,self.signal_handling)
# print("*** RUNNING ***")
# while True:
# if self.terminate:
# break
config.set('decoder','seed',f'{datetime.now().microsecond}')
s=self.maple_message
if len(s)>1:
prompt=s.strip();del(s)
del(self.maple_message)
print(f'human > {prompt}')
if max_turns_history==0:
turns=[]
turn={
'human_messages':[],
'maple_messages':[]
}
turns.append(turn)
turn['human_messages'].append(prompt)
history=""
from_index=max(len(turns)-max_turns_history-1,0) if max_turns_history>=0 else 0
for turn in turns[from_index:]:
for message in turn['human_messages']:
history+=message+tokenizer.eos_token
for message in turn['maple_messages']:
history+=message+tokenizer.eos_token
maple_messages=self.generate_response(
model,
tokenizer,
history,
config,
mmi_model=mmi_model,
mmi_tokenizer=mmi_tokenizer
)
if num_samples==1:
maple_message=maple_messages[0]
else:
maple_message=random.choice(maple_messages)
turn['maple_messages'].append(maple_message)
print(f'maple > {maple_message}')
print(maple_message)
self.bot.privmsg('#staff',self.bot.emo(maple_message))
print('cya')
#######################################################################################
#######################################################################################
def main(self):
loop=self.bot.loop
loop.call_later(self.delay,self.main)
tasks=[]
task=loop.run_in_executor(None,self.run_chat(self.model,self.tokenizer,self.config,mmi_model=self.mmi_model,mmi_tokenizer=self.mmi_tokenizer))
tasks.append(task)
print('l8r')
###########################################################################################################
###########################################################################################################

145
plugins/model.py Normal file
View File

@ -0,0 +1,145 @@
import os
import requests
from tqdm import tqdm
from glob import glob
import torch
import configparser
import argparse
import logging
###########################################################################################
###########################################################################################
from transformers import GPT2Config, GPT2LMHeadModel, GPT2Tokenizer
###########################################################################################
###########################################################################################
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)
###########################################################################################
###########################################################################################
CONFIG_FILE = {
'small': 'https://convaisharables.blob.core.windows.net/lsp/117M/config.json',
'medium': 'https://convaisharables.blob.core.windows.net/lsp/345M/config.json'
}
VOCAB_FILE = {
'small': 'https://convaisharables.blob.core.windows.net/lsp/117M/vocab.json',
'medium': 'https://convaisharables.blob.core.windows.net/lsp/345M/vocab.json'
}
MERGE_FILE = {
'small': 'https://convaisharables.blob.core.windows.net/lsp/117M/merges.txt',
'medium': 'https://convaisharables.blob.core.windows.net/lsp/345M/merges.txt'
}
LSP_MODEL_URL = {
'multiref': {
'medium_fs': 'https://convaisharables.blob.core.windows.net/lsp/multiref/medium_fs.pkl',
'medium_ft': 'https://convaisharables.blob.core.windows.net/lsp/multiref/medium_ft.pkl',
'small_fs': 'https://convaisharables.blob.core.windows.net/lsp/multiref/small_fs.pkl',
'small_ft': 'https://convaisharables.blob.core.windows.net/lsp/multiref/small_ft.pkl'
},
'dstc': {
'small_ft': 'https://convaisharables.blob.core.windows.net/lsp/DSTC/medium_ft.pkl'
}
}
###########################################################################################
###########################################################################################
REVERSE_MODEL_URL = 'https://convaisharables.blob.core.windows.net/lsp/multiref/small_reverse.pkl'
###########################################################################################
###########################################################################################
def http_get(url, temp_file):
req = requests.get(url, stream=True)
content_length = req.headers.get('Content-Length')
total = int(content_length) if content_length is not None else None
progress = tqdm(unit="B", total=total)
for chunk in req.iter_content(chunk_size=1024):
if chunk:
progress.update(len(chunk))
temp_file.write(chunk)
progress.close()
###########################################################################################
###########################################################################################
def download_file(url, folder):
if not os.path.exists(folder):
os.makedirs(folder, exist_ok=True)
file_name = os.path.basename(url)
if 'pytorch_model.bin' in file_name:
file_name = 'pytorch_model.bin'
if os.path.isfile(os.path.join(folder, file_name)):
return
with open(os.path.join(folder, file_name), 'wb') as f:
http_get(url, f)
###########################################################################################
###########################################################################################
def download_model_folder(config):
data_folder = config.get('model', 'data_folder')
model_size = config.get('model', 'model_size')
dataset = config.get('model', 'dataset')
from_scratch = config.getboolean('model', 'from_scratch')
if not os.path.exists(data_folder):
os.makedirs(data_folder, exist_ok=True)
target_folder_name = model_size + "_" + dataset + ("_fs" if from_scratch else "_ft")
target_folder = os.path.join(data_folder, target_folder_name)
logger.info(f"Downloading model files to {target_folder_name}...")
download_file(CONFIG_FILE[model_size], target_folder)
download_file(VOCAB_FILE[model_size], target_folder)
download_file(MERGE_FILE[model_size], target_folder)
model_train_type = model_size + ('_fs' if from_scratch else '_ft')
if model_train_type not in LSP_MODEL_URL[dataset]:
k = ','.join(list(LSP_MODEL_URL[dataset].keys()))
raise ValueError(f"'{model_train_type}' not exist for dataset '{dataset}', please choose from [{k}]")
download_file(LSP_MODEL_URL[dataset][model_train_type], target_folder)
return target_folder_name
###########################################################################################
###########################################################################################
def download_reverse_model_folder(config):
data_folder = config.get('model', 'data_folder')
model_size = 'medium'
if not os.path.exists(data_folder):
os.makedirs(data_folder, exist_ok=True)
target_folder_name = model_size + '_reverse'
target_folder = os.path.join(data_folder, target_folder_name)
logger.info(f"Downloading model files to {target_folder_name}...")
download_file(CONFIG_FILE[model_size], target_folder)
download_file(VOCAB_FILE[model_size], target_folder)
download_file(MERGE_FILE[model_size], target_folder)
download_file(REVERSE_MODEL_URL, target_folder)
return target_folder_name
###########################################################################################
###########################################################################################
def load_model(target_folder_name, config):
data_folder = config.get('model', 'data_folder')
model_size = config.get('model', 'model_size')
no_cuda = config.getboolean('model', 'no_cuda')
logger.info(f"Loading model from {target_folder_name}...")
device = torch.device("cuda" if torch.cuda.is_available() and not no_cuda else "cpu")
target_folder = os.path.join(data_folder, target_folder_name)
tokenizer = GPT2Tokenizer(os.path.join(target_folder, 'vocab.json'), os.path.join(target_folder, 'merges.txt'))
config = GPT2Config.from_json_file(os.path.join(target_folder, 'config.json'))
state_dict_path = glob(os.path.join(target_folder, f'*.pkl'))[0]
state_dict = torch.load(state_dict_path, map_location=device)
if model_size == 'small':
for key in list(state_dict.keys()):
state_dict[key.replace('module.', '')] = state_dict.pop(key)
state_dict['lm_head.weight'] = state_dict['lm_head.decoder.weight']
state_dict.pop("lm_head.decoder.weight", None)
model = GPT2LMHeadModel(config)
model.load_state_dict(state_dict)
model.to(device)
model.eval()
return model, tokenizer
###########################################################################################
###########################################################################################
def main():
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('--config', type=str, default="personality.cfg")
args = arg_parser.parse_args()
config = configparser.ConfigParser(allow_no_value=True)
with open(args.config) as f:
config.read_file(f)
download_model_folder(config)
use_mmi = config.getboolean('model', 'use_mmi')
if use_mmi:
download_reverse_model_folder(config)
###########################################################################################
###########################################################################################
if __name__ == '__main__':
main()
###########################################################################################
###########################################################################################

166
plugins/notes_plugin.py Normal file
View File

@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
from datetime import datetime
import dateutil.parser
import timeago
import uuid
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@command(permission='admin', public=True, show_in_help_list=True)
def notes(self, *args, **kwargs):
"""list/write/del notes
%%notes [<cmd>] [<operation>]
"""
return self.note(*args)
#######################################################################################
#######################################################################################
@command(permission='admin', public=True, show_in_help_list=True)
def note(self, mask, target, args):
"""list/write/del notes
%%note [<cmd>] [<operation>]
"""
cmd = args.get("<cmd>")
if not cmd:
msg = "Please specify read/write/delete/list"
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
elif cmd in ["d","del","delete","remove"]:
self.note_del(mask, target, args)
elif cmd in ["w", "write","a", "add"]:
self.note_write(mask, target, args)
elif cmd in ["l", "list"]:
self.note_list(mask, target, args)
elif cmd in ["r", "read"]:
self.note_read(mask, target, args)
return
#######################################################################################
#######################################################################################
@command(permission='admin', public=True, show_in_help_list=True)
def note_del(self, mask, target, args):
"""Delete Note or * for all notes
%%note <cmd> <operation>
"""
note_uuid_hash = args.get("<operation>")
if not note_uuid_hash:
msg = "Please specify note"
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
if note_uuid_hash == "*":
self.bot.db.setlist("notes", [])
msg = "All notes cleared!"
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
else:
note_list = self.bot.db.getlist("notes", [])
if not note_list:
msg = "{} Not Found".format(note_uuid_hash)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
else:
if note_uuid_hash in [item.get("uuid") for item in note_list]:
new_note_list = [item for item in note_list if item.get("uuid") != note_uuid_hash]
self.bot.db.setlist("notes", new_note_list)
msg = "{} Removed".format(note_uuid_hash)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
#######################################################################################
#######################################################################################
@command(permission='admin', public=True, show_in_help_list=True)
def note_list(self, mask, target, args):
"""List All Note Names
%%note list
"""
note_list = self.bot.db.getlist("notes")
if not note_list:
msg = "No notes!"
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
for note in note_list:
note_uuid = note.get("uuid")
note_from = note.get("from")
note_time = dateutil.parser.parse(note.get("time"))
note_time = timeago.format(note_time, datetime.now())
note_msg = note.get("note_msg")
msg = "<{}> {} | {} | {}".format(note_from, note_time, note_msg, note_uuid)
self.bot.privmsg(target, msg)
#######################################################################################
#######################################################################################
@command(permission='admin', public=True, show_in_help_list=True)
def note_read(self, mask, target, args):
"""Display Note
%%note read <operation>
"""
note_name = args.get("<operation>")
if not note_name:
msg = "Please specify name or note id"
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
note_list = self.bot.db.getlist("notes")
if not note_list:
msg = "No Notes in DB"
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
if not any(note_name in d["uuid"] for d in note_list):
msg = "No notes with {} found".format(note_name)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
else:
note = [d for d in note_list if d.get("uuid") == note_name]
if note:
note = note.pop()
else:
try:
note = note_list[int(note_name)]
except:
msg = "No notes with {} found".format(note_name)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
note_uuid = note.get("uuid")
note_from = note.get("from")
note_time = dateutil.parser.parse(note.get("time"))
note_time = timeago.format(note_time, datetime.now())
note_msg = note.get("note_msg")
msg = "<{}> {} | {} | {}".format(note_from, note_time, note_msg, note_uuid)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
#######################################################################################
#######################################################################################
@command(permission='admin', public=True, show_in_help_list=True)
def note_write(self, mask, target, args):
"""Add Note
%%note write <note>
"""
note_msg = args.get("<operation>")
note_list = self.bot.db.getlist("notes")
if not note_list:
note_list = []
self.bot.db.setlist("notes", note_list)
note_uuid = uuid.uuid4().hex
note = {"time": datetime.now().isoformat(),
"from": mask.nick, "uuid": note_uuid,
"note_msg": note_msg}
note_list.append(note)
self.bot.db.setlist("notes", note_list)
msg = "Note Added! {}".format(note_uuid)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
self.bot.history.push_user_messages(mask.nick.lower(),note)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

86
plugins/quote_plugin.py Normal file
View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import random
import uuid
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self,bot):
self.bot=bot
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.JOIN)
def quote_user_join(self, mask, channel, **kw):
"""quote a user when they join"""
quote_list=self.bot.db.getlist("quotes")
if not quote_list:
quote_list=[]
self.bot.db.setlist('quotes',[])
quote_user=[]
for i in range(len(quote_list)):
user=mask.nick.lower()
if mask.nick==self.bot.nick: user=self.bot.original_nick.lower()
if(quote_list[i]['user']==user):
quote_user.append(quote_list[i]['message'])
if quote_user:
msg=random.choice(quote_user)+' \x02\x0303▶\x0F '+user
msg=self.bot.emo(msg)
print(f'\n{msg}\n')
self.bot.privmsg(channel,msg)
#######################################################################################
#######################################################################################
@command(permission='view')
def quote(self,mask,target, args):
"""quote user message
%%quote <noise>...
"""
noise=' '.join(args['<noise>'])
user=noise.split(' ')[0]
noise=noise.split(' ')[1:]
message=' '.join(noise)
status=''
try:
quote_list=self.bot.db.getlist("quotes")
if not quote_list:
quote_list=[]
self.bot.db.setlist("quotes",quote_list)
quote_uuid=uuid.uuid4().hex
quote={"user":user.lower(),"message":message,"uuid":quote_uuid}
quote_list.append(quote)
self.bot.db.setlist("quotes",quote_list)
status=f"TCPDIRECT/QUOTED: {user} "
status+=f"\x02\x0303▶\x0F {message} "
status+=f"\x02\x0303▶\x0F {quote_uuid}"
except Exception as e:
status=f"\x02\x0304error \x02\x0303▶\x0F {e.message[0]['message']}'"
msg=self.bot.emo(status)
self.bot.privmsg(target,msg)
self.bot.history.push_user_messages(mask.nick.lower(),message)
#######################################################################################
#######################################################################################
@command(permission='view')
def quotes(self, mask, target, args):
"""quotes user
%%quotes <nick>
"""
user=args.get("<nick>")
quote_list=self.bot.db.getlist("quotes")
if not quote_list:
quote_list=[]
self.bot.db.setlist('quotes',[])
quote_user=[]
for i in range(len(quote_list)):
if(quote_list[i]['user']==user):
quote_user.append(quote_list[i]['message'])
for i in range(len(quote_user)):
msg=user+' \x02\x0303▶\x0F '+quote_user[i]
msg=self.bot.emo(msg)
self.bot.privmsg(target,msg)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

355
plugins/ratesex_plugin.py Normal file
View File

@ -0,0 +1,355 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
from irc3.plugins.cron import cron
import irc3
__doc__ = '''##########################################################################################################
####################################################################################################################'''
import os
import sys
import re
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
from random import randint
__doc__ = '''##########################################################################################################
#######################################################################################################################
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh+MMMMMMMMMMMMMMhsMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMm/ oMMMMMMMMMMMMMMm +NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMy` yMMMMMMMMMMMMMMM- -mMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMs+dMMMMMMMMMM+ sMMMMMMMMMMMMMMM- `dMMMMMMMMMMms/NMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMM+ .omMMMMMM: -MMMMMMMMMMMMMMo `yMMMMMMMy: `dMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMM- /dMMM+ sMMMMMMMMMMMMh `hMMMNo` sMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMd :dm `mMMMMMMMMMMN. .NNo` .MMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMM: - :MMMMMMMMMMs :` sMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMs ymNMMMMMNm. NMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMy `-/-` .MMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMo .NMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMNh+. :sdMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMhso+:. `-/+syMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM- dMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMM` `.:+/. `/s+:. sMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMNo -oms. .//-` `:/:` `+md+` .hMMMMMMMMMMMMMMM
MMMMMMMMMMMMMNs` .odNdo. .ohmd+` :dMMMMMMMMMMMMM
MMMMMMMMMMMNo` .. .- :hMMMMMMMMMMM
MMMMMMMMMd+` -sNMMMMMMMM
MMMMMMNs- `.. `/-. `+dMMMMMM
MMMNy: ./sdNMMMh: `sNMMMNds/. .odMMM
MM+ :ymMMMMMMMMMMh. +NMMMMMMMMMMmo- /NM
MMMh: .sNMMMMMMMMMMMMMMN- `hMMMMMMMMMMMMMMMm+` :hMMM
MMMMMd:` ``-:+shmMMMMMMMMMMMMMMMMMMN. hMMMMMMMMMMMMMMMMMMMmhs+/-..``````./dMMMMM
MMMMMMMMMNNNNNNMMMMMMMMMMMMMMMMMMMMMMMMMMMo .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMy .MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN. /MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN+` `+NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNs. -hMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMdyymMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
#######################################################################################################################
####################################################################################################################'''
rgb2irc = { 52: '16', 94: '17', 100: '18', 58: '19', 22: '20', 29: '21', 23: '22', 24: '23', 17: '24', 54: '25', 53: '26', 89: '27',
88: '28', 130: '29', 142: '30', 64: '31', 28: '32', 35: '33', 30: '34', 25: '35', 18: '36', 91: '37', 90: '38', 125: '39',
124: '40', 166: '41', 184: '42', 106: '43', 34: '44', 49: '45', 37: '46', 33: '47', 19: '48', 129: '49', 127: '50', 161: '51',
196: '52', 208: '53', 226: '54', 154: '55', 46: '56', 86: '57', 51: '58', 75: '59', 21: '60', 171: '61', 201: '62', 198: '63',
203: '64', 215: '65', 227: '66', 191: '67', 83: '68', 122: '69', 87: '70', 111: '71', 63: '72', 177: '73', 207: '74', 205: '75',
217: '76', 223: '77', 229: '78', 193: '79', 157: '80', 158: '81', 159: '82', 153: '83', 147: '84', 183: '85', 219: '86', 212: '87',
16: '88', 233: '89', 235: '90', 237: '91', 239: '92', 241: '93', 244: '94', 247: '95', 250: '96', 254: '97', 231: '98', }
__doc__ = '''##########################################################################################################
####################################################################################################################'''
rgb2set = { "ef0": "#000000", "ef1": "#CD0000", "ef2": "#00CD00", "ef3": "#CDCD00", "ef4": "#0000EE", "ef5": "#CD00CD", "ef6": "#00CDCD", "ef7": "#E5E5E5",
"ef8": "#7F7F7F", "ef9": "#FF0000", "ef10": "#00FF00", "ef11": "#FFFF00", "ef12": "#5C5CFF", "ef13": "#FF00FF", "ef14": "#00FFFF", "ef15": "#FFFFFF",
"eb8": "#7F7F7F", "eb9": "#FF0000", "eb10": "#00FF00", "eb11": "#FFFF00", "eb12": "#5C5CFF", "eb13": "#FF00FF", "eb14": "#00FFFF", "eb15": "#FFFFFF", "ef16": "#000000",
"ef17": "#00005f", "ef18": "#000087", "ef19": "#0000af", "ef20": "#0000d7", "ef21": "#0000ff", "ef22": "#005f00", "ef23": "#005f5f", "ef24": "#005f87", "ef25": "#005faf",
"ef26": "#005fd7", "ef27": "#005fff", "ef28": "#008700", "ef29": "#00875f", "ef30": "#008787", "ef31": "#0087af", "ef32": "#0087d7", "ef33": "#0087ff", "ef34": "#00af00",
"ef35": "#00af5f", "ef36": "#00af87", "ef37": "#00afaf", "ef38": "#00afd7", "ef39": "#00afff", "ef40": "#00d700", "ef41": "#00d75f", "ef42": "#00d787", "ef43": "#00d7af",
"ef44": "#00d7d7", "ef45": "#00d7ff", "ef46": "#00ff00", "ef47": "#00ff5f", "ef48": "#00ff87", "ef49": "#00ffaf", "ef50": "#00ffd7", "ef51": "#00ffff", "ef52": "#5f0000",
"ef53": "#5f005f", "ef54": "#5f0087", "ef55": "#5f00af", "ef56": "#5f00d7", "ef57": "#5f00ff", "ef58": "#5f5f00", "ef59": "#5f5f5f", "ef60": "#5f5f87", "ef61": "#5f5faf",
"ef62": "#5f5fd7", "ef63": "#5f5fff", "ef64": "#5f8700", "ef65": "#5f875f", "ef66": "#5f8787", "ef67": "#5f87af", "ef68": "#5f87d7", "ef69": "#5f87ff", "ef70": "#5faf00",
"ef71": "#5faf5f", "ef72": "#5faf87", "ef73": "#5fafaf", "ef74": "#5fafd7", "ef75": "#5fafff", "ef76": "#5fd700", "ef77": "#5fd75f", "ef78": "#5fd787", "ef79": "#5fd7af",
"ef80": "#5fd7d7", "ef81": "#5fd7ff", "ef82": "#5fff00", "ef83": "#5fff5f", "ef84": "#5fff87", "ef85": "#5fffaf", "ef86": "#5fffd7", "ef87": "#5fffff", "ef88": "#870000",
"ef89": "#87005f", "ef90": "#870087", "ef91": "#8700af", "ef92": "#8700d7", "ef93": "#8700ff", "ef94": "#875f00", "ef95": "#875f5f", "ef96": "#875f87", "ef97": "#875faf",
"ef98": "#875fd7", "ef99": "#875fff", "ef100": "#878700", "ef101": "#87875f", "ef102": "#878787", "ef103": "#8787af", "ef104": "#8787d7", "ef105": "#8787ff", "ef106": "#87af00",
"ef107": "#87af5f", "ef108": "#87af87", "ef109": "#87afaf", "ef110": "#87afd7", "ef111": "#87afff", "ef112": "#87d700", "ef113": "#87d75f", "ef114": "#87d787", "ef115": "#87d7af",
"ef116": "#87d7d7", "ef117": "#87d7ff", "ef118": "#87ff00", "ef119": "#87ff5f", "ef120": "#87ff87", "ef121": "#87ffaf", "ef122": "#87ffd7", "ef123": "#87ffff", "ef124": "#af0000",
"ef125": "#af005f", "ef126": "#af0087", "ef127": "#af00af", "ef128": "#af00d7", "ef129": "#af00ff", "ef130": "#af5f00", "ef131": "#af5f5f", "ef132": "#af5f87", "ef133": "#af5faf",
"ef134": "#af5fd7", "ef135": "#af5fff", "ef136": "#af8700", "ef137": "#af875f", "ef138": "#af8787", "ef139": "#af87af", "ef140": "#af87d7", "ef141": "#af87ff", "ef142": "#afaf00",
"ef143": "#afaf5f", "ef144": "#afaf87", "ef145": "#afafaf", "ef146": "#afafd7", "ef147": "#afafff", "ef148": "#afd700", "ef149": "#afd75f", "ef150": "#afd787", "ef151": "#afd7af",
"ef152": "#afd7d7", "ef153": "#afd7ff", "ef154": "#afff00", "ef155": "#afff5f", "ef156": "#afff87", "ef157": "#afffaf", "ef158": "#afffd7", "ef159": "#afffff", "ef160": "#d70000",
"ef161": "#d7005f", "ef162": "#d70087", "ef163": "#d700af", "ef164": "#d700d7", "ef165": "#d700ff", "ef166": "#d75f00", "ef167": "#d75f5f", "ef168": "#d75f87", "ef169": "#d75faf",
"ef170": "#d75fd7", "ef171": "#d75fff", "ef172": "#d78700", "ef173": "#d7875f", "ef174": "#d78787", "ef175": "#d787af", "ef176": "#d787d7", "ef177": "#d787ff", "ef178": "#d7af00",
"ef179": "#d7af5f", "ef180": "#d7af87", "ef181": "#d7afaf", "ef182": "#d7afd7", "ef183": "#d7afff", "ef184": "#d7d700", "ef185": "#d7d75f", "ef186": "#d7d787", "ef187": "#d7d7af",
"ef188": "#d7d7d7", "ef189": "#d7d7ff", "ef190": "#d7ff00", "ef191": "#d7ff5f", "ef192": "#d7ff87", "ef193": "#d7ffaf", "ef194": "#d7ffd7", "ef195": "#d7ffff", "ef196": "#ff0000",
"ef197": "#ff005f", "ef198": "#ff0087", "ef199": "#ff00af", "ef200": "#ff00d7", "ef201": "#ff00ff", "ef202": "#ff5f00", "ef203": "#ff5f5f", "ef204": "#ff5f87", "ef205": "#ff5faf",
"ef206": "#ff5fd7", "ef207": "#ff5fff", "ef208": "#ff8700", "ef209": "#ff875f", "ef210": "#ff8787", "ef211": "#ff87af", "ef212": "#ff87d7", "ef213": "#ff87ff", "ef214": "#ffaf00",
"ef215": "#ffaf5f", "ef216": "#ffaf87", "ef217": "#ffafaf", "ef218": "#ffafd7", "ef219": "#ffafff", "ef220": "#ffd700", "ef221": "#ffd75f", "ef222": "#ffd787", "ef223": "#ffd7af",
"ef224": "#ffd7d7", "ef225": "#ffd7ff", "ef226": "#ffff00", "ef227": "#ffff5f", "ef228": "#ffff87", "ef229": "#ffffaf", "ef230": "#ffffd7", "ef231": "#ffffff", "ef232": "#080808",
"ef233": "#121212", "ef234": "#1c1c1c", "ef235": "#262626", "ef236": "#303030", "ef237": "#3a3a3a", "ef238": "#444444", "ef239": "#4e4e4e", "ef240": "#585858", "ef241": "#626262",
"ef242": "#6c6c6c", "ef243": "#767676", "ef244": "#808080", "ef245": "#8a8a8a", "ef246": "#949494", "ef247": "#9e9e9e", "ef248": "#a8a8a8", "ef249": "#b2b2b2", "ef250": "#bcbcbc",
"ef251": "#c6c6c6", "ef252": "#d0d0d0", "ef253": "#dadada", "ef254": "#e4e4e4", "ef255": "#eeeeee", }
__doc__ = '''##########################################################################################################
####################################################################################################################'''
set2rgb = { 52: '#470000', 94: '#472100', 100: '#474700', 58: '#324700', 22: '#004700', 29: '#00472C', 23: '#004747', 24: '#002747', 17: '#000047', 54: '#2E0047', 53: '#470047', 89: '#47002A',
88: '#740000', 130: '#743A00', 142: '#747400', 64: '#517400', 28: '#007400', 35: '#007449', 30: '#007474', 25: '#004074', 18: '#000074', 91: '#4B0074', 90: '#740074', 125: '#740045',
124: '#B50000', 166: '#B56300', 184: '#B5B500', 106: '#7DB500', 34: '#00B500', 49: '#00B571', 37: '#00B5B5', 33: '#0063B5', 19: '#0000B5', 129: '#7500B5', 127: '#B500B5', 161: '#B5006B',
196: '#FF0000', 208: '#FF8C00', 226: '#FFFF00', 154: '#B2FF00', 46: '#00FF00', 86: '#00FFA0', 51: '#00FFFF', 75: '#008CFF', 21: '#0000FF', 171: '#A500FF', 201: '#FF00FF', 198: '#FF0098',
203: '#FF5959', 215: '#FFB459', 227: '#FFFF71', 191: '#CFFF60', 83: '#6FFF6F', 122: '#65FFC9', 87: '#6DFFFF', 111: '#59B4FF', 63: '#5959FF', 177: '#C459FF', 207: '#FF66FF', 205: '#FF59BC',
217: '#FF9C9C', 223: '#FFD39C', 229: '#FFFF9C', 193: '#E2FF9C', 157: '#9CFF9C', 158: '#9CFFDB', 159: '#9CFFFF', 153: '#9CD3FF', 147: '#9CD3FF', 183: '#DC9CFF', 219: '#FF9CFF', 212: '#FF94D3',
16: '#000000', 233: '#131313', 235: '#282828', 237: '#363636', 239: '#4D4D4D', 241: '#656565', 244: '#818181', 247: '#9F9F9F', 250: '#BCBCBC', 254: '#E2E2E2', 231: '#FFFFFF', }
__doc__ = '''##########################################################################################################
####################################################################################################################'''
@irc3.plugin
class Plugin:
__doc__ = ''' ##################################################################################################'''
def __init__(self, bot):
__doc__ = ''' ##############################################################################################'''
self.bot = bot
__doc__ = ''' ##############################################################################################'''
__doc__ = ''' ##################################################################################################'''
def ratesex_request(self,site,commands):
USER_AGENT_BROWSER="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
USER_AGENT_CURL="curl/7.29.0"
STATUS_BAD_CODE=":( - error code: {}"
STATUS_BAD_REASON=":( - failed reason: {}"
STATUS_OK=":)"
if site != 'rate':
url = f"https://{site}.rate.sx/{commands}"
else:
url = f"https://rate.sx/{commands}"
r = Request(url,data=None,headers={ 'User-Agent': USER_AGENT_CURL })
try:
response = urlopen(r,timeout=10).read().decode('utf-8')
except HTTPError as e:
return STATUS_BAD_CODE.format(e.code)
except URLError as e:
return STATUS_BAD_REASON.format(e.reason)
else:
return STATUS_OK + response
__doc__ = ''' ##################################################################################################'''
def escape_ansi(self,line):
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
return ansi_escape.sub('', str(line))
__doc__ = ''' ##################################################################################################'''
def invert_dict(self,d):
return {v: k for k, v in d.items()}
__doc__ = ''' ##################################################################################################'''
def enumerate_dict(self,d):
return list(zip(list(d),list(invert_dict(d)),range(len(d))))
__doc__ = ''' ##################################################################################################'''
def organize_dict(self,d):
_d=list(d.values())
return _d.sort()
__doc__ = ''' ##################################################################################################'''
def escape_ansi(self,line):
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]')
return ansi_escape.sub('', str(line))
__doc__ = ''' ##################################################################################################'''
def hex2gravity(self,h):
r,g,b=int(h[1:3],16),int(h[3:5],16),int(h[5:7],16)
o=list(set2rgb.values()); o.sort()
_R=[]; _G=[]; _B=[];
for _ in o:
R,G,B=(''.join([x for x in _[1:][:2]]).zfill(2)),(''.join([x for x in _[1:][2:4]]).zfill(2)),(''.join([x for x in _[1:][4:6]]).zfill(2))
_R.append(int(R,16)); _G.append(int(G,16)); _B.append(int(B,16));
_r = []
for _ in _R:
if r < _:
rsub = _ - r
else:
rsub = r - _
_r.append(rsub)
_g = []
for _ in _G:
if g < _:
gsub = _ - g
else:
gsub = g - _
_g.append(gsub)
_b = []
for _ in _B:
if b < _:
bsub = _ - b
else:
bsub = b - _
_b.append(bsub)
rgb = []
for _ in range(len(_r)):
rgb.append(_r[_]+_g[_]+_b[_])
nearest_color_minus = min(rgb)
nearest_color_index = [i for i, x in enumerate(rgb) if x == nearest_color_minus]
nearest_color = o[nearest_color_index[0]]
return str(f"\x03{rgb2irc[self.invert_dict(set2rgb)[nearest_color]]}")
__doc__ = ''' ##################################################################################################'''
def parse_control(self,s):
px=[]
py=[]
_s=s
px=self.findall(_s,'\x1b')
for i,_ in enumerate(px):
py.append( _s.find('m',_)+1 )
return px,py
__doc__ = ''' ##################################################################################################'''
def findall(self,s,w):
return [i for i in range(len(s)) if s.startswith(w, i)]
__doc__ = ''' ##################################################################################################'''
def color_line(self,s,t):
codes=["\x1b[0m","\x1b[30m","\x1b[31m","\x1b[32m","\x1b[33m","\x1b[34m","\x1b[35m","\x1b[36m","\x1b[37m","\x1b[40m","\x1b[41m","\x1b[42m","\x1b[43m","\x1b[44m","\x1b[45m","\x1b[46m","\x1b[47m","\x1b(B","\x1b[m","\x1b[2m"]
colors=["\x0f","\x0301","\x0304","\x0303","\x0308","\x03002","\x0313","\x0311","\x0300","\x03,01","\x03,04","\x03,03","\x03,08","\x03,02","\x03,13","\x03,11","\x03,00","","\x0f",""] #f.write('\x0301,00decoded\n')
_s=s
p=[]
for _ in range(len(t[0])):
r=self.findall(s[t[0][_]:t[1][_]],'\x1b')
for __ in range(len(r)):
if not __ == len(r)-1:
p.append(s[t[0][_]:t[1][_]][r[__]:r[__+1]])
else:
check = s[t[0][_]:t[1][_]][r[__]:]
if check.find('mm') == -1:
p.append(check)
else:
p.append(check[:-1])
for __ in p:
_s = _s.replace(__,"{}")
c=[]
for _ in p:
for i,__ in enumerate(codes):
if _ == __:
c.append(colors[i])
if _.find('\x1b[38;5;') != -1:
gravity = _.replace('\x1b[38;5;','')[:-1]
farthest_color_hex = rgb2set['ef{}'.format(gravity)]
result = self.hex2gravity(farthest_color_hex)
c.append(result)
r=self.findall(_s,'{}')
for _ in range(len(r)):
_s=_s.replace('{}',c[_],1)
return _s
__doc__ = ''' ##################################################################################################'''
@command(permission='view')
def ratesex(self, mask, target, args):
"""ratesex - help/commands: visit 'https://rate.sx/:help' or try '?ratesex rate :help', to check exchange rates for top 10 ^cripdoeocurrencies try '?ratesex rate top10.. sites added. rate,eur,btc,rub.. e.g. ?ratesex rate command, ?ratesex eur, ?ratesex btc, ?ratesex rub'
%%ratesex [<site>] [<command>]
"""
site = args.get("<site>")
command = args.get("<command>")
if command == "":
msg="error: no command issued.. ?ratesex rate, ?ratesex rate eth, ?ratesex rate :help, ?ratesex btc top10"
self.bot.privmsg(target, msg)
sites=['rate','rub','eur','btc']
FLAG=0
for _ in sites:
if site == _:
FLAG=1
if not FLAG==1:
msg="error: no site issued. sites: rate,rub,eur,btc. e.g. ?ratesex rate :help, ?ratesex btc top10, ?ratesex rub top10"
self.bot.privmsg(target, msg)
if command.lower() == 'top10': command = ''
response=self.ratesex_request(site,command)
s = ''
for _ in response:
s = s + ''.join(_)
r1=s[2:].splitlines()
for i in range(len(r1)-1):
d=self.parse_control(r1[i])
r=self.color_line(r1[i],d)
if not r == '':
msg = r+'\n'
self.bot.privmsg(target, msg)
__doc__ = ''' ##################################################################################################'''
__doc__ = ''':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.
/mMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMNd-
-MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN`
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMmNMMMMMMMMMMMmMMMMMMMMMMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh:NMMMMMMMMMMoyMMMMMMMMMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMm -NMMMMMMMMMs.NMMMMMMMMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMy -hmmmmmNNm- sMMMMMMMMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMmdyo+:` ```````.` .NMMMymMMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMmy+-.` -hNm-+MMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMms:` `.. /MMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMh/. /MMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMmMMMMMMMMMMMmhN:` /MMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMM+sNMMMMMMMMMN-h: `-+syyys/- -NMMMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMs +NMMMMMMMhm--d` :. -sdNMMMMMNNmy. :ydMMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMMMM+ :yhyyyhhso` os yhshNMMMMMMMh+:-:. :s- .NMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMMMMmho` ` `yo.h:sMMMMMMMMMMNd+. -NNs- yMMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMMMNh/. :++`-MMMMMMMMMMMMMm+` :ymds. -NMMMMMMMMMMMMMMMM-
/MMMMMMMMMMMmo- .MMMMMMMMMMMMMMMdo. `.-` yMMMMMMMMMMMMMMMM-
/MMMMMMMMMmo. `NMMMMMMMMMMMMMMMMNy/.` `mMMMMMMMMMMMMMMM-
/MMMMMMMNs. hMMMMMMMMMMMMMMMMMMMNho-` :NMMMMMMMMMMMMMM-
/MMMMMMm: ./syyyo- -hmNMMMMMMMMMMMMMMMMMMMMmho:.` /NMMMMMMMMMMMMM-
/MMMMMd. .smMMMNNNms` ` `+MMMMMMMMMMMMMMMMMMMMMMMMNdy/ `.yMMMMMMMMMMMMM-
/MMMMd. /mMMMMMy/:--` so. `mMMMMMMMMMMMMMMMMMMMMMMMNdo--:+sdNMMMMMMMMMMMMMM-
/MMMN- /NMMMMMMMMdo. oMm+. /MMMMMMMMMMMMMMMMdNMMMMMMNNNMMmMMMMMMMMMMMMMMMMM-
/MMMo -NMMMMMMMMMMdso-` /hmm+ sMMMMMMMMMMMMMMMs-mMMMMMMMMMM:dMMMMMMMMMMMMMMMM-
/MMN. sMMMMMMMMMMMo .os/.``.. `dMMMMMMMMMMMMMMs -NMMMMMMMMM-:MMMMMMMMMMMMMMMM-
/MMd mMMMMMMMMMMM/ `:os+-` .dMMMMMMMMMMMNm. -soosyhdms `mMMMMMMMMMMMMMMM-
/MMs mMMMMMMMMMMM: .hNhs/.` .dMMMMNmhs+:-` +MMMNoMMMMMMMMMM-
/MMy hMMMMMMMMMMM: oMMMMMNdyo/. .mNh+-` +mNy`mMMMMMMMMM-
/MMd +MMMMMMMMMMM/ :MMMMMMMMNs.`.:ohh/` ` mMMMMMMMMM-
/MMN. `mMMMMMMMMMMo `NMMMMMMNhhdNMMh: mMMMMMMMMM-
/MMM+ /MMMMMMMMMMh yMMMMMMMMMMMN+ `NMMMMMMMMM-
/MMMm` +MMMMMMMMMN` .NMMMMMMMMMN- :sdmNNNdy+` dMMMMMMMMM-
/MMMMo +MMMMMMMMM+ +MMMMMMMMM/ -dMMMMMMNmmNN/ .sdMMMMMMM-
/MMMMN: :mMMMMMMMm` oMMMMMMMh .mMMMMMMMms- `` /o` `mMMMMMM-
/MMMMMm. .yMMMMMMMo oMMMMMM/ sMMMMMMMMMMMh: :NNo. sMMMMMM-
/MMMMMMm. -hMMMMMN: /NMMMM. dMMMMMMMMMMMMMh- :hmNy` .NMMMMM-
/MMMMMMMm- -yNMMMm. .yMMM. dMMMMMMMMMMMMMMNh:` `..` yMMMMM-
/MMMMMMMMN+ .+hNMd. :hM: dMMMMMMMMMMMMMMMMNmo- .NMMMM-
/MMMMMMMMMMh- ./ss. `:: sMMMMMMMMMMMMMMMMMMMNms/. /MMMM-
/MMMMMMMMMMMNo. ` :MMMMMMMMMMMMMMMMMMMMMMMNdo:.` oMMM-
/MMMMMMMMMMMMMmo. `mMMMMMMMMMMMMMMMMMMMMMMMMMMNmh: .dMM-
/MMMMMMMMMMMMMMMNy:` +MMMMMMMMMMMMMMMMMMMMMMMMMMNh+::/+sdNMMM-
/MMMMMMMMMMMMMMMMMNdo- `dMMMMMMMMMMMMMMMMMMMMMMMMMNNNNNMMMMMMMM-
/MMMMMMMMMMMMMMMMMMMMNd+-` -NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM-
-NMMMMMMMMMMMMMMMMMMMMMMNdo:` /NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMd`
-ymNNNNNNNNNNNNNNNNNNNNNNNNdo-` +NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNmy.
............................ .-...............................`
`````` ````````` `````````````` `````````` ```'''

107
plugins/remind_plugin.py Normal file
View File

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
from irc3.plugins.cron import cron
import irc3
from datetime import datetime
from time import time
import re
REMIND_RE = re.compile('maple.remind\s(.+?)\s(.+)')
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
def __triggered(i):
time_now = int(str(time()).split('.')[0])
if i <= time_now:
print('triggered')
else:
print('not triggered')
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_for_remind(self, mask=None, target=None, data=None, **kw):
match_list = REMIND_RE.findall(data)
if len(match_list) > 0:
stime = ""
trigger = ""
bhours = False
bminutes = False
tell_nick, message = match_list[0]
if tell_nick == 'me': tell_nick = mask.nick
if not message.split()[0].lower() == 'in':
irc_message = "TCPDIRECT/REMIND: reminding {} the format is maple remind ircnick in 2h15m to pet cat, or maple remind me in 1h to pet cat.".format(mask.nick)
self.bot.privmsg(target, self.bot.emo(irc_message))
return
else:
message = message[3:]
trigger = message.split()[0]
message = message[len(trigger)+1:]
message_list = self.bot.db.getlist("remind_%s" % tell_nick.lower())
ihours = 0
iminutes = 0
xpos = 0
ypos = 0
itrigger = 0
epoch_time = int(str(time()).split('.')[0])
stime = trigger
try:
if not stime.lower().find('h') == -1:
xpos = stime.lower().find('h')+1
hours = int(stime[:stime.lower().find('h')])
ihours = hours * (60*60)
if not stime.lower().find('m') == -1:
ypos = stime.lower().find('m')
minutes = int(stime[xpos:ypos])
if minutes < 1:
irc_message = "TCPDIRECT/REMIND: reminding {} to quit wasting my time. format is maple remind ircnick in 2h15m to pet cat, or maple remind me in 1h to pet cat.".format(mask.nick)
self.bot.privmsg(target, self.bot.emo(irc_message))
return
iminutes = minutes * 60
except:
irc_message = "TCPDIRECT/REMIND: reminding {} to go and fuck themself err i mean, format is maple remind ircnick in 2h15m to pet cat, or maple remind me in 1h to pet cat.".format(mask.nick)
self.bot.privmsg(target, self.bot.emo(irc_message))
return
epoch_trigger = epoch_time + ihours + iminutes
if epoch_trigger <= epoch_time:
irc_message = "TCPDIRECT/REMIND: reminding {} to quit wasting my time. format is maple remind ircnick in 2h15m to pet cat, or maple remind me in 1h to pet cat.".format(mask.nick)
self.bot.privmsg(target, self.bot.emo(irc_message))
return
new_message = {"from": mask.nick.lower(), "target": target, "message": message, "time": datetime.now().isoformat(), "etime": epoch_time, "etrigger": epoch_trigger }
if not message_list:
message_list = self.bot.db.setlist("remind_%s" % tell_nick.lower(), [new_message])
else:
message_list.append(new_message)
self.bot.db.setlist("remind_%s" % tell_nick.lower(), message_list)
irc_message = "TCPDIRECT/REMIND: {} < {} > reminding < {} > {}".format(new_message.get("time"),new_message.get("from"),tell_nick,new_message.get("message"))
self.bot.privmsg(target, self.bot.emo(irc_message))
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################
@cron('* * * * *')
def _reminding(bot):
nicks = ','.join(bot.db.context.nicks.keys()).split(',')
for _ in nicks:
if bot.db.getlist('remind_{}'.format(_)):
_keys = []
for __ in bot.db.getlist('remind_{}'.format(_)):
etime = __['etime']
etrigger = __['etrigger']
_from = __['from']
_target = __['target']
_message = __['message']
etime_now = int(str(time()).split('.')[0])
if etime_now >= etrigger:
msg = "TCPDIRECT/REMIND: < {} > reminded < {} > - {}".format(_from,_,_message)
bot.privmsg(_target,msg)
else:
_keys.append(__)
bot.db.setlist("remind_{}".format(_),_keys)
###########################################################################################
###########################################################################################

94
plugins/sed_plugin.py Normal file
View File

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
import irc3
import os
import random
from string import ascii_lowercase as alpha
SED1_RE = "juggle s/"
SED2_RE = "j/"
###########################################################################################
###########################################################################################
class TCPSED():
buffer_text=[]
buffer_nick=[]
#######################################################################################
#######################################################################################
def __init__(self):
return
#######################################################################################
#######################################################################################
def push(self,data,nick):
self.buffer_text=self.buffer_text[-1:]+self.buffer_text[:-1]
self.buffer_text[0]=data
self.buffer_nick=self.buffer_nick[-1:]+self.buffer_nick[:-1]
self.buffer_nick[0]=nick
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.d=TCPSED()
for _ in range(2000):
self.d.buffer_text.append('')
self.d.buffer_nick.append('')
self.bot = bot
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_for_sed(self, mask=None, target=None, data=None, **kw):
if self.bot.config.nick == mask.nick:
return
if mask.nick.lower() == 'nickserv':
return
flag=0
offset = -1
offset = data.find(SED1_RE)
if not offset == 0:
offset = data.find(SED2_RE)
if offset == 0:
flag=1
if flag==0:
self.d.push(data,mask.nick)
return
_data=data.split('/')
_from=''
_to=''
_mode=''
try:
_from=_data[1]
_to=_data[2]
if len(_data) == 4:
if _data[3].lower() == 'g': _mode='g'
except Exception as e:
irc_message = f'TCPDIRECT/SED - Error: {e}'
self.bot.privmsg(target, self.bot.emo(irc_message))
return
itwist=-1
count=0
for i,_ in enumerate(self.d.buffer_text):
if not _ == '':
itwist=i
count = len([_i for _i in range(len(_)) if _.startswith(_from, _i)])
if count == 1:
self.d.buffer_text[i] = self.d.buffer_text[i].replace(_from,_to)
break
elif count > 1:
if _mode == 'g':
for y in range(count):
self.d.buffer_text[i] = self.d.buffer_text[i].replace(_from,_to)
break
else:
self.d.buffer_text[i] = self.d.buffer_text[i].replace(_from,_to,1)
break
if count != 0:
irc_message = "{}: {}".format(self.d.buffer_nick[itwist],self.d.buffer_text[itwist])
else:
irc_message = f"TCPDIRECT/SED - Error: no result for: {data}"
self.bot.privmsg(target, self.bot.emo(irc_message))
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

92
plugins/seen_plugin.py Normal file
View File

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
from datetime import datetime
import operator
import irc3
import timeago
import dateutil.parser
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
return
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.NEW_NICK)
def on_nick_change_for_seen(self, nick, new_nick):
new_key = "last_msg_for_{}".format(new_nick).lower()
msg_list = self.bot.db.getlist(new_key)
if not msg_list:
msg_list = []
seen_msg = { "type": "newnick",
"time": datetime.now().isoformat(),
"msg": "{} changed nick to {}".format(nick.nick, new_nick)}
msg_list.append(seen_msg)
self.bot.db.setlist(new_key, msg_list)
return
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_for_seen(self, mask=None, target=None, data=None, **kw):
if data.startswith("?"): return # no ?
if mask.lnick == self.bot.get_nick().lower(): return # Ignore ourseves
key = "last_msg_for_{}".format(mask.nick).lower()
priv_msg = { "type": "privmsg",
"time": datetime.now().isoformat(),
"msg": data }
messages = self.bot.db.getlist(key)
if not messages:
messages = []
else:
for count, msg in enumerate(messages):
if msg.get("type") == "privmsg":
del(messages[count])
messages.append(priv_msg)
self.bot.db.setlist(key, messages)
return
#######################################################################################
#######################################################################################
@command(permission='view')
def seen(self, mask, target, args):
"""Display last time user was seen
%%seen <nick>
"""
nick = args.get("<nick>")
if nick.lower() == self.bot.get_nick().lower():
msg = "please don't spy on me..."
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
key = "last_msg_for_{}".format(nick).lower()
message_list = self.bot.db.getlist(key)
if message_list:
message_list.sort(key=operator.itemgetter('time'), reverse=True)
nick_seen_set = set()
for msg in message_list:
if msg.get("type") == "newnick":
notice_msg = msg.get("msg").lower()
nick_to_remember = [ item.strip() for item in notice_msg.split("changed nick to")].pop()
if nick_to_remember in nick_seen_set:
continue
else:
nick_seen_set.add(nick_to_remember)
msg_time = dateutil.parser.parse(msg.get("time"))
time_since = timeago.format(msg_time, datetime.now())
msg = "\x02{}\x0F \x0303▶\x0F \x02\x0302{}\x0F \x0306፨ \x0F\x1F\x1D{}\x0F".format(nick, msg.get("msg"), time_since.capitalize())
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
self.bot.history.push_user_messages(mask.nick.lower(),f"have you seen {nick}")
else:
msg = "{} Has Not Been Seen".format(nick)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
self.bot.history.push_user_messages(mask.nick.lower(),f"have you seen {nick}")
return
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
from urllib.parse import quote_plus
import html
import requests
from lxml.html import fromstring
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
def __soundcloud__request(self,command,query):
USER_AGENT_CURL="curl/7.29.0"
STATUS_BAD_CODE=":( - error code: {}"
STATUS_BAD_REASON=":( - failed reason: {}"
STATUS_OK=":)"
COMMANDS=['search']
for _ in COMMANDS:
if _==command.lower():
url=f'https://soundcloud.com/{_}?q={quote_plus(query)}'
r=Request(url,data=None,headers={'User-Agent':USER_AGENT_CURL})
try:
response=urlopen(r,timeout=10).read().decode('utf-8')
except HTTPError as e:
return STATUS_BAD_CODE.format(e.code)
except URLError as e:
return STATUS_BAD_REASON.format(e.reason)
else:
return STATUS_OK+response
#######################################################################################
#######################################################################################
@command(permission='view')
def sc(self, mask, target, args):
"""Soundcloud artist/song search.. example: ?sc yung innanet nano tapes cronjob
%%sc <query>...
"""
NICK=mask.nick
query=' '.join(args['<query>'])
result=self.__soundcloud__request('search',query)
pop=[];_path=[];_name=[];title='';
for _ in result.splitlines():
if _.find('<li><h2>') != -1:
pop.append(_.strip())
for _ in pop:
_path.append(_.split('="/').pop().split('">')[0])
_name.append(_.split('="/').pop().split('">')[1].split('<')[0])
try:
url=f'https://soundcloud.com/{_path[0]}'
try:
read_size = 0
r=requests.get(url,timeout=3,stream=True)
content_length=r.headers.get('Content-Length')
if not content_length:
content_length=0
while read_size<=(2000*10):
for content in r.iter_content(chunk_size=2000):
tree=fromstring(content)
title=tree.find(".//title")
if title is not None:
title=title.text.strip()[:100]
break
except:
pass
URL=f'https://soundcloud.com/{_path[0]}'
TITLE=title.split('|')[0].split('by')[-1].strip()
NAME=html.unescape(_name[0]);
msg=f"\x02\x0302{NICK}\x0F\x02\x0304 ▶ "
msg+=f"\x0F\x02\x0313{NAME}\x0F\x02\x0304 ▶ "
msg+=f"\x0F\x02\x0312{URL}\x0F\x02\x0313\x0F\x02\x0304 ▶ "
msg+=f"\x0F\x1D\x0314{TITLE}\x0F\x02\x0304 "
except:
MSG='no result'
msg=f"\x02\x0302{NICK}\x0F\x02\x0304 ▶ "
msg+=f"\x0F\x02\x0313{MSG}\x0F\x02\x0304 "
self.bot.privmsg(target,self.bot.emo(f"{msg}"))
self.bot.history.push_user_messages(mask.nick.lower(),f'{TITLE} {NAME}')
###########################################################################################
###########################################################################################

473
plugins/storage_plugin.py Normal file
View File

@ -0,0 +1,473 @@
# -*- coding: utf-8 -*-
import os
try:
import ujson as json
except ImportError:
import json
import irc3
import shelve
__doc__ = '''
==========================================
:mod:`irc3.plugins.storage` Storage plugin
==========================================
Add a ``db`` attribute to the bot
..
>>> from irc3.testing import IrcBot
>>> from irc3.testing import ini2config
>>> import tempfile
>>> fd = tempfile.NamedTemporaryFile(prefix='irc3', suffix='.db')
>>> db_file = fd.name
>>> fd.close()
>>> fd = tempfile.NamedTemporaryFile(prefix='irc3', suffix='.json')
>>> json_file = fd.name
>>> fd.close()
>>> fd = tempfile.NamedTemporaryFile(prefix='irc3', suffix='.sqlite')
>>> sqlite_file = fd.name
>>> fd.close()
Usage::
>>> config = ini2config("""
... [bot]
... includes =
... irc3.plugins.storage
... storage = json://%s
... """ % json_file)
>>> bot = IrcBot(**config)
Then use it::
>>> bot.db['mykey'] = dict(key='value')
>>> 'mykey' in bot.db
True
>>> bot.db['mykey']
{'key': 'value'}
>>> bot.db.setdefault('mykey', key='default')
{'key': 'value'}
>>> bot.db.setdefault('mykey', item='default')
{'item': 'default'}
>>> bot.db.set('mykey', item='value')
>>> bot.db.setdefault('mykey', item='default')
{'item': 'value'}
>>> del bot.db['mykey']
>>> bot.db.get('mykey')
>>> bot.db.get('mykey', 'default')
'default'
>>> bot.db['mykey']
Traceback (most recent call last):
...
KeyError: 'mykey'
>>> 'mykey' in bot.db
False
>>> bot.db.setlist('mylist', ['foo', 'bar'])
>>> bot.db.getlist('mylist')
['foo', 'bar']
>>> del bot.db['mylist']
You can use an instance as key::
>>> class MyPlugin:
... pass
>>> plugin = MyPlugin()
>>> bot.db[plugin] = dict(key='value')
>>> bot.db[plugin]
{'key': 'value'}
>>> del bot.db[plugin]
>>> bot.db.get(plugin)
..
>>> bot.db.SIGINT()
You can also use shelve::
>>> config = ini2config("""
... [bot]
... includes =
... irc3.plugins.storage
... storage = shelve://%s
... """ % db_file)
>>> bot = IrcBot(**config)
>>> bot.db['mykey'] = dict(key='value')
>>> bot.db['mykey']
{'key': 'value'}
>>> del bot.db['mykey']
>>> bot.db.get('mykey')
>>> bot.db.setlist('mylist', ['foo', 'bar'])
>>> bot.db.getlist('mylist')
['foo', 'bar']
>>> del bot.db['mylist']
..
>>> bot.db.getlist('mylist', ['foo', 'bar'])
['foo', 'bar']
>>> bot.db.setlist('mylist', ['foo', 'bar'])
>>> bot.db.setlist('mylist', ['foo', 'bar'])
>>> del bot.db['mylist']
>>> bot.db.SIGINT()
Or redis::
>>> config = ini2config("""
... [bot]
... includes =
... irc3.plugins.storage
... storage = redis://localhost:6379/10
... """)
>>> bot = IrcBot(**config)
..
>>> bot.db.backend.flushdb() # require redis
>>> bot.db.SIGINT()
Then use it::
>>> bot.db['mykey'] = dict(key='value')
>>> bot.db['mykey']
{'key': 'value'}
>>> del bot.db['mykey']
>>> bot.db.get('mykey')
>>> bot.db['mykey']
Traceback (most recent call last):
...
KeyError: 'mykey'
>>> bot.db.setlist('mylist', ['foo', 'bar'])
>>> bot.db.getlist('mylist')
['foo', 'bar']
>>> del bot.db['mylist']
Or sqlite::
>>> config = ini2config("""
... [bot]
... includes =
... irc3.plugins.storage
... storage = sqlite://%s
... """ % sqlite_file)
>>> bot = IrcBot(**config)
..
>>> bot.db.backend.flushdb() # require redis
>>> bot.db.SIGINT()
Then use it::
>>> bot.db['mykey'] = dict(key='value')
>>> bot.db['mykey']
{'key': 'value'}
>>> del bot.db['mykey']
>>> bot.db.get('mykey')
>>> bot.db['mykey']
Traceback (most recent call last):
...
KeyError: 'mykey'
>>> bot.db.setlist('mylist', ['foo', 'bar'])
>>> bot.db.getlist('mylist')
['foo', 'bar']
>>> del bot.db['mylist']
Api
===
.. autoclass:: Storage
:members: __getitem__,__setitem__,__delitem__,__contains__,get,set,setdefault
'''
class Shelve:
def __init__(self, uri=None, **kwargs):
self.filename = uri[9:]
self.db = shelve.open(self.filename)
def set(self, key, value):
self.db[key] = value
self.db.sync()
def get(self, key):
return self.db[key]
def delete(self, key):
del self.db[key]
self.sync()
def contains(self, key):
return key in self.db
def sync(self):
self.db.sync()
def close(self):
self.db.close()
class JSON:
def __init__(self, uri=None, **kwargs):
self.filename = uri[7:]
if os.path.isfile(self.filename): # pragma: no cover
with open(self.filename) as fd:
self.db = json.load(fd)
else:
self.db = {}
def set(self, key, value):
self.db[key] = value
self.sync()
def get(self, key):
return self.db[key]
def delete(self, key):
del self.db[key]
self.sync()
def contains(self, key):
return key in self.db
def sync(self):
with open(self.filename, 'w') as fd:
json.dump(self.db, fd, indent=2, sort_keys=True)
def close(self):
self.sync()
class Redis:
def __init__(self, uri=None, **kwargs):
ConnectionPool = irc3.utils.maybedotted(
'redis.connection.ConnectionPool')
pool = ConnectionPool.from_url(uri)
StrictRedis = irc3.utils.maybedotted('redis.client.StrictRedis')
self.db = StrictRedis(connection_pool=pool)
def set(self, key, value):
self.db.hmset(key, value)
def get(self, key):
keys = self.db.hkeys(key)
if not keys:
raise KeyError()
values = self.db.hmget(key, keys)
keys = [k.decode('utf8') for k in keys]
values = [v.decode('utf8') for v in values]
values = dict(zip(keys, values))
return values
def delete(self, key):
self.db.delete(key)
def contains(self, key):
return self.db.exists(key)
def flushdb(self):
self.db.flushdb()
def sync(self):
self.db.save()
def close(self):
self.sync()
class SQLite:
CREATE_TABLE = """
CREATE TABLE IF NOT EXISTS
irc3_storage (
key text not null,
value text default '',
PRIMARY KEY (key)
);
"""
UPSERT = """
INSERT OR REPLACE INTO irc3_storage(key,value) VALUES(?, ?);
"""
def __init__(self, uri=None, **kwargs):
self.sqlite = irc3.utils.maybedotted('sqlite3')
self.uri = uri.split('://')[-1]
conn = self.sqlite.connect(self.uri)
cursor = conn.cursor()
cursor.execute(self.CREATE_TABLE)
conn.commit()
conn.close()
def set(self, key, value):
conn = self.sqlite.connect(self.uri)
cursor = conn.cursor()
cursor.execute(self.UPSERT, (key, json.dumps(value)))
cursor.fetchall()
conn.commit()
conn.close()
def get(self, key):
value = None
conn = self.sqlite.connect(self.uri)
cursor = conn.cursor()
cursor.execute("SELECT value FROM irc3_storage where key=?;", (key,))
for row in cursor.fetchall():
value = json.loads(row[0])
break
cursor.close()
conn.close()
if value is None:
raise KeyError(key)
return value
def delete(self, key):
conn = self.sqlite.connect(self.uri)
cursor = conn.cursor()
cursor.execute("DELETE FROM irc3_storage where key=?;", (key,))
cursor.close()
conn.commit()
conn.close()
def contains(self, key):
conn = self.sqlite.connect(self.uri)
cursor = conn.cursor()
cursor.execute("SELECT value FROM irc3_storage where key=?;", (key,))
res = False
if len(list(cursor.fetchall())) == 1:
res = True
cursor.close()
conn.close()
return res
def flushdb(self):
conn = self.sqlite.connect(self.uri)
cursor = conn.cursor()
cursor.execute("DROP TABLE IF EXISTS irc3_storage;")
cursor.execute(self.CREATE_TABLE)
cursor.close()
conn.commit()
conn.close()
def sync(self):
pass
def close(self):
pass
@irc3.plugin
class Storage:
backends = {
'shelve': Shelve,
'json': JSON,
'unix': Redis,
'redis': Redis,
'rediss': Redis,
'sqlite': SQLite,
}
def __init__(self, context):
uri = context.config.storage
name = uri.split('://', 1)[0]
try:
factory = self.backends[name]
except KeyError: # pragma: no cover
raise LookupError('No such backend %s' % name)
self.backend = factory(uri)
self.context = context
self.context.db = self
def setdefault(self, key_, **kwargs):
"""Update storage value for key with kwargs iif the keys doesn't
exist. Return stored values"""
stored = self[key_]
changed = False
for k, v in kwargs.items():
if k not in stored:
stored[k] = v
changed = True
else:
kwargs[k] = stored[k]
if changed:
self[key_] = stored
return kwargs
def get(self, key_, default=None):
"""Get storage value for key or return default"""
if key_ not in self:
return default
else:
return self[key_]
def getlist(self, key_, default=None):
"""Get storage value (as list) for key or return default"""
if key_ not in self:
return default
else:
value = self[key_]
value = [(int(i), v) for i, v in value.items()]
return [v for k, v in sorted(value)]
def set(self, key_, **kwargs):
"""Update storage value for key with kwargs"""
stored = self.get(key_, dict())
changed = False
for k, v in kwargs.items():
if k not in stored or stored[k] != v:
stored[k] = v
changed = True
if changed:
self[key_] = stored
def setlist(self, key_, value):
"""Update storage value (as list)"""
value = dict([(str(i), v) for i, v in enumerate(value)])
if key_ in self:
del self[key_]
self.set(key_, **value)
def __setitem__(self, key, value):
"""Set storage value for key"""
key = getattr(key, '__module__', key)
if not isinstance(value, dict): # pragma: no cover
raise TypeError('value must be a dict')
try:
return self.backend.set(key, value)
except Exception as e: # pragma: no cover
self.context.log.exception(e)
raise
def __getitem__(self, key):
"""Get storage value for key"""
key = getattr(key, '__module__', key)
try:
return self.backend.get(key)
except KeyError:
raise KeyError(key)
except Exception as e: # pragma: no cover
self.context.log.exception(e)
raise
def __delitem__(self, key):
"""Delete key in storage"""
key = getattr(key, '__module__', key)
try:
self.backend.delete(key)
except Exception as e: # pragma: no cover
self.context.log.exception(e)
raise
def __contains__(self, key):
"""Return True if storage contains key"""
key = getattr(key, '__module__', key)
try:
return self.backend.contains(key)
except Exception as e: # pragma: no cover
self.context.log.exception(e)
raise
def SIGINT(self):
self.backend.close()

92
plugins/strain_plugin.py Normal file
View File

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import requests
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
def _get_weed(self,t,s):
try:
url=""
if t == "search":
s = s.lower().replace(' ','-')
url = 'https://api.wikileaf.com/api/v7/search/all/?type=S&num=24&offset=0&sort=popular&query={}'.format(s)
if t == "review":
url = 'https://api.wikileaf.com/api/v6/reviews/?content_type__model=strain&object_id={}'.format(s)
r = requests.get(url)
try:
if r.json()['detail'] == 'Not found.':
return 'Not Found.'
except:
return r.json()
except:
return -1
#######################################################################################
#######################################################################################
@command(permission='view')
def strain(self, mask, target, args):
"""strain
%%strain <message>...
"""
try:
msg = ' '.join(args['<message>'])
r_strain_id = -1
r = self._get_weed('search',msg)
b = r['results'][0]
try:
r_name = b['name']
r_score = b['score']
r_review_avg = b['review_avg']
r_review_count = b['review_count']
r_type = b['type']
r_compound_thc_min = b['compound']['THC']['min']
r_compound_thc_max = b['compound']['THC']['max']
r_compound_cbd_min = b['compound']['CBD']['min']
r_compound_cbd_max = b['compound']['CBD']['max']
r_consumption_time = b['consumption_time']
r_uses = b['uses']
r_effects = b['effects']
r_logo_url = "https://assets.wikileaf.com/{}".format(b['logo_url'])
r_strain_id = b['strain_id']
msg = "▶ name: {}".format(r_name)
msg = msg + "" + "score: {}".format(r_score)
msg = msg + "" + "review avg: {}".format(r_review_avg)
msg = msg + "" + "review count: {}".format(r_review_count)
msg = msg + "" + "type: {}".format(r_type)
msg = msg + "" + "compound thc min: {} / max: {}".format(r_compound_thc_min,r_compound_thc_max)
msg = msg + "" + "compound cbd min: {} / max: {}".format(r_compound_cbd_min,r_compound_cbd_max)
msg = msg + "" + "consumption time: {}".format(r_consumption_time)
msg = msg + "" + "uses: {}".format(r_uses)
msg = msg + "" + "effects: {}".format(r_effects)
msg = msg + "" + "logo: {}".format(r_logo_url)
self.bot.privmsg(target, msg)
except:
msg = "strain: not found"
self.bot.privmsg(target, msg)
try:
r = self._get_weed('review',r_strain_id)
b = r['results']
for i,_ in enumerate(b):
msg = "▶▶ " + "review {} - rating: {} / comment: {}".format(i+1,_['rating'],_['comment'])
self.bot.privmsg(target, msg)
if i >= 2: break
url = b[0]['url']
msg = "▶▶▶ " + "url: {}".format(url)
self.bot.privmsg(target, msg)
self.bot.history.push_user_messages(mask.nick.lower(),msg)
except:
pass
except:
msg = "strain: not found"
self.bot.privmsg(target, msg)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

46
plugins/tell_plugin.py Normal file
View File

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
from datetime import datetime
import irc3
import re
TELL_RE = re.compile('maple.tell\s(.+?)\s(.+)')
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_to_tell(self, mask=None, target=None, data=None, **kw):
if mask.nick.lower() == "maple":
return
messages_to_send = self.bot.db.getlist("tell_%s" % mask.nick.lower())
if messages_to_send:
msg = messages_to_send[0]
irc_message = "TCPDIRECT/TOLD: {} <{}> told <{}> {}".format(msg.get("time"),msg.get("from"),mask.nick,msg.get("message"))
self.bot.privmsg(target, self.bot.emo(irc_message))
self.bot.db.setlist("tell_%s" % mask.nick.lower(), messages_to_send[1:])
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_for_tell(self, mask=None, target=None, data=None, **kw):
match_list = TELL_RE.findall(data)
if len(match_list) > 0:
tell_nick, message = match_list[0]
if tell_nick == 'me' or tell_nick == 'us' or tell_nick == 'a' or tell_nick == 'some': return
message_list = self.bot.db.getlist("tell_%s" % tell_nick.lower())
new_message = {"from": mask.nick.lower(), "message": message, "time": datetime.now().isoformat() }
if not message_list:
message_list = self.bot.db.setlist("tell_%s" % tell_nick.lower(), [new_message])
else:
message_list.append(new_message)
self.bot.db.setlist("tell_%s" % tell_nick.lower(), message_list)
irc_message = "TCPDIRECT/TELL: {} <{}> telling <{}> {}".format(new_message.get("time"),new_message.get("from"),tell_nick,new_message.get("message"))
self.bot.privmsg(target, self.bot.emo(irc_message))
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

193
plugins/twitter_plugin.py Normal file
View File

@ -0,0 +1,193 @@
# -*- coding: utf-8 -*-
import irc3
from datetime import datetime
import twitter
import re
import os
import time
import timeago
import os
import requests
from lxml.html import fromstring
from difflib import SequenceMatcher
###########################################################################################
###########################################################################################
CONSUMER_KEY = os.environ['CONSUMER_KEY']
CONSUMER_SECRET = os.environ['CONSUMER_SECRET']
ACCESS_TOKEN_KEY = os.environ['ACCESS_TOKEN_KEY']
ACCESS_TOKEN_SECRET = os.environ['ACCESS_TOKEN_SECRET']
TOO_LONG = 2000
YOUTUBE_REGEX = re.compile('http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?', re.IGNORECASE)
TWITTER_REGEX = re.compile('https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)$', re.IGNORECASE)
URL_REGEX = re.compile('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', re.IGNORECASE)
twitter = twitter.Api(consumer_key=CONSUMER_KEY, consumer_secret=CONSUMER_SECRET,
access_token_key=ACCESS_TOKEN_KEY, access_token_secret=ACCESS_TOKEN_SECRET)
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@irc3.extend
def _similar(self, a, b):
return SequenceMatcher(None, a, b).ratio()
#######################################################################################
#######################################################################################
@irc3.extend
def _check_for_url(self, og_tweet, d_nick, d_url, d_unrolled, d_text, d_target):
match_list = URL_REGEX.findall(d_unrolled)
read_size = 0
if match_list:
url = match_list.pop()
try:
if not d_unrolled.find('https://twitter.com/') == -1:
if not d_unrolled.find('status') == -1:
try:
e_status = d_unrolled.split('/')[-1]
e_tweet = twitter.GetStatus(e_status)
e_text = e_tweet.text
if self._similar(og_tweet.text,e_text) > 0.7: return
msg = "\x02\x0302{nick1:}:{nick2:}\x0F\x02\x0303 ▶▶ {e_text:} \x0F".format(nick1=d_nick,nick2='UNROLLED',e_text=e_text)
if e_tweet.media:
for y in range(len(e_tweet.media)):
m_turl = e_tweet.media[y].url
m_murl = e_tweet.media[y].media_url
m_eurl = e_tweet.media[y].expanded_url
msg = msg + " ▶▶ [media] \x0F\x02\x0312{media_url:}".format(media_url=m_murl)
if e_tweet.urls:
for y in range(len(e_tweet.urls)):
e_turl = e_tweet.urls[y].url
e_eurl = e_tweet.urls[y].expanded_url
msg = msg + " ▶▶ [url] \x0F\x02\x0312{e_url:}".format(e_url=e_eurl)
msg = self.bot.emo(msg)
self.bot.privmsg(d_target, msg)
return
except Exception as e:
msg = "wu/tang >>>>>>>>>>> sub-unrolling: {}".format(e)
msg = self.bot.emo(msg)
self.bot.privmsg(d_target, msg)
return
r = requests.get(d_unrolled, timeout=3, stream=True)
content_type = r.headers.get("Content-Type")
content_length = r.headers.get('Content-Length')
if not content_length:
content_length = 0
if content_type.startswith('image'):
msg = "\x02\x0302{nick1:}:{nick2:}\x0F\x02\x0303 ▶▶ [media] {media:} \x0F".format(nick1=d_nick,nick2='UNROLLED',media=d_unrolled)
msg = self.bot.emo(msg)
self.bot.privmsg(d_target, msg)
return
if not content_type.startswith("text/html"):
return
if int(content_length) > 200000:
self.bot.privmsg(d_target, "pre-fetch aborted -> fuck your large ass content -> {} -> {}".format(d_url,d_unrolled))
while read_size <= (2000 * 10):
for content in r.iter_content(chunk_size=2000):
tree = fromstring(content)
title = tree.find(".//title")
if title is not None:
title = title.text.strip()[:100]
print('title: {}'.format(title))
similarity = self.bot._similar(title,d_text)
if similarity > 0.4:
print('wu/tang: similarity')
return
msg = "\x02\x0302{nick1:}:{nick2:}\x0F\x02\x0304 ▶▶ \x0F\x1D\x0314{url:}\x0F\x0304 ▶▶ \x0F\x0303{unrolled:} \x0F\x0304▶▶ \x0F\x1D\x0314{title:}\x0F".format(nick1=d_nick,nick2='UNROLLED',url=d_url,unrolled=d_unrolled,title=title)
msg = self.bot.emo(msg)
self.bot.privmsg(d_target, msg)
return
read_size = read_size + 2000
except Exception as e:
self.bot.privmsg("_debug_check_for_url_error: {}".format(e))
print("original: {} nick: {} url: {} unrolled: {} text: {} error: {}".format(og_tweet,d_nick,d_url,d_unrolled,d_text,e))
pass
#######################################################################################
#######################################################################################
def _check_for_twitter(self, mask=None, data=None, target=None, **kw):
match_list = TWITTER_REGEX.findall(data)
if match_list:
status_id = match_list[0][2]
try:
tweet = twitter.GetStatus(status_id=status_id)
tweet_text = tweet.text
user = tweet.user.screen_name
fav_count = tweet.favorite_count
retweet_count = tweet.retweet_count
if tweet.coordinates:
location = tweet.coordinates
else:
location = ""
tweet_time = time.strptime(tweet.created_at, '%a %b %d %H:%M:%S +0000 %Y')
time_since = timeago.format(time.strftime('%Y-%m-%d %H:%M:%S', tweet_time), datetime.now())
msg = "\x02\x0302{} \x0F\x0303▶\x0F \x02\x0301{}\x0F\x0314 | Retweets:\x0F \x1D\x0306{}\x0F\x0314 Favorites:\x0F\x1D\x0306 {} \x0F\x1D\x0314\x1D {} {}".format(user, tweet_text, retweet_count, fav_count, time_since, location)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
match_list = URL_REGEX.findall(msg)
try:
if(match_list):
try:
if len(tweet.urls) == 0:
if tweet.media:
for y in range(len(tweet.media)):
m_turl = tweet.media[y].url
m_murl = tweet.media[y].media_url
m_eurl = tweet.media[y].expanded_url
msg = "\x02\x0302{nick1:}:{nick2:}\x0F\x02\x0304 ▶▶ [media] \x0F\x02\x0312{m_turl:}\x0F\x0304 ▶▶ \x0F\x0303{m_murl:} \x0F\x0304▶▶ \x0F\x1D\x0314{m_eurl:}\x0F".format(nick1=user,nick2='UNROLLED',m_turl=m_turl,m_murl=m_murl,m_eurl=m_eurl)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
else:
for y in range(len(tweet.urls)):
t_turl = tweet.urls[y].url
try:
match_list.remove(t_turl)
except:
print('cant remove from matchlist, does not exist')
t_eurl = tweet.urls[y].expanded_url
yt_match_list = YOUTUBE_REGEX.findall(t_eurl)
if yt_match_list:
d_video_id = t_eurl.split('=')[1]
self.bot.madjust = "{}:UNROLLED".format(user)
self.bot.yt(mask,target,{'<keyword>': [d_video_id],'yt': True})
self.bot.madjust = ""
else:
if not str(tweet.id) == t_eurl.split('/')[-1]:
self.bot._check_for_url(tweet,user,t_turl,t_eurl,tweet_text,target)
else:
print('bypassing original tweet')
try:
if len(match_list) > 0:
print('items in matchlist remain')
print(match_list)
except:
print('errrororororororo: cant remove from matchlist, does not exist')
except Exception as e:
self.bot.privmsg(target,'twitter_plugin <> _debug_unrolling -> wu/tang: {}'.format(e))
except Exception as e:
self.bot.privmsg(target,'twitter_plugin <> wu/tang: {}'.format(e))
except Exception as e:
_msg = e.message[0]['message']
_code = e.message[0]['code']
_erid = ''
if _code == 179:
_erid = "PROTECTED TW33T"
else:
_erid = "DON'T CARE EXCEPTION"
msg = "\x02\x0302{} \x0F\x0304▶ \x0F\x02\x0312{} aka {}\x0F\x0303".format(_code,_msg,_erid)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
pass
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_for_twitter(self, mask=None, target=None, data=None, **kw):
if data.startswith("?"): return
if mask.nick.lower() not in self.bot.ignore_list:
self._check_for_twitter(mask, data, target)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

35
plugins/ud_plugin.py Normal file
View File

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import requests
import urllib.parse
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@command(permission='view')
def ud(self, mask, target, args):
"""Urban Dictonary A Term
%%ud <term>...
"""
term = ' '.join(args['<term>'])
term = urllib.parse.quote(term)
r = requests.get('https://api.urbandictionary.com/v0/define?term={}'.format(term))
d = r.json()
term = urllib.parse.unquote(term)
try:
msg = "{} - {} - example: {}".format(term, d.get("list")[0].get("definition"), d.get("list")[0].get("example"))
except:
msg = "{} Term Not Found".format(term)
self.bot.privmsg(target,msg)
self.bot.history.push_user_messages(mask.nick.lower(),msg)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

View File

@ -0,0 +1,84 @@
# -*- coding: utf-8 -*-
import irc3
import re
import requests
from lxml.html import fromstring
TOO_LONG = 2000
URL_REGEX = re.compile('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', re.IGNORECASE)
YOUTUBE_REGEX = re.compile('http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?', re.IGNORECASE)
TWITTER_REGEX = re.compile('https?:\/\/twitter\.com\/(?:#!\/)?(\w+)\/status(es)?\/(\d+)$', re.IGNORECASE)
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg(self, mask=None, target=None, data=None, **kw):
if not data.find('reacted with :') == -1: return
if data.startswith("?"): return
if self.bot.check_if_ignored(mask): return
if mask.nick == '[0]' or mask.nick == '[0]_': return
self.__check_for_url(data, target, mask)
#######################################################################################
#######################################################################################
def __check_for_url(self, msg, target, mask):
match_list = URL_REGEX.findall(msg)
read_size = 0
if match_list:
url = match_list.pop()
if not url.lower().find('wp-login') == -1:
msg = 'pre-fetch aborted -> hell nah nigga'
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
y_match = YOUTUBE_REGEX.findall(url)
if y_match:
y_match = y_match.pop()
if len(y_match) == 3:
return
t_match = TWITTER_REGEX.findall(url)
if t_match:
t_match = t_match.pop()
if len(t_match) == 3:
return
try:
if not url.find("giphy.com") == -1:
msg = "\x02\x0302{nick:}\x0F\x02\x0304 ▶ \x0F\x02\x0303{url:}\x0F\x0303".format(nick=mask.nick,url="fuk giphy!!!")
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
if not url.find("facebook.com") == -1:
msg = "\x02\x0302{nick:}\x0F\x02\x0304 ▶ \x0F\x02\x0312{url:}\x0F\x0303".format(nick=mask.nick,url="fuk facebook!!!")
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
r = requests.get(url, timeout=3, stream=True)
content_type = r.headers.get("Content-Type")
content_length = r.headers.get('Content-Length')
if not content_length:
content_length = 0
if int(content_length) > 200000:
return
while read_size <= (2000 * 10):
for content in r.iter_content(chunk_size=2000):
tree = fromstring(content)
title = tree.find(".//title")
if title is not None:
title = title.text.strip()[:100]
msg = "\x02\x0302{nick:}\x0F\x02\x0304 ▶ \x0F\x1D\x0314{title:}\x0F".format(nick=mask.nick,title=title)
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
return
read_size = read_size + 2000
except Exception as e:
print("%s" % e)
pass
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

143
plugins/youtube_plugin.py Normal file
View File

@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
from irc3.plugins.command import command
import irc3
import os
import re
import datetime
import dateutil.parser
import timeago
import isodate
from apiclient.discovery import build
dir_path = os.path.dirname(os.path.realpath(__file__))
DEVELOPER_KEY = os.environ['DEVELOPER_KEY']
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
YOUTUBE_REGEX = re.compile('http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?', re.IGNORECASE)
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY)
###########################################################################################
###########################################################################################
@irc3.plugin
class Plugin:
#######################################################################################
#######################################################################################
def __init__(self, bot):
self.bot = bot
self.bot.channel_live = []
#######################################################################################
#######################################################################################
@irc3.extend
def youtube_search(self, q=None, eventType=None, max_results=1, order="relevance", channelId=None, token=None, location=None, location_radius=None):
search_response = youtube.search().list(
q=q,
channelId=channelId,
type="video",
pageToken=token,
order=order,
eventType=eventType,
part="id,snippet",
maxResults=max_results,
location=location,
locationRadius=location_radius
).execute()
for search_result in search_response.get("items", []):
if search_result["id"]["kind"] == "youtube#video":
return(search_result)
#######################################################################################
#######################################################################################
@irc3.event(irc3.rfc.PRIVMSG)
def on_privmsg_search_for_youtube(self, mask=None, target=None, data=None, **kw):
if data.startswith("?"): return
if self.bot.check_if_ignored(mask): return
self.__check_for_youtube(mask, data, target)
#######################################################################################
#######################################################################################
def __check_for_youtube(self, mask, msg, target):
match_list = YOUTUBE_REGEX.findall(msg)
if match_list:
video_id = match_list.pop()
if int(len(video_id)) == 3:
video_id = video_id[0]
video_info = self.videos_list_by_id(id=video_id)
title = video_info.get("snippet",{}).get("title")
published_at = video_info.get("snippet",{}).get("publishedAt")
view_count = int(video_info.get("statistics").get("viewCount"))
if published_at:
published_at = dateutil.parser.parse(published_at)
published_at = timeago.format(published_at.replace(tzinfo=None), datetime.datetime.now())
try:
topics = video_info.get("topicDetails",{}).get("topicCategories")
topics[:] = [i.replace("https://en.wikipedia.org/wiki/", "").replace("_"," ").title() for i in topics]
except:
topics = []
duration = isodate.parse_duration(video_info.get("contentDetails").get("duration"))
msg = "\x02\x0302{nick:}\x0F\x02\x0304 ▶▶ \x02\x0303\x1D\x1F{title:}\x0F".format(nick=mask.nick, title=title)
msg = msg + "\x02\x1D\x0304 ▶ \x0F\x1D\x0314Duration: \x0F\x1D{duration:} \x0F".format(duration=duration)
msg = msg + "\x0F\x1D\x0314Published: \x0F\x1D{published:} \x0F\x1D\x0314Views: \x0F\x1D{views:,}\x0F".format(published=published_at, views=view_count)
msg = msg + "\x0F\x02\x0312 ♫ \x0F\x02\x0313\x1D{topics:}\x0F\x02\x0312".format(topics=", ".join(topics))
msg = msg
msg = self.bot.emo(msg)
self.bot.privmsg(target,msg)
self.bot.history.push_user_messages(mask.nick.lower(),title)
#######################################################################################
#######################################################################################
@irc3.extend
def videos_list_by_id(self, id):
search_response = youtube.videos().list(part="id,snippet,statistics,topicDetails,contentDetails", id=id).execute()
for search_result in search_response.get("items", []):
if search_result["kind"] == "youtube#video":
return(search_result)
#######################################################################################
#######################################################################################
@command(permission='view', public=True, show_in_help_list=True)
def y(self, *args, **kwargs):
"""Search for youtube video
%%y <keyword>...
"""
return self.yt(*args)
#######################################################################################
#######################################################################################
@irc3.extend
@command(permission='view')
def yt(self, mask, target, args):
"""Search for youtube video
%%yt <keyword>...
"""
keyword = ' '.join(args['<keyword>'])
video = self.youtube_search(q=keyword)
if video:
video_id = video.get("id",{}).get("videoId")
video = video.get("snippet")
video_info = self.videos_list_by_id(id=video_id)
title = video_info.get("snippet",{}).get("title")
published_at = video_info.get("snippet",{}).get("publishedAt")
view_count = int(video_info.get("statistics").get("viewCount"))
if published_at:
published_at = dateutil.parser.parse(published_at)
published_at = timeago.format(published_at.replace(tzinfo=None), datetime.datetime.now())
try:
topics = video_info.get("topicDetails",{}).get("topicCategories")
topics[:] = [i.replace("https://en.wikipedia.org/wiki/", "").replace("_"," ").title() for i in topics]
except:
topics = []
duration = isodate.parse_duration(video_info.get("contentDetails").get("duration"))
url = "https://youtu.be/{}".format(video_id)
_nick = ""
try:
if len(self.bot.madjust) > 0:
_nick = self.bot.madjust
else:
_nick = mask.nick
except:
_nick = mask.nick
msg = "\x02\x0302{nick:}\x0F\x02\x0304 ▶▶ \x02\x0303\x1D\x1F{title:}\x0F".format(nick=_nick, title=title)
msg = msg + "\x02\x1D\x0304 ▶ \x0F\x1D\x0314Duration: \x0F\x1D{duration:} \x0F".format(duration=duration)
msg = msg + "\x0F\x1D\x0314Published: \x0F\x1D{published:} \x0F\x1D\x0314Views: \x0F\x1D{views:,}\x0F".format(published=published_at, views=view_count)
msg = msg + "\x0F\x02\x0312 ♫ \x0F\x02\x0313\x1D{topics:}\x0F\x02\x0312 ".format(topics=", ".join(topics))
msg = msg + url
msg = self.bot.emo(msg)
self.bot.privmsg(target, msg)
self.bot.history.push_user_messages(mask.nick.lower(),title)
#######################################################################################
#######################################################################################
###########################################################################################
###########################################################################################

20
requirements.txt Normal file
View File

@ -0,0 +1,20 @@
irc3
aiocron
timeago
isodate
google-api-python-client
oauth2client
aiohttp
asyncio
async_timeout
lxml
python-twitter
imgaug==0.2.7
folium==0.2.1
numpy==1.19.2
torch==1.9.1
transformers==2.3.0
googletrans==2.4.0
textblob==0.15.3
matplotlib==3.1.1
pyfiglet