Compare commits
4 Commits
cdb9f023e7
...
0ab4f38b9c
Author | SHA1 | Date |
---|---|---|
Derek | 0ab4f38b9c | |
Derek | 13750c5946 | |
Derek | 273ef7908c | |
Derek | 2c8b82868c |
1
Pipfile
1
Pipfile
|
@ -13,6 +13,7 @@ num2words = "*"
|
|||
pyaudio = "*"
|
||||
soundfile = "*"
|
||||
numpy = "*"
|
||||
pillow = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "ec8c647f9d261eaa99df3678f82e3ad988581a7f8722d31c01a5057f443c0826"
|
||||
"sha256": "ea641cba1add8b89dcbf9d467bc289fb4a29e8d6bceff2d9d7786be2a33365e8"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
|
@ -26,14 +26,23 @@
|
|||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813",
|
||||
"sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373",
|
||||
"sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69",
|
||||
"sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f",
|
||||
"sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06",
|
||||
"sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05",
|
||||
"sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea",
|
||||
"sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee",
|
||||
"sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0",
|
||||
"sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396",
|
||||
"sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7",
|
||||
"sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f",
|
||||
"sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73",
|
||||
"sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315",
|
||||
"sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76",
|
||||
"sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1",
|
||||
"sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49",
|
||||
"sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed",
|
||||
"sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892",
|
||||
"sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482",
|
||||
"sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058",
|
||||
|
@ -41,6 +50,7 @@
|
|||
"sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53",
|
||||
"sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045",
|
||||
"sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3",
|
||||
"sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55",
|
||||
"sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5",
|
||||
"sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e",
|
||||
"sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c",
|
||||
|
@ -58,8 +68,10 @@
|
|||
"sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e",
|
||||
"sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991",
|
||||
"sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6",
|
||||
"sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc",
|
||||
"sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1",
|
||||
"sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406",
|
||||
"sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333",
|
||||
"sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d",
|
||||
"sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"
|
||||
],
|
||||
|
@ -105,33 +117,72 @@
|
|||
},
|
||||
"numpy": {
|
||||
"hashes": [
|
||||
"sha256:2428b109306075d89d21135bdd6b785f132a1f5a3260c371cee1fae427e12727",
|
||||
"sha256:377751954da04d4a6950191b20539066b4e19e3b559d4695399c5e8e3e683bf6",
|
||||
"sha256:4703b9e937df83f5b6b7447ca5912b5f5f297aba45f91dbbbc63ff9278c7aa98",
|
||||
"sha256:471c0571d0895c68da309dacee4e95a0811d0a9f9f532a48dc1bea5f3b7ad2b7",
|
||||
"sha256:61d5b4cf73622e4d0c6b83408a16631b670fc045afd6540679aa35591a17fe6d",
|
||||
"sha256:6c915ee7dba1071554e70a3664a839fbc033e1d6528199d4621eeaaa5487ccd2",
|
||||
"sha256:6e51e417d9ae2e7848314994e6fc3832c9d426abce9328cf7571eefceb43e6c9",
|
||||
"sha256:719656636c48be22c23641859ff2419b27b6bdf844b36a2447cb39caceb00935",
|
||||
"sha256:780ae5284cb770ade51d4b4a7dce4faa554eb1d88a56d0e8b9f35fca9b0270ff",
|
||||
"sha256:878922bf5ad7550aa044aa9301d417e2d3ae50f0f577de92051d739ac6096cee",
|
||||
"sha256:924dc3f83de20437de95a73516f36e09918e9c9c18d5eac520062c49191025fb",
|
||||
"sha256:97ce8b8ace7d3b9288d88177e66ee75480fb79b9cf745e91ecfe65d91a856042",
|
||||
"sha256:9c0fab855ae790ca74b27e55240fe4f2a36a364a3f1ebcfd1fb5ac4088f1cec3",
|
||||
"sha256:9cab23439eb1ebfed1aaec9cd42b7dc50fc96d5cd3147da348d9161f0501ada5",
|
||||
"sha256:a8e6859913ec8eeef3dbe9aed3bf475347642d1cdd6217c30f28dee8903528e6",
|
||||
"sha256:aa046527c04688af680217fffac61eec2350ef3f3d7320c07fd33f5c6e7b4d5f",
|
||||
"sha256:abc81829c4039e7e4c30f7897938fa5d4916a09c2c7eb9b244b7a35ddc9656f4",
|
||||
"sha256:bad70051de2c50b1a6259a6df1daaafe8c480ca98132da98976d8591c412e737",
|
||||
"sha256:c73a7975d77f15f7f68dacfb2bca3d3f479f158313642e8ea9058eea06637931",
|
||||
"sha256:d15007f857d6995db15195217afdbddfcd203dfaa0ba6878a2f580eaf810ecd6",
|
||||
"sha256:d76061ae5cab49b83a8cf3feacefc2053fac672728802ac137dd8c4123397677",
|
||||
"sha256:e8e4fbbb7e7634f263c5b0150a629342cc19b47c5eba8d1cd4363ab3455ab576",
|
||||
"sha256:e9459f40244bb02b2f14f6af0cd0732791d72232bbb0dc4bab57ef88e75f6935",
|
||||
"sha256:edb1f041a9146dcf02cd7df7187db46ab524b9af2515f392f337c7cbbf5b52cd"
|
||||
"sha256:1676b0a292dd3c99e49305a16d7a9f42a4ab60ec522eac0d3dd20cdf362ac010",
|
||||
"sha256:16f221035e8bd19b9dc9a57159e38d2dd060b48e93e1d843c49cb370b0f415fd",
|
||||
"sha256:43909c8bb289c382170e0282158a38cf306a8ad2ff6dfadc447e90f9961bef43",
|
||||
"sha256:4e465afc3b96dbc80cf4a5273e5e2b1e3451286361b4af70ce1adb2984d392f9",
|
||||
"sha256:55b745fca0a5ab738647d0e4db099bd0a23279c32b31a783ad2ccea729e632df",
|
||||
"sha256:5d050e1e4bc9ddb8656d7b4f414557720ddcca23a5b88dd7cff65e847864c400",
|
||||
"sha256:637d827248f447e63585ca3f4a7d2dfaa882e094df6cfa177cc9cf9cd6cdf6d2",
|
||||
"sha256:6690080810f77485667bfbff4f69d717c3be25e5b11bb2073e76bb3f578d99b4",
|
||||
"sha256:66fbc6fed94a13b9801fb70b96ff30605ab0a123e775a5e7a26938b717c5d71a",
|
||||
"sha256:67d44acb72c31a97a3d5d33d103ab06d8ac20770e1c5ad81bdb3f0c086a56cf6",
|
||||
"sha256:6ca2b85a5997dabc38301a22ee43c82adcb53ff660b89ee88dded6b33687e1d8",
|
||||
"sha256:6e51534e78d14b4a009a062641f465cfaba4fdcb046c3ac0b1f61dd97c861b1b",
|
||||
"sha256:70eb5808127284c4e5c9e836208e09d685a7978b6a216db85960b1a112eeace8",
|
||||
"sha256:830b044f4e64a76ba71448fce6e604c0fc47a0e54d8f6467be23749ac2cbd2fb",
|
||||
"sha256:8b7bb4b9280da3b2856cb1fc425932f46fba609819ee1c62256f61799e6a51d2",
|
||||
"sha256:a9c65473ebc342715cb2d7926ff1e202c26376c0dcaaee85a1fd4b8d8c1d3b2f",
|
||||
"sha256:c1c09247ccea742525bdb5f4b5ceeacb34f95731647fe55774aa36557dbb5fa4",
|
||||
"sha256:c5bf0e132acf7557fc9bb8ded8b53bbbbea8892f3c9a1738205878ca9434206a",
|
||||
"sha256:db250fd3e90117e0312b611574cd1b3f78bec046783195075cbd7ba9c3d73f16",
|
||||
"sha256:e515c9a93aebe27166ec9593411c58494fa98e5fcc219e47260d9ab8a1cc7f9f",
|
||||
"sha256:e55185e51b18d788e49fe8305fd73ef4470596b33fc2c1ceb304566b99c71a69",
|
||||
"sha256:ea9cff01e75a956dbee133fa8e5b68f2f92175233de2f88de3a682dd94deda65",
|
||||
"sha256:f1452578d0516283c87608a5a5548b0cdde15b99650efdfd85182102ef7a7c17",
|
||||
"sha256:f39a995e47cb8649673cfa0579fbdd1cdd33ea497d1728a6cb194d6252268e48"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.20.2"
|
||||
"version": "==1.20.3"
|
||||
},
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:01425106e4e8cee195a411f729cff2a7d61813b0b11737c12bd5991f5f14bcd5",
|
||||
"sha256:031a6c88c77d08aab84fecc05c3cde8414cd6f8406f4d2b16fed1e97634cc8a4",
|
||||
"sha256:083781abd261bdabf090ad07bb69f8f5599943ddb539d64497ed021b2a67e5a9",
|
||||
"sha256:0d19d70ee7c2ba97631bae1e7d4725cdb2ecf238178096e8c82ee481e189168a",
|
||||
"sha256:0e04d61f0064b545b989126197930807c86bcbd4534d39168f4aa5fda39bb8f9",
|
||||
"sha256:12e5e7471f9b637762453da74e390e56cc43e486a88289995c1f4c1dc0bfe727",
|
||||
"sha256:22fd0f42ad15dfdde6c581347eaa4adb9a6fc4b865f90b23378aa7914895e120",
|
||||
"sha256:238c197fc275b475e87c1453b05b467d2d02c2915fdfdd4af126145ff2e4610c",
|
||||
"sha256:3b570f84a6161cf8865c4e08adf629441f56e32f180f7aa4ccbd2e0a5a02cba2",
|
||||
"sha256:463822e2f0d81459e113372a168f2ff59723e78528f91f0bd25680ac185cf797",
|
||||
"sha256:4d98abdd6b1e3bf1a1cbb14c3895226816e666749ac040c4e2554231068c639b",
|
||||
"sha256:5afe6b237a0b81bd54b53f835a153770802f164c5570bab5e005aad693dab87f",
|
||||
"sha256:5b70110acb39f3aff6b74cf09bb4169b167e2660dabc304c1e25b6555fa781ef",
|
||||
"sha256:5cbf3e3b1014dddc45496e8cf38b9f099c95a326275885199f427825c6522232",
|
||||
"sha256:624b977355cde8b065f6d51b98497d6cd5fbdd4f36405f7a8790e3376125e2bb",
|
||||
"sha256:63728564c1410d99e6d1ae8e3b810fe012bc440952168af0a2877e8ff5ab96b9",
|
||||
"sha256:66cc56579fd91f517290ab02c51e3a80f581aba45fd924fcdee01fa06e635812",
|
||||
"sha256:6c32cc3145928c4305d142ebec682419a6c0a8ce9e33db900027ddca1ec39178",
|
||||
"sha256:8bb1e155a74e1bfbacd84555ea62fa21c58e0b4e7e6b20e4447b8d07990ac78b",
|
||||
"sha256:95d5ef984eff897850f3a83883363da64aae1000e79cb3c321915468e8c6add5",
|
||||
"sha256:a013cbe25d20c2e0c4e85a9daf438f85121a4d0344ddc76e33fd7e3965d9af4b",
|
||||
"sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1",
|
||||
"sha256:a7d5e9fad90eff8f6f6106d3b98b553a88b6f976e51fce287192a5d2d5363713",
|
||||
"sha256:aac00e4bc94d1b7813fe882c28990c1bc2f9d0e1aa765a5f2b516e8a6a16a9e4",
|
||||
"sha256:b91c36492a4bbb1ee855b7d16fe51379e5f96b85692dc8210831fbb24c43e484",
|
||||
"sha256:c03c07ed32c5324939b19e36ae5f75c660c81461e312a41aea30acdd46f93a7c",
|
||||
"sha256:c5236606e8570542ed424849f7852a0ff0bce2c4c8d0ba05cc202a5a9c97dee9",
|
||||
"sha256:c6b39294464b03457f9064e98c124e09008b35a62e3189d3513e5148611c9388",
|
||||
"sha256:cb7a09e173903541fa888ba010c345893cd9fc1b5891aaf060f6ca77b6a3722d",
|
||||
"sha256:d68cb92c408261f806b15923834203f024110a2e2872ecb0bd2a110f89d3c602",
|
||||
"sha256:dc38f57d8f20f06dd7c3161c59ca2c86893632623f33a42d592f097b00f720a9",
|
||||
"sha256:e98eca29a05913e82177b3ba3d198b1728e164869c613d76d0de4bde6768a50e",
|
||||
"sha256:f217c3954ce5fd88303fc0c317af55d5e0204106d86dea17eb8205700d47dec2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==8.2.0"
|
||||
},
|
||||
"pyaudio": {
|
||||
"hashes": [
|
||||
|
@ -211,14 +262,6 @@
|
|||
"index": "pypi",
|
||||
"version": "==2.25.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
|
||||
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.15.0"
|
||||
},
|
||||
"soundfile": {
|
||||
"hashes": [
|
||||
"sha256:2d17e0a6fc2af0d6c1d868bafa5ec80aae6e186a97fec8db07ad6af29842fbc7",
|
||||
|
@ -248,11 +291,11 @@
|
|||
},
|
||||
"websocket-client": {
|
||||
"hashes": [
|
||||
"sha256:44b5df8f08c74c3d82d28100fdc81f4536809ce98a17f0757557813275fbb663",
|
||||
"sha256:63509b41d158ae5b7f67eb4ad20fecbb4eee99434e73e140354dc3ff8e09716f"
|
||||
"sha256:5051b38a2f4c27fbd7ca077ebb23ec6965a626ded5a95637f36be1b35b6c4f81",
|
||||
"sha256:57f876f1af4731cacb806cf54d02f5fbf75dee796053b9a5b94fd7c1d9621db9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.58.0"
|
||||
"version": "==1.0.0"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
|
|
|
@ -14,9 +14,10 @@ class LIFECYCLE_MESSAGES(Enum):
|
|||
|
||||
|
||||
class ChatProcess(Process, ABC):
|
||||
def __init__(self, event_poll_frequency):
|
||||
def __init__(self, event_poll_frequency, process_name):
|
||||
super().__init__()
|
||||
self._event_poll_frequency = event_poll_frequency
|
||||
self.__class__.__name__ = process_name
|
||||
|
||||
self._message_queue = Queue()
|
||||
self._pipe, self._caller_pipe = Pipe()
|
||||
|
|
|
@ -34,7 +34,7 @@ class Process(ChatProcess):
|
|||
running = not self.state == STATES.RUNNING
|
||||
text = 'Fake chat activated!' if running else 'Disabled fake chat'
|
||||
|
||||
sys_msg = Message(text, Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM)
|
||||
sys_msg = Message(text, Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM, self.__class__.__name__)
|
||||
self._message_queue.put(sys_msg)
|
||||
|
||||
return STATES.RUNNING if running else STATES.PAUSED
|
||||
|
@ -71,7 +71,7 @@ class Process(ChatProcess):
|
|||
'USRE VERY EXCITE POGGGG POG POGGGGGGGGGGGGGGGGGGGGGGGG POGPOGPOGGGG',
|
||||
'spaamamspmapmdpmaspmspsapmspmapsmpasmspmapmpasmspmapmspampsmpaspaspamapmspmapmspmapsmpamspamspmapsmpmaspmapmspamspmapsmpamspmpamspms',
|
||||
])
|
||||
fake_message = Message(text, author_name, author_id, author_type)
|
||||
fake_message = Message(text, author_name, author_id, author_type, self.__class__.__name__)
|
||||
self._message_queue.put(fake_message)
|
||||
|
||||
return random.random() * self._max_delay
|
||||
|
|
|
@ -3,13 +3,26 @@ import time
|
|||
from multiprocessing import Process, Pipe
|
||||
from enum import Enum, auto
|
||||
from traceback import format_exception
|
||||
import os
|
||||
import tempfile
|
||||
from itertools import chain, islice
|
||||
|
||||
import requests
|
||||
from miniirc import ircv3_message_parser
|
||||
from PIL import Image
|
||||
|
||||
from . import AUTHOR_TYPES, Message
|
||||
from .ChatProcess import ChatProcess
|
||||
|
||||
|
||||
def split_every(n, iterable):
|
||||
i = iter(iterable)
|
||||
piece = list(islice(i, n))
|
||||
while piece:
|
||||
yield piece
|
||||
piece = list(islice(i, n))
|
||||
|
||||
|
||||
class CONTROL_MESSAGES(Enum):
|
||||
RESTART = auto()
|
||||
|
||||
|
@ -82,6 +95,9 @@ class Process(ChatProcess):
|
|||
|
||||
self.state = STATES.CONNECTING
|
||||
|
||||
self._tmp = tempfile.TemporaryDirectory()
|
||||
self._emotes = {}
|
||||
|
||||
@property
|
||||
def keybinds(self):
|
||||
return {
|
||||
|
@ -99,7 +115,7 @@ class Process(ChatProcess):
|
|||
|
||||
message = status_messages.get(new_state)
|
||||
if message is not None:
|
||||
sys_msg = Message(message, Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM)
|
||||
sys_msg = Message(message, Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM, self.__class__.__name__)
|
||||
self._message_queue.put(sys_msg)
|
||||
|
||||
def on_connecting(self, next_state):
|
||||
|
@ -125,7 +141,7 @@ class Process(ChatProcess):
|
|||
for message in messages.splitlines():
|
||||
cmd, hostmask, tags, args = ircv3_message_parser(message)
|
||||
if cmd == 'PRIVMSG':
|
||||
normalized_message = Process.normalize_message(hostmask, tags, args)
|
||||
normalized_message = self.normalize_message(hostmask, tags, args)
|
||||
self._message_queue.put(normalized_message)
|
||||
elif cmd == 'USERNOTICE':
|
||||
normalized_message = Process.normalize_event(hostmask, tags, args)
|
||||
|
@ -150,24 +166,71 @@ class Process(ChatProcess):
|
|||
self._ws.terminate()
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def parse_badges(self, tags):
|
||||
if isinstance(tags.get('badges'), str):
|
||||
return [badge.split('/')[0] for badge in tags['badges'].split(',')]
|
||||
else:
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def parse_message(self, args):
|
||||
# First arg is the room (which we dont care about, since it should only ever be #user)
|
||||
# First character of the second arg is the data delimiter (:)
|
||||
return ' '.join(args[1:])[1:]
|
||||
|
||||
@classmethod
|
||||
def normalize_message(cls, hostmask, tags, args):
|
||||
# TODO: Amongus dum poster on model forhead please and yes thank
|
||||
def parse_emotes(self, message, tags):
|
||||
raw_emotes = tags.get('emotes')
|
||||
if not isinstance(raw_emotes, str):
|
||||
return message, []
|
||||
|
||||
badges = Process.parse_badges(tags)
|
||||
message = Process.parse_message(args)
|
||||
points_where_we_put_the_delimiters = []
|
||||
emotes_used = []
|
||||
|
||||
for emote in raw_emotes.split('/'):
|
||||
emote_id, indexesisis = emote.split(':')
|
||||
|
||||
usages = [[int(index) for index in usage.split('-')] for usage in indexesisis.split(',')]
|
||||
emote_name = message[usages[0][0]:usages[0][1] + 1].replace(':', '_')
|
||||
|
||||
points_where_we_put_the_delimiters.extend(chain.from_iterable(usages))
|
||||
emotes_used.append(emote_name)
|
||||
|
||||
if self._emotes.get(emote_name) is not None:
|
||||
continue
|
||||
|
||||
response = requests.get(f'http://static-cdn.jtvnw.net/emoticons/v1/{emote_id}/2.0', stream=True)
|
||||
response.raise_for_status()
|
||||
|
||||
filename = os.path.join(self._tmp.name, emote_id + '.png')
|
||||
Image.open(response.raw).convert(mode='RGBA').save(filename)
|
||||
# with open(filename, 'wb') as f:
|
||||
# f.write(response.content)
|
||||
|
||||
self._emotes[emote_name] = filename
|
||||
|
||||
slice = []
|
||||
indecies = list(split_every(2, sorted(points_where_we_put_the_delimiters)))
|
||||
for index in range(len(indecies)):
|
||||
start, end = indecies[index]
|
||||
next_item = indecies[index + 1] if index + 1 < len(indecies) else None
|
||||
|
||||
if index == 0:
|
||||
slice.append(message[:start])
|
||||
|
||||
slice.append(message[start:end + 1].replace(':', '_'))
|
||||
|
||||
if next_item:
|
||||
slice.append(message[end + 1:next_item[0]])
|
||||
else:
|
||||
slice.append(message[end + 1:])
|
||||
|
||||
return ':'.join(slice), emotes_used
|
||||
|
||||
def normalize_message(self, hostmask, tags, args):
|
||||
badges = self.parse_badges(tags)
|
||||
message = self.parse_message(args)
|
||||
message, emotes_used = self.parse_emotes(message, tags)
|
||||
emote_map = {emote_name: self._emotes[emote_name] for emote_name in emotes_used} if len(emotes_used) else None
|
||||
|
||||
bits = tags.get('bits')
|
||||
if bits:
|
||||
|
@ -186,13 +249,12 @@ class Process(ChatProcess):
|
|||
|
||||
author_color = tags['color'] if isinstance(tags.get('color'), str) else None
|
||||
|
||||
return Message(message, tags.get('display-name', hostmask[0]), tags.get('user-id'), author_type,
|
||||
author_color=author_color, monitization=monitization)
|
||||
return Message(message, tags.get('display-name', hostmask[0]), tags.get('user-id'), author_type, self.__class__.__name__,
|
||||
author_color=author_color, monitization=monitization, emotes=emote_map)
|
||||
|
||||
@classmethod
|
||||
def normalize_event(cls, hostmask, tags, args):
|
||||
badges = Process.parse_badges(tags)
|
||||
user_message = Process.parse_message(args)
|
||||
def normalize_event(self, hostmask, tags, args):
|
||||
badges = self.parse_badges(tags)
|
||||
user_message = self.parse_message(args)
|
||||
|
||||
message = f"*{tags['system-msg'].strip()}*"
|
||||
if user_message != '':
|
||||
|
@ -211,5 +273,5 @@ class Process(ChatProcess):
|
|||
|
||||
event = EVENTS.__members__[tags['msg-id'].upper()]
|
||||
|
||||
return Message(message, tags.get('display-name', hostmask[0]), tags.get('user-id'), author_type,
|
||||
return Message(message, tags.get('display-name', hostmask[0]), tags.get('user-id'), author_type, self.__class__.__name__,
|
||||
author_color=author_color, for_event=event)
|
||||
|
|
|
@ -113,7 +113,7 @@ class Process(ChatProcess):
|
|||
self._page_token = data['nextPageToken']
|
||||
if len(data['items']):
|
||||
for message in data['items']:
|
||||
normalized = Process.normalize_message(message)
|
||||
normalized = self.normalize_message(message)
|
||||
self._message_queue.put(normalized)
|
||||
|
||||
sleep_milis = max(data['pollingIntervalMillis'], 5000)
|
||||
|
@ -132,7 +132,7 @@ class Process(ChatProcess):
|
|||
|
||||
message = status_messages.get(new_state)
|
||||
if message is not None:
|
||||
sys_msg = Message(message, Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM)
|
||||
sys_msg = Message(message, Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM, self.__class__.__name__)
|
||||
self._message_queue.put(sys_msg)
|
||||
|
||||
def process_messages(self, message_type, args, next_state):
|
||||
|
@ -142,14 +142,15 @@ class Process(ChatProcess):
|
|||
elif message_type == CONTROL_MESSAGES.RESTART:
|
||||
if self.state == STATES.POLLING:
|
||||
self._message_queue.put(Message('Restart requested, but service is in healthy state! Ignoring...',
|
||||
Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM))
|
||||
Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM,
|
||||
self.__class__.__name__))
|
||||
else:
|
||||
self._message_queue.put(Message('Restarting service...',
|
||||
Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM))
|
||||
Process.CHAT_NAME, self.__class__.__name__, AUTHOR_TYPES.SYSTEM,
|
||||
self.__class__.__name__))
|
||||
return None, None
|
||||
|
||||
@classmethod
|
||||
def normalize_message(cls, message):
|
||||
def normalize_message(self, message):
|
||||
if message['authorDetails']['isChatOwner']:
|
||||
author_type = AUTHOR_TYPES.OWNER
|
||||
elif message['authorDetails']['isChatModerator']:
|
||||
|
@ -162,7 +163,7 @@ class Process(ChatProcess):
|
|||
text = message['snippet']['displayMessage']
|
||||
author_name = message['authorDetails']['displayName']
|
||||
author_id = message['authorDetails']['channelId']
|
||||
return Message(text, author_name, author_id, author_type)
|
||||
return Message(text, author_name, author_id, author_type, self.__class__.__name__)
|
||||
|
||||
def request_oauth_consent(self):
|
||||
params = {
|
||||
|
|
|
@ -11,17 +11,19 @@ class AUTHOR_TYPES(Enum):
|
|||
|
||||
|
||||
class Message:
|
||||
def __init__(self, text, author_name, author_id, author_type,
|
||||
author_color=None, monitization=None, for_event=None):
|
||||
def __init__(self, text, author_name, author_id, author_type, via,
|
||||
author_color=None, monitization=None, for_event=None, emotes=None):
|
||||
self.text = text
|
||||
self.author_name = author_name
|
||||
self.author_id = author_id
|
||||
if not isinstance(author_type, AUTHOR_TYPES):
|
||||
raise ValueError('author_type must be an instance of AUTHOR_TYPES enum')
|
||||
self.author_type = author_type
|
||||
self.via = via
|
||||
self.author_color = author_color
|
||||
self.monitization_local, self.monitization = monitization or (None, None)
|
||||
self.for_event = for_event
|
||||
self.emotes = emotes
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.author_name} - \"{self.text}\" : author_type = {self.author_type}, monitization = {self.monitization}, for_event = {self.for_event}"
|
||||
|
|
14
main.py
14
main.py
|
@ -15,7 +15,7 @@ if __name__ == '__main__':
|
|||
EVENT_POLL_FREQUENCY = config['event_poll_frequency']
|
||||
|
||||
# Load dynamic compoents
|
||||
chat_processes = []
|
||||
chat_processes = {}
|
||||
for chat_name, chat_config in config.get('chat', {}).items():
|
||||
if not chat_config['enabled']:
|
||||
continue
|
||||
|
@ -23,12 +23,12 @@ if __name__ == '__main__':
|
|||
|
||||
chat_module = importlib.import_module(f'.{chat_name}', package='chats')
|
||||
try:
|
||||
chat_process = chat_module.Process(EVENT_POLL_FREQUENCY, **chat_config)
|
||||
chat_processes.append(chat_process)
|
||||
chat_process = chat_module.Process(EVENT_POLL_FREQUENCY, chat_name, **chat_config)
|
||||
chat_processes[chat_name] = chat_process
|
||||
except Exception as e:
|
||||
print(f'Failed to initalize {chat_name} - {e}')
|
||||
|
||||
if len(chat_processes) == 0:
|
||||
if len(chat_processes.keys()) == 0:
|
||||
print('No chats configured!')
|
||||
|
||||
plugins = []
|
||||
|
@ -45,7 +45,7 @@ if __name__ == '__main__':
|
|||
# Start the app and subprocesses
|
||||
app = App(chat_processes, plugins)
|
||||
|
||||
for process in chat_processes:
|
||||
for process in chat_processes.values():
|
||||
process.start()
|
||||
app.start()
|
||||
|
||||
|
@ -54,7 +54,7 @@ if __name__ == '__main__':
|
|||
if not app.is_alive():
|
||||
break
|
||||
|
||||
for process in chat_processes:
|
||||
for process in chat_processes.values():
|
||||
# HACK: need to find a generic way to do this
|
||||
if process.control_pipe.poll():
|
||||
chat_control_msg = process.control_pipe.recv()
|
||||
|
@ -67,7 +67,7 @@ if __name__ == '__main__':
|
|||
time.sleep(EVENT_POLL_FREQUENCY)
|
||||
|
||||
# Cleanup
|
||||
for process in chat_processes:
|
||||
for process in chat_processes.values():
|
||||
process.control_pipe.send({'type': LIFECYCLE_MESSAGES.SHUTDOWN})
|
||||
process.join(10)
|
||||
if process.exitcode is None:
|
||||
|
|
|
@ -49,7 +49,7 @@ class Plugin(PluginBase):
|
|||
if not (message.monitization is not None and message.monitization == float(criterion['monitization'])):
|
||||
continue
|
||||
if criterion.get('regex'):
|
||||
if re.search(criterion['regex'], message.text) is None:
|
||||
if re.search(criterion['regex'], message.text, flags=re.IGNORECASE) is None:
|
||||
continue
|
||||
return True
|
||||
|
||||
|
|
|
@ -38,13 +38,13 @@ class App(Process):
|
|||
if event.type == pygame.QUIT:
|
||||
self._running = False
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
for process in self._chat_processes:
|
||||
for process in self._chat_processes.values():
|
||||
bound_action = process.keybinds.get(event.key)
|
||||
if bound_action is not None:
|
||||
process.control_pipe.send(bound_action)
|
||||
|
||||
def tick(self, dt):
|
||||
for process in self._chat_processes:
|
||||
for process in self._chat_processes.values():
|
||||
if not process.message_queue.empty():
|
||||
message = process.message_queue.get()
|
||||
for plugin in self._plugins:
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import pygame.image
|
||||
|
||||
|
||||
class ImageFragment:
|
||||
def __init__(self, filepath):
|
||||
self._image = pygame.image.load(filepath)
|
||||
|
||||
@property
|
||||
def rect(self):
|
||||
return self._image.get_rect()
|
||||
|
||||
def tick(self, dt):
|
||||
pass
|
||||
|
||||
def draw(self):
|
||||
return self._image.convert_alpha()
|
|
@ -9,8 +9,10 @@ from chats import AUTHOR_TYPES
|
|||
|
||||
from . import BG_COLOR, XTERM_COLORS
|
||||
from .TextFragment import TextFragment
|
||||
from .ImageFragment import ImageFragment
|
||||
|
||||
hex_color_regex = re.compile('^#[a-fA-F0-9]{6}$')
|
||||
emote_regex = re.compile(':([A-z0-9]+):')
|
||||
|
||||
|
||||
def closest_xterm(target_color):
|
||||
|
@ -21,7 +23,7 @@ def closest_xterm(target_color):
|
|||
xr, xg, xb = xterm_color
|
||||
distance = math.sqrt(abs(r - xr) ** 2 + abs(g - xg) ** 2 + abs(b - xb) ** 2)
|
||||
if distance == 0:
|
||||
return xterm_color
|
||||
return index
|
||||
distances.append((distance, index))
|
||||
return min(distances)[1]
|
||||
|
||||
|
@ -70,19 +72,35 @@ class MessageView:
|
|||
|
||||
# TODO: Handle icons, emoji with special fragment
|
||||
fragments = list(TextFragment.from_unwrapped(f'[ {author_name} ]', tag_fg, tag_bg, screen_width))
|
||||
fragments.extend(
|
||||
TextFragment.from_unwrapped(text, text_fg, text_bg, screen_width, first_line_offset=fragments[-1].rect.width)
|
||||
)
|
||||
|
||||
offset_x = fragments[-1].rect.width
|
||||
for index, text_or_emote in enumerate(emote_regex.split(text)):
|
||||
if index % 2 == 0:
|
||||
if text_or_emote == '':
|
||||
continue
|
||||
fragments.extend(
|
||||
TextFragment.from_unwrapped(text_or_emote.strip(), text_fg, text_bg, screen_width, first_line_offset=offset_x)
|
||||
)
|
||||
offset_x = fragments[-1].rect.width
|
||||
else:
|
||||
img_fragment = ImageFragment(message.emotes[text_or_emote])
|
||||
offset_x += img_fragment.rect.width
|
||||
fragments.append(img_fragment)
|
||||
|
||||
if offset_x > self.screen_size[0]:
|
||||
offset_x = 0
|
||||
|
||||
return fragments
|
||||
|
||||
def layout_fragments(self):
|
||||
offset_x, offset_y = 0, 0
|
||||
offset_x, offset_y, max_y = 0, 0, 0
|
||||
for fragment in self._fragments:
|
||||
max_y = max(max_y, fragment.rect.height)
|
||||
if offset_x + fragment.rect.width > self.screen_size[0]:
|
||||
offset_y += fragment.rect.height
|
||||
offset_y += max_y
|
||||
yield 0, offset_y, fragment
|
||||
offset_x = fragment.rect.width + self._padding[0]
|
||||
max_y = 0
|
||||
else:
|
||||
yield offset_x, offset_y, fragment
|
||||
offset_x += fragment.rect.width + self._padding[0]
|
||||
|
|
Loading…
Reference in New Issue