Compare commits

...

4 Commits

6 changed files with 253 additions and 263 deletions

View File

@ -6,9 +6,8 @@ name = "pypi"
[packages]
requests = "*"
pygame = "*"
[dev-packages]
python-language-server = {extras = ["all"], version = "*"}
websocket-client = "*"
miniirc = "*"
[requires]
python_version = "3.9"

326
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "659dc7baae3e246c60460dd8167ae448e6980ede9ccb2b10b2d6e0b995d73eeb"
"sha256": "c6f4727f4fbf44c5155fd9276c2a575224bd4ce1914e7051b84c01dea7168336"
},
"pipfile-spec": 6,
"requires": {
@ -18,17 +18,18 @@
"default": {
"certifi": {
"hashes": [
"sha256:1f422849db327d534e3d0c5f02a263458c3955ec0aae4ff09b95f195c59f4edd",
"sha256:f05def092c44fbf25834a51509ef6e631dc19765ab8a57b4e7ab85531f0a9cf4"
"sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c",
"sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"
],
"version": "==2020.11.8"
"version": "==2020.12.5"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
"sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa",
"sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"
],
"version": "==3.0.4"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==4.0.0"
},
"idna": {
"hashes": [
@ -38,209 +39,68 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.10"
},
"pygame": {
"miniirc": {
"hashes": [
"sha256:00268b75204519628760030d256b17e557710a859fadf7cbf80ead80efc22779",
"sha256:0ba624e8cc2056f0c8f7f819f2564284bb675dd9a8097e03762763a63f99e1b3",
"sha256:0fa2dfa9daacaa5533ab733c0fd038e319b83d685f92e986fe3233dd06e508e4",
"sha256:19b66c7546261996e2533b922f78b04edc1901586d6e023af7ec0aef4d6d4a9f",
"sha256:1bc6e76e31e7ce6b734f12a06d975af2ef29da93e5ccbecbc8ed2d38d1bea8ea",
"sha256:208fbc0f25a641b953c7ec1c537a3c0b43a4faf6a8f303be15d02e308c671bab",
"sha256:21f4e50c1f13e143c590a48e63644ed2d0cfb50f9ce699c5e8b7af7caaa5cbe3",
"sha256:2c2475f706e49b4a67d6958e5cce1157f3875083eba92ab298bdf7ba33780524",
"sha256:3a2e7a0e6377224d3956ac9791382f7baadf66957679be8a9cc493f488245584",
"sha256:3d0be0275b1d4939c9c9074d879407f330cbac0c837cd0f4b24ab0377959f6da",
"sha256:411fa087a21f065d720d199b848652bf02d61cb39ff4d62745be37257fd84361",
"sha256:4e58cc6f47412cf441a0c9b98dcb8141e1f2cdb6bbd0b00d1b89572d54195002",
"sha256:5450704eab972951cce02231e21dbbdffcf7e7c569cfb8d26346e2b18197ae0f",
"sha256:579d2162591241dc98c80c796576bb93edbd8107a8a43e13a18bf3c9c0dfb446",
"sha256:5a3f0f436174e95027c60a37f06d84d25d2275de3255fe85846baa47c0e36e6b",
"sha256:5ed4b00612b11c1ebbfbff1379616de2fa4d1acd9830232cc9a4a2ac2aa55e84",
"sha256:63b038da116a643046181b02173fd894d87d2f85ecfd6aa7d5ece73c6ef501e9",
"sha256:697599838b559b9f6573c3064357b404d3fd7af145168e2f4e3ed551bc4400ec",
"sha256:69f9452365eef5ef476eca2657dcc488d8f93423a2f6e80e6dc5ada9fa813d21",
"sha256:6bd16df20e5b9bc82a4dae7342573a7917530c2e4713c576f2684ebc79a9aa73",
"sha256:6f5b10de20a6d6a4c84371fd55d25038ef3fa3ceb1a20a61bcab1b1f2459a115",
"sha256:7c228e067b5e212acc2ee1412e2cf29f5900fd290b09556014aee74665ffaded",
"sha256:7ee08691262b1a22dfd28b9b0e126cfc0276b349ddfd7ef8964a0e54d000ab0e",
"sha256:87795c07c1de05150759b52e7bc3ccb38e76148ae8e40f07bf2b1368e7fabf0e",
"sha256:8a240f598c21a4d2218eaeccfdd77bf0d0f6789133a154b07667285157b95ffa",
"sha256:9d10a197518f8b50d3a61b923762a37063b9d6e27d1abe5167bb3a762e816833",
"sha256:a03f0357ad4a9daf6e70b239804b77088d0b1543fc32e672f97f38e35fb1c206",
"sha256:a7d298ebc7239dcf98e093b3510abc5279c8c7c149c60d2a8a81a1b44a671da3",
"sha256:abed99f21c11d7f8deb0b3a41e2e4b0d00a98c17c23edd4dd344f169b317a586",
"sha256:b5ac39ef5453252cb4b4ce2956ad9832688476a7a99bbdee1a7e17bf40e0a11f",
"sha256:c2aea8cfa8156016d5316a601e804e8eacc77facd550d6bff893130f8f506a45",
"sha256:cb6dda696df8326eebf8514aa7d6e18977d37822241d8661069ca42a45f957d6",
"sha256:d1b9279133bb9f1ff5e7f5369a7a25749279724f64428980f6cec58eb7ce18da",
"sha256:d700ffe744efde7eba1709950066429bdd21e9eec2288e29d39c3a9f21a04a7c",
"sha256:d768ff1f2dd3de84585a68b491821badc35b2c9c4453c6cbcf48949be99ea781",
"sha256:db05ce075aed6a9ac6b5613f273eb134a643a7b910ded4f6395b09a7f24edacf",
"sha256:dc7cbfc0a0a0f1f8b1be4dbf0788a4ac7d3dd2991067e1cfd869c65c323a24a5",
"sha256:e21e68b1110bea64ed1dee6e644b49423f9539fb3e29d27ca6c68011f999c8f9",
"sha256:e716b3a5ca469959ad0d631cbb7846386741fc056968a3abb097ba5b43757214",
"sha256:e75fe7624d2fc03b93a706f4d8f8204cb9c83c8f16245553546b3bd0a733556c",
"sha256:e8effa8b5a8d2bb9c07dccb18337b07174d4956516978a35350bc23e254189cc"
"sha256:3734fde677785fd1f735a1710b94b93643f6ecd769b8b41c084ef42515a70c47",
"sha256:7be5d125b02275508b65421de91af6a2e3efeac0f5b7708454ddd2cbac9a5250"
],
"index": "pypi",
"version": "==2.0.0"
"version": "==1.6.3"
},
"pygame": {
"hashes": [
"sha256:0571dde0277483f5060c8ee43cbfd8df5776b12505e3948eee241c8ce9b93371",
"sha256:07ed57062be4bb9741f57dab1751d95574c091c9958ed7e39cdb246d50903283",
"sha256:107d5f82f471baee4b9522a691cb320dd52dbf329ed7a0e9ab25f75cd3caf890",
"sha256:10ca736eecedadf492ba1191f9fa3a5e6f30db2b9f8882b3ee7706d5a89c14e0",
"sha256:19357c826ab94f9ae5b4ec5cb752cc806cfc29ea32cf7bdaacb65fa2615607e8",
"sha256:21475405bcdeb20b8a796a3da6704ebb816e06b29749dd64ff619e80816b7932",
"sha256:2d9b0a66034fed390ee367a549435853502c9d4fe82ac0fa3a520f0ad5648e6e",
"sha256:30eb5c7adb0b3362024cec2c461be6978fbfc99c3bca974e438b1b540cd09438",
"sha256:3270cbcff40ca2b5622a145346298a33285c91b6d50097e0b85123d9a2bc7c9b",
"sha256:328d70d40bc9a6defb9f330f5e7f3d0726af1e7c2308ebca582e69480db2950d",
"sha256:3b31d088129977885f72037c55cfa1140e9bcf3468e68b46141f6cc2b33d456b",
"sha256:3c2676b4fd278d632037eacd3b0524ce1a592c048e8e5eb5830475f83585cb3a",
"sha256:44f3ff8224d7cb998642400371c685005c8316b55e87794cbf1f6407b88ec424",
"sha256:49c2f58559c1fbf4ba258e4b141578ccb0e83da3d4f823894f6171a8f0d594ed",
"sha256:4d3135a1f8c76c3fff1ef8b7a51e4c6523748e9bdbd7bca6daa69790ce0e798a",
"sha256:4f41252dfa1e8bb95f2ea51fba710827dde9820a535623d002a65621bafe7e3f",
"sha256:5aeeb6659a7fe7760a78e449566553ae8c949ae29dd907a8eb4171fa0a274c16",
"sha256:5afc34f0af0cec09a20b6bb09090054fac5169ab01909e01b06e7e0752ab0153",
"sha256:5f057e5aa4c383fcf18560dcae2c5593e37e3fc941083a0a00a17f7cf25ee522",
"sha256:72625dc949c6d08ba7ce7c37a33163bb498d90ca0d7e626db3cfbf486df4db1d",
"sha256:7ea518d8eeb072c77c16977cdee3c59d9fffa750ed9c7c9c533ba520b6b08af7",
"sha256:81510ffb1c31a3827c6be047b1926d81caf36dc734564ca0e14903d6bce60c6f",
"sha256:845385caf99f8d941607791c60e560d24b4a35c70eef0b01c30cfde0b913ff92",
"sha256:898874521a9be1f9dbc5b036a9755803287c2664e335afd3e10963f7f4ccb853",
"sha256:8b1e7b63f47aafcdd8849933b206778747ef1802bd3d526aca45ed77141e4001",
"sha256:9aead3f2eed90260136b201f398965900c5335c974bb7b47c381d98e39284018",
"sha256:9de559462aaa68c40bb7625dcd587584b4eb85c4208528dc97b9ee7254945294",
"sha256:9f48277de1daa83fd58a722b2e3423201b5eb39842227f32702fb78e4bba5a71",
"sha256:9fd0691c4fe58b932674bb6a91d2808790e8269c3183ef16052f13e1c602ac00",
"sha256:a4e35d89b6754941e82df1ce980a1c370943d3c076938d94ed1e48165dd6a11b",
"sha256:ad230911d61f448c09886d3c92b2eae44ca7530babe9c48e74e02a0622ce2d34",
"sha256:b812285d23b5644c643a6ae30553a772f935f47f61826660b108b8727936384b",
"sha256:bf833c853a0568738ee5d88e1345c17bf3e8db626c36fb895327a35bb1827b0b",
"sha256:c188ce4bf1544f2758e8b651f4349a0f3dc441e09d8ab7c4863db1ae8f084a32",
"sha256:d8059084ce54b2c3d7b2c8bacd5f6490db849b2d2d6e7368c160b08504c87e73",
"sha256:e72cdc97a49509ca2298350c2c3a0ac26bc8e943ce003a7d245df42e91439d5d",
"sha256:eab18df58dcc8512f1b694f7218146828d7e3dd3f4e73bfd6942a11810293fd5",
"sha256:ece424c83a575c2e0ba25815871458d3bbade46d76b7997236fb51a0251229ab",
"sha256:ed80b40da839d60f4c03915bb3638e3c96ea8c30e689d0cc309b7597d82cc217",
"sha256:fd5ee0f42d59a290c049f91894e0739f62c2908e7edc028ffb847a105e68bfc3",
"sha256:fd6acd09d2a0fd3f616b18f977f399ed3dd95e2d6754f115837f026d19d62e10"
],
"index": "pypi",
"version": "==2.0.1"
},
"requests": {
"hashes": [
"sha256:7f1a0b932f4a60a1a65caa4263921bb7d9ee911957e0ae4a23a6dd08185ad5f8",
"sha256:e786fa28d8c9154e6a4de5d46a1d921b8749f8b74e28bde23768e5e16eece998"
"sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804",
"sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"
],
"index": "pypi",
"version": "==2.25.0"
},
"urllib3": {
"hashes": [
"sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08",
"sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.2"
}
},
"develop": {
"astroid": {
"hashes": [
"sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703",
"sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"
],
"markers": "python_version >= '3.5'",
"version": "==2.4.2"
},
"autopep8": {
"hashes": [
"sha256:d21d3901cb0da6ebd1e83fc9b0dfbde8b46afc2ede4fe32fbda0c7c6118ca094"
],
"version": "==1.5.4"
},
"flake8": {
"hashes": [
"sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839",
"sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"
],
"version": "==3.8.4"
},
"isort": {
"hashes": [
"sha256:dcab1d98b469a12a1a624ead220584391648790275560e1a43e54c5dceae65e7",
"sha256:dcaeec1b5f0eca77faea2a35ab790b4f3680ff75590bfcb7145986905aab2f58"
],
"markers": "python_version >= '3.6' and python_version < '4.0'",
"version": "==5.6.4"
},
"jedi": {
"hashes": [
"sha256:86ed7d9b750603e4ba582ea8edc678657fb4007894a12bcf6f4bb97892f31d20",
"sha256:98cc583fa0f2f8304968199b01b6b4b94f469a1f4a74c1560506ca2a211378b5"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
"version": "==0.17.2"
},
"lazy-object-proxy": {
"hashes": [
"sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d",
"sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449",
"sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08",
"sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a",
"sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50",
"sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd",
"sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239",
"sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb",
"sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea",
"sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e",
"sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156",
"sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142",
"sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442",
"sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62",
"sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db",
"sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531",
"sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383",
"sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a",
"sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357",
"sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4",
"sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.4.3"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"parso": {
"hashes": [
"sha256:97218d9159b2520ff45eb78028ba8b50d2bc61dcc062a9682666f2dc4bd331ea",
"sha256:caba44724b994a8a5e086460bb212abc5a8bc46951bf4a9a1210745953622eb9"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.7.1"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.13.1"
},
"pycodestyle": {
"hashes": [
"sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
"sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
],
"version": "==2.6.0"
},
"pydocstyle": {
"hashes": [
"sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325",
"sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"
],
"version": "==5.1.1"
},
"pyflakes": {
"hashes": [
"sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
"sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
],
"version": "==2.2.0"
},
"pylint": {
"hashes": [
"sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210",
"sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"
],
"version": "==2.6.0"
},
"python-jsonrpc-server": {
"hashes": [
"sha256:62c543e541f101ec5b57dc654efc212d2c2e3ea47ff6f54b2e7dcb36ecf20595",
"sha256:e5a908ff182e620aac07db5f57887eeb0afe33993008f57dc1b85b594cea250c"
],
"version": "==0.4.0"
},
"python-language-server": {
"extras": [
"all"
],
"hashes": [
"sha256:0c672aec88fa73f47c36aa4d0b7717868b316a1398d3fb73554955675ce54bae",
"sha256:c85d718ef6860319ad59fd6f2acb1166e9349b782ee8e8908e08ecf241615f52"
],
"index": "pypi",
"version": "==0.36.1"
},
"rope": {
"hashes": [
"sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04"
],
"version": "==0.18.0"
"version": "==2.25.1"
},
"six": {
"hashes": [
@ -250,60 +110,22 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.15.0"
},
"snowballstemmer": {
"urllib3": {
"hashes": [
"sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
"sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
"sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df",
"sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"
],
"version": "==2.0.0"
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'",
"version": "==1.26.4"
},
"toml": {
"websocket-client": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
"sha256:44b5df8f08c74c3d82d28100fdc81f4536809ce98a17f0757557813275fbb663",
"sha256:63509b41d158ae5b7f67eb4ad20fecbb4eee99434e73e140354dc3ff8e09716f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"ujson": {
"hashes": [
"sha256:078808c385036cba73cad96f498310c61e9b5ae5ac9ea01e7c3996ece544b556",
"sha256:0a2e1b211714eb1ec0772a013ec9967f8f95f21c84e8f46382e9f8a32ae781fe",
"sha256:0f412c3f59b1ab0f40018235224ca0cf29232d0201ff5085618565a8a9c810ed",
"sha256:26cf6241b36ff5ce4539ae687b6b02673109c5e3efc96148806a7873eaa229d3",
"sha256:2b2d9264ac76aeb11f590f7a1ccff0689ba1313adacbb6d38d3b15f21a392897",
"sha256:4f12b0b4e235b35d49f15227b0a827e614c52dda903c58a8f5523936c233dfc7",
"sha256:4fe8c6112b732cba5a722f7cbe22f18d405f6f44415794a5b46473a477635233",
"sha256:51480048373cf97a6b97fcd70c3586ca0a31f27e22ab680fb14c1f22bedbf743",
"sha256:568bb3e7f035006147af4ce3a9ced7d126c92e1a8607c7b2266007b1c1162c53",
"sha256:5fe1536465b1c86e32a47113abd3178001b7c2dcd61f95f336fe2febf4661e74",
"sha256:71703a269f074ff65b9d7746662e4b3e76a4af443e532218af1e8ce15d9b1e7b",
"sha256:7a1545ac2476db4cc1f0f236603ccbb50991fc1bba480cda1bc06348cc2a2bf0",
"sha256:a5200a68f1dcf3ce275e1cefbcfa3914b70c2b5e2f71c2e31556aa1f7244c845",
"sha256:a618af22407baeadb3f046f81e7a5ee5e9f8b0b716d2b564f92276a54d26a823",
"sha256:a79bca47eafb31c74b38e68623bc9b2bb930cb48fab1af31c8f2cb68cf473421",
"sha256:b87379a3f8046d6d111762d81f3384bf38ab24b1535c841fe867a4a097d84523",
"sha256:bd4c77aee3ffb920e2dbc21a9e0c7945a400557ce671cfd57dbd569f5ebc619d",
"sha256:c354c1617b0a4378b6279d0cd511b769500cf3fa7c42e8e004cbbbb6b4c2a875",
"sha256:c604024bd853b5df6be7d933e934da8dd139e6159564db7c55b92a9937678093",
"sha256:e7ab24942b2d57920d75b817b8eead293026db003247e26f99506bdad86c61b4",
"sha256:f8a60928737a9a47e692fcd661ef2b5d75ba22c7c930025bd95e338f2a6e15bc"
],
"markers": "python_version >= '3.1'",
"version": "==4.0.1"
},
"wrapt": {
"hashes": [
"sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"
],
"version": "==1.12.1"
},
"yapf": {
"hashes": [
"sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427",
"sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"
],
"version": "==0.30.0"
"index": "pypi",
"version": "==0.58.0"
}
}
},
"develop": {}
}

View File

@ -1,6 +1,6 @@
from abc import ABC, abstractmethod
from multiprocessing import Process, Pipe, Queue
from aenum import Enum, auto
from enum import Enum, auto
from traceback import format_exception
import time
@ -40,10 +40,6 @@ class ChatProcess(Process, ABC):
def control_pipe(self):
return self._caller_pipe
@property
def deamon(self):
return True
@property
def state(self):
pass

142
chats/Twitch.py Normal file
View File

@ -0,0 +1,142 @@
import websocket
from multiprocessing import Process, Pipe
from enum import Enum, auto
from traceback import format_exception
from miniirc import ircv3_message_parser
from . import AUTHOR_TYPES
from .ChatProcess import ChatProcess
class CONTROL_MESSAGES(Enum):
RESTART = auto()
class STATES(Enum):
DISCONNECTED = auto()
READING = auto()
FAILURE = auto()
class NonBlockingWebsocket(Process):
def __init__(self):
super().__init__()
self._ws = websocket.WebSocket()
self._pipe, self._caller_pipe = Pipe()
def send(self, data):
return self._ws.send(data)
def poll(self, *args):
return self._caller_pipe.poll(*args)
def recv(self, *args):
return self._caller_pipe.recv(*args)
def connect(self, *args):
self._ws.connect(*args)
def run(self):
try:
while self.is_alive():
data = self._ws.recv()
self._pipe.send(data)
except Exception as e:
print(f'Failure in {self.__class__.__name__}: {e}')
print(''.join(format_exception(None, e, e.__traceback__)))
self._caller_pipe.close()
return -1
class TwitchIRCProcess(ChatProcess):
WEBSOCKET_ADDRESS = 'wss://irc-ws.chat.twitch.tv:443'
def __init__(self, username, token, *args):
super().__init__(*args)
self._state_machine = self.bind_to_states(STATES)
self._username = username
self._token = token
self.state = STATES.DISCONNECTED
@property
def keybinds(self):
return {
ord('r'): {'type': CONTROL_MESSAGES.RESTART}
}
def loop(self, next_state):
return self._state_machine(self.state, next_state)
def on_state_enter(self, new_state):
status_messages = {
STATES.READING: 'Connected to channel!',
STATES.FAILURE: 'Connection closed - see terminal',
}
message = status_messages.get(new_state)
if message is not None:
self._message_queue.put({
'text': message,
'author_name': 'Twitch IRC Bot', 'author_id': self.__class__.__name__, 'author_type': AUTHOR_TYPES.SYSTEM,
})
def on_disconnected(self, next_state):
self._ws = NonBlockingWebsocket()
self._ws.connect(TwitchIRCProcess.WEBSOCKET_ADDRESS)
self._ws.start()
self._ws.send(f'PASS {self._token}')
self._ws.send(f'NICK {self._username}')
response = self._ws.recv()
if any('Welcome, GLHF!' in msg for msg in response.splitlines()):
self._ws.send(f'JOIN #{self._username.lower()}')
self._ws.send('CAP REQ :twitch.tv/tags')
# Not currently using the data we get back from these, so leaving it to READING state to ignore
return STATES.READING
else:
print(response)
return STATES.FAILURE
def on_reading(self, next_state):
if self._ws.poll(0.1):
messages = self._ws.recv()
for message in messages.splitlines():
cmd, hostmask, tags, args = ircv3_message_parser(message)
if cmd == 'PRIVMSG':
normalized_message = TwitchIRCProcess.normalize_message(hostmask, tags, args)
self._message_queue.put(normalized_message)
elif cmd == 'PING':
self._ws.send(f"PONG {' '.join(args)}")
else:
# HACK: ignoring quite a lot of messages rn
pass
return 0
def on_failure(self, next_state):
self._ws.terminate()
return None
@classmethod
def normalize_message(cls, hostmask, tags, args):
badges = [badge.split('/')[0] for badge in tags.get('badges', '').split(',')]
# 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 (:)
message = ' '.join(args[1:])[1:]
if 'broadcaster' in badges:
author_type = AUTHOR_TYPES.OWNER
elif any(target_badge in badges for target_badge in ['admin', 'moderator', 'global_mod']):
author_type = AUTHOR_TYPES.MODERATOR
elif 'subscriber' in badges:
author_type = AUTHOR_TYPES.PATRON
else:
author_type = AUTHOR_TYPES.USER
return {
'text': message,
'author_name': tags.get('display-name', hostmask[0]),
'author_id': tags.get('id'),
'author_type': author_type,
'author_color': tags.get('color'),
}

14
main.py
View File

@ -5,11 +5,14 @@ import time
from chats import YoutubeLive
from chats.ChatProcess import LIFECYCLE_MESSAGES
from chats.FakeChat import FakeChat
from chats.Twitch import TwitchIRCProcess
from ui.App import App
from plugins.PogCount import PogCounter
EVENT_POLL_FREQ = 0.1
GOOGLE_API_SECRETS_PATH = 'googleapi.secret.json'
TWITCH_SECRETS_PATH = 'twitch.secret.json'
if __name__ == '__main__':
chat_processes = [FakeChat(EVENT_POLL_FREQ)]
@ -18,7 +21,16 @@ if __name__ == '__main__':
client_secrets = json.load(f)['installed']
chat_processes.append(YoutubeLive.YoutubeLiveProcess(client_secrets, EVENT_POLL_FREQ))
else:
print('No client secrets - disabling youtube chat client. Hit "f" to enable a testing client')
print('No client secrets - disabling youtube chat client')
if os.path.exists(TWITCH_SECRETS_PATH):
with open(TWITCH_SECRETS_PATH ,'r') as f:
secrets = json.load(f)
chat_processes.append(TwitchIRCProcess(secrets.get('username'), secrets.get('oauth'), EVENT_POLL_FREQ))
else:
print('No twitch config - disabling twitch chat client')
if len(chat_processes) == 1:
print('Hit "f" with the window focused to enable a testing client')
plugins = [PogCounter('../live-status.txt', prefix='Pog count: ')]

View File

@ -1,4 +1,5 @@
from hashlib import md5
import re
import pygame
from pygame.locals import Rect
@ -8,6 +9,20 @@ from chats import AUTHOR_TYPES
from . import BG_COLOR, XTERM_COLORS
from .TextFragment import TextFragment
hex_color_regex = re.compile('^#[a-f0-9]{6}$')
def closest_xterm(target_color):
r, g, b = (int(target_color[i:i+2], 16) for i in range(1, len(target_color), 2))
distances = []
for xterm_color in XTERM_COLORS:
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
distances.append((distance, xterm_color))
return min(distances)[1]
class MessageView:
# TODO: Superchat and chat sponsor handling
@ -26,8 +41,12 @@ class MessageView:
author_id = message['author_id']
author_type = message['author_type']
author_hash = int(md5(author_id.encode('utf-8')).hexdigest(), 16)
author_color = (author_hash % 144) + 88
author_color = message.get('author_color')
if author_color is not None and hex_color_regex.match(author_color):
author_color = closest_xterm(author_color)
else:
author_hash = int(md5(author_id.encode('utf-8')).hexdigest(), 16)
author_color = (author_hash % 144) + 88
tag_fg = XTERM_COLORS[15]
tag_bg = BG_COLOR