add server code

This commit is contained in:
geoffrey45 2021-12-14 09:02:02 +03:00
parent 951d58623b
commit 803c813786
14 changed files with 1680 additions and 0 deletions

1
server/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vscode

23
server/Pipfile Normal file
View File

@ -0,0 +1,23 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask = "*"
tk = "*"
flask-cors = "*"
mutagen = "*"
pymongo = "*"
click = "*"
requests = "*"
watchdog = "*"
progress = "*"
pillow = "*"
[dev-packages]
autopep8 = "*"
ipykernel = "*"
[requires]
python_version = "3.8"

662
server/Pipfile.lock generated Normal file
View File

@ -0,0 +1,662 @@
{
"_meta": {
"hash": {
"sha256": "99f472c203bd38494cccddd96820194910b1693da8ea6ed6d4b141895ff3002e"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"certifi": {
"hashes": [
"sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872",
"sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"
],
"version": "==2021.10.8"
},
"charset-normalizer": {
"hashes": [
"sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721",
"sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"
],
"markers": "python_version >= '3'",
"version": "==2.0.9"
},
"click": {
"hashes": [
"sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
"sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"
],
"index": "pypi",
"version": "==8.0.3"
},
"flask": {
"hashes": [
"sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2",
"sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"
],
"index": "pypi",
"version": "==2.0.2"
},
"flask-cors": {
"hashes": [
"sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438",
"sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"
],
"index": "pypi",
"version": "==3.0.10"
},
"idna": {
"hashes": [
"sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
"sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"
],
"markers": "python_version >= '3'",
"version": "==3.3"
},
"itsdangerous": {
"hashes": [
"sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c",
"sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"
],
"version": "==2.0.1"
},
"jinja2": {
"hashes": [
"sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8",
"sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"
],
"version": "==3.0.3"
},
"markupsafe": {
"hashes": [
"sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
"sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
"sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
"sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194",
"sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
"sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
"sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724",
"sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
"sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646",
"sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
"sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6",
"sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a",
"sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6",
"sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad",
"sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
"sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38",
"sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac",
"sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
"sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6",
"sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047",
"sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
"sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
"sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b",
"sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
"sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
"sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a",
"sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
"sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1",
"sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9",
"sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864",
"sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
"sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee",
"sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f",
"sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
"sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
"sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
"sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
"sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b",
"sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
"sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86",
"sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6",
"sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
"sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
"sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
"sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28",
"sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e",
"sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
"sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
"sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f",
"sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d",
"sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
"sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
"sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145",
"sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
"sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c",
"sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1",
"sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a",
"sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207",
"sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
"sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53",
"sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd",
"sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134",
"sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85",
"sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9",
"sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
"sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
"sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
"sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
"sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
],
"version": "==2.0.1"
},
"mutagen": {
"hashes": [
"sha256:6397602efb3c2d7baebd2166ed85731ae1c1d475abca22090b7141ff5034b3e1",
"sha256:9c9f243fcec7f410f138cb12c21c84c64fde4195481a30c9bfb05b5f003adfed"
],
"index": "pypi",
"version": "==1.45.1"
},
"pillow": {
"hashes": [
"sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76",
"sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585",
"sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b",
"sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8",
"sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55",
"sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc",
"sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645",
"sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff",
"sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc",
"sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b",
"sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6",
"sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20",
"sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e",
"sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a",
"sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779",
"sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02",
"sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39",
"sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f",
"sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a",
"sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409",
"sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c",
"sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488",
"sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b",
"sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d",
"sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09",
"sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b",
"sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153",
"sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9",
"sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad",
"sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df",
"sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df",
"sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed",
"sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed",
"sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698",
"sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29",
"sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649",
"sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49",
"sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b",
"sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2",
"sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a",
"sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"
],
"index": "pypi",
"version": "==8.4.0"
},
"progress": {
"hashes": [
"sha256:c9c86e98b5c03fa1fe11e3b67c1feda4788b8d0fe7336c2ff7d5644ccfba34cd"
],
"index": "pypi",
"version": "==1.6"
},
"pymongo": {
"hashes": [
"sha256:0238e53b452ab699b5e2e3f8af2557844c80ab0d0c7a0e066226882838e72756",
"sha256:0271bbba36bb130202e011171c1883c4c193036ad0b1e02ecfbea6837790b7de",
"sha256:069d49b193f94bb1d748cfd8faf697060a2299f40d86bf5b6d41dd3cedf0fd48",
"sha256:06af6e6374ee2bb70f724e09ddf9402907a3d6714828b908737948cd83e5685c",
"sha256:0c77cd3dbe0dd9e7cdf8c93dc24e5a4fcb56e115ffb259d4f399e4aaf3f3c62d",
"sha256:0e9a2628bcd896368ede456bcfe189d9ca65b18fb0dd91974cb734baf2e24af9",
"sha256:12d336bdbe60982de55651be397b5e49d7eadd2aa144f11da353002cd52502ed",
"sha256:132cc67b909835d7c230888387b4cc9596d4559a3ce90d947e03bc0b0ffe420b",
"sha256:13d0624c13a91da71fa0d960205d93b3d98344481be865ee7cc238c972d41d73",
"sha256:1498f388181ae5592c7b60549faaefaffc62d6e3754097576611cb642d21d37b",
"sha256:1617fd52da7b208fe5ea176d251dd7cf1b5309e5a4272754b9599edfdf7e64e5",
"sha256:177ed1b14aa4f84f00ebef1b0f785680fbaa610361942b23eb54f562fe4c6b34",
"sha256:186b2ff4518c1c169fcef5047deb0e6c13a2354d143859587e745fd9f2cf68e9",
"sha256:1ba8eb426d56556fffec53d600a8f2572589c19d50b30f61daa8f4d72ab92fbe",
"sha256:1c153274699424e8f89f2097d5113f8cbe7898a8d62afaad0270a0f0bd0af53b",
"sha256:1fd71b4d7070b01c7f66edc44c1ec2f8bcace2761c3a6ecc10449a40e474d2fa",
"sha256:28afb00423e521f4b04fb8f75da7c0215e46631e821e27abf5a7176f9b671f47",
"sha256:349c8e522e0b785f442fc9d7fc01c59f7f13f1abe9395310d0d817cff03ec034",
"sha256:35a5843546bcbe0422f30b4b2bd5e0b630b04cc4006492c70e8168a921d94b9e",
"sha256:38b21eddd021a943b1978b0a3d42e974956a338e3dbb88d56aeb8b8799abd6e8",
"sha256:3a4eb0a4db8a2d960bdd5354f05e2e57530e83d333cb644fb2b7120a7a954a69",
"sha256:40269fe6bb79fe00c8ba7c2f2d542a82711eb234c3dedb90b7e489386120e9d1",
"sha256:426584e99af31ad2398e617c3eb0f1ebcda37f0ffb2d3e56087cdaf23a2f1689",
"sha256:47a58f15fc70198cf95982f9699e17fec12287b90f30e90c5e2b7c1c1bc07914",
"sha256:512059a902ea2cbcd0afac370af580e67ccd4c7e41ecaff0f0fbd03653b25ca2",
"sha256:51664dac8d9b138259876f324adca5ab31d991acf88d1d0ffcc94f423ff2e31b",
"sha256:59a4a5fe5379e4fa93380fd0b55bccbdbeb8d04fcfbbad8b42bd31610d5ed3ad",
"sha256:5cbfa85a12cfe3dca21951cd432051c505ac461bd9f4a635207d982dd9df2373",
"sha256:5fea4207fec8909e155a7948c987eac61949dbbe97fd0c388e587d06ba9bc78d",
"sha256:6183476860511cb553a7e4c40936221b6985af7852029c84df898370ec8a028c",
"sha256:62459b91a513a7b441cfd70ea7fd15c50b858877ca823915d32bab08fe173edb",
"sha256:633ca2001f80900142068bab907feca99554b557ac105c74a9ed157ed38ca5d6",
"sha256:65f8a93816dcb2202710839907759aca9eece94d9f13215686f224fcc8966f9e",
"sha256:686c40344f7f82c4deaa4e17aa46ad97df51263be1434aeedd2d6b6f38c7f44a",
"sha256:6cd7a4321e718cb98a7c7c475b0757e77fdaf1cdb013d7d2e781ba45219e1144",
"sha256:6f0605b1146bc24c720aac0e806492144aea9d5a4dc956589e0544301862756a",
"sha256:716499113650aacfe1b94d37e0a863f1e84b8d47737c74a2f44f8dfccad46952",
"sha256:71810eade75ae1c466adc158d1fa8141040f75427b76240316d97f3c89edd72f",
"sha256:72a0c06b76b254bdec18af9add3b8d35796dda51e64a5e0e48d40bff7b41ab13",
"sha256:7450b25a803b0f57dae4c3fbd0df742f7f3344c3c9cabb86e4180083c3ebd893",
"sha256:75e449ab068af63b7729195343315bc63d242166d88467314be182cc54ce235d",
"sha256:7629abba158610cb5db6c22041b287f9398555d72bf9468d44d2efc03d837b81",
"sha256:774b9f48bdc385af6654def31e7a7617e01b99cc8aaca1ab3ef6ea0492205e57",
"sha256:7a091050bb8d54a5200193b4998e0cf763d083f93d97c7780963c09996f85a38",
"sha256:7bdb66340e246b5dcddfcfe79a63ac2ec3808dc394853476f49fc785425040f4",
"sha256:812650a2e8a08b812d6a3c937f482bd2c9355e90574964fa283b4d8ef4ae665e",
"sha256:84eec41ed982f21ceb58689e16a630a70301eb14499c929388a5bf6464518d9d",
"sha256:86d0e28dd5867153d9d9963a4eb17764854a925758fc2db0a814260f82fd4319",
"sha256:87dce7c85387ca033cf76cce773ace7675550dcffc456db32a34403439e53e45",
"sha256:8869feff59f08cd63979df26aa12343a85bdc7fbd1b79fda8ae39f31a310fa62",
"sha256:8baf23d6a0a08b697854e5bcdf82afb91da732cf575fd47ee93945c3654132d8",
"sha256:8da525765dbcc1b7abf1bba623f9f701d8759a8fb19594cd71a13b7b0c2c56bd",
"sha256:9043bfb816ed50d831acc8d06469dcc41597b4f50c30e62227a93f9f9e37d6c7",
"sha256:91c049104b51321e4e18d41edc6850d9f0890ac609b3cb3b8db86dc51666de17",
"sha256:93c25fbb5dbc436edbb74101f4da49a42bd3af534513fdf8e75fc72ef035d5e0",
"sha256:953129b6b952a9d22042ac23050053444624f630e1928f5f590788660905fa9c",
"sha256:9ff0dbec451a2c6226bbd6f2bbbde438bc263e002f3f97d151c8708732ba5197",
"sha256:a47f4b24b1360da172cae07ce90e9bd425b6db0052d76142c7fef47173a27283",
"sha256:a57e271a0647002b5683dd0c7c2fd7f5fb939357c44396d85298e51a3561b9e3",
"sha256:b0606d14892ae2a2b1450e37c8924381e9b64683386a9853e4467f02fd5b44b6",
"sha256:b73ff8582964f52ab1bf1a9fdddc1454143172a0b8a9d7d6e3972dd1134f7982",
"sha256:bf6047dea1bc8ae19fc14e01b5cb70b3810f91b100d9a535751dd3eadcd3016c",
"sha256:c0efc5ab7d9b9e64726496bf650dbc7f1754124a48d076e5292cc5306e61a530",
"sha256:c86a0614eda95db036fae01a89f3917d7abdc657c806bac2a32eec74724d9330",
"sha256:c878286b1464f462616a47f315d14f02f03512c6b81cb568e996c3f1f79bff8a",
"sha256:cd4cde3dfdd347d638171eca53ee6e787d4b1247c6e182f8616039b1df6278d5",
"sha256:ceb9a4986f56595e73fffeef3ec037280eda938ed5fe6e4e0961656669d89b32",
"sha256:d419e2dbc4943ad6df7ee05e707d7b2c2b512b92407bb6ff643bccbdea399c3a",
"sha256:d66462f740dcea496bd779775688a0f805860f0b01998bb59ca22566b098ee26",
"sha256:d7514231a03e95072b32d9b335b96253799802ab94647ce83585d5010749380a",
"sha256:d9f61b08b60909d936c1f3a4e12c163ca71fd1a4665fc6e078afc6f54f886977",
"sha256:da576e59f5f8a642ee26d027479325a45be45defe075b6fa7c84506dabc76883",
"sha256:ddaf391ba74eef47eb5afbc40d0b6ddcdbdb417ec8edc8ae95352d25485076db",
"sha256:e2b6a323ca545bcb4286d14c0bd75d9a1f5bce2fa1d7fa3621e5f71fd9b8d196",
"sha256:e3f6faea65a73ed54111f209b4a411fe012c68f04e8bde96dd7af89b13cac92b",
"sha256:e4e36810c541bd1976cd05452e797860b775886cf32c3e8136b9fe48c2c8ba95",
"sha256:e5441f4c8142a250695e249e432637c14f79d856a2b60e0974da082e006c53e2",
"sha256:e7aedefc87cb46544a3865a19c1d5ca7ddf5ec5ed7dfe162d9538d7543aef499",
"sha256:ee2c1fd5bd57fd0092dfa31c1f9f166cf2850f191311603ce343cadcc8608d60",
"sha256:f2b6e12f98cce588525f3db802c88f9795d294549ebfe7c2c9bb81333f533ecd",
"sha256:f333c0d71dd892683e608f8d1731785a0aa67b1ec012b0d9fc863e8d7224f64e",
"sha256:f3e20eb096deea92350f7198a4287d45883a62fe4459d027ce789e72ceba12ee",
"sha256:f785375ca2b4e2192786f1e0d2a94c66900d12e780ebae1eccbbab85eb9a7054"
],
"index": "pypi",
"version": "==4.0.1"
},
"requests": {
"hashes": [
"sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24",
"sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"
],
"index": "pypi",
"version": "==2.26.0"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"version": "==1.16.0"
},
"tk": {
"hashes": [
"sha256:60bc8923d5d35f67f5c6bd93d4f0c49d2048114ec077768f959aef36d4ed97f8",
"sha256:703a69ff0d5ba2bd2f7440582ad10160e4a6561595d33457dc6caa79b9bf4930"
],
"index": "pypi",
"version": "==0.1.0"
},
"urllib3": {
"hashes": [
"sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
"sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
],
"version": "==1.26.7"
},
"watchdog": {
"hashes": [
"sha256:25fb5240b195d17de949588628fdf93032ebf163524ef08933db0ea1f99bd685",
"sha256:3386b367e950a11b0568062b70cc026c6f645428a698d33d39e013aaeda4cc04",
"sha256:3becdb380d8916c873ad512f1701f8a92ce79ec6978ffde92919fd18d41da7fb",
"sha256:4ae38bf8ba6f39d5b83f78661273216e7db5b00f08be7592062cb1fc8b8ba542",
"sha256:8047da932432aa32c515ec1447ea79ce578d0559362ca3605f8e9568f844e3c6",
"sha256:8f1c00aa35f504197561060ca4c21d3cc079ba29cf6dd2fe61024c70160c990b",
"sha256:922a69fa533cb0c793b483becaaa0845f655151e7256ec73630a1b2e9ebcb660",
"sha256:9693f35162dc6208d10b10ddf0458cc09ad70c30ba689d9206e02cd836ce28a3",
"sha256:a0f1c7edf116a12f7245be06120b1852275f9506a7d90227648b250755a03923",
"sha256:a36e75df6c767cbf46f61a91c70b3ba71811dfa0aca4a324d9407a06a8b7a2e7",
"sha256:aba5c812f8ee8a3ff3be51887ca2d55fb8e268439ed44110d3846e4229eb0e8b",
"sha256:ad6f1796e37db2223d2a3f302f586f74c72c630b48a9872c1e7ae8e92e0ab669",
"sha256:ae67501c95606072aafa865b6ed47343ac6484472a2f95490ba151f6347acfc2",
"sha256:b2fcf9402fde2672545b139694284dc3b665fd1be660d73eca6805197ef776a3",
"sha256:b52b88021b9541a60531142b0a451baca08d28b74a723d0c99b13c8c8d48d604",
"sha256:b7d336912853d7b77f9b2c24eeed6a5065d0a0cc0d3b6a5a45ad6d1d05fb8cd8",
"sha256:bd9ba4f332cf57b2c1f698be0728c020399ef3040577cde2939f2e045b39c1e5",
"sha256:be9be735f827820a06340dff2ddea1fb7234561fa5e6300a62fe7f54d40546a0",
"sha256:cca7741c0fcc765568350cb139e92b7f9f3c9a08c4f32591d18ab0a6ac9e71b6",
"sha256:d0d19fb2441947b58fbf91336638c2b9f4cc98e05e1045404d7a4cb7cddc7a65",
"sha256:e02794ac791662a5eafc6ffeaf9bcc149035a0e48eb0a9d40a8feb4622605a3d",
"sha256:e0f30db709c939cabf64a6dc5babb276e6d823fd84464ab916f9b9ba5623ca15",
"sha256:e92c2d33858c8f560671b448205a268096e17870dcf60a9bb3ac7bfbafb7f5f9"
],
"index": "pypi",
"version": "==2.1.6"
},
"werkzeug": {
"hashes": [
"sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f",
"sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"
],
"version": "==2.0.2"
}
},
"develop": {
"autopep8": {
"hashes": [
"sha256:44f0932855039d2c15c4510d6df665e4730f2b8582704fa48f9c55bd3e17d979",
"sha256:ed77137193bbac52d029a52c59bec1b0629b5a186c495f1eb21b126ac466083f"
],
"index": "pypi",
"version": "==1.6.0"
},
"backcall": {
"hashes": [
"sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e",
"sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"
],
"version": "==0.2.0"
},
"debugpy": {
"hashes": [
"sha256:01e98c594b3e66d529e40edf314f849cd1a21f7a013298df58cd8e263bf8e184",
"sha256:16db27b4b91991442f91d73604d32080b30de655aca9ba821b1972ea8171021b",
"sha256:17a25ce9d7714f92fc97ef00cc06269d7c2b163094990ada30156ed31d9a5030",
"sha256:194f95dd3e84568b5489aab5689a3a2c044e8fdc06f1890b8b4f70b6b89f2778",
"sha256:1ec3a086e14bba6c472632025b8fe5bdfbaef2afa1ebd5c6615ce6ed8d89bc67",
"sha256:23df67fc56d59e386c342428a7953c2c06cc226d8525b11319153e96afb65b0c",
"sha256:26fbe53cca45a608679094791ce587b6e2798acd1d4777a8b303b07622e85182",
"sha256:2b073ad5e8d8c488fbb6a116986858bab0c9c4558f28deb8832c7a5a27405bd6",
"sha256:318f81f37341e4e054b4267d39896b73cddb3612ca13b39d7eea45af65165e1d",
"sha256:3a457ad9c0059a21a6c7d563c1f18e924f5cf90278c722bd50ede6f56b77c7fe",
"sha256:4404a62fb5332ea5c8c9132290eef50b3a0ba38cecacad5529e969a783bcbdd7",
"sha256:5d76a4fd028d8009c3faf1185b4b78ceb2273dd2499447664b03939e0368bb90",
"sha256:70b422c63a833630c33e3f9cdbd9b6971f8c5afd452697e464339a21bbe862ba",
"sha256:82f5f9ce93af6861a0713f804e62ab390bb12a17f113153e47fea8bbb1dfbe36",
"sha256:a2aa64f6d2ca7ded8a7e8a4e7cae3bc71866b09876b7b05cecad231779cb9156",
"sha256:b2df2c373e85871086bd55271c929670cd4e1dba63e94a08d442db830646203b",
"sha256:b5b3157372e0e0a1297a8b6b5280bcf1d35a40f436c7973771c972726d1e32d5",
"sha256:d2b09e91fbd1efa4f4fda121d49af89501beda50c18ed7499712c71a4bf3452e",
"sha256:d876db8c312eeb02d85611e0f696abe66a2c1515e6405943609e725d5ff36f2a",
"sha256:f3a3dca9104aa14fd4210edcce6d9ce2b65bd9618c0b222135a40b9d6e2a9eeb",
"sha256:f73988422b17f071ad3c4383551ace1ba5ed810cbab5f9c362783d22d40a08dc"
],
"version": "==1.5.1"
},
"decorator": {
"hashes": [
"sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374",
"sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"
],
"version": "==5.1.0"
},
"entrypoints": {
"hashes": [
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
],
"version": "==0.3"
},
"ipykernel": {
"hashes": [
"sha256:3a227788216b43982d9ac28195949467627b0d16e6b8af9741d95dcaa8c41a89",
"sha256:82ded8919fa7f5483be2b6219c3b13380d93faab1fc49cc2cfcd10e9e24cc158"
],
"index": "pypi",
"version": "==6.6.0"
},
"ipython": {
"hashes": [
"sha256:cb6aef731bf708a7727ab6cde8df87f0281b1427d41e65d62d4b68934fa54e97",
"sha256:fc60ef843e0863dd4e24ab2bb5698f071031332801ecf8d1aeb4fb622056545c"
],
"version": "==7.30.1"
},
"jedi": {
"hashes": [
"sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d",
"sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"
],
"version": "==0.18.1"
},
"jupyter-client": {
"hashes": [
"sha256:64d93752d8cbfba0c1030c3335c3f0d9797cd1efac012652a14aac1653db11a3",
"sha256:a5f995a73cffb314ed262713ae6dfce53c6b8216cea9f332071b8ff44a6e1654"
],
"version": "==7.1.0"
},
"jupyter-core": {
"hashes": [
"sha256:1c091f3bbefd6f2a8782f2c1db662ca8478ac240e962ae2c66f0b87c818154ea",
"sha256:dce8a7499da5a53ae3afd5a9f4b02e5df1d57250cf48f3ad79da23b4778cd6fa"
],
"version": "==4.9.1"
},
"matplotlib-inline": {
"hashes": [
"sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee",
"sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"
],
"version": "==0.1.3"
},
"nest-asyncio": {
"hashes": [
"sha256:3fdd0d6061a2bb16f21fe8a9c6a7945be83521d81a0d15cff52e9edee50101d6",
"sha256:f969f6013a16fadb4adcf09d11a68a4f617c6049d7af7ac2c676110169a63abd"
],
"version": "==1.5.4"
},
"parso": {
"hashes": [
"sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0",
"sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"
],
"version": "==0.8.3"
},
"pexpect": {
"hashes": [
"sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937",
"sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"
],
"markers": "sys_platform != 'win32'",
"version": "==4.8.0"
},
"pickleshare": {
"hashes": [
"sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca",
"sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
],
"version": "==0.7.5"
},
"prompt-toolkit": {
"hashes": [
"sha256:1bb05628c7d87b645974a1bad3f17612be0c29fa39af9f7688030163f680bad6",
"sha256:e56f2ff799bacecd3e88165b1e2f5ebf9bcd59e80e06d395fa0cc4b8bd7bb506"
],
"version": "==3.0.24"
},
"ptyprocess": {
"hashes": [
"sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35",
"sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"
],
"version": "==0.7.0"
},
"pycodestyle": {
"hashes": [
"sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20",
"sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"
],
"version": "==2.8.0"
},
"pygments": {
"hashes": [
"sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380",
"sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"
],
"version": "==2.10.0"
},
"python-dateutil": {
"hashes": [
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
],
"version": "==2.8.2"
},
"pyzmq": {
"hashes": [
"sha256:08c4e315a76ef26eb833511ebf3fa87d182152adf43dedee8d79f998a2162a0b",
"sha256:0ca6cd58f62a2751728016d40082008d3b3412a7f28ddfb4a2f0d3c130f69e74",
"sha256:1621e7a2af72cced1f6ec8ca8ca91d0f76ac236ab2e8828ac8fe909512d566cb",
"sha256:18cd854b423fce44951c3a4d3e686bac8f1243d954f579e120a1714096637cc0",
"sha256:2841997a0d85b998cbafecb4183caf51fd19c4357075dfd33eb7efea57e4c149",
"sha256:2b97502c16a5ec611cd52410bdfaab264997c627a46b0f98d3f666227fd1ea2d",
"sha256:3a4c9886d61d386b2b493377d980f502186cd71d501fffdba52bd2a0880cef4f",
"sha256:3c1895c95be92600233e476fe283f042e71cf8f0b938aabf21b7aafa62a8dac9",
"sha256:42abddebe2c6a35180ca549fadc7228d23c1e1f76167c5ebc8a936b5804ea2df",
"sha256:468bd59a588e276961a918a3060948ae68f6ff5a7fa10bb2f9160c18fe341067",
"sha256:480b9931bfb08bf8b094edd4836271d4d6b44150da051547d8c7113bf947a8b0",
"sha256:53f4fd13976789ffafedd4d46f954c7bb01146121812b72b4ddca286034df966",
"sha256:62bcade20813796c426409a3e7423862d50ff0639f5a2a95be4b85b09a618666",
"sha256:67db33bea0a29d03e6eeec55a8190e033318cee3cbc732ba8fd939617cbf762d",
"sha256:6b217b8f9dfb6628f74b94bdaf9f7408708cb02167d644edca33f38746ca12dd",
"sha256:7661fc1d5cb73481cf710a1418a4e1e301ed7d5d924f91c67ba84b2a1b89defd",
"sha256:76c532fd68b93998aab92356be280deec5de8f8fe59cd28763d2cc8a58747b7f",
"sha256:79244b9e97948eaf38695f4b8e6fc63b14b78cc37f403c6642ba555517ac1268",
"sha256:7c58f598d9fcc52772b89a92d72bf8829c12d09746a6d2c724c5b30076c1f11d",
"sha256:7dc09198e4073e6015d9a8ea093fc348d4e59de49382476940c3dd9ae156fba8",
"sha256:80e043a89c6cadefd3a0712f8a1322038e819ebe9dbac7eca3bce1721bcb63bf",
"sha256:851977788b9caa8ed011f5f643d3ee8653af02c5fc723fa350db5125abf2be7b",
"sha256:8eddc033e716f8c91c6a2112f0a8ebc5e00532b4a6ae1eb0ccc48e027f9c671c",
"sha256:902319cfe23366595d3fa769b5b751e6ee6750a0a64c5d9f757d624b2ac3519e",
"sha256:954e73c9cd4d6ae319f1c936ad159072b6d356a92dcbbabfd6e6204b9a79d356",
"sha256:ab888624ed68930442a3f3b0b921ad7439c51ba122dbc8c386e6487a658e4a4e",
"sha256:acebba1a23fb9d72b42471c3771b6f2f18dcd46df77482612054bd45c07dfa36",
"sha256:b4ebed0977f92320f6686c96e9e8dd29eed199eb8d066936bac991afc37cbb70",
"sha256:badb868fff14cfd0e200eaa845887b1011146a7d26d579aaa7f966c203736b92",
"sha256:be4e0f229cf3a71f9ecd633566bd6f80d9fa6afaaff5489492be63fe459ef98c",
"sha256:c0f84360dcca3481e8674393bdf931f9f10470988f87311b19d23cda869bb6b7",
"sha256:c1e41b32d6f7f9c26bc731a8b529ff592f31fc8b6ef2be9fa74abd05c8a342d7",
"sha256:c88fa7410e9fc471e0858638f403739ee869924dd8e4ae26748496466e27ac59",
"sha256:cf98fd7a6c8aaa08dbc699ffae33fd71175696d78028281bc7b832b26f00ca57",
"sha256:d072f7dfbdb184f0786d63bda26e8a0882041b1e393fbe98940395f7fab4c5e2",
"sha256:d1b5d457acbadcf8b27561deeaa386b0217f47626b29672fa7bd31deb6e91e1b",
"sha256:d3dcb5548ead4f1123851a5ced467791f6986d68c656bc63bfff1bf9e36671e2",
"sha256:d6157793719de168b199194f6b6173f0ccd3bf3499e6870fac17086072e39115",
"sha256:d728b08448e5ac3e4d886b165385a262883c34b84a7fe1166277fe675e1c197a",
"sha256:de8df0684398bd74ad160afdc2a118ca28384ac6f5e234eb0508858d8d2d9364",
"sha256:e6a02cf7271ee94674a44f4e62aa061d2d049001c844657740e156596298b70b",
"sha256:ea12133df25e3a6918718fbb9a510c6ee5d3fdd5a346320421aac3882f4feeea",
"sha256:ea5a79e808baef98c48c884effce05c31a0698c1057de8fc1c688891043c1ce1",
"sha256:f43b4a2e6218371dd4f41e547bd919ceeb6ebf4abf31a7a0669cd11cd91ea973",
"sha256:f762442bab706fd874064ca218b33a1d8e40d4938e96c24dafd9b12e28017f45",
"sha256:f89468059ebc519a7acde1ee50b779019535db8dcf9b8c162ef669257fef7a93",
"sha256:f907c7359ce8bf7f7e63c82f75ad0223384105f5126f313400b7e8004d9b33c3"
],
"version": "==22.3.0"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"version": "==1.16.0"
},
"toml": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"version": "==0.10.2"
},
"tornado": {
"hashes": [
"sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb",
"sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c",
"sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288",
"sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95",
"sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558",
"sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe",
"sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791",
"sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d",
"sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326",
"sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b",
"sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4",
"sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c",
"sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910",
"sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5",
"sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c",
"sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0",
"sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675",
"sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd",
"sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f",
"sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c",
"sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea",
"sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6",
"sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05",
"sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd",
"sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575",
"sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a",
"sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37",
"sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795",
"sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f",
"sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32",
"sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c",
"sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01",
"sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4",
"sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2",
"sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921",
"sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085",
"sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df",
"sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102",
"sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5",
"sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68",
"sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"
],
"version": "==6.1"
},
"traitlets": {
"hashes": [
"sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7",
"sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033"
],
"version": "==5.1.1"
},
"wcwidth": {
"hashes": [
"sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784",
"sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"
],
"version": "==0.2.5"
}
}
}

17
server/app/__init__.py Normal file
View File

@ -0,0 +1,17 @@
from flask import Flask
from flask_cors import CORS
def create_app():
app = Flask(__name__)
CORS(app)
from . import api
app.register_blueprint(api.bp, url_prefix='/')
return app
if __name__ == '__main__':
app = create_app()
app.run(debug=True)

Binary file not shown.

335
server/app/api.py Normal file
View File

@ -0,0 +1,335 @@
import os
from re import sub
import requests
import urllib
import time
from progress.bar import Bar
from mutagen.flac import MutagenError
from flask import Blueprint, request, send_from_directory
from app.models import AllSongs, Folders, Artists
from app.configs import default_configs
from app.helpers import (
all_songs_instance,
convert_one_to_json,
getTags,
convert_to_json,
remove_duplicates,
save_image,
isValidFile,
create_config_dir,
extract_thumb,
home_dir, app_dir,
run_fast_scandir
)
bp = Blueprint('api', __name__, url_prefix='')
artist_instance = Artists()
folder_instance = Folders()
def main_whatever():
create_config_dir()
main_whatever()
@bp.route('/search')
def search_by_title():
if not request.args.get('q'):
query = "mexican girl"
else:
query = request.args.get('q')
songs = all_songs_instance.find_song_by_title(query)
all_songs = convert_to_json(songs)
albums = all_songs_instance.find_songs_by_album(query)
all_songs.append(convert_to_json(albums))
artists = all_songs_instance.find_songs_by_artist(query)
all_songs.append(convert_to_json(artists))
songs = remove_duplicates(all_songs)
return {'songs': songs}
@bp.route('/populate')
def populate():
sub_dirs, files = run_fast_scandir(home_dir, [".flac", ".mp3"])
bar = Bar('Processing', max=len(files))
for file in files:
file_in_db_obj = all_songs_instance.find_song_by_path(file)
song_obj = convert_one_to_json(file_in_db_obj)
try:
image = song_obj['image']
except:
image = None
if image is None:
try:
getTags(file)
except MutagenError:
pass
if image is not None and not os.path.exists(image):
extract_thumb(file)
bar.next()
bar.finish()
# dirs = []
# files = []
# for dir in sub_dirs:
# files_in_dir = run_fast_scandir(dir, [".flac", ".mp3"])[1]
# if len(files_in_dir) != 0:
# dir_content = os.scandir(dir)
# for entry in dir_content:
# dirs = []
# files = []
# if entry.is_dir() and not entry.name.startswith('.'):
# print(dir)
# files_in_dir = run_fast_scandir(entry.path, [".flac", ".mp3"])[1]
# if len(files_in_dir) != 0:
# dir_data = {
# "name": entry.name,
# "count": len(files_in_dir),
# "path": entry.path.replace(home_dir, "")
# }
# dirs.append(dir_data)
# if entry.is_file():
# if isValidFile(entry.name) == True:
# files.append(entry.path)
# print(dirs)
# return {"info": ''}
@bp.route('/file/<file_id>')
def send_audio(file_id):
song_obj = all_songs_instance.get_song_by_id(file_id)
loaded_song = convert_one_to_json(song_obj)
filepath = loaded_song['filepath'].split('/')[-1]
print(loaded_song['folder'] + filepath)
return send_from_directory(home_dir + loaded_song['folder'], filepath)
@bp.route("/folder/artists")
def get_folder_artists():
dir = request.args.get('dir')
songs = all_songs_instance.find_songs_by_folder(dir)
songs_array = convert_to_json(songs)
without_duplicates = remove_duplicates(songs_array)
artists = []
for song in without_duplicates:
this_artists = song['artists'].split(', ')
for artist in this_artists:
if artist not in artists:
artists.append(artist)
final_artists = []
for artist in artists[:15]:
artist_obj = artist_instance.find_artists_by_name(artist)
if artist_obj != []:
final_artists.append(convert_to_json(artist_obj))
return {'artists': final_artists}
@bp.route("/populate/images")
def populate_images():
all_songs = all_songs_instance.get_all_songs()
songs_array = convert_to_json(all_songs)
remove_duplicates(songs_array)
artists = []
for song in songs_array:
this_artists = song['artists'].split(', ')
for artist in this_artists:
if artist not in artists:
artists.append(artist)
bar = Bar('Processing images', max=len(artists))
for artist in artists:
file_path = app_dir + '/images/artists/' + artist + '.jpg'
if not os.path.exists(file_path):
url = 'https://api.deezer.com/search/artist?q={}'.format(artist)
response = requests.get(url)
data = response.json()
try:
image_path = data['data'][0]['picture_xl']
except:
image_path = None
if image_path is not None:
try:
save_image(image_path, file_path)
artist_obj = {
'name': artist
}
artist_instance.insert_artist(artist_obj)
except:
pass
else:
pass
bar.next()
bar.finish()
artists_in_db = artist_instance.get_all_artists()
artists_in_db_array = convert_to_json(artists_in_db)
return {'sample': artists_in_db_array[:25]}
@bp.route("/artist")
def getArtistData():
artist = urllib.parse.unquote(request.args.get('q'))
artist_obj = artist_instance.find_artists_by_name(artist)
artist_obj_json = convert_to_json(artist_obj)
def getArtistSongs():
songs = all_songs_instance.find_songs_by_artist(artist)
songs_array = convert_to_json(songs)
return songs_array
artist_songs = getArtistSongs()
songs = remove_duplicates(artist_songs)
def getArtistAlbums():
artist_albums = []
albums_with_count = []
albums = all_songs_instance.find_songs_by_album_artist(artist)
albums_array = convert_to_json(albums)
for song in songs:
song['artists'] = song['artists'].split(', ')
for song in albums_array:
if song['album'] not in artist_albums:
artist_albums.append(song['album'])
for album in artist_albums:
count = 0
length = 0
for song in artist_songs:
if song['album'] == album:
count = count + 1
length = length + song['length']
album_ = {
"title": album,
"count": count,
"length": length
}
albums_with_count.append(album_)
return albums_with_count
return {'artist': artist_obj_json, 'songs': songs, 'albums': getArtistAlbums()}
@bp.route("/")
def getFolderTree():
start = time.time()
req_dir = request.args.get('f')
if req_dir is not None:
requested_dir = home_dir + req_dir
else:
requested_dir = home_dir
dir_content = os.scandir(requested_dir)
folders = []
files = []
for entry in dir_content:
if entry.is_dir() and not entry.name.startswith('.'):
files_in_dir = run_fast_scandir(entry.path, [".flac", ".mp3"])[1]
if len(files_in_dir) != 0:
dir = {
"name": entry.name,
"count": len(files_in_dir),
"path": entry.path.replace(home_dir, "")
}
folders.append(dir)
if entry.is_file():
if isValidFile(entry.name) == True:
songs_array = all_songs_instance.find_songs_by_folder(req_dir)
songs = convert_to_json(songs_array)
for song in songs:
song['artists'] = song['artists'].split(', ')
files = songs
for file in files:
del file['filepath']
dir_content.close()
end = time.time()
print(end - start)
return {"requested": req_dir, "files": files[:25], "folders": folders}
@bp.route('/image/<img_type>/<image_id>')
def send_image(img_type, image_id):
if img_type == "thumbnail":
song_obj = all_songs_instance.get_song_by_id(image_id)
loaded_song = convert_one_to_json(song_obj)
img_dir = app_dir + "/images/thumbnails"
image = loaded_song['image']
if img_type == "artist":
artist_obj = artist_instance.get_artist_by_id(image_id)
artist = convert_one_to_json(artist_obj)
img_dir = app_dir + "/images/artists"
image = artist['name'] + ".jpg"
print(img_dir + image)
return send_from_directory(img_dir, image)

6
server/app/configs.py Normal file
View File

@ -0,0 +1,6 @@
default_configs = {
"dirs": [
"/home/cwilvx/Music/",
"/home/cwilvx/FreezerMusic"
]
}

262
server/app/helpers.py Normal file
View File

@ -0,0 +1,262 @@
from genericpath import exists
import os
import json
import requests
import urllib
from mutagen.mp3 import MP3
from mutagen.id3 import ID3
from mutagen.flac import FLAC
from bson import json_util
from io import BytesIO
from PIL import Image
from app.models import AllSongs
from app.configs import default_configs
all_songs_instance = AllSongs()
music_dir = os.environ.get("music_dir")
music_dirs = os.environ.get("music_dirs")
home_dir = os.path.expanduser('~')
app_dir = home_dir + '/.shit'
PORT = os.environ.get("PORT")
def run_fast_scandir(dir, ext):
subfolders = []
files = []
for f in os.scandir(dir):
if f.is_dir() and not f.name.startswith('.'):
subfolders.append(f.path)
if f.is_file():
if os.path.splitext(f.name)[1].lower() in ext:
files.append(f.path)
for dir in list(subfolders):
sf, f = run_fast_scandir(dir, ext)
subfolders.extend(sf)
files.extend(f)
return subfolders, files
def extract_thumb(path):
img_path = app_dir + "/images/thumbnails/" + path.split('/')[-1] + '.jpg'
if os.path.exists(img_path):
return path.split('/')[-1] + '.jpg'
if path.endswith('.flac'):
audio = FLAC(path)
try:
album_art = audio.pictures[0].data
except IndexError:
album_art = None
elif path.endswith('.mp3'):
audio = ID3(path)
try:
album_art = audio.getall('APIC')[0].data
except IndexError:
album_art = None
if album_art is not None:
img = Image.open(BytesIO(album_art))
try:
img.save(img_path, 'JPEG')
except OSError:
try:
img.convert('RGB'.save(img_path, 'JPEG'))
except:
img_path = None
return path.split('/')[-1] + '.jpg'
def getTags(full_path):
if full_path.endswith('.flac'):
audio = FLAC(full_path)
elif full_path.endswith('.mp3'):
audio = MP3(full_path)
try:
artists = audio['artist'][0]
except KeyError:
try:
artists = audio['TPE1'][0]
except:
artists = 'Unknown'
except IndexError:
artists = 'Unknown'
try:
album_artist = audio['albumartist'][0]
except KeyError:
try:
album_artist = audio['TPE2'][0]
except:
album_artist = 'Unknown'
except IndexError:
album_artist = 'Unknown'
try:
title = audio['title'][0]
except KeyError:
try:
title = audio['TIT2'][0]
except:
title = 'Unknown'
except IndexError:
title = 'Unknown'
try:
album = audio['album'][0]
except KeyError:
try:
album = audio['TALB'][0]
except:
album = "Unknown"
except IndexError:
album = "Unknown"
try:
genre = audio['genre'][0]
except KeyError:
try:
genre = audio['TCON'][0]
except:
genre = "Unknown"
except IndexError:
genre = "Unknown"
img_path = extract_thumb(full_path)
tags = {
"filepath": full_path,
"folder": os.path.dirname(full_path).replace(home_dir, ""),
"title": title,
"artists": artists,
"album_artist": album_artist,
"album": album,
"genre": genre,
"length": round(audio.info.length),
"bitrate": audio.info.bitrate,
"image": img_path
}
all_songs_instance.insert_song(tags)
return tags
def convert_one_to_json(song):
json_song = json.dumps(song, default=json_util.default)
loaded_song = json.loads(json_song)
return loaded_song
def convert_to_json(array):
songs = []
for song in array:
json_song = json.dumps(song, default=json_util.default)
loaded_song = json.loads(json_song)
songs.append(loaded_song)
return songs
def get_folders():
folders = []
for dir in default_configs['dirs']:
entry = os.scandir(dir)
folders.append(entry)
def remove_duplicates(array):
return array
def save_image(url, path):
response = requests.get(url)
img = Image.open(BytesIO(response.content))
img.save(path, 'JPEG')
def isValidFile(filename):
if filename.endswith('.flac') or filename.endswith('.mp3'):
return True
else:
return False
def isValidAudioFrom(folder):
folder_content = os.scandir(folder)
files = []
for entry in folder_content:
if isValidFile(entry.name) == True:
file = {
"path": entry.path,
"name": entry.name
}
files.append(file)
return files
def getFolderContents(filepath, folder):
folder_name = urllib.parse.unquote(folder)
path = filepath
name = filepath.split('/')[-1]
tags = {}
if name.endswith('.flac'):
image_path = folder_name + '/.thumbnails/' + \
name.replace('.flac', '.jpg')
audio = FLAC(path)
if name.endswith('.mp3'):
image_path = folder_name + '/.thumbnails/' + \
name.replace('.mp3', '.jpg')
audio = MP3(path)
abslt_path = urllib.parse.quote(path.replace(music_dir, ''))
if os.path.exists(image_path):
img_url = 'http://localhost:{}/{}'.format(
PORT,
urllib.parse.quote(image_path.replace(music_dir, ''))
)
try:
audio_url = 'http://localhost:{}/{}'.format(
PORT, abslt_path
)
tags = getTags(audio_url, audio, img_url, folder_name)
except:
pass
return tags
def create_config_dir():
home_dir = os.path.expanduser('~')
config_folder = home_dir + "/.shit"
dirs = ["", "/images", "/images/artists", "/images/thumbnails"]
for dir in dirs:
if not os.path.exists(config_folder + dir):
os.makedirs(config_folder + dir)

82
server/app/models.py Normal file
View File

@ -0,0 +1,82 @@
import pymongo
from bson import ObjectId
class Mongo:
def __init__(self, database):
mongo_uri = pymongo.MongoClient()
self.db = mongo_uri[database]
class Folders(Mongo):
def __init__(self):
super(Folders, self).__init__('LOCAL_FOLDERS')
self.collection = self.db['LOCAL_FOLDERS']
def insert_folder(self, folder):
self.collection.insert_one(folder)
def find_folder(self, folder_id):
return self.collection.find_one({'_id': ObjectId(folder_id)})
class Artists(Mongo):
def __init__(self):
super(Artists, self).__init__('ALL_ARTISTS')
self.collection = self.db['THEM_ARTISTS']
def insert_artist(self, artist_obj):
self.collection.update(artist_obj, artist_obj, upsert=True)
def get_all_artists(self):
return self.collection.find()
def get_artist_by_id(self, artist_id):
return self.collection.find_one({'_id': ObjectId(artist_id)})
def find_artists_by_name(self, query):
return self.collection.find({'name': {'$regex': query, '$options': 'i'}})
class AllSongs(Mongo):
def __init__(self):
super(AllSongs, self).__init__('ALL_SONGS')
self.collection = self.db['ALL_SONGS']
# def drop_db(self):
# self.collection.drop()
def get_song_by_id(self, file_id):
return self.collection.find_one({'_id': ObjectId(file_id)})
def insert_song(self, song_obj):
self.collection.update({'filepath': song_obj['filepath']}, song_obj, upsert=True)
def find_song_by_title(self, query):
self.collection.create_index([('title', pymongo.TEXT)])
return self.collection.find({'title': {'$regex': query, '$options': 'i'}})
def find_songs_by_album(self, query):
return self.collection.find({'album': {'$regex': query, '$options': 'i'}})
def get_all_songs(self):
return self.collection.find()
def find_songs_by_folder(self, query):
return self.collection.find({'folder': query})
def find_songs_by_artist(self, query):
return self.collection.find({'artists': {'$regex': query, '$options': 'i'}})
def find_songs_by_album_artist(self, query):
return self.collection.find({'album_artist': {'$regex': query, '$options': 'i'}})
def find_song_by_path(self, path):
return self.collection.find_one({'filepath': path})
def remove_song_by_filepath(self, filepath):
try:
self.collection.remove({'filepath': filepath})
return True
except:
return False

58
server/app/watchdoge.py Normal file
View File

@ -0,0 +1,58 @@
import time
import os
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
class OnMyWatch:
watchDirectory = "/home/cwilvx/Music"
def __init__(self):
self.observer = Observer()
def run(self):
event_handler = Handler()
self.observer.schedule(
event_handler, self.watchDirectory, recursive=True)
self.observer.start()
try:
while True:
time.sleep(5)
except:
self.observer.stop()
print("Observer Stopped")
self.observer.join()
def create_thumb_dir(filepath):
f_name = filepath.split('/')[-1]
parent_dir = filepath.replace(f_name, '')
thumb_dir = parent_dir + ".thumbnails"
if not os.path.exists(thumb_dir):
os.makedirs(thumb_dir)
class Handler(PatternMatchingEventHandler):
def __init__(self):
PatternMatchingEventHandler.__init__(
self, patterns=['*.flac', '*.mp3'], ignore_directories=True, case_sensitive=False)
def on_created(self, event):
print(event.src_path)
create_thumb_dir(event.src_path)
def on_deleted(self, event):
print(event.src_path)
def on_moved(self, event):
print(event.src_path)
print(event.dest_path)
if __name__ == '__main__':
watch = OnMyWatch()
watch.run()

63
server/roadmap.md Normal file
View File

@ -0,0 +1,63 @@
# Fixes !
- [ ] Use click event to play song instead of url ⚠
- [ ] Show play/pause button correctly according to state ⚠
- [ ] Click on artist image to go to artist page ⚠
- [ ] Play next song if current song can't be loaded ⚠
- [ ] List item song icon for long song titles ⚠
<!-- -->
- [ ] Broken CSS
- [ ] Prevent scanning unchanged folders
- [ ] Handle '/' and '&' characters in song artists
- [ ] Nginx not serving all files in a folder
- [ ] Removing song duplicates from queries
- [ ] Different songs having same link
- [ ] ConnectionError
- [ ] Move thumbnails to .config
- [ ] Write a multithreaded file server
- [ ] Add support for WAV files
- [ ] Support multiple folders
- [ ] Compress thumbnails
# Features +
## Needed features
- [ ] Seeking current song
- [ ] Adding songs to queue
- [ ] Implement search on frontend
<!-- -->
- [ ] Watching for changes in folders and updating them instantly ⚠
- [ ] Display folders and files in a tree view. ⚠ 🔵
<!-- -->
- [ ] Add favicon
- [ ] Add keyboard shortcuts
- [ ] Right click on song to do stuff
- [ ] Adjust volume
- [ ] Add listening statistics for all songs
- [ ] Extract color from artist image [for use with artist card gradient]
- [ ] Adding songs to favorites
- [ ] Adding songs to playlist
- [ ] Playing song radio
## Future features
- [ ] Toggle shuffle
- [ ] Toggle repeat
- [ ] Display artist albums
- [ ] Suggest similar artists
- [ ] Getting artist info
- [ ] Getting album info
- [ ] Create a Python script to build, bundle and serve the app
- [ ] Getting extra song info (probably from genius)
- [ ] Getting lyrics
- [ ] Notifications
- [ ] Sorting songs
- [ ] Suggest undiscorvered artists, albums and songs
- [ ] Remember last played song
- [ ] Add next and previous song transition and progress bar reset animations
- [ ] Hover animations for list items
- [ ] Highlight currently playing song in playlist
- [ ] Add functionality to 'Listen now' button
- [ ] Add a 'Scan' button to the sidebar
- [ ] Paginated requests for songs
- [ ] Package app as installable PWA
## Finished ✅

10
server/start.sh Executable file
View File

@ -0,0 +1,10 @@
export PORT=8000
export music_dir="/home/cwilvx/Music/"
export FLASK_APP=app
export FLASK_DEBUG=1
export FLASK_RUN_PORT=8008
# export music_dirs="['/home/cwilvx/Music/', '/home/cwilvx/FreezerMusic']"
flask run

29
server/test.py Normal file
View File

@ -0,0 +1,29 @@
import os
def fast_scandir(dirname):
subfolders= [f.path for f in os.scandir(dirname) if f.is_dir()]
for dirname in list(subfolders):
subfolders.extend(fast_scandir(dirname))
return subfolders
list = fast_scandir('/home/cwilvx/Music')
def remove_rejects(folders):
rejects = []
for item in folders:
if item.find(".thumbnails") != -1:
rejects.append(item)
if len(os.listdir(item)) == 0 and item not in rejects:
rejects.append(item)
for item in rejects:
folders.remove(item)
print(len(folders))
remove_rejects(list)

View File

@ -0,0 +1,132 @@
import os, sys, logging, time
from io import BytesIO
from pathlib import Path
import PIL
from watchdog import observers
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler, FileSystemEventHandler
from mutagen.mp3 import MP3, MutagenError
from mutagen.id3 import ID3
from mutagen.flac import FLAC
from PIL import Image
music_dir = "/home/cwilvx/Music/"
folders = os.listdir(music_dir)
def updateThumbnails():
start_time = time.time()
print("Updating thumbnails ...")
for folder in folders:
print(folder)
try:
dir = music_dir + folder
thumbnail_folder = dir + "/"+ ".thumbnails"
if not os.path.exists(thumbnail_folder):
os.makedirs(thumbnail_folder)
def thumbnail_extractor(type, song):
if type == "mp3":
tags = ID3(song)
image_path = "{}/.thumbnails/{}".format(dir, song.name.replace(".mp3", ".jpg"))
album_art = tags.getall('APIC')[0].data
elif type == "flac":
tags = FLAC(song)
image_path = "{}/.thumbnails/{}".format(dir, song.name.replace(".flac", ".jpg"))
album_art = tags.pictures[0].data
else:
print("Unsupported file type")
return
image = Image.open(BytesIO(album_art))
if not os.path.exists(image_path):
try:
image.save(image_path, 'JPEG')
except OSError:
image.convert('RGB').save(image_path, 'JPEG')
for song in Path(dir).rglob('*.mp3'):
try:
thumbnail_extractor("mp3", song)
except (MutagenError, IndexError):
pass
for song in Path(dir).rglob('*.flac'):
try:
thumbnail_extractor("flac", song)
except (MutagenError, IndexError):
pass
except NotADirectoryError:
pass
print("done")
print("Done in: %s seconds" % round((time.time() - start_time), 1))
class watchMusicDirs(FileSystemEventHandler):
def __init__(self, logger=None):
super().__init__()
self.logger = logger or logging.root
# def on_moved(self, event):
# super().on_moved(event)
# what = 'directory' if event.is_directory else 'file'
# self.logger.info("Moved %s: from %s to %s", what, event.src_path,
# event.dest_path)
# def on_created(self, event):
# super().on_created(event)
# what = 'directory' if event.is_directory else 'file'
# self.logger.info("Created %s: %s", what, event.src_path)
# def on_deleted(self, event):
# super().on_deleted(event)
# what = 'directory' if event.is_directory else 'file'
# self.logger.info("Deleted %s: %s", what, event.src_path)
def on_modified(self, event):
super().on_modified(event)
what = 'directory' if event.is_directory else 'file'
# self.logger.info("Modified %s: %s", what, event.src_path)
print("Modified %s: %s" % (what, event.src_path))
updateThumbnails()
paths = [music_dir, '/home/cwilvx/watched']
if __name__ == "__main__":
observer = Observer()
event_handler = watchMusicDirs()
observers = []
for path in paths:
observer.schedule(event_handler, path, recursive=True)
observers.append(observer)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
for observer in observers:
observer.unschedule_all()
observer.stop()
for observer in observers:
observer.join()